From 68656b4a4dfb83bfecb456ed39f8624fc427717a Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Wed, 18 Aug 2021 10:33:47 +1000 Subject: [PATCH] chore: Prune old contracts (#304) Prune exchange-libs deploy migrations at specific address remove exchange-libs, moving LibMath into Utils Remove staking order-utils multisig and remaining asset-proxy --- README.md | 45 +- contracts/README.md | 13 - contracts/TESTING.md | 48 - contracts/asset-proxy/.npmignore | 10 - contracts/asset-proxy/.solhintignore | 2 - contracts/asset-proxy/CHANGELOG.json | 904 ----- contracts/asset-proxy/CHANGELOG.md | 362 -- contracts/asset-proxy/DEPLOYS.json | 47 - contracts/asset-proxy/README.md | 73 - contracts/asset-proxy/compiler.json | 27 - .../archive/MixinAssetProxyDispatcher.sol | 172 - .../contracts/archive/MixinAuthorizable.sol | 117 - .../asset-proxy/contracts/archive/Ownable.sol | 33 - .../contracts/src/ERC1155Proxy.sol | 97 - .../contracts/src/ERC20BridgeProxy.sol | 126 - .../asset-proxy/contracts/src/ERC20Proxy.sol | 184 -- .../asset-proxy/contracts/src/ERC721Proxy.sol | 171 - .../contracts/src/MultiAssetProxy.sol | 335 -- .../contracts/src/StaticCallProxy.sol | 83 - .../contracts/src/bridges/BalancerBridge.sol | 103 - .../contracts/src/bridges/BancorBridge.sol | 144 - .../contracts/src/bridges/ChaiBridge.sol | 75 - .../contracts/src/bridges/CreamBridge.sol | 103 - .../contracts/src/bridges/CryptoComBridge.sol | 136 - .../contracts/src/bridges/CurveBridge.sol | 119 - .../contracts/src/bridges/DODOBridge.sol | 147 - .../src/bridges/DexForwarderBridge.sol | 200 -- .../contracts/src/bridges/DydxBridge.sol | 242 -- .../contracts/src/bridges/Eth2DaiBridge.sol | 98 - .../contracts/src/bridges/KyberBridge.sol | 169 - .../contracts/src/bridges/MStableBridge.sol | 94 - .../contracts/src/bridges/MixinGasToken.sol | 55 - .../contracts/src/bridges/MooniswapBridge.sol | 148 - .../contracts/src/bridges/ShellBridge.sol | 95 - .../contracts/src/bridges/SnowSwapBridge.sol | 119 - .../contracts/src/bridges/SushiSwapBridge.sol | 136 - .../contracts/src/bridges/SwerveBridge.sol | 119 - .../contracts/src/bridges/UniswapBridge.sol | 220 -- .../contracts/src/bridges/UniswapV2Bridge.sol | 135 - .../contracts/src/interfaces/IAssetData.sol | 88 - .../contracts/src/interfaces/IAssetProxy.sol | 43 - .../src/interfaces/IAssetProxyDispatcher.sol | 43 - .../src/interfaces/IAuthorizable.sol | 64 - .../src/interfaces/IBalancerPool.sol | 39 - .../src/interfaces/IBancorNetwork.sol | 38 - .../contracts/src/interfaces/IChai.sol | 66 - .../contracts/src/interfaces/ICurve.sol | 70 - .../contracts/src/interfaces/IDydx.sol | 192 -- .../contracts/src/interfaces/IDydxBridge.sol | 42 - .../contracts/src/interfaces/IERC20Bridge.sol | 59 - .../contracts/src/interfaces/IEth2Dai.sol | 38 - .../contracts/src/interfaces/IGasToken.sol | 40 - .../src/interfaces/IKyberNetworkProxy.sol | 72 - .../contracts/src/interfaces/IMStable.sol | 32 - .../contracts/src/interfaces/IMooniswap.sol | 40 - .../contracts/src/interfaces/IShell.sol | 34 - .../src/interfaces/IUniswapExchange.sol | 70 - .../interfaces/IUniswapExchangeFactory.sol | 32 - .../src/interfaces/IUniswapV2Router01.sol | 40 - .../contracts/test/TestBancorBridge.sol | 247 -- .../contracts/test/TestChaiBridge.sol | 80 - .../contracts/test/TestDexForwarderBridge.sol | 244 -- .../contracts/test/TestDydxBridge.sol | 246 -- .../contracts/test/TestERC20Bridge.sol | 108 - .../contracts/test/TestEth2DaiBridge.sol | 206 -- .../contracts/test/TestKyberBridge.sol | 355 -- .../contracts/test/TestStaticCallTarget.sol | 82 - .../contracts/test/TestUniswapBridge.sol | 436 --- .../contracts/test/TestUniswapV2Bridge.sol | 253 -- contracts/asset-proxy/package.json | 99 - contracts/asset-proxy/src/artifacts.ts | 127 - contracts/asset-proxy/src/asset_data.ts | 112 - .../asset-proxy/src/dex_forwarder_bridge.ts | 27 - .../asset-proxy/src/dydx_bridge_encoder.ts | 40 - .../asset-proxy/src/erc1155_proxy_wrapper.ts | 410 --- contracts/asset-proxy/src/erc20_wrapper.ts | 164 - contracts/asset-proxy/src/erc721_wrapper.ts | 220 -- contracts/asset-proxy/src/index.ts | 93 - contracts/asset-proxy/src/wrappers.ts | 64 - contracts/asset-proxy/test/artifacts.ts | 127 - contracts/asset-proxy/test/authorizable.ts | 128 - contracts/asset-proxy/test/bancor_bridge.ts | 185 -- contracts/asset-proxy/test/chai_bridge.ts | 60 - contracts/asset-proxy/test/dydx_bridge.ts | 399 --- contracts/asset-proxy/test/erc1155_proxy.ts | 1849 ----------- .../asset-proxy/test/erc20bridge_proxy.ts | 287 -- contracts/asset-proxy/test/eth2dai_bridge.ts | 191 -- contracts/asset-proxy/test/global_hooks.ts | 19 - contracts/asset-proxy/test/kyber_bridge.ts | 284 -- contracts/asset-proxy/test/proxies.ts | 1557 --------- .../asset-proxy/test/static_call_proxy.ts | 245 -- contracts/asset-proxy/test/uniswap_bridge.ts | 370 --- .../asset-proxy/test/uniswapv2_bridge.ts | 216 -- contracts/asset-proxy/test/wrappers.ts | 64 - contracts/asset-proxy/truffle-config.js | 96 - contracts/asset-proxy/tsconfig.json | 126 - contracts/asset-proxy/tslint.json | 6 - contracts/asset-proxy/typedoc-tsconfig.json | 7 - contracts/broker/.npmignore | 10 - contracts/broker/CHANGELOG.json | 373 --- contracts/broker/CHANGELOG.md | 170 - contracts/broker/DEPLOYS.json | 1 - contracts/broker/README.md | 73 - contracts/broker/compiler.json | 27 - contracts/broker/contracts/src/Broker.sol | 314 -- .../contracts/src/interfaces/IBroker.sol | 101 - .../src/interfaces/IGodsUnchained.sol | 33 - .../src/interfaces/IPropertyValidator.sol | 35 - .../src/libs/LibBrokerRichErrors.sol | 109 - .../src/validators/GodsUnchainedValidator.sol | 61 - .../contracts/test/TestGodsUnchained.sol | 55 - contracts/broker/package.json | 97 - contracts/broker/src/artifacts.ts | 23 - contracts/broker/src/gods_unchained_utils.ts | 62 - contracts/broker/src/index.ts | 32 - contracts/broker/src/wrappers.ts | 12 - contracts/broker/test/artifacts.ts | 23 - .../test/gods_unchained_validator_test.ts | 56 - contracts/broker/test/wrappers.ts | 12 - contracts/broker/truffle-config.js | 96 - contracts/broker/tsconfig.json | 22 - contracts/broker/tslint.json | 6 - contracts/broker/typedoc-tsconfig.json | 7 - contracts/coordinator/.npmignore | 10 - contracts/coordinator/.solhintignore | 2 - contracts/coordinator/CHANGELOG.json | 720 ---- contracts/coordinator/CHANGELOG.md | 301 -- contracts/coordinator/DEPLOYS.json | 1 - contracts/coordinator/README.md | 73 - contracts/coordinator/compiler.json | 26 - .../coordinator/contracts/src/Coordinator.sol | 45 - .../src/MixinCoordinatorApprovalVerifier.sol | 195 -- .../contracts/src/MixinCoordinatorCore.sol | 72 - .../contracts/src/MixinSignatureValidator.sol | 142 - .../ICoordinatorApprovalVerifier.sol | 51 - .../src/interfaces/ICoordinatorCore.sol | 42 - .../ICoordinatorSignatureValidator.sol | 45 - .../contracts/src/libs/LibConstants.sol | 36 - .../src/libs/LibCoordinatorApproval.sol | 98 - .../src/libs/LibCoordinatorRichErrors.sol | 87 - .../src/libs/LibEIP712CoordinatorDomain.sol | 66 - .../src/registry/CoordinatorRegistry.sol | 32 - .../registry/MixinCoordinatorRegistryCore.sol | 49 - .../interfaces/ICoordinatorRegistryCore.sol | 42 - contracts/coordinator/package.json | 102 - contracts/coordinator/src/approval_factory.ts | 31 - contracts/coordinator/src/artifacts.ts | 21 - contracts/coordinator/src/client/index.ts | 820 ----- .../coordinator/src/client/utils/assert.ts | 18 - .../client/utils/coordinator_server_types.ts | 57 - .../src/client/utils/decorators.ts | 133 - contracts/coordinator/src/hash_utils.ts | 15 - contracts/coordinator/src/index.ts | 67 - contracts/coordinator/src/types.ts | 17 - contracts/coordinator/src/wrappers.ts | 11 - contracts/coordinator/test/artifacts.ts | 37 - .../coordinator/test/coordinator_registry.ts | 73 - contracts/coordinator/test/global_hooks.ts | 19 - contracts/coordinator/test/libs.ts | 52 - contracts/coordinator/test/mixins.ts | 534 --- contracts/coordinator/test/wrappers.ts | 19 - contracts/coordinator/truffle-config.js | 96 - contracts/coordinator/tsconfig.json | 28 - contracts/coordinator/tslint.json | 6 - contracts/coordinator/typedoc-tsconfig.json | 7 - contracts/dev-utils/.npmignore | 10 - contracts/dev-utils/CHANGELOG.json | 665 ---- contracts/dev-utils/CHANGELOG.md | 280 -- contracts/dev-utils/DEPLOYS.json | 1 - contracts/dev-utils/README.md | 73 - contracts/dev-utils/compiler.json | 27 - .../dev-utils/contracts/src/Addresses.sol | 54 - .../dev-utils/contracts/src/AssetBalance.sol | 388 --- .../dev-utils/contracts/src/DevUtils.sol | 84 - .../contracts/src/EthBalanceChecker.sol | 39 - .../contracts/src/ExternalFunctions.sol | 322 -- .../dev-utils/contracts/src/LibAssetData.sol | 354 -- .../contracts/src/LibDydxBalance.sol | 436 --- .../src/LibOrderTransferSimulation.sol | 227 -- .../contracts/src/LibTransactionDecoder.sol | 188 -- .../src/OrderTransferSimulationUtils.sol | 233 -- .../contracts/src/OrderValidationUtils.sol | 279 -- .../dev-utils/contracts/test/TestDydx.sol | 181 - .../contracts/test/TestLibDydxBalance.sol | 116 - contracts/dev-utils/package.json | 73 - contracts/dev-utils/src/artifacts.ts | 19 - contracts/dev-utils/src/index.ts | 31 - contracts/dev-utils/src/wrappers.ts | 10 - contracts/dev-utils/test/artifacts.ts | 35 - .../dev-utils/test/lib_dydx_balance_test.ts | 1170 ------- contracts/dev-utils/test/wrappers.ts | 18 - contracts/dev-utils/truffle-config.js | 96 - contracts/dev-utils/tsconfig.json | 26 - contracts/dev-utils/tslint.json | 6 - contracts/dev-utils/typedoc-tsconfig.json | 7 - contracts/erc1155/.npmignore | 10 - contracts/erc1155/CHANGELOG.json | 623 ---- contracts/erc1155/CHANGELOG.md | 277 -- contracts/erc1155/DEPLOYS.json | 1 - contracts/erc1155/README.md | 73 - contracts/erc1155/compiler.json | 27 - contracts/erc1155/contracts/src/ERC1155.sol | 248 -- .../erc1155/contracts/src/ERC1155Mintable.sol | 219 -- .../contracts/src/MixinNonFungibleToken.sol | 73 - .../contracts/src/interfaces/IERC1155.sol | 153 - .../src/interfaces/IERC1155Mintable.sol | 61 - .../src/interfaces/IERC1155Receiver.sol | 68 - .../contracts/test/DummyERC1155Receiver.sol | 126 - contracts/erc1155/package.json | 93 - contracts/erc1155/src/artifacts.ts | 17 - contracts/erc1155/src/erc1155_wrapper.ts | 155 - contracts/erc1155/src/index.ts | 43 - contracts/erc1155/src/wrappers.ts | 9 - contracts/erc1155/test/artifacts.ts | 23 - contracts/erc1155/test/erc1155_token.ts | 459 --- contracts/erc1155/test/global_hooks.ts | 19 - contracts/erc1155/test/wrappers.ts | 12 - contracts/erc1155/truffle-config.js | 96 - contracts/erc1155/tsconfig.json | 19 - contracts/erc1155/tslint.json | 6 - contracts/erc1155/typedoc-tsconfig.json | 7 - contracts/erc721/.npmignore | 10 - contracts/erc721/.solhintignore | 3 - contracts/erc721/CHANGELOG.json | 700 ---- contracts/erc721/CHANGELOG.md | 312 -- contracts/erc721/DEPLOYS.json | 1 - contracts/erc721/README.md | 73 - contracts/erc721/compiler.json | 27 - .../erc721/contracts/src/ERC721Token.sol | 278 -- .../contracts/src/MintableERC721Token.sol | 85 - .../src/interfaces/IERC721Receiver.sol | 44 - .../contracts/src/interfaces/IERC721Token.sol | 158 - .../contracts/test/DummyERC721Receiver.sol | 67 - .../contracts/test/DummyERC721Token.sol | 63 - .../contracts/test/InvalidERC721Receiver.sol | 66 - contracts/erc721/package.json | 93 - contracts/erc721/src/artifacts.ts | 17 - contracts/erc721/src/index.ts | 38 - contracts/erc721/src/wrappers.ts | 9 - contracts/erc721/test/artifacts.ts | 23 - contracts/erc721/test/erc721_token.ts | 282 -- contracts/erc721/test/global_hooks.ts | 19 - contracts/erc721/test/wrappers.ts | 12 - contracts/erc721/truffle-config.js | 96 - contracts/erc721/tsconfig.json | 19 - contracts/erc721/tslint.json | 6 - contracts/erc721/typedoc-tsconfig.json | 7 - contracts/exchange-forwarder/.npmignore | 10 - contracts/exchange-forwarder/CHANGELOG.json | 721 ---- contracts/exchange-forwarder/CHANGELOG.md | 318 -- contracts/exchange-forwarder/DEPLOYS.json | 32 - contracts/exchange-forwarder/README.md | 73 - contracts/exchange-forwarder/compiler.json | 27 - .../contracts/src/Forwarder.sol | 275 -- .../contracts/src/MixinExchangeWrapper.sol | 581 ---- .../contracts/src/MixinReceiver.sol | 76 - .../contracts/src/interfaces/IExchangeV2.sol | 75 - .../contracts/src/interfaces/IForwarder.sol | 95 - .../src/libs/LibForwarderRichErrors.sol | 110 - .../contracts/test/TestForwarder.sol | 63 - contracts/exchange-forwarder/package.json | 101 - contracts/exchange-forwarder/src/artifacts.ts | 10 - contracts/exchange-forwarder/src/index.ts | 32 - contracts/exchange-forwarder/src/wrappers.ts | 7 - .../exchange-forwarder/test/artifacts.ts | 23 - .../exchange-forwarder/test/asset_test.ts | 374 --- contracts/exchange-forwarder/test/wrappers.ts | 12 - .../exchange-forwarder/truffle-config.js | 96 - contracts/exchange-forwarder/tsconfig.json | 17 - contracts/exchange-forwarder/tslint.json | 6 - .../exchange-forwarder/typedoc-tsconfig.json | 7 - contracts/exchange-libs/.npmignore | 10 - contracts/exchange-libs/CHANGELOG.json | 925 ------ contracts/exchange-libs/CHANGELOG.md | 367 -- contracts/exchange-libs/README.md | 69 - contracts/exchange-libs/compiler.json | 27 - .../exchange-libs/contracts/src/IWallet.sol | 38 - .../contracts/src/LibEIP712ExchangeDomain.sol | 54 - .../contracts/src/LibExchangeRichErrors.sol | 614 ---- .../contracts/src/LibFillResults.sol | 426 --- .../exchange-libs/contracts/src/LibOrder.sol | 174 - .../contracts/src/LibZeroExTransaction.sol | 109 - .../test/TestLibEIP712ExchangeDomain.sol | 36 - .../contracts/test/TestLibFillResults.sol | 85 - .../contracts/test/TestLibOrder.sol | 44 - .../test/TestLibZeroExTransaction.sol | 44 - contracts/exchange-libs/package.json | 96 - contracts/exchange-libs/src/artifacts.ts | 23 - contracts/exchange-libs/src/index.ts | 43 - .../exchange-libs/src/reference_functions.ts | 256 -- contracts/exchange-libs/src/wrappers.ts | 12 - contracts/exchange-libs/test/artifacts.ts | 35 - contracts/exchange-libs/test/global_hooks.ts | 29 - .../test/lib_eip712_exchange_domain.ts | 53 - .../exchange-libs/test/lib_fill_results.ts | 1930 ----------- contracts/exchange-libs/test/lib_order.ts | 154 - .../test/lib_zero_ex_transaction.ts | 137 - .../exchange-libs/test/reference_functions.ts | 328 -- contracts/exchange-libs/test/utils/index.ts | 1 - contracts/exchange-libs/test/utils/schema.ts | 24 - contracts/exchange-libs/test/wrappers.ts | 18 - contracts/exchange-libs/truffle-config.js | 96 - contracts/exchange-libs/tsconfig.json | 28 - contracts/exchange-libs/tslint.json | 6 - contracts/exchange/.npmignore | 10 - contracts/exchange/CHANGELOG.json | 1136 ------- contracts/exchange/CHANGELOG.md | 422 --- contracts/exchange/DEPLOYS.json | 17 - contracts/exchange/README.md | 73 - contracts/exchange/compiler.json | 27 - contracts/exchange/contracts/src/Exchange.sol | 45 - .../src/MixinAssetProxyDispatcher.sol | 136 - .../contracts/src/MixinExchangeCore.sol | 499 --- .../contracts/src/MixinMatchOrders.sol | 543 --- .../contracts/src/MixinProtocolFees.sol | 197 -- .../contracts/src/MixinSignatureValidator.sol | 625 ---- .../contracts/src/MixinTransactions.sol | 221 -- .../contracts/src/MixinTransferSimulator.sol | 60 - .../contracts/src/MixinWrapperFunctions.sol | 353 -- .../contracts/src/interfaces/IAssetProxy.sol | 43 - .../src/interfaces/IAssetProxyDispatcher.sol | 43 - .../contracts/src/interfaces/IEIP1271Data.sol | 48 - .../src/interfaces/IEIP1271Wallet.sol | 38 - .../contracts/src/interfaces/IExchange.sol | 42 - .../src/interfaces/IExchangeCore.sol | 98 - .../contracts/src/interfaces/IMatchOrders.sol | 102 - .../src/interfaces/IProtocolFees.sol | 51 - .../src/interfaces/ISignatureValidator.sol | 130 - .../src/interfaces/ITransactions.sol | 63 - .../src/interfaces/ITransferSimulator.sol | 43 - .../contracts/src/interfaces/IWallet.sol | 38 - .../src/interfaces/IWrapperFunctions.sol | 150 - .../src/libs/LibExchangeRichErrorDecoder.sol | 356 -- .../contracts/test/IsolatedExchange.sol | 86 - .../contracts/test/ReentrancyTester.sol | 201 -- .../test/TestAssetProxyDispatcher.sol | 41 - .../contracts/test/TestExchangeInternals.sol | 130 - .../contracts/test/TestFillRounding.sol | 61 - .../test/TestLibExchangeRichErrorDecoder.sol | 270 -- .../test/TestProtocolFeeCollector.sol | 69 - .../contracts/test/TestProtocolFees.sol | 74 - .../test/TestProtocolFeesReceiver.sol | 347 -- .../contracts/test/TestTransactions.sol | 123 - .../contracts/test/TestValidatorWallet.sol | 228 -- .../contracts/test/TestWrapperFunctions.sol | 128 - contracts/exchange/package.json | 104 - contracts/exchange/src/artifacts.ts | 10 - .../exchange/src/exchange_data_encoder.ts | 52 - contracts/exchange/src/index.ts | 51 - contracts/exchange/src/wrappers.ts | 7 - contracts/exchange/test/artifacts.ts | 79 - contracts/exchange/test/codesize.ts | 16 - contracts/exchange/test/dispatcher.ts | 386 --- .../test/exchange_transfer_simulator_test.ts | 153 - contracts/exchange/test/fill_order.ts | 678 ---- contracts/exchange/test/global_hooks.ts | 19 - contracts/exchange/test/internal.ts | 637 ---- .../exchange/test/isolated_fill_order.ts | 608 ---- .../test/lib_exchange_rich_error_decoder.ts | 152 - contracts/exchange/test/protocol_fees.ts | 254 -- .../exchange/test/protocol_fees_manager.ts | 138 - contracts/exchange/test/reentrancy_tests.ts | 125 - .../exchange/test/reference_functions.ts | 225 -- .../exchange/test/signature_validator.ts | 1292 -------- .../exchange/test/transactions_unit_tests.ts | 703 ---- ...act_balance_and_proxy_allowance_fetcher.ts | 23 - ..._balance_and_proxy_allowance_lazy_store.ts | 11 - ...abstract_order_filled_cancelled_fetcher.ts | 15 - ...tract_order_filled_cancelled_lazy_store.ts | 10 - ...set_balance_and_proxy_allowance_fetcher.ts | 20 - .../exchange/test/utils/asset_wrapper.ts | 366 -- contracts/exchange/test/utils/constants.ts | 16 - .../test/utils/dependency_artifacts.ts | 9 - .../test/utils/exchange_transfer_simulator.ts | 161 - .../exchange/test/utils/exchange_wrapper.ts | 356 -- .../utils/fill_order_combinatorial_utils.ts | 1040 ------ .../test/utils/fill_order_scenarios.ts | 95 - .../test/utils/fill_order_simulator.ts | 163 - .../test/utils/isolated_exchange_wrapper.ts | 177 - .../test/utils/order_factory_from_scenario.ts | 506 --- ...set_balance_and_proxy_allowance_fetcher.ts | 19 - ...c20_balance_and_proxy_allowance_fetcher.ts | 27 - .../balance_and_proxy_allowance_lazy_store.ts | 119 - .../order_filled_cancelled_lazy_store.ts | 90 - contracts/exchange/test/utils/types.ts | 48 - contracts/exchange/test/wrapper_unit_tests.ts | 1280 ------- contracts/exchange/test/wrappers.ts | 40 - contracts/exchange/truffle-config.js | 96 - contracts/exchange/tsconfig.json | 45 - contracts/exchange/tslint.json | 9 - contracts/exchange/typedoc-tsconfig.json | 7 - contracts/extensions/.npmignore | 10 - contracts/extensions/CHANGELOG.json | 789 ----- contracts/extensions/CHANGELOG.md | 343 -- contracts/extensions/DEPLOYS.json | 1 - contracts/extensions/README.md | 73 - contracts/extensions/compiler.json | 27 - .../contracts/src/LibAssetDataTransfer.sol | 258 -- .../contracts/src/MaximumGasPrice.sol | 50 - .../contracts/src/MixinWethUtils.sol | 135 - .../LibAssetDataTransferRichErrors.sol | 58 - .../rich-errors/LibWethUtilsRichErrors.sol | 91 - contracts/extensions/package.json | 102 - contracts/extensions/src/artifacts.ts | 19 - contracts/extensions/src/index.ts | 32 - .../extensions/src/max_gas_price_utils.ts | 38 - contracts/extensions/src/wrappers.ts | 10 - contracts/extensions/test/artifacts.ts | 19 - .../extensions/test/max_gas_price_test.ts | 89 - contracts/extensions/test/wrappers.ts | 10 - contracts/extensions/truffle-config.js | 96 - contracts/extensions/tsconfig.json | 18 - contracts/extensions/tslint.json | 6 - contracts/extensions/typedoc-tsconfig.json | 7 - contracts/integrations/.npmignore | 10 - contracts/integrations/CHANGELOG.json | 348 -- contracts/integrations/CHANGELOG.md | 146 - contracts/integrations/README.md | 65 - contracts/integrations/compiler.json | 27 - .../contracts/src/ChainlinkStopLimit.sol | 50 - .../src/interfaces/IChainlinkAggregator.sol | 30 - .../test/TestChainlinkAggregator.sol | 43 - .../contracts/test/TestContractWrapper.sol | 60 - .../contracts/test/TestDydxUser.sol | 207 -- .../contracts/test/TestEth2Dai.sol | 59 - .../contracts/test/TestEth2DaiBridge.sol | 44 - .../test/TestFixinProtocolFeesIntegration.sol | 39 - .../contracts/test/TestFramework.sol | 47 - .../test/TestMainnetAggregatorFills.sol | 180 - .../test/TestSignatureValidationWallet.sol | 53 - .../contracts/test/TestStaking.sol | 110 - .../contracts/test/TestUniswapBridge.sol | 57 - .../contracts/test/TestUniswapExchange.sol | 109 - .../test/TestUniswapExchangeFactory.sol | 52 - .../contracts/test/TestWethIntegration.sol | 24 - contracts/integrations/package.json | 119 - contracts/integrations/src/artifacts.ts | 9 - contracts/integrations/src/chainlink_utils.ts | 58 - contracts/integrations/src/index.ts | 3 - contracts/integrations/src/wrappers.ts | 6 - contracts/integrations/test/artifacts.ts | 41 - .../test/benchmarks/chai_bridge_test.ts | 199 -- .../test/benchmarks/dydx_bridge_test.ts | 267 -- .../test/bridges/abi/dydxEvents.ts | 1002 ------ .../bridges/balancer_bridge_mainnet_test.ts | 103 - .../test/bridges/curve_bridge_mainnet_test.ts | 132 - .../test/bridges/deploy_dydx_bridge.ts | 22 - .../test/bridges/deploy_eth2dai_bridge.ts | 31 - .../test/bridges/deploy_uniswap_bridge.ts | 51 - .../test/bridges/dydx_bridge_mainnet_test.ts | 159 - .../integrations/test/broker/broker_test.ts | 741 ----- .../test/coordinator/client_test.ts | 648 ---- .../test/coordinator/coordinator_test.ts | 399 --- .../test/coordinator/deploy_coordinator.ts | 23 - .../integrations/test/deployment_test.ts | 412 --- .../test/dev-utils/dev_utils_mainnet_test.ts | 78 - .../dev-utils/dydx_order_validation_test.ts | 452 --- .../test/dev-utils/get_order_hash.ts | 57 - .../test/dev-utils/global_hooks.ts | 19 - .../test/dev-utils/lib_asset_data.ts | 554 ---- .../test/dev-utils/lib_transaction_decoder.ts | 141 - .../test/dev-utils/order_validation_utils.ts | 655 ---- .../test/exchange/batch_match_orders_test.ts | 880 ----- .../integrations/test/exchange/core_test.ts | 1154 ------- .../test/exchange/exchange_wrapper_test.ts | 1090 ------ .../test/exchange/fill_dydx_order_test.ts | 284 -- .../test/exchange/fill_order_test.ts | 360 -- .../test/exchange/fill_order_wrapper.ts | 220 -- .../test/exchange/match_order_tester.ts | 1004 ------ .../match_orders_maximal_fill_test.ts | 1076 ------ .../test/exchange/match_orders_test.ts | 1083 ------ .../exchange/transaction_protocol_fee_test.ts | 499 --- .../test/exchange/transaction_test.ts | 806 ----- .../test/forwarder/bridge_test.ts | 362 -- .../test/forwarder/deploy_forwarder.ts | 23 - .../test/forwarder/forwarder_mainnet_test.ts | 212 -- .../test/forwarder/forwarder_test.ts | 788 ----- .../test/forwarder/forwarder_test_factory.ts | 335 -- .../integrations/test/forwarder/types.ts | 22 - .../test/framework/actors/base.ts | 155 - .../test/framework/actors/fee_recipient.ts | 62 - .../test/framework/actors/hybrids.ts | 13 - .../test/framework/actors/keeper.ts | 162 - .../test/framework/actors/maker.ts | 247 -- .../test/framework/actors/pool_operator.ts | 151 - .../test/framework/actors/staker.ts | 274 -- .../test/framework/actors/taker.ts | 176 - .../test/framework/actors/tslint.json | 8 - .../test/framework/actors/utils.ts | 26 - .../framework/assertions/createStakingPool.ts | 91 - .../decreaseStakingPoolOperatorShare.ts | 68 - .../test/framework/assertions/endEpoch.ts | 166 - .../test/framework/assertions/fillOrder.ts | 149 - .../test/framework/assertions/finalizePool.ts | 221 -- .../assertions/function_assertion.ts | 111 - .../assertions/generic_assertions.ts | 24 - .../framework/assertions/joinStakingPool.ts | 43 - .../test/framework/assertions/matchOrders.ts | 78 - .../assertions/matchOrdersWithMaximalFill.ts | 27 - .../test/framework/assertions/moveStake.ts | 223 -- .../test/framework/assertions/stake.ts | 85 - .../test/framework/assertions/unstake.ts | 110 - .../assertions/withdrawDelegatorRewards.ts | 97 - .../test/framework/balances/balance_store.ts | 151 - .../balances/blockchain_balance_store.ts | 139 - .../framework/balances/local_balance_store.ts | 255 -- .../test/framework/balances/types.ts | 51 - .../test/framework/deployment_manager.ts | 538 --- .../integrations/test/framework/simulation.ts | 81 - .../tests/deployment_manager_test.ts | 181 - .../tests/function_assertion_test.ts | 134 - .../framework/utils/assert_protocol_fee.ts | 118 - .../test/framework/utils/logger.ts | 55 - .../test/framework/utils/pseudorandom.ts | 98 - .../framework/utils/verify_match_events.ts | 151 - .../framework/utils/wrapper_interfaces.ts | 21 - .../exchange_signature_validation_test.ts | 736 ----- .../test/fuzz_tests/match_orders_test.ts | 83 - .../test/fuzz_tests/pool_management_test.ts | 61 - .../test/fuzz_tests/pool_membership_test.ts | 88 - .../test/fuzz_tests/stake_management_test.ts | 90 - .../test/fuzz_tests/staking_rewards_test.ts | 128 - .../integrations/test/fuzz_tests/tslint.json | 7 - .../integrations/test/mainnet_configs_test.ts | 207 -- .../test/mainnet_contract_wrapper_test.ts | 53 - .../integrations/test/mainnet_fork_utils.ts | 14 - .../stop-limit/chainlink_stop_limit_test.ts | 192 -- contracts/integrations/test/wrappers.ts | 21 - .../zero-ex/protocol_fees_staking_test.ts | 85 - contracts/integrations/tsconfig.json | 24 - contracts/integrations/tslint.json | 9 - contracts/multisig/.npmignore | 10 - contracts/multisig/CHANGELOG.json | 746 ----- contracts/multisig/CHANGELOG.md | 332 -- contracts/multisig/DEPLOYS.json | 17 - contracts/multisig/README.md | 69 - contracts/multisig/compiler.json | 27 - .../multisig/contracts/src/MultiSigWallet.sol | 462 --- .../src/MultiSigWalletWithTimeLock.sol | 124 - .../multisig/contracts/src/ZeroExGovernor.sol | 220 -- .../contracts/test/ContractCallReceiver.sol | 51 - .../contracts/test/TestRejectEther.sol | 23 - .../contracts/test/TestZeroExGovernor.sol | 78 - contracts/multisig/package.json | 89 - contracts/multisig/src/artifacts.ts | 13 - contracts/multisig/src/index.ts | 2 - contracts/multisig/src/wrappers.ts | 7 - contracts/multisig/test/artifacts.ts | 21 - contracts/multisig/test/global_hooks.ts | 19 - .../multisig/test/multi_sig_with_time_lock.ts | 324 -- contracts/multisig/test/utils/index.ts | 2 - .../multisig/test/utils/multi_sig_wrapper.ts | 56 - .../test/utils/zero_ex_governor_wrapper.ts | 55 - contracts/multisig/test/wrappers.ts | 11 - contracts/multisig/test/zero_ex_governor.ts | 671 ---- contracts/multisig/truffle-config.js | 96 - contracts/multisig/tsconfig.json | 16 - contracts/multisig/tslint.json | 6 - contracts/staking/.npmignore | 10 - contracts/staking/CHANGELOG.json | 703 ---- contracts/staking/CHANGELOG.md | 269 -- contracts/staking/DEPLOYS.json | 1 - contracts/staking/README.md | 85 - contracts/staking/compiler.json | 27 - contracts/staking/contracts/src/Staking.sol | 46 - .../staking/contracts/src/StakingPatch.sol | 55 - .../staking/contracts/src/StakingProxy.sol | 208 -- contracts/staking/contracts/src/ZrxVault.sol | 252 -- .../contracts/src/fees/MixinExchangeFees.sol | 178 - .../src/fees/MixinExchangeManager.sol | 72 - .../src/immutable/MixinConstants.sol | 32 - .../immutable/MixinDeploymentConstants.sol | 76 - .../contracts/src/immutable/MixinStorage.sol | 118 - .../contracts/src/interfaces/IStaking.sol | 251 -- .../src/interfaces/IStakingEvents.sol | 131 - .../src/interfaces/IStakingProxy.sol | 55 - .../contracts/src/interfaces/IStorage.sol | 87 - .../contracts/src/interfaces/IStorageInit.sol | 27 - .../contracts/src/interfaces/IStructs.sol | 93 - .../contracts/src/interfaces/IZrxVault.sol | 104 - .../contracts/src/libs/LibCobbDouglas.sol | 96 - .../contracts/src/libs/LibFixedMath.sol | 391 --- .../src/libs/LibFixedMathRichErrors.sol | 97 - .../contracts/src/libs/LibSafeDowncast.sol | 77 - .../src/libs/LibStakingRichErrors.sol | 323 -- .../contracts/src/stake/MixinStake.sol | 237 -- .../src/stake/MixinStakeBalances.sol | 109 - .../contracts/src/stake/MixinStakeStorage.sol | 187 -- .../staking_pools/MixinCumulativeRewards.sol | 199 -- .../src/staking_pools/MixinStakingPool.sol | 193 -- .../staking_pools/MixinStakingPoolRewards.sol | 333 -- .../contracts/src/sys/MixinAbstract.sol | 46 - .../contracts/src/sys/MixinFinalizer.sol | 255 -- .../staking/contracts/src/sys/MixinParams.sol | 158 - .../contracts/src/sys/MixinScheduler.sol | 98 - .../test/TestAssertStorageParams.sol | 55 - .../contracts/test/TestCobbDouglas.sol | 49 - .../test/TestCumulativeRewardTracking.sol | 64 - .../contracts/test/TestDelegatorRewards.sol | 215 -- .../contracts/test/TestExchangeManager.sol | 42 - .../staking/contracts/test/TestFinalizer.sol | 181 - .../staking/contracts/test/TestInitTarget.sol | 64 - .../contracts/test/TestLibFixedMath.sol | 88 - .../contracts/test/TestLibSafeDowncast.sol | 41 - .../test/TestMixinCumulativeRewards.sol | 115 - .../contracts/test/TestMixinParams.sol | 47 - .../contracts/test/TestMixinScheduler.sol | 96 - .../staking/contracts/test/TestMixinStake.sol | 241 -- .../contracts/test/TestMixinStakeBalances.sol | 122 - .../contracts/test/TestMixinStakeStorage.sol | 98 - .../contracts/test/TestMixinStakingPool.sol | 53 - .../test/TestMixinStakingPoolRewards.sol | 281 -- .../contracts/test/TestProtocolFees.sol | 142 - .../contracts/test/TestProxyDestination.sol | 82 - .../staking/contracts/test/TestStaking.sol | 93 - .../contracts/test/TestStakingNoWETH.sol | 64 - .../contracts/test/TestStakingProxy.sol | 44 - .../contracts/test/TestStakingProxyUnit.sol | 62 - .../test/TestStorageLayoutAndConstants.sol | 304 -- contracts/staking/package.json | 101 - contracts/staking/src/artifacts.ts | 27 - contracts/staking/src/constants.ts | 22 - contracts/staking/src/index.ts | 91 - contracts/staking/src/types.ts | 262 -- contracts/staking/src/wrappers.ts | 14 - contracts/staking/test/actors/base_actor.ts | 17 - .../staking/test/actors/finalizer_actor.ts | 274 -- contracts/staking/test/actors/maker_actor.ts | 22 - .../test/actors/pool_operator_actor.ts | 53 - contracts/staking/test/actors/staker_actor.ts | 320 -- contracts/staking/test/artifacts.ts | 119 - contracts/staking/test/codesize_test.ts | 18 - .../test/cumulative_reward_tracking_test.ts | 429 --- contracts/staking/test/epoch_test.ts | 49 - contracts/staking/test/global_hooks.ts | 19 - .../layout_and_constant_regression_test.ts | 15 - contracts/staking/test/migration_test.ts | 335 -- contracts/staking/test/patch_mainnet_test.ts | 66 - contracts/staking/test/pools_test.ts | 208 -- contracts/staking/test/rewards_test.ts | 700 ---- contracts/staking/test/stake_test.ts | 391 --- .../staking/test/unit_tests/authorizable.ts | 88 - .../test/unit_tests/delegator_reward_test.ts | 789 ----- .../staking/test/unit_tests/exchange_test.ts | 171 - .../staking/test/unit_tests/finalizer_test.ts | 579 ---- .../test/unit_tests/lib_cobb_douglas_test.ts | 209 -- .../test/unit_tests/lib_fixed_math_test.ts | 960 ------ .../test/unit_tests/lib_safe_downcast_test.ts | 85 - .../mixin_cumulative_rewards_test.ts | 240 -- .../test/unit_tests/mixin_scheduler_test.ts | 108 - .../unit_tests/mixin_stake_storage_test.ts | 207 -- .../unit_tests/mixin_staking_pool_rewards.ts | 496 --- .../staking/test/unit_tests/params_test.ts | 83 - .../test/unit_tests/protocol_fees_test.ts | 474 --- .../test/unit_tests/stake_balances_test.ts | 212 -- .../staking/test/unit_tests/stake_test.ts | 489 --- .../test/unit_tests/staking_pool_test.ts | 366 -- .../test/unit_tests/staking_proxy_test.ts | 300 -- .../staking/test/unit_tests/zrx_vault_test.ts | 437 --- contracts/staking/test/utils/api_wrapper.ts | 282 -- .../cumulative_reward_tracking_simulation.ts | 167 - contracts/staking/test/utils/queue.ts | 39 - contracts/staking/test/wrappers.ts | 60 - contracts/staking/truffle-config.js | 96 - contracts/staking/tsconfig.json | 72 - contracts/staking/tslint.json | 7 - contracts/staking/typedoc-tsconfig.json | 7 - contracts/test-utils/src/index.ts | 5 - contracts/test-utils/src/types.ts | 40 - .../contracts/src/LibMath.sol | 4 +- .../contracts/src/LibMathRichErrors.sol | 0 .../contracts/test/TestLibMath.sol | 0 contracts/utils/package.json | 4 +- contracts/utils/src/artifacts.ts | 4 + contracts/utils/src/reference_functions.ts | 76 +- contracts/utils/src/wrappers.ts | 2 + contracts/utils/test/artifacts.ts | 6 + .../{exchange-libs => utils}/test/lib_math.ts | 3 +- contracts/utils/test/wrappers.ts | 3 + contracts/utils/tsconfig.json | 5 + package.json | 8 +- packages/contract-addresses/addresses.json | 22 +- packages/contract-wrappers-test/.npmignore | 9 - .../contract-wrappers-test/coverage/.gitkeep | 0 packages/contract-wrappers-test/package.json | 57 - .../test/calldata_decoder_test.ts | 137 - .../test/global_hooks.ts | 6 - .../test/utils/chai_setup.ts | 1 - .../test/utils/constants.ts | 18 - .../test/utils/web3_wrapper.ts | 12 - packages/contract-wrappers-test/tsconfig.json | 9 - packages/contract-wrappers-test/tslint.json | 3 - packages/migrations/package.json | 1 + packages/migrations/src/migration.ts | 405 +-- .../migrations/src/test_contract_configs.ts | 198 +- packages/migrations/src/testnet_migrations.ts | 133 - packages/migrations/src/utils/timelocks.ts | 62 - packages/order-utils/.npmignore | 9 - packages/order-utils/CHANGELOG.json | 1419 -------- packages/order-utils/CHANGELOG.md | 544 --- packages/order-utils/README.md | 65 - packages/order-utils/coverage/.gitkeep | 0 packages/order-utils/docs/reference.mdx | 2937 ----------------- packages/order-utils/package.json | 85 - packages/order-utils/src/assert.ts | 33 - packages/order-utils/src/asset_data_utils.ts | 188 -- packages/order-utils/src/constants.ts | 186 -- packages/order-utils/src/eip712_utils.ts | 152 - packages/order-utils/src/hash_utils.ts | 29 - packages/order-utils/src/index.ts | 94 - packages/order-utils/src/market_utils.ts | 208 -- .../src/order_calculation_utils.ts | 99 - packages/order-utils/src/order_factory.ts | 141 - packages/order-utils/src/order_hash_utils.ts | 10 - packages/order-utils/src/rate_utils.ts | 48 - .../src/remaining_fillable_calculator.ts | 86 - packages/order-utils/src/salt.ts | 12 - .../validate_order_fillable_opts_schema.ts | 7 - packages/order-utils/src/signature_utils.ts | 456 --- packages/order-utils/src/sorting_utils.ts | 54 - .../order-utils/src/transaction_hash_utils.ts | 12 - packages/order-utils/src/transformer_utils.ts | 271 -- packages/order-utils/src/types.ts | 82 - packages/order-utils/src/utils.ts | 22 - .../UntransferrableDummyERC20Token.ts | 409 --- packages/order-utils/test/assert_test.ts | 34 - .../order-utils/test/asset_data_utils_test.ts | 186 -- .../order-utils/test/eip712_utils_test.ts | 78 - .../order-utils/test/market_utils_test.ts | 396 --- packages/order-utils/test/rate_utils_test.ts | 55 - .../remaining_fillable_calculator_test.ts | 252 -- .../order-utils/test/signature_utils_test.ts | 384 --- .../order-utils/test/sorting_utils_test.ts | 67 - packages/order-utils/test/utils/chai_setup.ts | 1 - .../test/utils/test_order_factory.ts | 35 - .../order-utils/test/utils/web3_wrapper.ts | 8 - packages/order-utils/tsconfig.json | 8 - packages/order-utils/tslint.json | 3 - packages/order-utils/typedoc-tsconfig.json | 7 - tsconfig.json | 16 +- yarn.lock | 1141 ++----- 741 files changed, 586 insertions(+), 121272 deletions(-) delete mode 100644 contracts/TESTING.md delete mode 100644 contracts/asset-proxy/.npmignore delete mode 100644 contracts/asset-proxy/.solhintignore delete mode 100644 contracts/asset-proxy/CHANGELOG.json delete mode 100644 contracts/asset-proxy/CHANGELOG.md delete mode 100644 contracts/asset-proxy/DEPLOYS.json delete mode 100644 contracts/asset-proxy/README.md delete mode 100644 contracts/asset-proxy/compiler.json delete mode 100644 contracts/asset-proxy/contracts/archive/MixinAssetProxyDispatcher.sol delete mode 100644 contracts/asset-proxy/contracts/archive/MixinAuthorizable.sol delete mode 100644 contracts/asset-proxy/contracts/archive/Ownable.sol delete mode 100644 contracts/asset-proxy/contracts/src/ERC1155Proxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/ERC20Proxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/ERC721Proxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/MultiAssetProxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/StaticCallProxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/DexForwarderBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/MStableBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IAssetData.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IAssetProxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IAssetProxyDispatcher.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IAuthorizable.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IBalancerPool.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IChai.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/ICurve.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IDydx.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IERC20Bridge.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IKyberNetworkProxy.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IMStable.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IMooniswap.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IShell.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IUniswapExchange.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol delete mode 100644 contracts/asset-proxy/contracts/src/interfaces/IUniswapV2Router01.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestBancorBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestChaiBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestDydxBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestERC20Bridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestKyberBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestStaticCallTarget.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestUniswapBridge.sol delete mode 100644 contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol delete mode 100644 contracts/asset-proxy/package.json delete mode 100644 contracts/asset-proxy/src/artifacts.ts delete mode 100644 contracts/asset-proxy/src/asset_data.ts delete mode 100644 contracts/asset-proxy/src/dex_forwarder_bridge.ts delete mode 100644 contracts/asset-proxy/src/dydx_bridge_encoder.ts delete mode 100644 contracts/asset-proxy/src/erc1155_proxy_wrapper.ts delete mode 100644 contracts/asset-proxy/src/erc20_wrapper.ts delete mode 100644 contracts/asset-proxy/src/erc721_wrapper.ts delete mode 100644 contracts/asset-proxy/src/index.ts delete mode 100644 contracts/asset-proxy/src/wrappers.ts delete mode 100644 contracts/asset-proxy/test/artifacts.ts delete mode 100644 contracts/asset-proxy/test/authorizable.ts delete mode 100644 contracts/asset-proxy/test/bancor_bridge.ts delete mode 100644 contracts/asset-proxy/test/chai_bridge.ts delete mode 100644 contracts/asset-proxy/test/dydx_bridge.ts delete mode 100644 contracts/asset-proxy/test/erc1155_proxy.ts delete mode 100644 contracts/asset-proxy/test/erc20bridge_proxy.ts delete mode 100644 contracts/asset-proxy/test/eth2dai_bridge.ts delete mode 100644 contracts/asset-proxy/test/global_hooks.ts delete mode 100644 contracts/asset-proxy/test/kyber_bridge.ts delete mode 100644 contracts/asset-proxy/test/proxies.ts delete mode 100644 contracts/asset-proxy/test/static_call_proxy.ts delete mode 100644 contracts/asset-proxy/test/uniswap_bridge.ts delete mode 100644 contracts/asset-proxy/test/uniswapv2_bridge.ts delete mode 100644 contracts/asset-proxy/test/wrappers.ts delete mode 100644 contracts/asset-proxy/truffle-config.js delete mode 100644 contracts/asset-proxy/tsconfig.json delete mode 100644 contracts/asset-proxy/tslint.json delete mode 100644 contracts/asset-proxy/typedoc-tsconfig.json delete mode 100644 contracts/broker/.npmignore delete mode 100644 contracts/broker/CHANGELOG.json delete mode 100644 contracts/broker/CHANGELOG.md delete mode 100644 contracts/broker/DEPLOYS.json delete mode 100644 contracts/broker/README.md delete mode 100644 contracts/broker/compiler.json delete mode 100644 contracts/broker/contracts/src/Broker.sol delete mode 100644 contracts/broker/contracts/src/interfaces/IBroker.sol delete mode 100644 contracts/broker/contracts/src/interfaces/IGodsUnchained.sol delete mode 100644 contracts/broker/contracts/src/interfaces/IPropertyValidator.sol delete mode 100644 contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol delete mode 100644 contracts/broker/contracts/src/validators/GodsUnchainedValidator.sol delete mode 100644 contracts/broker/contracts/test/TestGodsUnchained.sol delete mode 100644 contracts/broker/package.json delete mode 100644 contracts/broker/src/artifacts.ts delete mode 100644 contracts/broker/src/gods_unchained_utils.ts delete mode 100644 contracts/broker/src/index.ts delete mode 100644 contracts/broker/src/wrappers.ts delete mode 100644 contracts/broker/test/artifacts.ts delete mode 100644 contracts/broker/test/gods_unchained_validator_test.ts delete mode 100644 contracts/broker/test/wrappers.ts delete mode 100644 contracts/broker/truffle-config.js delete mode 100644 contracts/broker/tsconfig.json delete mode 100644 contracts/broker/tslint.json delete mode 100644 contracts/broker/typedoc-tsconfig.json delete mode 100644 contracts/coordinator/.npmignore delete mode 100644 contracts/coordinator/.solhintignore delete mode 100644 contracts/coordinator/CHANGELOG.json delete mode 100644 contracts/coordinator/CHANGELOG.md delete mode 100644 contracts/coordinator/DEPLOYS.json delete mode 100644 contracts/coordinator/README.md delete mode 100644 contracts/coordinator/compiler.json delete mode 100644 contracts/coordinator/contracts/src/Coordinator.sol delete mode 100644 contracts/coordinator/contracts/src/MixinCoordinatorApprovalVerifier.sol delete mode 100644 contracts/coordinator/contracts/src/MixinCoordinatorCore.sol delete mode 100644 contracts/coordinator/contracts/src/MixinSignatureValidator.sol delete mode 100644 contracts/coordinator/contracts/src/interfaces/ICoordinatorApprovalVerifier.sol delete mode 100644 contracts/coordinator/contracts/src/interfaces/ICoordinatorCore.sol delete mode 100644 contracts/coordinator/contracts/src/interfaces/ICoordinatorSignatureValidator.sol delete mode 100644 contracts/coordinator/contracts/src/libs/LibConstants.sol delete mode 100644 contracts/coordinator/contracts/src/libs/LibCoordinatorApproval.sol delete mode 100644 contracts/coordinator/contracts/src/libs/LibCoordinatorRichErrors.sol delete mode 100644 contracts/coordinator/contracts/src/libs/LibEIP712CoordinatorDomain.sol delete mode 100644 contracts/coordinator/contracts/src/registry/CoordinatorRegistry.sol delete mode 100644 contracts/coordinator/contracts/src/registry/MixinCoordinatorRegistryCore.sol delete mode 100644 contracts/coordinator/contracts/src/registry/interfaces/ICoordinatorRegistryCore.sol delete mode 100644 contracts/coordinator/package.json delete mode 100644 contracts/coordinator/src/approval_factory.ts delete mode 100644 contracts/coordinator/src/artifacts.ts delete mode 100644 contracts/coordinator/src/client/index.ts delete mode 100644 contracts/coordinator/src/client/utils/assert.ts delete mode 100644 contracts/coordinator/src/client/utils/coordinator_server_types.ts delete mode 100644 contracts/coordinator/src/client/utils/decorators.ts delete mode 100644 contracts/coordinator/src/hash_utils.ts delete mode 100644 contracts/coordinator/src/index.ts delete mode 100644 contracts/coordinator/src/types.ts delete mode 100644 contracts/coordinator/src/wrappers.ts delete mode 100644 contracts/coordinator/test/artifacts.ts delete mode 100644 contracts/coordinator/test/coordinator_registry.ts delete mode 100644 contracts/coordinator/test/global_hooks.ts delete mode 100644 contracts/coordinator/test/libs.ts delete mode 100644 contracts/coordinator/test/mixins.ts delete mode 100644 contracts/coordinator/test/wrappers.ts delete mode 100644 contracts/coordinator/truffle-config.js delete mode 100644 contracts/coordinator/tsconfig.json delete mode 100644 contracts/coordinator/tslint.json delete mode 100644 contracts/coordinator/typedoc-tsconfig.json delete mode 100644 contracts/dev-utils/.npmignore delete mode 100644 contracts/dev-utils/CHANGELOG.json delete mode 100644 contracts/dev-utils/CHANGELOG.md delete mode 100644 contracts/dev-utils/DEPLOYS.json delete mode 100644 contracts/dev-utils/README.md delete mode 100644 contracts/dev-utils/compiler.json delete mode 100644 contracts/dev-utils/contracts/src/Addresses.sol delete mode 100644 contracts/dev-utils/contracts/src/AssetBalance.sol delete mode 100644 contracts/dev-utils/contracts/src/DevUtils.sol delete mode 100644 contracts/dev-utils/contracts/src/EthBalanceChecker.sol delete mode 100644 contracts/dev-utils/contracts/src/ExternalFunctions.sol delete mode 100644 contracts/dev-utils/contracts/src/LibAssetData.sol delete mode 100644 contracts/dev-utils/contracts/src/LibDydxBalance.sol delete mode 100644 contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol delete mode 100644 contracts/dev-utils/contracts/src/LibTransactionDecoder.sol delete mode 100644 contracts/dev-utils/contracts/src/OrderTransferSimulationUtils.sol delete mode 100644 contracts/dev-utils/contracts/src/OrderValidationUtils.sol delete mode 100644 contracts/dev-utils/contracts/test/TestDydx.sol delete mode 100644 contracts/dev-utils/contracts/test/TestLibDydxBalance.sol delete mode 100644 contracts/dev-utils/package.json delete mode 100644 contracts/dev-utils/src/artifacts.ts delete mode 100644 contracts/dev-utils/src/index.ts delete mode 100644 contracts/dev-utils/src/wrappers.ts delete mode 100644 contracts/dev-utils/test/artifacts.ts delete mode 100644 contracts/dev-utils/test/lib_dydx_balance_test.ts delete mode 100644 contracts/dev-utils/test/wrappers.ts delete mode 100644 contracts/dev-utils/truffle-config.js delete mode 100644 contracts/dev-utils/tsconfig.json delete mode 100644 contracts/dev-utils/tslint.json delete mode 100644 contracts/dev-utils/typedoc-tsconfig.json delete mode 100644 contracts/erc1155/.npmignore delete mode 100644 contracts/erc1155/CHANGELOG.json delete mode 100644 contracts/erc1155/CHANGELOG.md delete mode 100644 contracts/erc1155/DEPLOYS.json delete mode 100644 contracts/erc1155/README.md delete mode 100644 contracts/erc1155/compiler.json delete mode 100644 contracts/erc1155/contracts/src/ERC1155.sol delete mode 100644 contracts/erc1155/contracts/src/ERC1155Mintable.sol delete mode 100644 contracts/erc1155/contracts/src/MixinNonFungibleToken.sol delete mode 100644 contracts/erc1155/contracts/src/interfaces/IERC1155.sol delete mode 100644 contracts/erc1155/contracts/src/interfaces/IERC1155Mintable.sol delete mode 100644 contracts/erc1155/contracts/src/interfaces/IERC1155Receiver.sol delete mode 100644 contracts/erc1155/contracts/test/DummyERC1155Receiver.sol delete mode 100644 contracts/erc1155/package.json delete mode 100644 contracts/erc1155/src/artifacts.ts delete mode 100644 contracts/erc1155/src/erc1155_wrapper.ts delete mode 100644 contracts/erc1155/src/index.ts delete mode 100644 contracts/erc1155/src/wrappers.ts delete mode 100644 contracts/erc1155/test/artifacts.ts delete mode 100644 contracts/erc1155/test/erc1155_token.ts delete mode 100644 contracts/erc1155/test/global_hooks.ts delete mode 100644 contracts/erc1155/test/wrappers.ts delete mode 100644 contracts/erc1155/truffle-config.js delete mode 100644 contracts/erc1155/tsconfig.json delete mode 100644 contracts/erc1155/tslint.json delete mode 100644 contracts/erc1155/typedoc-tsconfig.json delete mode 100644 contracts/erc721/.npmignore delete mode 100644 contracts/erc721/.solhintignore delete mode 100644 contracts/erc721/CHANGELOG.json delete mode 100644 contracts/erc721/CHANGELOG.md delete mode 100644 contracts/erc721/DEPLOYS.json delete mode 100644 contracts/erc721/README.md delete mode 100644 contracts/erc721/compiler.json delete mode 100644 contracts/erc721/contracts/src/ERC721Token.sol delete mode 100644 contracts/erc721/contracts/src/MintableERC721Token.sol delete mode 100644 contracts/erc721/contracts/src/interfaces/IERC721Receiver.sol delete mode 100644 contracts/erc721/contracts/src/interfaces/IERC721Token.sol delete mode 100644 contracts/erc721/contracts/test/DummyERC721Receiver.sol delete mode 100644 contracts/erc721/contracts/test/DummyERC721Token.sol delete mode 100644 contracts/erc721/contracts/test/InvalidERC721Receiver.sol delete mode 100644 contracts/erc721/package.json delete mode 100644 contracts/erc721/src/artifacts.ts delete mode 100644 contracts/erc721/src/index.ts delete mode 100644 contracts/erc721/src/wrappers.ts delete mode 100644 contracts/erc721/test/artifacts.ts delete mode 100644 contracts/erc721/test/erc721_token.ts delete mode 100644 contracts/erc721/test/global_hooks.ts delete mode 100644 contracts/erc721/test/wrappers.ts delete mode 100644 contracts/erc721/truffle-config.js delete mode 100644 contracts/erc721/tsconfig.json delete mode 100644 contracts/erc721/tslint.json delete mode 100644 contracts/erc721/typedoc-tsconfig.json delete mode 100644 contracts/exchange-forwarder/.npmignore delete mode 100644 contracts/exchange-forwarder/CHANGELOG.json delete mode 100644 contracts/exchange-forwarder/CHANGELOG.md delete mode 100644 contracts/exchange-forwarder/DEPLOYS.json delete mode 100644 contracts/exchange-forwarder/README.md delete mode 100644 contracts/exchange-forwarder/compiler.json delete mode 100644 contracts/exchange-forwarder/contracts/src/Forwarder.sol delete mode 100644 contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol delete mode 100644 contracts/exchange-forwarder/contracts/src/MixinReceiver.sol delete mode 100644 contracts/exchange-forwarder/contracts/src/interfaces/IExchangeV2.sol delete mode 100644 contracts/exchange-forwarder/contracts/src/interfaces/IForwarder.sol delete mode 100644 contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol delete mode 100644 contracts/exchange-forwarder/contracts/test/TestForwarder.sol delete mode 100644 contracts/exchange-forwarder/package.json delete mode 100644 contracts/exchange-forwarder/src/artifacts.ts delete mode 100644 contracts/exchange-forwarder/src/index.ts delete mode 100644 contracts/exchange-forwarder/src/wrappers.ts delete mode 100644 contracts/exchange-forwarder/test/artifacts.ts delete mode 100644 contracts/exchange-forwarder/test/asset_test.ts delete mode 100644 contracts/exchange-forwarder/test/wrappers.ts delete mode 100644 contracts/exchange-forwarder/truffle-config.js delete mode 100644 contracts/exchange-forwarder/tsconfig.json delete mode 100644 contracts/exchange-forwarder/tslint.json delete mode 100644 contracts/exchange-forwarder/typedoc-tsconfig.json delete mode 100644 contracts/exchange-libs/.npmignore delete mode 100644 contracts/exchange-libs/CHANGELOG.json delete mode 100644 contracts/exchange-libs/CHANGELOG.md delete mode 100644 contracts/exchange-libs/README.md delete mode 100644 contracts/exchange-libs/compiler.json delete mode 100644 contracts/exchange-libs/contracts/src/IWallet.sol delete mode 100644 contracts/exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol delete mode 100644 contracts/exchange-libs/contracts/src/LibExchangeRichErrors.sol delete mode 100644 contracts/exchange-libs/contracts/src/LibFillResults.sol delete mode 100644 contracts/exchange-libs/contracts/src/LibOrder.sol delete mode 100644 contracts/exchange-libs/contracts/src/LibZeroExTransaction.sol delete mode 100644 contracts/exchange-libs/contracts/test/TestLibEIP712ExchangeDomain.sol delete mode 100644 contracts/exchange-libs/contracts/test/TestLibFillResults.sol delete mode 100644 contracts/exchange-libs/contracts/test/TestLibOrder.sol delete mode 100644 contracts/exchange-libs/contracts/test/TestLibZeroExTransaction.sol delete mode 100644 contracts/exchange-libs/package.json delete mode 100644 contracts/exchange-libs/src/artifacts.ts delete mode 100644 contracts/exchange-libs/src/index.ts delete mode 100644 contracts/exchange-libs/src/reference_functions.ts delete mode 100644 contracts/exchange-libs/src/wrappers.ts delete mode 100644 contracts/exchange-libs/test/artifacts.ts delete mode 100644 contracts/exchange-libs/test/global_hooks.ts delete mode 100644 contracts/exchange-libs/test/lib_eip712_exchange_domain.ts delete mode 100644 contracts/exchange-libs/test/lib_fill_results.ts delete mode 100644 contracts/exchange-libs/test/lib_order.ts delete mode 100644 contracts/exchange-libs/test/lib_zero_ex_transaction.ts delete mode 100644 contracts/exchange-libs/test/reference_functions.ts delete mode 100644 contracts/exchange-libs/test/utils/index.ts delete mode 100644 contracts/exchange-libs/test/utils/schema.ts delete mode 100644 contracts/exchange-libs/test/wrappers.ts delete mode 100644 contracts/exchange-libs/truffle-config.js delete mode 100644 contracts/exchange-libs/tsconfig.json delete mode 100644 contracts/exchange-libs/tslint.json delete mode 100644 contracts/exchange/.npmignore delete mode 100644 contracts/exchange/CHANGELOG.json delete mode 100644 contracts/exchange/CHANGELOG.md delete mode 100644 contracts/exchange/DEPLOYS.json delete mode 100644 contracts/exchange/README.md delete mode 100644 contracts/exchange/compiler.json delete mode 100644 contracts/exchange/contracts/src/Exchange.sol delete mode 100644 contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol delete mode 100644 contracts/exchange/contracts/src/MixinExchangeCore.sol delete mode 100644 contracts/exchange/contracts/src/MixinMatchOrders.sol delete mode 100644 contracts/exchange/contracts/src/MixinProtocolFees.sol delete mode 100644 contracts/exchange/contracts/src/MixinSignatureValidator.sol delete mode 100644 contracts/exchange/contracts/src/MixinTransactions.sol delete mode 100644 contracts/exchange/contracts/src/MixinTransferSimulator.sol delete mode 100644 contracts/exchange/contracts/src/MixinWrapperFunctions.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IAssetProxy.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IAssetProxyDispatcher.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IEIP1271Data.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IEIP1271Wallet.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IExchange.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IExchangeCore.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IMatchOrders.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IProtocolFees.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/ISignatureValidator.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/ITransactions.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/ITransferSimulator.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IWallet.sol delete mode 100644 contracts/exchange/contracts/src/interfaces/IWrapperFunctions.sol delete mode 100644 contracts/exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol delete mode 100644 contracts/exchange/contracts/test/IsolatedExchange.sol delete mode 100644 contracts/exchange/contracts/test/ReentrancyTester.sol delete mode 100644 contracts/exchange/contracts/test/TestAssetProxyDispatcher.sol delete mode 100644 contracts/exchange/contracts/test/TestExchangeInternals.sol delete mode 100644 contracts/exchange/contracts/test/TestFillRounding.sol delete mode 100644 contracts/exchange/contracts/test/TestLibExchangeRichErrorDecoder.sol delete mode 100644 contracts/exchange/contracts/test/TestProtocolFeeCollector.sol delete mode 100644 contracts/exchange/contracts/test/TestProtocolFees.sol delete mode 100644 contracts/exchange/contracts/test/TestProtocolFeesReceiver.sol delete mode 100644 contracts/exchange/contracts/test/TestTransactions.sol delete mode 100644 contracts/exchange/contracts/test/TestValidatorWallet.sol delete mode 100644 contracts/exchange/contracts/test/TestWrapperFunctions.sol delete mode 100644 contracts/exchange/package.json delete mode 100644 contracts/exchange/src/artifacts.ts delete mode 100644 contracts/exchange/src/exchange_data_encoder.ts delete mode 100644 contracts/exchange/src/index.ts delete mode 100644 contracts/exchange/src/wrappers.ts delete mode 100644 contracts/exchange/test/artifacts.ts delete mode 100644 contracts/exchange/test/codesize.ts delete mode 100644 contracts/exchange/test/dispatcher.ts delete mode 100644 contracts/exchange/test/exchange_transfer_simulator_test.ts delete mode 100644 contracts/exchange/test/fill_order.ts delete mode 100644 contracts/exchange/test/global_hooks.ts delete mode 100644 contracts/exchange/test/internal.ts delete mode 100644 contracts/exchange/test/isolated_fill_order.ts delete mode 100644 contracts/exchange/test/lib_exchange_rich_error_decoder.ts delete mode 100644 contracts/exchange/test/protocol_fees.ts delete mode 100644 contracts/exchange/test/protocol_fees_manager.ts delete mode 100644 contracts/exchange/test/reentrancy_tests.ts delete mode 100644 contracts/exchange/test/reference_functions.ts delete mode 100644 contracts/exchange/test/signature_validator.ts delete mode 100644 contracts/exchange/test/transactions_unit_tests.ts delete mode 100644 contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_fetcher.ts delete mode 100644 contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts delete mode 100644 contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts delete mode 100644 contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts delete mode 100644 contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts delete mode 100644 contracts/exchange/test/utils/asset_wrapper.ts delete mode 100644 contracts/exchange/test/utils/constants.ts delete mode 100644 contracts/exchange/test/utils/dependency_artifacts.ts delete mode 100644 contracts/exchange/test/utils/exchange_transfer_simulator.ts delete mode 100644 contracts/exchange/test/utils/exchange_wrapper.ts delete mode 100644 contracts/exchange/test/utils/fill_order_combinatorial_utils.ts delete mode 100644 contracts/exchange/test/utils/fill_order_scenarios.ts delete mode 100644 contracts/exchange/test/utils/fill_order_simulator.ts delete mode 100644 contracts/exchange/test/utils/isolated_exchange_wrapper.ts delete mode 100644 contracts/exchange/test/utils/order_factory_from_scenario.ts delete mode 100644 contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts delete mode 100644 contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts delete mode 100644 contracts/exchange/test/utils/store/balance_and_proxy_allowance_lazy_store.ts delete mode 100644 contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts delete mode 100644 contracts/exchange/test/utils/types.ts delete mode 100644 contracts/exchange/test/wrapper_unit_tests.ts delete mode 100644 contracts/exchange/test/wrappers.ts delete mode 100644 contracts/exchange/truffle-config.js delete mode 100644 contracts/exchange/tsconfig.json delete mode 100644 contracts/exchange/tslint.json delete mode 100644 contracts/exchange/typedoc-tsconfig.json delete mode 100644 contracts/extensions/.npmignore delete mode 100644 contracts/extensions/CHANGELOG.json delete mode 100644 contracts/extensions/CHANGELOG.md delete mode 100644 contracts/extensions/DEPLOYS.json delete mode 100644 contracts/extensions/README.md delete mode 100644 contracts/extensions/compiler.json delete mode 100644 contracts/extensions/contracts/src/LibAssetDataTransfer.sol delete mode 100644 contracts/extensions/contracts/src/MaximumGasPrice.sol delete mode 100644 contracts/extensions/contracts/src/MixinWethUtils.sol delete mode 100644 contracts/extensions/contracts/src/rich-errors/LibAssetDataTransferRichErrors.sol delete mode 100644 contracts/extensions/contracts/src/rich-errors/LibWethUtilsRichErrors.sol delete mode 100644 contracts/extensions/package.json delete mode 100644 contracts/extensions/src/artifacts.ts delete mode 100644 contracts/extensions/src/index.ts delete mode 100644 contracts/extensions/src/max_gas_price_utils.ts delete mode 100644 contracts/extensions/src/wrappers.ts delete mode 100644 contracts/extensions/test/artifacts.ts delete mode 100644 contracts/extensions/test/max_gas_price_test.ts delete mode 100644 contracts/extensions/test/wrappers.ts delete mode 100644 contracts/extensions/truffle-config.js delete mode 100644 contracts/extensions/tsconfig.json delete mode 100644 contracts/extensions/tslint.json delete mode 100644 contracts/extensions/typedoc-tsconfig.json delete mode 100644 contracts/integrations/.npmignore delete mode 100644 contracts/integrations/CHANGELOG.json delete mode 100644 contracts/integrations/CHANGELOG.md delete mode 100644 contracts/integrations/README.md delete mode 100644 contracts/integrations/compiler.json delete mode 100644 contracts/integrations/contracts/src/ChainlinkStopLimit.sol delete mode 100644 contracts/integrations/contracts/src/interfaces/IChainlinkAggregator.sol delete mode 100644 contracts/integrations/contracts/test/TestChainlinkAggregator.sol delete mode 100644 contracts/integrations/contracts/test/TestContractWrapper.sol delete mode 100644 contracts/integrations/contracts/test/TestDydxUser.sol delete mode 100644 contracts/integrations/contracts/test/TestEth2Dai.sol delete mode 100644 contracts/integrations/contracts/test/TestEth2DaiBridge.sol delete mode 100644 contracts/integrations/contracts/test/TestFixinProtocolFeesIntegration.sol delete mode 100644 contracts/integrations/contracts/test/TestFramework.sol delete mode 100644 contracts/integrations/contracts/test/TestMainnetAggregatorFills.sol delete mode 100644 contracts/integrations/contracts/test/TestSignatureValidationWallet.sol delete mode 100644 contracts/integrations/contracts/test/TestStaking.sol delete mode 100644 contracts/integrations/contracts/test/TestUniswapBridge.sol delete mode 100644 contracts/integrations/contracts/test/TestUniswapExchange.sol delete mode 100644 contracts/integrations/contracts/test/TestUniswapExchangeFactory.sol delete mode 100644 contracts/integrations/contracts/test/TestWethIntegration.sol delete mode 100644 contracts/integrations/package.json delete mode 100644 contracts/integrations/src/artifacts.ts delete mode 100644 contracts/integrations/src/chainlink_utils.ts delete mode 100644 contracts/integrations/src/index.ts delete mode 100644 contracts/integrations/src/wrappers.ts delete mode 100644 contracts/integrations/test/artifacts.ts delete mode 100644 contracts/integrations/test/benchmarks/chai_bridge_test.ts delete mode 100644 contracts/integrations/test/benchmarks/dydx_bridge_test.ts delete mode 100644 contracts/integrations/test/bridges/abi/dydxEvents.ts delete mode 100644 contracts/integrations/test/bridges/balancer_bridge_mainnet_test.ts delete mode 100644 contracts/integrations/test/bridges/curve_bridge_mainnet_test.ts delete mode 100644 contracts/integrations/test/bridges/deploy_dydx_bridge.ts delete mode 100644 contracts/integrations/test/bridges/deploy_eth2dai_bridge.ts delete mode 100644 contracts/integrations/test/bridges/deploy_uniswap_bridge.ts delete mode 100644 contracts/integrations/test/bridges/dydx_bridge_mainnet_test.ts delete mode 100644 contracts/integrations/test/broker/broker_test.ts delete mode 100644 contracts/integrations/test/coordinator/client_test.ts delete mode 100644 contracts/integrations/test/coordinator/coordinator_test.ts delete mode 100644 contracts/integrations/test/coordinator/deploy_coordinator.ts delete mode 100644 contracts/integrations/test/deployment_test.ts delete mode 100644 contracts/integrations/test/dev-utils/dev_utils_mainnet_test.ts delete mode 100644 contracts/integrations/test/dev-utils/dydx_order_validation_test.ts delete mode 100644 contracts/integrations/test/dev-utils/get_order_hash.ts delete mode 100644 contracts/integrations/test/dev-utils/global_hooks.ts delete mode 100644 contracts/integrations/test/dev-utils/lib_asset_data.ts delete mode 100644 contracts/integrations/test/dev-utils/lib_transaction_decoder.ts delete mode 100644 contracts/integrations/test/dev-utils/order_validation_utils.ts delete mode 100644 contracts/integrations/test/exchange/batch_match_orders_test.ts delete mode 100644 contracts/integrations/test/exchange/core_test.ts delete mode 100644 contracts/integrations/test/exchange/exchange_wrapper_test.ts delete mode 100644 contracts/integrations/test/exchange/fill_dydx_order_test.ts delete mode 100644 contracts/integrations/test/exchange/fill_order_test.ts delete mode 100644 contracts/integrations/test/exchange/fill_order_wrapper.ts delete mode 100644 contracts/integrations/test/exchange/match_order_tester.ts delete mode 100644 contracts/integrations/test/exchange/match_orders_maximal_fill_test.ts delete mode 100644 contracts/integrations/test/exchange/match_orders_test.ts delete mode 100644 contracts/integrations/test/exchange/transaction_protocol_fee_test.ts delete mode 100644 contracts/integrations/test/exchange/transaction_test.ts delete mode 100644 contracts/integrations/test/forwarder/bridge_test.ts delete mode 100644 contracts/integrations/test/forwarder/deploy_forwarder.ts delete mode 100644 contracts/integrations/test/forwarder/forwarder_mainnet_test.ts delete mode 100644 contracts/integrations/test/forwarder/forwarder_test.ts delete mode 100644 contracts/integrations/test/forwarder/forwarder_test_factory.ts delete mode 100644 contracts/integrations/test/forwarder/types.ts delete mode 100644 contracts/integrations/test/framework/actors/base.ts delete mode 100644 contracts/integrations/test/framework/actors/fee_recipient.ts delete mode 100644 contracts/integrations/test/framework/actors/hybrids.ts delete mode 100644 contracts/integrations/test/framework/actors/keeper.ts delete mode 100644 contracts/integrations/test/framework/actors/maker.ts delete mode 100644 contracts/integrations/test/framework/actors/pool_operator.ts delete mode 100644 contracts/integrations/test/framework/actors/staker.ts delete mode 100644 contracts/integrations/test/framework/actors/taker.ts delete mode 100644 contracts/integrations/test/framework/actors/tslint.json delete mode 100644 contracts/integrations/test/framework/actors/utils.ts delete mode 100644 contracts/integrations/test/framework/assertions/createStakingPool.ts delete mode 100644 contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts delete mode 100644 contracts/integrations/test/framework/assertions/endEpoch.ts delete mode 100644 contracts/integrations/test/framework/assertions/fillOrder.ts delete mode 100644 contracts/integrations/test/framework/assertions/finalizePool.ts delete mode 100644 contracts/integrations/test/framework/assertions/function_assertion.ts delete mode 100644 contracts/integrations/test/framework/assertions/generic_assertions.ts delete mode 100644 contracts/integrations/test/framework/assertions/joinStakingPool.ts delete mode 100644 contracts/integrations/test/framework/assertions/matchOrders.ts delete mode 100644 contracts/integrations/test/framework/assertions/matchOrdersWithMaximalFill.ts delete mode 100644 contracts/integrations/test/framework/assertions/moveStake.ts delete mode 100644 contracts/integrations/test/framework/assertions/stake.ts delete mode 100644 contracts/integrations/test/framework/assertions/unstake.ts delete mode 100644 contracts/integrations/test/framework/assertions/withdrawDelegatorRewards.ts delete mode 100644 contracts/integrations/test/framework/balances/balance_store.ts delete mode 100644 contracts/integrations/test/framework/balances/blockchain_balance_store.ts delete mode 100644 contracts/integrations/test/framework/balances/local_balance_store.ts delete mode 100644 contracts/integrations/test/framework/balances/types.ts delete mode 100644 contracts/integrations/test/framework/deployment_manager.ts delete mode 100644 contracts/integrations/test/framework/simulation.ts delete mode 100644 contracts/integrations/test/framework/tests/deployment_manager_test.ts delete mode 100644 contracts/integrations/test/framework/tests/function_assertion_test.ts delete mode 100644 contracts/integrations/test/framework/utils/assert_protocol_fee.ts delete mode 100644 contracts/integrations/test/framework/utils/logger.ts delete mode 100644 contracts/integrations/test/framework/utils/pseudorandom.ts delete mode 100644 contracts/integrations/test/framework/utils/verify_match_events.ts delete mode 100644 contracts/integrations/test/framework/utils/wrapper_interfaces.ts delete mode 100644 contracts/integrations/test/fuzz_tests/exchange_signature_validation_test.ts delete mode 100644 contracts/integrations/test/fuzz_tests/match_orders_test.ts delete mode 100644 contracts/integrations/test/fuzz_tests/pool_management_test.ts delete mode 100644 contracts/integrations/test/fuzz_tests/pool_membership_test.ts delete mode 100644 contracts/integrations/test/fuzz_tests/stake_management_test.ts delete mode 100644 contracts/integrations/test/fuzz_tests/staking_rewards_test.ts delete mode 100644 contracts/integrations/test/fuzz_tests/tslint.json delete mode 100644 contracts/integrations/test/mainnet_configs_test.ts delete mode 100644 contracts/integrations/test/mainnet_contract_wrapper_test.ts delete mode 100644 contracts/integrations/test/mainnet_fork_utils.ts delete mode 100644 contracts/integrations/test/stop-limit/chainlink_stop_limit_test.ts delete mode 100644 contracts/integrations/test/wrappers.ts delete mode 100644 contracts/integrations/test/zero-ex/protocol_fees_staking_test.ts delete mode 100644 contracts/integrations/tsconfig.json delete mode 100644 contracts/integrations/tslint.json delete mode 100644 contracts/multisig/.npmignore delete mode 100644 contracts/multisig/CHANGELOG.json delete mode 100644 contracts/multisig/CHANGELOG.md delete mode 100644 contracts/multisig/DEPLOYS.json delete mode 100644 contracts/multisig/README.md delete mode 100644 contracts/multisig/compiler.json delete mode 100644 contracts/multisig/contracts/src/MultiSigWallet.sol delete mode 100644 contracts/multisig/contracts/src/MultiSigWalletWithTimeLock.sol delete mode 100644 contracts/multisig/contracts/src/ZeroExGovernor.sol delete mode 100644 contracts/multisig/contracts/test/ContractCallReceiver.sol delete mode 100644 contracts/multisig/contracts/test/TestRejectEther.sol delete mode 100644 contracts/multisig/contracts/test/TestZeroExGovernor.sol delete mode 100644 contracts/multisig/package.json delete mode 100644 contracts/multisig/src/artifacts.ts delete mode 100644 contracts/multisig/src/index.ts delete mode 100644 contracts/multisig/src/wrappers.ts delete mode 100644 contracts/multisig/test/artifacts.ts delete mode 100644 contracts/multisig/test/global_hooks.ts delete mode 100644 contracts/multisig/test/multi_sig_with_time_lock.ts delete mode 100644 contracts/multisig/test/utils/index.ts delete mode 100644 contracts/multisig/test/utils/multi_sig_wrapper.ts delete mode 100644 contracts/multisig/test/utils/zero_ex_governor_wrapper.ts delete mode 100644 contracts/multisig/test/wrappers.ts delete mode 100644 contracts/multisig/test/zero_ex_governor.ts delete mode 100644 contracts/multisig/truffle-config.js delete mode 100644 contracts/multisig/tsconfig.json delete mode 100644 contracts/multisig/tslint.json delete mode 100644 contracts/staking/.npmignore delete mode 100644 contracts/staking/CHANGELOG.json delete mode 100644 contracts/staking/CHANGELOG.md delete mode 100644 contracts/staking/DEPLOYS.json delete mode 100644 contracts/staking/README.md delete mode 100644 contracts/staking/compiler.json delete mode 100644 contracts/staking/contracts/src/Staking.sol delete mode 100644 contracts/staking/contracts/src/StakingPatch.sol delete mode 100644 contracts/staking/contracts/src/StakingProxy.sol delete mode 100644 contracts/staking/contracts/src/ZrxVault.sol delete mode 100644 contracts/staking/contracts/src/fees/MixinExchangeFees.sol delete mode 100644 contracts/staking/contracts/src/fees/MixinExchangeManager.sol delete mode 100644 contracts/staking/contracts/src/immutable/MixinConstants.sol delete mode 100644 contracts/staking/contracts/src/immutable/MixinDeploymentConstants.sol delete mode 100644 contracts/staking/contracts/src/immutable/MixinStorage.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IStaking.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IStakingEvents.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IStakingProxy.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IStorage.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IStorageInit.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IStructs.sol delete mode 100644 contracts/staking/contracts/src/interfaces/IZrxVault.sol delete mode 100644 contracts/staking/contracts/src/libs/LibCobbDouglas.sol delete mode 100644 contracts/staking/contracts/src/libs/LibFixedMath.sol delete mode 100644 contracts/staking/contracts/src/libs/LibFixedMathRichErrors.sol delete mode 100644 contracts/staking/contracts/src/libs/LibSafeDowncast.sol delete mode 100644 contracts/staking/contracts/src/libs/LibStakingRichErrors.sol delete mode 100644 contracts/staking/contracts/src/stake/MixinStake.sol delete mode 100644 contracts/staking/contracts/src/stake/MixinStakeBalances.sol delete mode 100644 contracts/staking/contracts/src/stake/MixinStakeStorage.sol delete mode 100644 contracts/staking/contracts/src/staking_pools/MixinCumulativeRewards.sol delete mode 100644 contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol delete mode 100644 contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol delete mode 100644 contracts/staking/contracts/src/sys/MixinAbstract.sol delete mode 100644 contracts/staking/contracts/src/sys/MixinFinalizer.sol delete mode 100644 contracts/staking/contracts/src/sys/MixinParams.sol delete mode 100644 contracts/staking/contracts/src/sys/MixinScheduler.sol delete mode 100644 contracts/staking/contracts/test/TestAssertStorageParams.sol delete mode 100644 contracts/staking/contracts/test/TestCobbDouglas.sol delete mode 100644 contracts/staking/contracts/test/TestCumulativeRewardTracking.sol delete mode 100644 contracts/staking/contracts/test/TestDelegatorRewards.sol delete mode 100644 contracts/staking/contracts/test/TestExchangeManager.sol delete mode 100644 contracts/staking/contracts/test/TestFinalizer.sol delete mode 100644 contracts/staking/contracts/test/TestInitTarget.sol delete mode 100644 contracts/staking/contracts/test/TestLibFixedMath.sol delete mode 100644 contracts/staking/contracts/test/TestLibSafeDowncast.sol delete mode 100644 contracts/staking/contracts/test/TestMixinCumulativeRewards.sol delete mode 100644 contracts/staking/contracts/test/TestMixinParams.sol delete mode 100644 contracts/staking/contracts/test/TestMixinScheduler.sol delete mode 100644 contracts/staking/contracts/test/TestMixinStake.sol delete mode 100644 contracts/staking/contracts/test/TestMixinStakeBalances.sol delete mode 100644 contracts/staking/contracts/test/TestMixinStakeStorage.sol delete mode 100644 contracts/staking/contracts/test/TestMixinStakingPool.sol delete mode 100644 contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol delete mode 100644 contracts/staking/contracts/test/TestProtocolFees.sol delete mode 100644 contracts/staking/contracts/test/TestProxyDestination.sol delete mode 100644 contracts/staking/contracts/test/TestStaking.sol delete mode 100644 contracts/staking/contracts/test/TestStakingNoWETH.sol delete mode 100644 contracts/staking/contracts/test/TestStakingProxy.sol delete mode 100644 contracts/staking/contracts/test/TestStakingProxyUnit.sol delete mode 100644 contracts/staking/contracts/test/TestStorageLayoutAndConstants.sol delete mode 100644 contracts/staking/package.json delete mode 100644 contracts/staking/src/artifacts.ts delete mode 100644 contracts/staking/src/constants.ts delete mode 100644 contracts/staking/src/index.ts delete mode 100644 contracts/staking/src/types.ts delete mode 100644 contracts/staking/src/wrappers.ts delete mode 100644 contracts/staking/test/actors/base_actor.ts delete mode 100644 contracts/staking/test/actors/finalizer_actor.ts delete mode 100644 contracts/staking/test/actors/maker_actor.ts delete mode 100644 contracts/staking/test/actors/pool_operator_actor.ts delete mode 100644 contracts/staking/test/actors/staker_actor.ts delete mode 100644 contracts/staking/test/artifacts.ts delete mode 100644 contracts/staking/test/codesize_test.ts delete mode 100644 contracts/staking/test/cumulative_reward_tracking_test.ts delete mode 100644 contracts/staking/test/epoch_test.ts delete mode 100644 contracts/staking/test/global_hooks.ts delete mode 100644 contracts/staking/test/layout_and_constant_regression_test.ts delete mode 100644 contracts/staking/test/migration_test.ts delete mode 100644 contracts/staking/test/patch_mainnet_test.ts delete mode 100644 contracts/staking/test/pools_test.ts delete mode 100644 contracts/staking/test/rewards_test.ts delete mode 100644 contracts/staking/test/stake_test.ts delete mode 100644 contracts/staking/test/unit_tests/authorizable.ts delete mode 100644 contracts/staking/test/unit_tests/delegator_reward_test.ts delete mode 100644 contracts/staking/test/unit_tests/exchange_test.ts delete mode 100644 contracts/staking/test/unit_tests/finalizer_test.ts delete mode 100644 contracts/staking/test/unit_tests/lib_cobb_douglas_test.ts delete mode 100644 contracts/staking/test/unit_tests/lib_fixed_math_test.ts delete mode 100644 contracts/staking/test/unit_tests/lib_safe_downcast_test.ts delete mode 100644 contracts/staking/test/unit_tests/mixin_cumulative_rewards_test.ts delete mode 100644 contracts/staking/test/unit_tests/mixin_scheduler_test.ts delete mode 100644 contracts/staking/test/unit_tests/mixin_stake_storage_test.ts delete mode 100644 contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts delete mode 100644 contracts/staking/test/unit_tests/params_test.ts delete mode 100644 contracts/staking/test/unit_tests/protocol_fees_test.ts delete mode 100644 contracts/staking/test/unit_tests/stake_balances_test.ts delete mode 100644 contracts/staking/test/unit_tests/stake_test.ts delete mode 100644 contracts/staking/test/unit_tests/staking_pool_test.ts delete mode 100644 contracts/staking/test/unit_tests/staking_proxy_test.ts delete mode 100644 contracts/staking/test/unit_tests/zrx_vault_test.ts delete mode 100644 contracts/staking/test/utils/api_wrapper.ts delete mode 100644 contracts/staking/test/utils/cumulative_reward_tracking_simulation.ts delete mode 100644 contracts/staking/test/utils/queue.ts delete mode 100644 contracts/staking/test/wrappers.ts delete mode 100644 contracts/staking/truffle-config.js delete mode 100644 contracts/staking/tsconfig.json delete mode 100644 contracts/staking/tslint.json delete mode 100644 contracts/staking/typedoc-tsconfig.json rename contracts/{exchange-libs => utils}/contracts/src/LibMath.sol (98%) rename contracts/{exchange-libs => utils}/contracts/src/LibMathRichErrors.sol (100%) rename contracts/{exchange-libs => utils}/contracts/test/TestLibMath.sol (100%) rename contracts/{exchange-libs => utils}/test/lib_math.ts (99%) delete mode 100644 packages/contract-wrappers-test/.npmignore delete mode 100644 packages/contract-wrappers-test/coverage/.gitkeep delete mode 100644 packages/contract-wrappers-test/package.json delete mode 100644 packages/contract-wrappers-test/test/calldata_decoder_test.ts delete mode 100644 packages/contract-wrappers-test/test/global_hooks.ts delete mode 100644 packages/contract-wrappers-test/test/utils/chai_setup.ts delete mode 100644 packages/contract-wrappers-test/test/utils/constants.ts delete mode 100644 packages/contract-wrappers-test/test/utils/web3_wrapper.ts delete mode 100644 packages/contract-wrappers-test/tsconfig.json delete mode 100644 packages/contract-wrappers-test/tslint.json delete mode 100644 packages/order-utils/.npmignore delete mode 100644 packages/order-utils/CHANGELOG.json delete mode 100644 packages/order-utils/CHANGELOG.md delete mode 100644 packages/order-utils/README.md delete mode 100644 packages/order-utils/coverage/.gitkeep delete mode 100644 packages/order-utils/docs/reference.mdx delete mode 100644 packages/order-utils/package.json delete mode 100644 packages/order-utils/src/assert.ts delete mode 100644 packages/order-utils/src/asset_data_utils.ts delete mode 100644 packages/order-utils/src/constants.ts delete mode 100644 packages/order-utils/src/eip712_utils.ts delete mode 100644 packages/order-utils/src/hash_utils.ts delete mode 100644 packages/order-utils/src/index.ts delete mode 100644 packages/order-utils/src/market_utils.ts delete mode 100644 packages/order-utils/src/order_calculation_utils.ts delete mode 100644 packages/order-utils/src/order_factory.ts delete mode 100644 packages/order-utils/src/order_hash_utils.ts delete mode 100644 packages/order-utils/src/rate_utils.ts delete mode 100644 packages/order-utils/src/remaining_fillable_calculator.ts delete mode 100644 packages/order-utils/src/salt.ts delete mode 100644 packages/order-utils/src/schemas/validate_order_fillable_opts_schema.ts delete mode 100644 packages/order-utils/src/signature_utils.ts delete mode 100644 packages/order-utils/src/sorting_utils.ts delete mode 100644 packages/order-utils/src/transaction_hash_utils.ts delete mode 100644 packages/order-utils/src/transformer_utils.ts delete mode 100644 packages/order-utils/src/types.ts delete mode 100644 packages/order-utils/src/utils.ts delete mode 100644 packages/order-utils/test/artifacts/UntransferrableDummyERC20Token.ts delete mode 100644 packages/order-utils/test/assert_test.ts delete mode 100644 packages/order-utils/test/asset_data_utils_test.ts delete mode 100644 packages/order-utils/test/eip712_utils_test.ts delete mode 100644 packages/order-utils/test/market_utils_test.ts delete mode 100644 packages/order-utils/test/rate_utils_test.ts delete mode 100644 packages/order-utils/test/remaining_fillable_calculator_test.ts delete mode 100644 packages/order-utils/test/signature_utils_test.ts delete mode 100644 packages/order-utils/test/sorting_utils_test.ts delete mode 100644 packages/order-utils/test/utils/chai_setup.ts delete mode 100644 packages/order-utils/test/utils/test_order_factory.ts delete mode 100644 packages/order-utils/test/utils/web3_wrapper.ts delete mode 100644 packages/order-utils/tsconfig.json delete mode 100644 packages/order-utils/tslint.json delete mode 100644 packages/order-utils/typedoc-tsconfig.json diff --git a/README.md b/README.md index ace0159318..c3cf9f75c3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ --- -[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md). +[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://protocol.0x.org/). This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM. @@ -15,40 +15,31 @@ This repository is a monorepo including the 0x protocol smart contracts and nume ## Packages -Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below. +Visit our [developer portal](https://0x.org/docs/) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below. ### Solidity Packages These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages. -| Package | Version | Description | -| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [![npm](https://img.shields.io/npm/v/@0x/contracts-asset-proxy.svg)](https://www.npmjs.com/package/@0x/contracts-asset-proxy) | [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts used within the protocol | -| [`@0x/contracts-erc20`](/contracts/erc20) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc20.svg)](https://www.npmjs.com/package/@0x/contracts-erc20) | Implementations of various ERC20 tokens | -| [`@0x/contracts-erc721`](/contracts/erc721) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc721.svg)](https://www.npmjs.com/package/@0x/contracts-erc721) | Implementations of various ERC721 tokens | -| [`@0x/contracts-erc1155`](/contracts/erc1155) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc1155.svg)](https://www.npmjs.com/package/@0x/contracts-erc1155) | Implementations of various ERC1155 tokens | -| [`@0x/contracts-exchange`](/contracts/exchange) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange.svg)](https://www.npmjs.com/package/@0x/contracts-exchange) | The [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract used for settling trades within the protocol | -| [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange-forwarder.svg)](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder) | A [`Forwarder`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract used to simplify UX for interacting with the protocol | -| [`@0x/contracts-exchange-libs`](/contracts/exchange-libs) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange-libs.svg)](https://www.npmjs.com/package/@0x/contracts-exchange-libs) | Protocol specific libraries used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract | -| [`@0x/contracts-extensions`](/contracts/extensions) | [![npm](https://img.shields.io/npm/v/@0x/contracts-extensions.svg)](https://www.npmjs.com/package/@0x/contracts-extensions) | Contracts that interact with and extend the functionality of the core protocol | -| [`@0x/contracts-multisig`](/contracts/multisig) | [![npm](https://img.shields.io/npm/v/@0x/contracts-multisig.svg)](https://www.npmjs.com/package/@0x/contracts-multisig) | Various implementations of multisignature wallets, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that has permissions to upgrade the protocol | -| [`@0x/contracts-test-utils`](/contracts/test-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-test-utils.svg)](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts | -| [`@0x/contracts-utils`](/contracts/utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-utils.svg)](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts | -| [`@0x/contracts-coordinator`](/contracts/coordinator) | [![npm](https://img.shields.io/npm/v/@0x/contracts-coordinator.svg)](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator | -| [`@0x/contracts-dev-utils`](/contracts/dev-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-dev-utils.svg)](https://www.npmjs.com/package/@0x/contracts-dev-utils) | A contract contains utility functions for developers (such as validating many orders using a single eth_call) | -| [`@0x/contracts-staking`](/contracts/staking) | [![npm](https://img.shields.io/npm/v/@0x/contracts-staking.svg)](https://www.npmjs.com/package/@0x/contracts-staking) | Implements the stake-based liquidity incentives defined by [`ZEIP-31`](https://github.com/0xProject/ZEIPs/issues/31) | +| Package | Version | Description | +| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| [`@0x/contracts-zero-ex`](/contracts/zero-ex) | [![npm](https://img.shields.io/npm/v/@0x/contracts-zero-ex.svg)](https://www.npmjs.com/package/@0x/contracts-zero-ex) | The contracts used for settling trades within the protocol | +| [`@0x/contracts-erc20`](/contracts/erc20) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc20.svg)](https://www.npmjs.com/package/@0x/contracts-erc20) | Implementations of various ERC20 tokens | +| [`@0x/contracts-test-utils`](/contracts/test-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-test-utils.svg)](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts | +| [`@0x/contracts-utils`](/contracts/utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-utils.svg)](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts | ### TypeScript/Javascript Packages #### 0x-specific packages | Package | Version | Description | -| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| [`@0x/asset-swapper`](/packages/asset-swapper) | [![npm](https://img.shields.io/npm/v/@0x/asset-swapper.svg)](https://www.npmjs.com/package/@0x/asset-swapper) | Package used to find and create aggregated swaps | +| [`@0x/protocol-utils`](/packages/protocol-utils) | [![npm](https://img.shields.io/npm/v/@0x/protocol-utils.svg)](https://www.npmjs.com/package/@0x/protocol-utils) | A set of utilities for generating, parsing, signing and validating 0x orders | | [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. | | [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts | -| [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders | | [`@0x/migrations`](/packages/migrations) | [![npm](https://img.shields.io/npm/v/@0x/migrations.svg)](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets | -| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | | +| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | | ## Usage @@ -92,7 +83,7 @@ yarn build To build a specific package: ```bash -PKG=@0x/contract-wrappers yarn build +PKG=@0x/asset-swapper yarn build ``` To build all contracts packages: @@ -115,7 +106,7 @@ To watch a specific package and all it's dependent packages: PKG=[NPM_PACKAGE_NAME] yarn watch e.g -PKG=@0x/contract-wrappers yarn watch +PKG=@0x/asset-swapper yarn watch ``` ### Clean @@ -129,7 +120,7 @@ yarn clean Clean a specific package ```bash -PKG=0x.js yarn clean +PKG=@0x/asset-swapper yarn clean ``` ### Rebuild @@ -143,7 +134,7 @@ yarn rebuild To re-build (clean & build) a specific package & it's deps: ```bash -PKG=@0x/contract-wrappers yarn rebuild +PKG=@0x/asset-swapper yarn rebuild ``` ### Lint @@ -157,7 +148,7 @@ yarn lint Lint a specific package: ```bash -PKG=@0x/contract-wrappers yarn lint +PKG=@0x/asset-swapper yarn lint ``` ### Run Tests @@ -171,7 +162,7 @@ yarn test Run a specific package's test: ```bash -PKG=@0x/contract-wrappers yarn test +PKG=@0x/asset-swapper yarn test ``` Run all contracts packages tests: diff --git a/contracts/README.md b/contracts/README.md index 4759cc7f0d..42b72f3995 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -1,16 +1,3 @@ -#### Deployed Contract Packages - -| Contract | Package | Version | Git Tag | -| --------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| AssetProxyOwner | [`@0x/contracts-multisig`](/contracts/multisig) | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-multisig/v/1.0.2) | [@0x/contracts-multisig@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-multisig@1.0.2) | -| ERC20Proxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) | -| ERC721Proxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) | -| Exchange | [`@0x/contracts-exchange`](/contracts/exchange) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange/v/1.0.1) | [@0x/contracts-exchange@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange@1.0.1) | -| DutchAuction | [`@0x/contracts-extensions`](/contracts/extensions) | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-extensions/v/1.0.2) | [@0x/contracts-extensions@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-extensions@1.0.2) | -| Forwarder | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) | -| MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) | -| ZRXToken | [`@0x/contracts-erc20`](/contracts/erc20) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1) | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1) | - #### Development Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages. diff --git a/contracts/TESTING.md b/contracts/TESTING.md deleted file mode 100644 index 3e6888c04b..0000000000 --- a/contracts/TESTING.md +++ /dev/null @@ -1,48 +0,0 @@ -# Contracts 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-coverage`, 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/contracts/asset-proxy/.npmignore b/contracts/asset-proxy/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/asset-proxy/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/asset-proxy/.solhintignore b/contracts/asset-proxy/.solhintignore deleted file mode 100644 index b51bf4177c..0000000000 --- a/contracts/asset-proxy/.solhintignore +++ /dev/null @@ -1,2 +0,0 @@ -# solhint can't parse `abi.decode` syntax. -contracts/src/ERC1155Proxy.sol diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json deleted file mode 100644 index b6671fbd59..0000000000 --- a/contracts/asset-proxy/CHANGELOG.json +++ /dev/null @@ -1,904 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "3.7.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "3.7.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "3.7.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "3.7.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "3.7.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "3.7.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "3.7.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "3.7.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "3.7.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "3.7.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "3.7.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "3.7.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "3.7.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "3.7.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "3.7.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "3.7.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "3.7.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "3.7.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "3.7.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.7.0", - "changes": [ - { - "note": "Fix Bancor support of ETH", - "pr": 88 - } - ], - "timestamp": 1608105788 - }, - { - "timestamp": 1607485227, - "version": "3.6.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "3.6.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "3.6.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "3.6.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "3.6.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "3.6.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "3.6.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "3.6.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "3.6.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.6.0", - "changes": [ - { - "note": "Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`)", - "pr": 2707 - } - ], - "timestamp": 1603833198 - }, - { - "version": "3.5.0", - "changes": [ - { - "note": "Update `CurveBridge` to support more varied curves", - "pr": 2633 - }, - { - "note": "Export DexForwarderBridgeContract", - "pr": 2656 - }, - { - "note": "Add BancorBridge and IBancorNetwork, ", - "pr": 2650 - }, - { - "note": "Added `MStableBridge`", - "pr": 2662 - }, - { - "note": "Added `MooniswapBridge`", - "pr": 2675 - }, - { - "note": "Reworked `KyberBridge`", - "pr": 2683 - }, - { - "note": "Added `CreamBridge`", - "pr": 2715 - }, - { - "note": "Added `ShellBridge`", - "pr": 2722 - }, - { - "note": "Added `DODOBridge`", - "pr": 2701 - } - ], - "timestamp": 1603265572 - }, - { - "version": "3.4.0", - "changes": [ - { - "note": "Fix instability with DFB.", - "pr": 2616 - }, - { - "note": "Add `BalancerBridge`", - "pr": 2613 - } - ], - "timestamp": 1594788383 - }, - { - "version": "3.3.0", - "changes": [ - { - "note": "Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals.", - "pr": 2512 - }, - { - "note": "Emit `ERC20BridgeTransfer` events in bridges.", - "pr": 2512 - }, - { - "note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.", - "pr": 2524 - }, - { - "note": "Added `MixinGasToken` allowing Gas Tokens to be freed", - "pr": 2523 - }, - { - "note": "Add `DexForwaderBridge` bridge contract.", - "pr": 2525 - }, - { - "note": "Add `UniswapV2Bridge` bridge contract.", - "pr": 2590 - }, - { - "note": "Add Gas Token freeing to `DexForwarderBridge` contract.", - "pr": 2536 - } - ], - "timestamp": 1592969527 - }, - { - "timestamp": 1583220306, - "version": "3.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "3.2.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "3.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "3.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "3.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.2.0", - "changes": [ - { - "note": "Add more types and functions to `IDydx`", - "pr": 2466 - }, - { - "note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`", - "pr": 2466 - }, - { - "note": "Fix broken tests.", - "pr": 2462 - }, - { - "note": "Remove dependency on `@0x/contracts-dev-utils`", - "pr": 2462 - }, - { - "note": "Add asset data decoding functions", - "pr": 2462 - }, - { - "note": "Add `setOperators()` to `IDydx`", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "3.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Integration tests for DydxBridge with ERC20BridgeProxy.", - "pr": 2401 - }, - { - "note": "Fix `UniswapBridge` token -> token transfer call.", - "pr": 2412 - }, - { - "note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.", - "pr": 2412 - } - ], - "timestamp": 1578272714 - }, - { - "timestamp": 1576540892, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Implement `KyberBridge`.", - "pr": 2352 - }, - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract", - "pr": 2034 - }, - { - "note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable", - "pr": 2019 - }, - { - "note": "Remove `LibAssetProxyIds` contract", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Remove unused dependency on IAuthorizable in IAssetProxy", - "pr": 1910 - }, - { - "note": "Add `ERC20BridgeProxy`", - "pr": 2220 - }, - { - "note": "Add `Eth2DaiBridge`", - "pr": 2221 - }, - { - "note": "Add `UniswapBridge`", - "pr": 2233 - }, - { - "note": "Replaced `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1575296764 - }, - { - "version": "2.3.0-beta.4", - "changes": [ - { - "note": "Implement `KyberBridge`.", - "pr": 2352 - }, - { - "note": "Implement `DydxBridge`.", - "pr": 2365 - } - ], - "timestamp": 1575290197 - }, - { - "version": "2.3.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "2.3.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - } - ], - "timestamp": 1574030254 - }, - { - "version": "2.3.0-beta.1", - "changes": [ - { - "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract", - "pr": 2034 - } - ], - "timestamp": 1573159180 - }, - { - "version": "2.3.0-beta.0", - "changes": [ - { - "note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable", - "pr": 2019 - }, - { - "note": "Remove `LibAssetProxyIds` contract", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Remove unused dependency on IAuthorizable in IAssetProxy", - "pr": 1910 - }, - { - "note": "Add `ERC20BridgeProxy`", - "pr": 2220 - }, - { - "note": "Add `Eth2DaiBridge`", - "pr": 2221 - }, - { - "note": "Add `UniswapBridge`", - "pr": 2233 - }, - { - "note": "Replaced `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "2.2.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "2.2.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "2.2.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "2.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.2.4", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564607468 - }, - { - "timestamp": 1563957393, - "version": "2.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "2.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "2.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.2.0", - "changes": [ - { - "note": "Add `LibAssetProxyIds` contract", - "pr": 1835 - }, - { - "note": "Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases.", - "pr": 1852 - }, - { - "note": "Implement StaticCallProxy", - "pr": 1863 - } - ], - "timestamp": 1563006338 - }, - { - "timestamp": 1558712885, - "version": "2.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "2.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557799313, - "version": "2.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.2", - "changes": [ - { - "note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`", - "pr": 1797 - }, - { - "note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID", - "pr": 1819 - }, - { - "note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`", - "pr": 1819 - }, - { - "note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.", - "pr": 1819 - } - ], - "timestamp": 1557507213 - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Do not reexport external dependencies", - "pr": 1682 - }, - { - "note": "Add ERC1155Proxy", - "pr": 1661 - }, - { - "note": "Bumped solidity version to ^0.5.5", - "pr": 1701 - }, - { - "note": "Integration testing for ERC1155Proxy", - "pr": 1673 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "1.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "1.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549373905, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Move all AssetProxy contracts out of contracts-protocol to new package", - "pr": 1539 - } - ] - } -] diff --git a/contracts/asset-proxy/CHANGELOG.md b/contracts/asset-proxy/CHANGELOG.md deleted file mode 100644 index e64972f803..0000000000 --- a/contracts/asset-proxy/CHANGELOG.md +++ /dev/null @@ -1,362 +0,0 @@ - - -CHANGELOG - -## v3.7.19 - _August 16, 2021_ - - * Dependencies updated - -## v3.7.18 - _August 11, 2021_ - - * Dependencies updated - -## v3.7.17 - _August 6, 2021_ - - * Dependencies updated - -## v3.7.16 - _June 22, 2021_ - - * Dependencies updated - -## v3.7.15 - _June 11, 2021_ - - * Dependencies updated - -## v3.7.14 - _June 2, 2021_ - - * Dependencies updated - -## v3.7.13 - _May 25, 2021_ - - * Dependencies updated - -## v3.7.12 - _May 21, 2021_ - - * Dependencies updated - -## v3.7.11 - _May 5, 2021_ - - * Dependencies updated - -## v3.7.10 - _April 28, 2021_ - - * Dependencies updated - -## v3.7.9 - _April 1, 2021_ - - * Dependencies updated - -## v3.7.8 - _March 17, 2021_ - - * Dependencies updated - -## v3.7.7 - _February 24, 2021_ - - * Dependencies updated - -## v3.7.6 - _February 10, 2021_ - - * Dependencies updated - -## v3.7.5 - _January 26, 2021_ - - * Dependencies updated - -## v3.7.4 - _January 13, 2021_ - - * Dependencies updated - -## v3.7.3 - _January 4, 2021_ - - * Dependencies updated - -## v3.7.2 - _December 23, 2020_ - - * Dependencies updated - -## v3.7.1 - _December 17, 2020_ - - * Dependencies updated - -## v3.7.0 - _December 16, 2020_ - - * Fix Bancor support of ETH (#88) - -## v3.6.9 - _December 9, 2020_ - - * Dependencies updated - -## v3.6.8 - _December 7, 2020_ - - * Dependencies updated - -## v3.6.7 - _December 3, 2020_ - - * Dependencies updated - -## v3.6.6 - _November 19, 2020_ - - * Dependencies updated - -## v3.6.5 - _November 13, 2020_ - - * Dependencies updated - -## v3.6.4 - _November 3, 2020_ - - * Dependencies updated - -## v3.6.3 - _November 3, 2020_ - - * Dependencies updated - -## v3.6.2 - _November 2, 2020_ - - * Dependencies updated - -## v3.6.1 - _October 28, 2020_ - - * Dependencies updated - -## v3.6.0 - _October 27, 2020_ - - * Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`) (#2707) - -## v3.5.0 - _October 21, 2020_ - - * Update `CurveBridge` to support more varied curves (#2633) - * Export DexForwarderBridgeContract (#2656) - * Add BancorBridge and IBancorNetwork, (#2650) - * Added `MStableBridge` (#2662) - * Added `MooniswapBridge` (#2675) - * Reworked `KyberBridge` (#2683) - * Added `CreamBridge` (#2715) - * Added `ShellBridge` (#2722) - * Added `DODOBridge` (#2701) - -## v3.4.0 - _July 15, 2020_ - - * Fix instability with DFB. (#2616) - * Add `BalancerBridge` (#2613) - -## v3.3.0 - _June 24, 2020_ - - * Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals. (#2512) - * Emit `ERC20BridgeTransfer` events in bridges. (#2512) - * Change names of `ERC20BridgeTransfer` args to be less ambiguous. (#2524) - * Added `MixinGasToken` allowing Gas Tokens to be freed (#2523) - * Add `DexForwaderBridge` bridge contract. (#2525) - * Add `UniswapV2Bridge` bridge contract. (#2590) - * Add Gas Token freeing to `DexForwarderBridge` contract. (#2536) - -## v3.2.5 - _March 3, 2020_ - - * Dependencies updated - -## v3.2.4 - _February 27, 2020_ - - * Dependencies updated - -## v3.2.3 - _February 26, 2020_ - - * Dependencies updated - -## v3.2.2 - _February 25, 2020_ - - * Dependencies updated - -## v3.2.1 - _February 15, 2020_ - - * Dependencies updated - -## v3.2.0 - _February 8, 2020_ - - * Add more types and functions to `IDydx` (#2466) - * Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466) - * Fix broken tests. (#2462) - * Remove dependency on `@0x/contracts-dev-utils` (#2462) - * Add asset data decoding functions (#2462) - * Add `setOperators()` to `IDydx` (#2462) - -## v3.1.3 - _February 6, 2020_ - - * Dependencies updated - -## v3.1.2 - _February 4, 2020_ - - * Dependencies updated - -## v3.1.1 - _January 22, 2020_ - - * Dependencies updated - -## v3.1.0 - _January 6, 2020_ - - * Integration tests for DydxBridge with ERC20BridgeProxy. (#2401) - * Fix `UniswapBridge` token -> token transfer call. (#2412) - * Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412) - -## v3.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v3.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v3.0.0 - _December 2, 2019_ - - * Implement `KyberBridge`. (#2352) - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) - * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019) - * Remove `LibAssetProxyIds` contract (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Remove unused dependency on IAuthorizable in IAssetProxy (#1910) - * Add `ERC20BridgeProxy` (#2220) - * Add `Eth2DaiBridge` (#2221) - * Add `UniswapBridge` (#2233) - * Replaced `SafeMath` with `LibSafeMath` (#2254) - -## v2.3.0-beta.4 - _December 2, 2019_ - - * Implement `KyberBridge`. (#2352) - * Implement `DydxBridge`. (#2365) - -## v2.3.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v2.3.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - -## v2.3.0-beta.1 - _November 7, 2019_ - - * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034) - -## v2.3.0-beta.0 - _October 3, 2019_ - - * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019) - * Remove `LibAssetProxyIds` contract (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Remove unused dependency on IAuthorizable in IAssetProxy (#1910) - * Add `ERC20BridgeProxy` (#2220) - * Add `Eth2DaiBridge` (#2221) - * Add `UniswapBridge` (#2233) - * Replaced `SafeMath` with `LibSafeMath` (#2254) - -## v2.2.8 - _September 17, 2019_ - - * Dependencies updated - -## v2.2.7 - _September 3, 2019_ - - * Dependencies updated - -## v2.2.6 - _August 22, 2019_ - - * Dependencies updated - -## v2.2.5 - _August 8, 2019_ - - * Dependencies updated - -## v2.2.4 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v2.2.3 - _July 24, 2019_ - - * Dependencies updated - -## v2.2.2 - _July 15, 2019_ - - * Dependencies updated - -## v2.2.1 - _July 13, 2019_ - - * Dependencies updated - -## v2.2.0 - _July 13, 2019_ - - * Add `LibAssetProxyIds` contract (#1835) - * Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases. (#1852) - * Implement StaticCallProxy (#1863) - -## v2.1.5 - _May 24, 2019_ - - * Dependencies updated - -## v2.1.4 - _May 15, 2019_ - - * Dependencies updated - -## v2.1.3 - _May 14, 2019_ - - * Dependencies updated - -## v2.1.2 - _May 10, 2019_ - - * Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797) - * Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819) - * Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819) - * Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819) - -## v2.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v2.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v2.0.0 - _March 20, 2019_ - - * Do not reexport external dependencies (#1682) - * Add ERC1155Proxy (#1661) - * Bumped solidity version to ^0.5.5 (#1701) - * Integration testing for ERC1155Proxy (#1673) - -## v1.0.9 - _March 1, 2019_ - - * Dependencies updated - -## v1.0.8 - _February 27, 2019_ - - * Dependencies updated - -## v1.0.7 - _February 26, 2019_ - - * Dependencies updated - -## v1.0.6 - _February 25, 2019_ - - * Dependencies updated - -## v1.0.5 - _February 9, 2019_ - - * Dependencies updated - -## v1.0.4 - _February 7, 2019_ - - * Dependencies updated - -## v1.0.3 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v1.0.2 - _February 6, 2019_ - - * Dependencies updated - -## v1.0.1 - _February 5, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Move all AssetProxy contracts out of contracts-protocol to new package (#1539) diff --git a/contracts/asset-proxy/DEPLOYS.json b/contracts/asset-proxy/DEPLOYS.json deleted file mode 100644 index 0f25da1c3a..0000000000 --- a/contracts/asset-proxy/DEPLOYS.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "name": "MultiAssetProxy", - "version": "1.0.0", - "changes": [ - { - "note": "Add MultiAssetProxy implementation", - "pr": 1224, - "networks": { - "3": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6", - "4": "0xb34cde0ad3a83d04abebc0b66e75196f22216621", - "42": "0xf6313a772c222f51c28f2304c0703b8cf5428fd8" - } - } - ] - }, - { - "name": "ERC20Proxy", - "version": "1.0.0", - "changes": [ - { - "note": "protocol v2 deploy", - "networks": { - "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e", - "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa", - "4": "0x3e809c563c15a295e832e37053798ddc8d6c8dab", - "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e" - } - } - ] - }, - { - "name": "ERC721Proxy", - "version": "1.0.0", - "changes": [ - { - "note": "protocol v2 deploy", - "networks": { - "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127", - "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4", - "4": "0x8e1ff02637cb5e39f2fa36c14706aa348b065b09", - "42": "0x2a9127c745688a165106c11cd4d647d2220af821" - } - } - ] - } -] diff --git a/contracts/asset-proxy/README.md b/contracts/asset-proxy/README.md deleted file mode 100644 index 21dd19f9c5..0000000000 --- a/contracts/asset-proxy/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## AssetProxy - -This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-asset-proxy --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-asset-proxy yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-asset-proxy yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/asset-proxy/compiler.json b/contracts/asset-proxy/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/asset-proxy/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/asset-proxy/contracts/archive/MixinAssetProxyDispatcher.sol b/contracts/asset-proxy/contracts/archive/MixinAssetProxyDispatcher.sol deleted file mode 100644 index bbc93ec6cb..0000000000 --- a/contracts/asset-proxy/contracts/archive/MixinAssetProxyDispatcher.sol +++ /dev/null @@ -1,172 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../archive/Ownable.sol"; -import "../src/interfaces/IAssetProxy.sol"; -import "../src/interfaces/IAssetProxyDispatcher.sol"; - - -contract MixinAssetProxyDispatcher is - Ownable, - IAssetProxyDispatcher -{ - // Mapping from Asset Proxy Id's to their respective Asset Proxy - mapping (bytes4 => address) 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 - { - // Ensure that no asset proxy exists with current id. - bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId(); - address currentAssetProxy = assetProxies[assetProxyId]; - require( - currentAssetProxy == address(0), - "ASSET_PROXY_ALREADY_EXISTS" - ); - - // Add asset proxy and log registration. - assetProxies[assetProxyId] = assetProxy; - 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/contracts/asset-proxy/contracts/archive/MixinAuthorizable.sol b/contracts/asset-proxy/contracts/archive/MixinAuthorizable.sol deleted file mode 100644 index 5efb1340b6..0000000000 --- a/contracts/asset-proxy/contracts/archive/MixinAuthorizable.sol +++ /dev/null @@ -1,117 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../archive/Ownable.sol"; -import "../src/interfaces/IAuthorizable.sol"; - - -contract MixinAuthorizable is - Ownable, - IAuthorizable -{ - /// @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/contracts/asset-proxy/contracts/archive/Ownable.sol b/contracts/asset-proxy/contracts/archive/Ownable.sol deleted file mode 100644 index b15e5d0266..0000000000 --- a/contracts/asset-proxy/contracts/archive/Ownable.sol +++ /dev/null @@ -1,33 +0,0 @@ -pragma solidity ^0.5.9; - -import "@0x/contracts-utils/contracts/src/interfaces/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/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol deleted file mode 100644 index 9ae6e5bc88..0000000000 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ /dev/null @@ -1,97 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; -import "../archive/MixinAuthorizable.sol"; -import "./interfaces/IAssetProxy.sol"; - - -contract ERC1155Proxy is - MixinAuthorizable, - IAssetProxy -{ - using LibBytes for bytes; - using LibSafeMath for uint256; - - // Id of this proxy. - bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)")); - - /// @dev Transfers batch of ERC1155 assets. Either succeeds or throws. - /// @param assetData Byte array encoded with ERC1155 token address, array of ids, array of values, and callback data. - /// @param from Address to transfer assets from. - /// @param to Address to transfer assets to. - /// @param amount Amount that will be multiplied with each element of `assetData.values` to scale the - /// values that will be transferred. - function transferFrom( - bytes calldata assetData, - address from, - address to, - uint256 amount - ) - external - onlyAuthorized - { - // Decode params from `assetData` - // solhint-disable indent - ( - address erc1155TokenAddress, - uint256[] memory ids, - uint256[] memory values, - bytes memory data - ) = abi.decode( - assetData.sliceDestructive(4, assetData.length), - (address, uint256[], uint256[], bytes) - ); - // solhint-enable indent - - // Scale values up by `amount` - uint256 length = values.length; - uint256[] memory scaledValues = new uint256[](length); - for (uint256 i = 0; i != length; i++) { - // We write the scaled values to an unused location in memory in order - // to avoid copying over `ids` or `data`. This is possible if they are - // identical to `values` and the offsets for each are pointing to the - // same location in the ABI encoded calldata. - scaledValues[i] = values[i].safeMul(amount); - } - - // Execute `safeBatchTransferFrom` call - // Either succeeds or throws - IERC1155(erc1155TokenAddress).safeBatchTransferFrom( - from, - to, - ids, - scaledValues, - data - ); - } - - /// @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/contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol b/contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol deleted file mode 100644 index 6efb3b376a..0000000000 --- a/contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol +++ /dev/null @@ -1,126 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/Authorizable.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "./interfaces/IAssetProxy.sol"; -import "./interfaces/IERC20Bridge.sol"; - - -contract ERC20BridgeProxy is - IAssetProxy, - Authorizable -{ - using LibBytes for bytes; - using LibSafeMath for uint256; - - // @dev Id of this proxy. Also the result of a successful bridge call. - // bytes4(keccak256("ERC20Bridge(address,address,bytes)")) - bytes4 constant private PROXY_ID = 0xdc1600f3; - - /// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from` - /// to `to`. Asserts that the balance of `to` has increased by `amount`. - /// @param assetData Abi-encoded data for this asset proxy encoded as: - /// abi.encodeWithSelector( - /// bytes4 PROXY_ID, - /// address tokenAddress, - /// address bridgeAddress, - /// bytes bridgeData - /// ) - /// @param from Address to transfer asset from. - /// @param to Address to transfer asset to. - /// @param amount Amount of asset to transfer. - function transferFrom( - bytes calldata assetData, - address from, - address to, - uint256 amount - ) - external - onlyAuthorized - { - // Extract asset data fields. - ( - address tokenAddress, - address bridgeAddress, - bytes memory bridgeData - ) = abi.decode( - assetData.sliceDestructive(4, assetData.length), - (address, address, bytes) - ); - - // Remember the balance of `to` before calling the bridge. - uint256 balanceBefore = balanceOf(tokenAddress, to); - // Call the bridge, who should transfer `amount` of `tokenAddress` to - // `to`. - bytes4 success = IERC20Bridge(bridgeAddress).bridgeTransferFrom( - tokenAddress, - from, - to, - amount, - bridgeData - ); - // Bridge must return the proxy ID to indicate success. - require(success == PROXY_ID, "BRIDGE_FAILED"); - // Ensure that the balance of `to` has increased by at least `amount`. - require( - balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to), - "BRIDGE_UNDERPAY" - ); - } - - /// @dev Gets the proxy id associated with this asset proxy. - /// @return proxyId The proxy id. - function getProxyId() - external - pure - returns (bytes4 proxyId) - { - return PROXY_ID; - } - - /// @dev Retrieves the balance of `owner` for this asset. - /// @return balance The balance of the ERC20 token being transferred by this - /// asset proxy. - function balanceOf(bytes calldata assetData, address owner) - external - view - returns (uint256 balance) - { - (address tokenAddress) = abi.decode( - assetData.sliceDestructive(4, assetData.length), - (address) - ); - return balanceOf(tokenAddress, owner); - } - - /// @dev Retrieves the balance of `owner` given an ERC20 address. - /// @return balance The balance of the ERC20 token for `owner`. - function balanceOf(address tokenAddress, address owner) - private - view - returns (uint256 balance) - { - return IERC20Token(tokenAddress).balanceOf(owner); - } -} diff --git a/contracts/asset-proxy/contracts/src/ERC20Proxy.sol b/contracts/asset-proxy/contracts/src/ERC20Proxy.sol deleted file mode 100644 index 645191e1ca..0000000000 --- a/contracts/asset-proxy/contracts/src/ERC20Proxy.sol +++ /dev/null @@ -1,184 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../archive/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/contracts/asset-proxy/contracts/src/ERC721Proxy.sol b/contracts/asset-proxy/contracts/src/ERC721Proxy.sol deleted file mode 100644 index 240ff26489..0000000000 --- a/contracts/asset-proxy/contracts/src/ERC721Proxy.sol +++ /dev/null @@ -1,171 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../archive/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/contracts/asset-proxy/contracts/src/MultiAssetProxy.sol b/contracts/asset-proxy/contracts/src/MultiAssetProxy.sol deleted file mode 100644 index a2c2e4aee9..0000000000 --- a/contracts/asset-proxy/contracts/src/MultiAssetProxy.sol +++ /dev/null @@ -1,335 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../archive/MixinAssetProxyDispatcher.sol"; -import "../archive/MixinAuthorizable.sol"; - - -contract MultiAssetProxy is - MixinAssetProxyDispatcher, - MixinAuthorizable -{ - // Id of this proxy. - bytes4 constant internal PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],bytes[])")); - - // solhint-disable-next-line payable-fallback - function () - external - { - // NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification. - // It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively - // expensive and we therefore do not check for overflows in these scenarios. - assembly { - // The first 4 bytes of calldata holds the function selector - let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) - - // `transferFrom` will be called with the following parameters: - // assetData Encoded byte array. - // from Address to transfer asset from. - // to Address to transfer asset to. - // amount Amount of asset to transfer. - // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4 - if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) { - - // To lookup a value in a mapping, we load from the storage location keccak256(k, p), - // where k is the key left padded to 32 bytes and p is the storage slot - mstore(0, caller) - mstore(32, authorized_slot) - - // Revert if authorized[msg.sender] == false - if iszero(sload(keccak256(0, 64))) { - // Revert with `Error("SENDER_NOT_AUTHORIZED")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000) - mstore(96, 0) - revert(0, 100) - } - - // `transferFrom`. - // The function is marked `external`, so no abi decoding is done for - // us. Instead, we expect the `calldata` memory to contain the - // following: - // - // | Area | Offset | Length | Contents | - // |----------|--------|---------|-------------------------------------| - // | Header | 0 | 4 | function selector | - // | Params | | 4 * 32 | function parameters: | - // | | 4 | | 1. offset to assetData (*) | - // | | 36 | | 2. from | - // | | 68 | | 3. to | - // | | 100 | | 4. amount | - // | Data | | | assetData: | - // | | 132 | 32 | assetData Length | - // | | 164 | ** | assetData Contents | - // - // (*): offset is computed from start of function parameters, so offset - // by an additional 4 bytes in the calldata. - // - // (**): see table below to compute length of assetData Contents - // - // WARNING: The ABIv2 specification allows additional padding between - // the Params and Data section. This will result in a larger - // offset to assetData. - - // Load offset to `assetData` - let assetDataOffset := add(calldataload(4), 4) - - // Load length in bytes of `assetData` - let assetDataLength := calldataload(assetDataOffset) - - // Asset data itself is encoded as follows: - // - // | Area | Offset | Length | Contents | - // |----------|-------------|---------|-------------------------------------| - // | Header | 0 | 4 | assetProxyId | - // | Params | | 2 * 32 | function parameters: | - // | | 4 | | 1. offset to amounts (*) | - // | | 36 | | 2. offset to nestedAssetData (*) | - // | Data | | | amounts: | - // | | 68 | 32 | amounts Length | - // | | 100 | a | amounts Contents | - // | | | | nestedAssetData: | - // | | 100 + a | 32 | nestedAssetData Length | - // | | 132 + a | b | nestedAssetData Contents (offsets) | - // | | 132 + a + b | | nestedAssetData[0, ..., len] | - - // Assert that the length of asset data: - // 1. Must be at least 68 bytes (see table above) - // 2. Must be a multiple of 32 (excluding the 4-byte selector) - if or(lt(assetDataLength, 68), mod(sub(assetDataLength, 4), 32)) { - // Revert with `Error("INVALID_ASSET_DATA_LENGTH")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000) - mstore(96, 0) - revert(0, 100) - } - - // End of asset data in calldata - // assetDataOffset - // + 32 (assetData len) - let assetDataEnd := add(assetDataOffset, add(assetDataLength, 32)) - if gt(assetDataEnd, calldatasize()) { - // Revert with `Error("INVALID_ASSET_DATA_END")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000) - mstore(96, 0) - revert(0, 100) - } - - // In order to find the offset to `amounts`, we must add: - // assetDataOffset - // + 32 (assetData len) - // + 4 (assetProxyId) - let amountsOffset := calldataload(add(assetDataOffset, 36)) - - // In order to find the offset to `nestedAssetData`, we must add: - // assetDataOffset - // + 32 (assetData len) - // + 4 (assetProxyId) - // + 32 (amounts offset) - let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68)) - - // In order to find the start of the `amounts` contents, we must add: - // assetDataOffset - // + 32 (assetData len) - // + 4 (assetProxyId) - // + amountsOffset - // + 32 (amounts len) - let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 68)) - - // Load number of elements in `amounts` - let amountsLen := calldataload(sub(amountsContentsStart, 32)) - - // In order to find the start of the `nestedAssetData` contents, we must add: - // assetDataOffset - // + 32 (assetData len) - // + 4 (assetProxyId) - // + nestedAssetDataOffset - // + 32 (nestedAssetData len) - let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 68)) - - // Load number of elements in `nestedAssetData` - let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32)) - - // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData` - if sub(amountsLen, nestedAssetDataLen) { - // Revert with `Error("LENGTH_MISMATCH")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000) - mstore(96, 0) - revert(0, 100) - } - - // Copy `transferFrom` selector, offset to `assetData`, `from`, and `to` from calldata to memory - calldatacopy( - 0, // memory can safely be overwritten from beginning - 0, // start of calldata - 100 // length of selector (4) and 3 params (32 * 3) - ) - - // Overwrite existing offset to `assetData` with our own - mstore(4, 128) - - // Load `amount` - let amount := calldataload(100) - - // Calculate number of bytes in `amounts` contents - let amountsByteLen := mul(amountsLen, 32) - - // Initialize `assetProxyId` and `assetProxy` to 0 - let assetProxyId := 0 - let assetProxy := 0 - - // Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element - for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} { - - // Calculate the total amount - let amountsElement := calldataload(add(amountsContentsStart, i)) - let totalAmount := mul(amountsElement, amount) - - // Revert if `amount` != 0 and multiplication resulted in an overflow - if iszero(or( - iszero(amount), - eq(div(totalAmount, amount), amountsElement) - )) { - // Revert with `Error("UINT256_OVERFLOW")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000) - mstore(96, 0) - revert(0, 100) - } - - // Write `totalAmount` to memory - mstore(100, totalAmount) - - // Load offset to `nestedAssetData[i]` - let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i)) - - // In order to find the start of the `nestedAssetData[i]` contents, we must add: - // assetDataOffset - // + 32 (assetData len) - // + 4 (assetProxyId) - // + nestedAssetDataOffset - // + 32 (nestedAssetData len) - // + nestedAssetDataElementOffset - // + 32 (nestedAssetDataElement len) - let nestedAssetDataElementContentsStart := add( - assetDataOffset, - add( - nestedAssetDataOffset, - add(nestedAssetDataElementOffset, 100) - ) - ) - - // Load length of `nestedAssetData[i]` - let nestedAssetDataElementLenStart := sub(nestedAssetDataElementContentsStart, 32) - let nestedAssetDataElementLen := calldataload(nestedAssetDataElementLenStart) - - // Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId` - if lt(nestedAssetDataElementLen, 4) { - // Revert with `Error("LENGTH_GREATER_THAN_3_REQUIRED")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x0000001e4c454e4754485f475245415445525f5448414e5f335f524551554952) - mstore(96, 0x4544000000000000000000000000000000000000000000000000000000000000) - revert(0, 100) - } - - // Load AssetProxy id - let currentAssetProxyId := and( - calldataload(nestedAssetDataElementContentsStart), - 0xffffffff00000000000000000000000000000000000000000000000000000000 - ) - - // Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId` - // We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0 - if sub(currentAssetProxyId, assetProxyId) { - // Update `assetProxyId` - assetProxyId := currentAssetProxyId - // To lookup a value in a mapping, we load from the storage location keccak256(k, p), - // where k is the key left padded to 32 bytes and p is the storage slot - mstore(132, assetProxyId) - mstore(164, assetProxies_slot) - assetProxy := sload(keccak256(132, 64)) - } - - // Revert if AssetProxy with given id does not exist - if iszero(assetProxy) { - // Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x0000001a41535345545f50524f58595f444f45535f4e4f545f45584953540000) - mstore(96, 0) - revert(0, 100) - } - - // Copy `nestedAssetData[i]` from calldata to memory - calldatacopy( - 132, // memory slot after `amounts[i]` - nestedAssetDataElementLenStart, // location of `nestedAssetData[i]` in calldata - add(nestedAssetDataElementLen, 32) // `nestedAssetData[i].length` plus 32 byte length - ) - - // call `assetProxy.transferFrom` - let success := call( - gas, // forward all gas - assetProxy, // call address of asset proxy - 0, // don't send any ETH - 0, // pointer to start of input - add(164, nestedAssetDataElementLen), // length of input - 0, // write output over memory that won't be reused - 0 // don't copy output to memory - ) - - // Revert with reason given by AssetProxy if `transferFrom` call failed - if iszero(success) { - returndatacopy( - 0, // copy to memory at 0 - 0, // copy from return data at 0 - returndatasize() // copy all return data - ) - revert(0, returndatasize()) - } - } - - // Return if no `transferFrom` calls reverted - return(0, 0) - } - - // Revert if undefined function is called - revert(0, 0) - } - } - - /// @dev Gets the proxy id associated with the proxy address. - /// @return Proxy id. - function getProxyId() - external - pure - returns (bytes4) - { - return PROXY_ID; - } -} diff --git a/contracts/asset-proxy/contracts/src/StaticCallProxy.sol b/contracts/asset-proxy/contracts/src/StaticCallProxy.sol deleted file mode 100644 index 268a4538c7..0000000000 --- a/contracts/asset-proxy/contracts/src/StaticCallProxy.sol +++ /dev/null @@ -1,83 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -// solhint-disable no-unused-vars -contract StaticCallProxy { - - using LibBytes for bytes; - - // Id of this proxy. - bytes4 constant internal PROXY_ID = bytes4(keccak256("StaticCall(address,bytes,bytes32)")); - - /// @dev Makes a staticcall to a target address and verifies that the data returned matches the expected return data. - /// @param assetData Byte array encoded with staticCallTarget, staticCallData, and expectedCallResultHash - /// @param from This value is ignored. - /// @param to This value is ignored. - /// @param amount This value is ignored. - function transferFrom( - bytes calldata assetData, - address from, - address to, - uint256 amount - ) - external - view - { - // Decode params from `assetData` - ( - address staticCallTarget, - bytes memory staticCallData, - bytes32 expectedReturnDataHash - ) = abi.decode( - assetData.sliceDestructive(4, assetData.length), - (address, bytes, bytes32) - ); - - // Execute staticcall - (bool success, bytes memory returnData) = staticCallTarget.staticcall(staticCallData); - - // Revert with returned data if staticcall is unsuccessful - if (!success) { - assembly { - revert(add(returnData, 32), mload(returnData)) - } - } - - // Revert if hash of return data is not as expected - bytes32 returnDataHash = keccak256(returnData); - require( - expectedReturnDataHash == returnDataHash, - "UNEXPECTED_STATIC_CALL_RESULT" - ); - } - - /// @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/contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol b/contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol deleted file mode 100644 index ef75c586fc..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol +++ /dev/null @@ -1,103 +0,0 @@ - -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IBalancerPool.sol"; - - -contract BalancerBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data. - (address fromTokenAddress, address poolAddress) = abi.decode( - bridgeData, - (address, address) - ); - require(toTokenAddress != fromTokenAddress, "BalancerBridge/INVALID_PAIR"); - - uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance); - - // Sell all of this contract's `fromTokenAddress` token balance. - (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn( - fromTokenAddress, // tokenIn - fromTokenBalance, // tokenAmountIn - toTokenAddress, // tokenOut - amount, // minAmountOut - uint256(-1) // maxPrice - ); - - // Transfer the converted `toToken`s to `to`. - LibERC20Token.transfer(toTokenAddress, to, boughtAmount); - - emit ERC20BridgeTransfer( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol b/contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol deleted file mode 100644 index 46a09107de..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol +++ /dev/null @@ -1,144 +0,0 @@ - -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IBancorNetwork.sol"; - - -contract BancorBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct TransferState { - address bancorNetworkAddress; - address[] path; - IEtherToken weth; - } - - /// @dev Bancor ETH pseudo-address. - address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - - // solhint-disable no-empty-blocks - /// @dev Payable fallback to receive ETH from Bancor/WETH. - function () - external - payable - { - // Poor man's receive in 0.5.9 - require(msg.data.length == 0); - } - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded conversion path addresses and Bancor network address - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // hold variables to get around stack depth limitations - TransferState memory state; - // Decode the bridge data. - ( - state.path, - state.bancorNetworkAddress - // solhint-disable indent - ) = abi.decode(bridgeData, (address[], address)); - // solhint-enable indent - state.weth = IEtherToken(_getWethAddress()); - - require(state.path.length >= 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO"); - - // Grant an allowance to the Bancor Network to spend `fromTokenAddress` token. - uint256 fromTokenBalance; - uint256 payableAmount = 0; - // If it's ETH in the path then withdraw from WETH - // The Bancor path will have ETH as the 0xeee address - // Bancor expects to be paid in ETH not WETH - if (state.path[0] == BANCOR_ETH_ADDRESS) { - fromTokenBalance = state.weth.balanceOf(address(this)); - state.weth.withdraw(fromTokenBalance); - payableAmount = fromTokenBalance; - } else { - fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); - LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance); - } - - // Convert the tokens - uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath.value(payableAmount)( - state.path, // path originating with source token and terminating in destination token - fromTokenBalance, // amount of source token to trade - amount, // minimum amount of destination token expected to receive - state.path[state.path.length-1] == BANCOR_ETH_ADDRESS ? address(this) : to, // beneficiary - address(0), // affiliateAccount; no fee paid - 0 // affiliateFee; no fee paid - ); - - if (state.path[state.path.length-1] == BANCOR_ETH_ADDRESS) { - state.weth.deposit.value(boughtAmount)(); - state.weth.transfer(to, boughtAmount); - } - - emit ERC20BridgeTransfer( - state.path[0] == BANCOR_ETH_ADDRESS ? address(state.weth) : state.path[0], - toTokenAddress, - fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } - -} diff --git a/contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol b/contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol deleted file mode 100644 index 9ff2908aff..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol +++ /dev/null @@ -1,75 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IChai.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; - - -// solhint-disable space-after-comma -contract ChaiBridge is - IERC20Bridge, - DeploymentConstants -{ - /// @dev Withdraws `amount` of `from` address's Dai from the Chai contract. - /// Transfers `amount` of Dai to `to` address. - /// @param from Address to transfer asset from. - /// @param to Address to transfer asset to. - /// @param amount Amount of asset to transfer. - /// @return success The magic bytes `0xdc1600f3` if successful. - function bridgeTransferFrom( - address /* tokenAddress */, - address from, - address to, - uint256 amount, - bytes calldata /* bridgeData */ - ) - external - returns (bytes4 success) - { - // Ensure that only the `ERC20BridgeProxy` can call this function. - require( - msg.sender == _getERC20BridgeProxyAddress(), - "ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" - ); - - // Withdraw `from` address's Dai. - // NOTE: This contract must be approved to spend Chai on behalf of `from`. - bytes memory drawCalldata = abi.encodeWithSelector( - IChai(address(0)).draw.selector, - from, - amount - ); - - (bool success,) = _getChaiAddress().call(drawCalldata); - require( - success, - "ChaiBridge/DRAW_DAI_FAILED" - ); - - // Transfer Dai to `to` - // This will never fail if the `draw` call was successful - IERC20Token(_getDaiAddress()).transfer(to, amount); - - return BRIDGE_SUCCESS; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol b/contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol deleted file mode 100644 index c1a5750afa..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol +++ /dev/null @@ -1,103 +0,0 @@ - -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IBalancerPool.sol"; - - -contract CreamBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data. - (address fromTokenAddress, address poolAddress) = abi.decode( - bridgeData, - (address, address) - ); - require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR"); - - uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance); - - // Sell all of this contract's `fromTokenAddress` token balance. - (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn( - fromTokenAddress, // tokenIn - fromTokenBalance, // tokenAmountIn - toTokenAddress, // tokenOut - amount, // minAmountOut - uint256(-1) // maxPrice - ); - - // Transfer the converted `toToken`s to `to`. - LibERC20Token.transfer(toTokenAddress, to, boughtAmount); - - emit ERC20BridgeTransfer( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol b/contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol deleted file mode 100644 index 3be8a4b80e..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol +++ /dev/null @@ -1,136 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IUniswapV2Router01.sol"; -import "../interfaces/IERC20Bridge.sol"; - - -// solhint-disable space-after-comma -// solhint-disable not-rely-on-time -contract CryptoComBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct TransferState { - address[] path; - address router; - uint256 fromTokenBalance; - } - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // hold variables to get around stack depth limitations - TransferState memory state; - - // Decode the bridge data to get the `fromTokenAddress`. - // solhint-disable indent - (state.path, state.router) = abi.decode(bridgeData, (address[], address)); - // solhint-enable indent - - require(state.path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); - require(state.path[state.path.length - 1] == toTokenAddress, "CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); - - // Just transfer the tokens if they're the same. - if (state.path[0] == toTokenAddress) { - LibERC20Token.transfer(state.path[0], to, amount); - return BRIDGE_SUCCESS; - } - - // Get our balance of `fromTokenAddress` token. - state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); - - // Grant the SushiSwap router an allowance. - LibERC20Token.approveIfBelow( - state.path[0], - state.router, - state.fromTokenBalance - ); - - // Buy as much `toTokenAddress` token with `fromTokenAddress` token - // and transfer it to `to`. - IUniswapV2Router01 router = IUniswapV2Router01(state.router); - uint[] memory amounts = router.swapExactTokensForTokens( - // Sell all tokens we hold. - state.fromTokenBalance, - // Minimum buy amount. - amount, - // Convert `fromTokenAddress` to `toTokenAddress`. - state.path, - // Recipient is `to`. - to, - // Expires after this block. - block.timestamp - ); - - emit ERC20BridgeTransfer( - // input token - state.path[0], - // output token - toTokenAddress, - // input token amount - state.fromTokenBalance, - // output token amount - amounts[amounts.length - 1], - from, - to - ); - - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol b/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol deleted file mode 100644 index 9515fef349..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol +++ /dev/null @@ -1,119 +0,0 @@ - -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/ICurve.sol"; - - -// solhint-disable not-rely-on-time -// solhint-disable space-after-comma -contract CurveBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct CurveBridgeData { - address curveAddress; - bytes4 exchangeFunctionSelector; - address fromTokenAddress; - int128 fromCoinIdx; - int128 toCoinIdx; - } - - /// @dev Callback for `ICurve`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the opposing asset - /// (DAI, USDC) to the Curve contract, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoeded "from" token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data to get the Curve metadata. - CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData)); - - require(toTokenAddress != data.fromTokenAddress, "CurveBridge/INVALID_PAIR"); - uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); - - // Try to sell all of this contract's `fromTokenAddress` token balance. - { - (bool didSucceed, bytes memory resultData) = - data.curveAddress.call(abi.encodeWithSelector( - data.exchangeFunctionSelector, - data.fromCoinIdx, - data.toCoinIdx, - // dx - fromTokenBalance, - // min dy - amount - )); - if (!didSucceed) { - assembly { revert(add(resultData, 32), mload(resultData)) } - } - } - - uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); - // Transfer the converted `toToken`s to `to`. - LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); - - emit ERC20BridgeTransfer( - data.fromTokenAddress, - toTokenAddress, - fromTokenBalance, - toTokenBalance, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol b/contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol deleted file mode 100644 index acd5beff09..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol +++ /dev/null @@ -1,147 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; - - -interface IDODOHelper { - - function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256); -} - - -interface IDODO { - - function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256); - - function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256); - -} - - -contract DODOBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - - struct TransferState { - address fromTokenAddress; - uint256 fromTokenBalance; - address pool; - bool isSellBase; - } - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - TransferState memory state; - // Decode the bridge data to get the `fromTokenAddress`. - (state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool)); - require(state.pool != address(0), "DODOBridge/InvalidPool"); - IDODO exchange = IDODO(state.pool); - // Get our balance of `fromTokenAddress` token. - state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this)); - - // Grant the pool an allowance. - LibERC20Token.approveIfBelow( - state.fromTokenAddress, - address(exchange), - state.fromTokenBalance - ); - - uint256 boughtAmount; - if (state.isSellBase) { - boughtAmount = exchange.sellBaseToken( - // amount to sell - state.fromTokenBalance, - // min receive amount - 1, - new bytes(0) - ); - } else { - // Need to re-calculate the sell quote amount into buyBase - boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken( - address(exchange), - state.fromTokenBalance - ); - exchange.buyBaseToken( - // amount to buy - boughtAmount, - // max pay amount - state.fromTokenBalance, - new bytes(0) - ); - } - // Transfer funds to `to` - IERC20Token(toTokenAddress).transfer(to, boughtAmount); - - - emit ERC20BridgeTransfer( - // input token - state.fromTokenAddress, - // output token - toTokenAddress, - // input token amount - state.fromTokenBalance, - // output token amount - boughtAmount, - from, - to - ); - - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/DexForwarderBridge.sol b/contracts/asset-proxy/contracts/src/bridges/DexForwarderBridge.sol deleted file mode 100644 index 33c763f2bb..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/DexForwarderBridge.sol +++ /dev/null @@ -1,200 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "./MixinGasToken.sol"; - - -// solhint-disable space-after-comma, indent -contract DexForwarderBridge is - IERC20Bridge, - IWallet, - DeploymentConstants, - MixinGasToken -{ - using LibSafeMath for uint256; - - /// @dev Data needed to reconstruct a bridge call. - struct BridgeCall { - address target; - uint256 inputTokenAmount; - uint256 outputTokenAmount; - bytes bridgeData; - } - - /// @dev Intermediate state variables used by `bridgeTransferFrom()`, in - /// struct form to get around stack limits. - struct TransferFromState { - address inputToken; - uint256 initialInputTokenBalance; - uint256 callInputTokenAmount; - uint256 callOutputTokenAmount; - uint256 totalInputTokenSold; - BridgeCall[] calls; - } - - /// @dev Spends this contract's entire balance of input tokens by forwarding - /// them to other bridges. Reverts if the entire balance is not spent. - /// @param outputToken The token being bought. - /// @param to The recipient of the bought tokens. - /// @param bridgeData The abi-encoded input token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address outputToken, - address /* from */, - address to, - uint256 /* amount */, - bytes calldata bridgeData - ) - external - freesGasTokensFromCollector - returns (bytes4 success) - { - require( - msg.sender == _getERC20BridgeProxyAddress(), - "DexForwarderBridge/SENDER_NOT_AUTHORIZED" - ); - TransferFromState memory state; - ( - state.inputToken, - state.calls - ) = abi.decode(bridgeData, (address, BridgeCall[])); - - state.initialInputTokenBalance = - IERC20Token(state.inputToken).balanceOf(address(this)); - - for (uint256 i = 0; i < state.calls.length; ++i) { - // Stop if the we've sold all our input tokens. - if (state.totalInputTokenSold >= state.initialInputTokenBalance) { - break; - } - - // Compute token amounts. - state.callInputTokenAmount = LibSafeMath.min256( - state.calls[i].inputTokenAmount, - state.initialInputTokenBalance.safeSub(state.totalInputTokenSold) - ); - state.callOutputTokenAmount = LibMath.getPartialAmountFloor( - state.callInputTokenAmount, - state.calls[i].inputTokenAmount, - state.calls[i].outputTokenAmount - ); - - // Execute the call in a new context so we can recoup transferred - // funds by reverting. - (bool didSucceed, ) = address(this) - .call(abi.encodeWithSelector( - this.executeBridgeCall.selector, - state.calls[i].target, - to, - state.inputToken, - outputToken, - state.callInputTokenAmount, - state.callOutputTokenAmount, - state.calls[i].bridgeData - )); - - if (didSucceed) { - // Increase the amount of tokens sold. - state.totalInputTokenSold = state.totalInputTokenSold.safeAdd( - state.callInputTokenAmount - ); - } - } - // Always succeed. - return BRIDGE_SUCCESS; - } - - /// @dev Transfers `inputToken` token to a bridge contract then calls - /// its `bridgeTransferFrom()`. This is executed in separate context - /// so we can revert the transfer on error. This can only be called - // by this contract itself. - /// @param bridge The bridge contract. - /// @param to The recipient of `outputToken` tokens. - /// @param inputToken The input token. - /// @param outputToken The output token. - /// @param inputTokenAmount The amount of input tokens to transfer to `bridge`. - /// @param outputTokenAmount The amount of expected output tokens to be sent - /// to `to` by `bridge`. - function executeBridgeCall( - address bridge, - address to, - address inputToken, - address outputToken, - uint256 inputTokenAmount, - uint256 outputTokenAmount, - bytes calldata bridgeData - ) - external - { - // Must be called through `bridgeTransferFrom()`. - require(msg.sender == address(this), "DexForwarderBridge/ONLY_SELF"); - // `bridge` must not be this contract. - require(bridge != address(this)); - - // Get the starting balance of output tokens for `to`. - uint256 initialRecipientBalance = IERC20Token(outputToken).balanceOf(to); - - // Transfer input tokens to the bridge. - LibERC20Token.transfer(inputToken, bridge, inputTokenAmount); - - // Call the bridge. - (bool didSucceed, bytes memory resultData) = - bridge.call(abi.encodeWithSelector( - IERC20Bridge(0).bridgeTransferFrom.selector, - outputToken, - bridge, - to, - outputTokenAmount, - bridgeData - )); - - // Revert if the call failed or not enough tokens were bought. - // This will also undo the token transfer. - require( - didSucceed - && resultData.length == 32 - && LibBytes.readBytes32(resultData, 0) == bytes32(BRIDGE_SUCCESS) - && IERC20Token(outputToken).balanceOf(to).safeSub(initialRecipientBalance) >= outputTokenAmount - ); - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol b/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol deleted file mode 100644 index 67baa1c14c..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol +++ /dev/null @@ -1,242 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IDydxBridge.sol"; -import "../interfaces/IDydx.sol"; - - -contract DydxBridge is - IERC20Bridge, - IDydxBridge, - DeploymentConstants -{ - - using LibSafeMath for uint256; - - /// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account. - /// Notes: - /// 1. This bridge must be set as an operator of the input dydx account. - /// 2. This function may only be called in the context of the 0x Exchange. - /// 3. The maker or taker of the 0x order must be the dydx account owner. - /// 4. Deposits into dydx are made from the `from` address. - /// 5. Withdrawals from dydx are made to the `to` address. - /// 6. Calling this function must always withdraw at least `amount`, - /// otherwise the `ERC20Bridge` will revert. - /// @param from The sender of the tokens and owner of the dydx account. - /// @param to The recipient of the tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw. - /// @param encodedBridgeData An abi-encoded `BridgeData` struct. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address, /* toTokenAddress */ - address from, - address to, - uint256 amount, - bytes calldata encodedBridgeData - ) - external - returns (bytes4 success) - { - // Ensure that only the `ERC20BridgeProxy` can call this function. - require( - msg.sender == _getERC20BridgeProxyAddress(), - "DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" - ); - - // Decode bridge data. - (BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData)); - - // The dydx accounts are owned by the `from` address. - IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData); - - // Create dydx actions to run on the dydx accounts. - IDydx.ActionArgs[] memory actions = _createActions( - from, - to, - amount, - bridgeData - ); - - // Run operation. This will revert on failure. - IDydx(_getDydxAddress()).operate(accounts, actions); - - return BRIDGE_SUCCESS; - } - - /// @dev Creates an array of accounts for dydx to operate on. - /// All accounts must belong to the same owner. - /// @param accountOwner Owner of the dydx account. - /// @param bridgeData A `BridgeData` struct. - function _createAccounts( - address accountOwner, - BridgeData memory bridgeData - ) - internal - returns (IDydx.AccountInfo[] memory accounts) - { - uint256[] memory accountNumbers = bridgeData.accountNumbers; - uint256 nAccounts = accountNumbers.length; - accounts = new IDydx.AccountInfo[](nAccounts); - for (uint256 i = 0; i < nAccounts; ++i) { - accounts[i] = IDydx.AccountInfo({ - owner: accountOwner, - number: accountNumbers[i] - }); - } - } - - /// @dev Creates an array of actions to carry out on dydx. - /// @param depositFrom Deposit value from this address (owner of the dydx account). - /// @param withdrawTo Withdraw value to this address. - /// @param amount The amount of value available to operate on. - /// @param bridgeData A `BridgeData` struct. - function _createActions( - address depositFrom, - address withdrawTo, - uint256 amount, - BridgeData memory bridgeData - ) - internal - returns (IDydx.ActionArgs[] memory actions) - { - BridgeAction[] memory bridgeActions = bridgeData.actions; - uint256 nBridgeActions = bridgeActions.length; - actions = new IDydx.ActionArgs[](nBridgeActions); - for (uint256 i = 0; i < nBridgeActions; ++i) { - // Cache current bridge action. - BridgeAction memory bridgeAction = bridgeActions[i]; - - // Scale amount, if conversion rate is set. - uint256 scaledAmount; - if (bridgeAction.conversionRateDenominator > 0) { - scaledAmount = LibMath.safeGetPartialAmountFloor( - bridgeAction.conversionRateNumerator, - bridgeAction.conversionRateDenominator, - amount - ); - } else { - scaledAmount = amount; - } - - // Construct dydx action. - if (bridgeAction.actionType == BridgeActionType.Deposit) { - // Deposit tokens from the account owner into their dydx account. - actions[i] = _createDepositAction( - depositFrom, - scaledAmount, - bridgeAction - ); - } else if (bridgeAction.actionType == BridgeActionType.Withdraw) { - // Withdraw tokens from dydx to the `otherAccount`. - actions[i] = _createWithdrawAction( - withdrawTo, - scaledAmount, - bridgeAction - ); - } else { - // If all values in the `Action` enum are handled then this - // revert is unreachable: Solidity will revert when casting - // from `uint8` to `Action`. - revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION"); - } - } - } - - /// @dev Returns a dydx `DepositAction`. - /// @param depositFrom Deposit tokens from this address who is also the account owner. - /// @param amount of tokens to deposit. - /// @param bridgeAction A `BridgeAction` struct. - /// @return depositAction The encoded dydx action. - function _createDepositAction( - address depositFrom, - uint256 amount, - BridgeAction memory bridgeAction - ) - internal - pure - returns ( - IDydx.ActionArgs memory depositAction - ) - { - // Create dydx amount. - IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({ - sign: true, // true if positive. - denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account. - ref: IDydx.AssetReference.Delta, // Delta => a relative amount. - value: amount // amount to deposit. - }); - - // Create dydx deposit action. - depositAction = IDydx.ActionArgs({ - actionType: IDydx.ActionType.Deposit, // deposit tokens. - amount: dydxAmount, // amount to deposit. - accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`. - primaryMarketId: bridgeAction.marketId, // indicates which token to deposit. - otherAddress: depositFrom, // deposit from the account owner. - // unused parameters - secondaryMarketId: 0, - otherAccountIdx: 0, - data: hex'' - }); - } - - /// @dev Returns a dydx `WithdrawAction`. - /// @param withdrawTo Withdraw tokens to this address. - /// @param amount of tokens to withdraw. - /// @param bridgeAction A `BridgeAction` struct. - /// @return withdrawAction The encoded dydx action. - function _createWithdrawAction( - address withdrawTo, - uint256 amount, - BridgeAction memory bridgeAction - ) - internal - pure - returns ( - IDydx.ActionArgs memory withdrawAction - ) - { - // Create dydx amount. - IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({ - sign: false, // false if negative. - denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account. - ref: IDydx.AssetReference.Delta, // Delta => a relative amount. - value: amount // amount to withdraw. - }); - - // Create withdraw action. - withdrawAction = IDydx.ActionArgs({ - actionType: IDydx.ActionType.Withdraw, // withdraw tokens. - amount: amountToWithdraw, // amount to withdraw. - accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`. - primaryMarketId: bridgeAction.marketId, // indicates which token to withdraw. - otherAddress: withdrawTo, // withdraw tokens to this address. - // unused parameters - secondaryMarketId: 0, - otherAccountIdx: 0, - data: hex'' - }); - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol b/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol deleted file mode 100644 index 6b3b18d1c8..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol +++ /dev/null @@ -1,98 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IEth2Dai.sol"; - - -// solhint-disable space-after-comma -contract Eth2DaiBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the opposing asset - /// (DAI or WETH) to the Eth2Dai contract, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to give to `to` (either DAI or WETH). - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoeded "from" token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data to get the `fromTokenAddress`. - (address fromTokenAddress) = abi.decode(bridgeData, (address)); - - IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress()); - uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance); - - // Try to sell all of this contract's `fromTokenAddress` token balance. - uint256 boughtAmount = exchange.sellAllAmount( - fromTokenAddress, - fromTokenBalance, - toTokenAddress, - amount - ); - // Transfer the converted `toToken`s to `to`. - LibERC20Token.transfer(toTokenAddress, to, boughtAmount); - - emit ERC20BridgeTransfer( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol b/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol deleted file mode 100644 index 035031a5d5..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol +++ /dev/null @@ -1,169 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IKyberNetworkProxy.sol"; - - -// solhint-disable space-after-comma -contract KyberBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - using LibSafeMath for uint256; - - // @dev Structure used internally to get around stack limits. - struct TradeState { - IKyberNetworkProxy kyber; - IEtherToken weth; - address fromTokenAddress; - uint256 fromTokenBalance; - uint256 payableAmount; - uint256 conversionRate; - bytes hint; - } - - /// @dev Kyber ETH pseudo-address. - address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - /// @dev `bridgeTransferFrom()` failure result. - bytes4 constant private BRIDGE_FAILED = 0x0; - /// @dev Precision of Kyber rates. - uint256 constant private KYBER_RATE_BASE = 10 ** 18; - - // solhint-disable no-empty-blocks - /// @dev Payable fallback to receive ETH from Kyber/WETH. - function () - external - payable - { - // Poor man's receive in 0.5.9 - require(msg.data.length == 0); - } - - /// @dev Callback for `IKyberBridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the opposing asset - /// to the `KyberNetworkProxy` contract, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to give to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoeded "from" token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - TradeState memory state; - state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress()); - state.weth = IEtherToken(_getWethAddress()); - // Decode the bridge data to get the `fromTokenAddress`. - (state.fromTokenAddress, state.hint) = abi.decode(bridgeData, (address, bytes)); - // Query the balance of "from" tokens. - state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this)); - if (state.fromTokenBalance == 0) { - // Return failure if no input tokens. - return BRIDGE_FAILED; - } - if (state.fromTokenAddress == toTokenAddress) { - // Just transfer the tokens if they're the same. - LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance); - return BRIDGE_SUCCESS; - } - if (state.fromTokenAddress == address(state.weth)) { - // From WETH - state.fromTokenAddress = KYBER_ETH_ADDRESS; - state.payableAmount = state.fromTokenBalance; - state.weth.withdraw(state.fromTokenBalance); - } else { - LibERC20Token.approveIfBelow( - state.fromTokenAddress, - address(state.kyber), - state.fromTokenBalance - ); - } - bool isToTokenWeth = toTokenAddress == address(state.weth); - - // Try to sell all of this contract's input token balance through - // `KyberNetworkProxy.trade()`. - uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)( - // Input token. - state.fromTokenAddress, - // Sell amount. - state.fromTokenBalance, - // Output token. - isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress, - // Transfer to this contract if converting to ETH, otherwise - // transfer directly to the recipient. - isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)), - // Buy as much as possible. - uint256(-1), - // The minimum conversion rate - 1, - // No affiliate address. - address(0), - state.hint - ); - // Wrap ETH output and transfer to recipient. - if (isToTokenWeth) { - state.weth.deposit.value(boughtAmount)(); - state.weth.transfer(to, boughtAmount); - } - - emit ERC20BridgeTransfer( - state.fromTokenAddress == KYBER_ETH_ADDRESS ? address(state.weth) : state.fromTokenAddress, - toTokenAddress, - state.fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } - -} diff --git a/contracts/asset-proxy/contracts/src/bridges/MStableBridge.sol b/contracts/asset-proxy/contracts/src/bridges/MStableBridge.sol deleted file mode 100644 index 935cce30b4..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/MStableBridge.sol +++ /dev/null @@ -1,94 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IMStable.sol"; - - -contract MStableBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - - /// @dev Swaps specified tokens against the mStable mUSD contract - /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded "from" token address. - /// @return success The magic bytes if successful. - // solhint-disable no-unused-vars - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data to get the `fromTokenAddress`. - (address fromTokenAddress) = abi.decode(bridgeData, (address)); - - IMStable exchange = IMStable(_getMUsdAddress()); - uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance); - - // Try to sell all of this contract's `fromTokenAddress` token balance. - uint256 boughtAmount = exchange.swap( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - to - ); - - emit ERC20BridgeTransfer( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol b/contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol deleted file mode 100644 index cd50e76173..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/MixinGasToken.sol +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright 2019 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.5.16; - -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IGasToken.sol"; - - -contract MixinGasToken is - DeploymentConstants -{ - - /// @dev Frees gas tokens based on the amount of gas consumed in the function - modifier freesGasTokens { - uint256 gasBefore = gasleft(); - _; - IGasToken gst = IGasToken(_getGstAddress()); - if (address(gst) != address(0)) { - // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN) - // 14154 24000 6870 - uint256 value = (gasBefore - gasleft() + 14154) / 41130; - gst.freeUpTo(value); - } - } - - /// @dev Frees gas tokens using the balance of `from`. Amount freed is based - /// on the gas consumed in the function - modifier freesGasTokensFromCollector() { - uint256 gasBefore = gasleft(); - _; - IGasToken gst = IGasToken(_getGstAddress()); - if (address(gst) != address(0)) { - // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN) - // 14154 24000 6870 - uint256 value = (gasBefore - gasleft() + 14154) / 41130; - gst.freeFromUpTo(_getGstCollectorAddress(), value); - } - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol deleted file mode 100644 index 9976372cf6..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol +++ /dev/null @@ -1,148 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IMooniswap.sol"; - - -// solhint-disable space-after-comma -// solhint-disable not-rely-on-time -contract MooniswapBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - - struct TransferState { - IMooniswap pool; - uint256 fromTokenBalance; - IEtherToken weth; - uint256 boughtAmount; - address fromTokenAddress; - address toTokenAddress; - } - - // solhint-disable no-empty-blocks - /// @dev Payable fallback to receive ETH from uniswap. - function () - external - payable - {} - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // State memory object to avoid stack overflows. - TransferState memory state; - // Decode the bridge data to get the `fromTokenAddress`. - address fromTokenAddress = abi.decode(bridgeData, (address)); - // Get the weth contract. - state.weth = IEtherToken(_getWethAddress()); - // Get our balance of `fromTokenAddress` token. - state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - - state.fromTokenAddress = fromTokenAddress == address(state.weth) ? address(0) : fromTokenAddress; - state.toTokenAddress = toTokenAddress == address(state.weth) ? address(0) : toTokenAddress; - state.pool = IMooniswap( - IMooniswapRegistry(_getMooniswapAddress()).pools( - state.fromTokenAddress, - state.toTokenAddress - ) - ); - - // withdraw WETH to ETH - if (state.fromTokenAddress == address(0)) { - state.weth.withdraw(state.fromTokenBalance); - } else { - // Grant the pool an allowance. - LibERC20Token.approveIfBelow( - state.fromTokenAddress, - address(state.pool), - state.fromTokenBalance - ); - } - uint256 ethValue = state.fromTokenAddress == address(0) ? state.fromTokenBalance : 0; - state.boughtAmount = state.pool.swap.value(ethValue)( - state.fromTokenAddress, - state.toTokenAddress, - state.fromTokenBalance, - amount, - address(0) - ); - // Deposit to WETH - if (state.toTokenAddress == address(0)) { - state.weth.deposit.value(state.boughtAmount)(); - } - - // Transfer funds to `to` - LibERC20Token.transfer(toTokenAddress, to, state.boughtAmount); - - emit ERC20BridgeTransfer( - // input token - fromTokenAddress, - // output token - toTokenAddress, - // input token amount - state.fromTokenBalance, - // output token amount - state.boughtAmount, - from, - to - ); - - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol b/contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol deleted file mode 100644 index f0dd9ef6f8..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol +++ /dev/null @@ -1,95 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/IShell.sol"; - - -contract ShellBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - - /// @dev Swaps specified tokens against the Shell contract - /// @param toTokenAddress The token to give to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded "from" token address. - /// @return success The magic bytes if successful. - // solhint-disable no-unused-vars - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data to get the `fromTokenAddress` and `pool`. - (address fromTokenAddress, address pool) = abi.decode(bridgeData, (address, address)); - - uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(fromTokenAddress, pool, fromTokenBalance); - - // Try to sell all of this contract's `fromTokenAddress` token balance. - uint256 boughtAmount = IShell(pool).originSwap( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - amount, // min amount - block.timestamp + 1 - ); - LibERC20Token.transfer(toTokenAddress, to, boughtAmount); - - emit ERC20BridgeTransfer( - fromTokenAddress, - toTokenAddress, - fromTokenBalance, - boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol deleted file mode 100644 index 614ef5017d..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol +++ /dev/null @@ -1,119 +0,0 @@ - -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/ICurve.sol"; - - -// solhint-disable not-rely-on-time -// solhint-disable space-after-comma -contract SnowSwapBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct SnowSwapBridgeData { - address curveAddress; - bytes4 exchangeFunctionSelector; - address fromTokenAddress; - int128 fromCoinIdx; - int128 toCoinIdx; - } - - /// @dev Callback for `ICurve`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the opposing asset - /// (DAI, USDC) to the Curve contract, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoeded "from" token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data to get the SnowSwap metadata. - SnowSwapBridgeData memory data = abi.decode(bridgeData, (SnowSwapBridgeData)); - - require(toTokenAddress != data.fromTokenAddress, "SnowSwapBridge/INVALID_PAIR"); - uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); - - // Try to sell all of this contract's `fromTokenAddress` token balance. - { - (bool didSucceed, bytes memory resultData) = - data.curveAddress.call(abi.encodeWithSelector( - data.exchangeFunctionSelector, - data.fromCoinIdx, - data.toCoinIdx, - // dx - fromTokenBalance, - // min dy - amount - )); - if (!didSucceed) { - assembly { revert(add(resultData, 32), mload(resultData)) } - } - } - - uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); - // Transfer the converted `toToken`s to `to`. - LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); - - emit ERC20BridgeTransfer( - data.fromTokenAddress, - toTokenAddress, - fromTokenBalance, - toTokenBalance, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol deleted file mode 100644 index 480942d9c3..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol +++ /dev/null @@ -1,136 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IUniswapV2Router01.sol"; -import "../interfaces/IERC20Bridge.sol"; - - -// solhint-disable space-after-comma -// solhint-disable not-rely-on-time -contract SushiSwapBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct TransferState { - address[] path; - address router; - uint256 fromTokenBalance; - } - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // hold variables to get around stack depth limitations - TransferState memory state; - - // Decode the bridge data to get the `fromTokenAddress`. - // solhint-disable indent - (state.path, state.router) = abi.decode(bridgeData, (address[], address)); - // solhint-enable indent - - require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); - require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); - - // Just transfer the tokens if they're the same. - if (state.path[0] == toTokenAddress) { - LibERC20Token.transfer(state.path[0], to, amount); - return BRIDGE_SUCCESS; - } - - // Get our balance of `fromTokenAddress` token. - state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); - - // Grant the SushiSwap router an allowance. - LibERC20Token.approveIfBelow( - state.path[0], - state.router, - state.fromTokenBalance - ); - - // Buy as much `toTokenAddress` token with `fromTokenAddress` token - // and transfer it to `to`. - IUniswapV2Router01 router = IUniswapV2Router01(state.router); - uint[] memory amounts = router.swapExactTokensForTokens( - // Sell all tokens we hold. - state.fromTokenBalance, - // Minimum buy amount. - amount, - // Convert `fromTokenAddress` to `toTokenAddress`. - state.path, - // Recipient is `to`. - to, - // Expires after this block. - block.timestamp - ); - - emit ERC20BridgeTransfer( - // input token - state.path[0], - // output token - toTokenAddress, - // input token amount - state.fromTokenBalance, - // output token amount - amounts[amounts.length - 1], - from, - to - ); - - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol b/contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol deleted file mode 100644 index ba650f51ba..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol +++ /dev/null @@ -1,119 +0,0 @@ - -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IERC20Bridge.sol"; -import "../interfaces/ICurve.sol"; - - -// solhint-disable not-rely-on-time -// solhint-disable space-after-comma -contract SwerveBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct SwerveBridgeData { - address curveAddress; - bytes4 exchangeFunctionSelector; - address fromTokenAddress; - int128 fromCoinIdx; - int128 toCoinIdx; - } - - /// @dev Callback for `ICurve`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the opposing asset - /// (DAI, USDC) to the Curve contract, then transfers the bought - /// tokens to `to`. - /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT). - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoeded "from" token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // Decode the bridge data to get the SwerveBridgeData metadata. - SwerveBridgeData memory data = abi.decode(bridgeData, (SwerveBridgeData)); - - require(toTokenAddress != data.fromTokenAddress, "SwerveBridge/INVALID_PAIR"); - uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this)); - // Grant an allowance to the exchange to spend `fromTokenAddress` token. - LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance); - - // Try to sell all of this contract's `fromTokenAddress` token balance. - { - (bool didSucceed, bytes memory resultData) = - data.curveAddress.call(abi.encodeWithSelector( - data.exchangeFunctionSelector, - data.fromCoinIdx, - data.toCoinIdx, - // dx - fromTokenBalance, - // min dy - amount - )); - if (!didSucceed) { - assembly { revert(add(resultData, 32), mload(resultData)) } - } - } - - uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this)); - // Transfer the converted `toToken`s to `to`. - LibERC20Token.transfer(toTokenAddress, to, toTokenBalance); - - emit ERC20BridgeTransfer( - data.fromTokenAddress, - toTokenAddress, - fromTokenBalance, - toTokenBalance, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Magic success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol deleted file mode 100644 index 4ea7ac2d3a..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol +++ /dev/null @@ -1,220 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IUniswapExchangeFactory.sol"; -import "../interfaces/IUniswapExchange.sol"; -import "../interfaces/IERC20Bridge.sol"; - - -// solhint-disable space-after-comma -// solhint-disable not-rely-on-time -contract UniswapBridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid - // stack overflows. - struct TransferState { - IUniswapExchange exchange; - uint256 fromTokenBalance; - IEtherToken weth; - uint256 boughtAmount; - } - - // solhint-disable no-empty-blocks - /// @dev Payable fallback to receive ETH from uniswap. - function () - external - payable - {} - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded "from" token address. - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // State memory object to avoid stack overflows. - TransferState memory state; - // Decode the bridge data to get the `fromTokenAddress`. - (address fromTokenAddress) = abi.decode(bridgeData, (address)); - - // Just transfer the tokens if they're the same. - if (fromTokenAddress == toTokenAddress) { - LibERC20Token.transfer(fromTokenAddress, to, amount); - return BRIDGE_SUCCESS; - } - - // Get the exchange for the token pair. - state.exchange = _getUniswapExchangeForTokenPair( - fromTokenAddress, - toTokenAddress - ); - // Get our balance of `fromTokenAddress` token. - state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); - // Get the weth contract. - state.weth = IEtherToken(_getWethAddress()); - - // Convert from WETH to a token. - if (fromTokenAddress == address(state.weth)) { - // Unwrap the WETH. - state.weth.withdraw(state.fromTokenBalance); - // Buy as much of `toTokenAddress` token with ETH as possible and - // transfer it to `to`. - state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)( - // Minimum buy amount. - amount, - // Expires after this block. - block.timestamp, - // Recipient is `to`. - to - ); - - // Convert from a token to WETH. - } else if (toTokenAddress == address(state.weth)) { - // Grant the exchange an allowance. - _grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance); - // Buy as much ETH with `fromTokenAddress` token as possible. - state.boughtAmount = state.exchange.tokenToEthSwapInput( - // Sell all tokens we hold. - state.fromTokenBalance, - // Minimum buy amount. - amount, - // Expires after this block. - block.timestamp - ); - // Wrap the ETH. - state.weth.deposit.value(state.boughtAmount)(); - // Transfer the WETH to `to`. - IEtherToken(toTokenAddress).transfer(to, state.boughtAmount); - - // Convert from one token to another. - } else { - // Grant the exchange an allowance. - _grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance); - // Buy as much `toTokenAddress` token with `fromTokenAddress` token - // and transfer it to `to`. - state.boughtAmount = state.exchange.tokenToTokenTransferInput( - // Sell all tokens we hold. - state.fromTokenBalance, - // Minimum buy amount. - amount, - // Must buy at least 1 intermediate ETH. - 1, - // Expires after this block. - block.timestamp, - // Recipient is `to`. - to, - // Convert to `toTokenAddress`. - toTokenAddress - ); - } - - emit ERC20BridgeTransfer( - fromTokenAddress, - toTokenAddress, - state.fromTokenBalance, - state.boughtAmount, - from, - to - ); - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } - - /// @dev Grants an unlimited allowance to the exchange for its token - /// on behalf of this contract. - /// @param exchange The Uniswap token exchange. - /// @param tokenAddress The token address for the exchange. - /// @param minimumAllowance The minimum necessary allowance. - function _grantExchangeAllowance( - IUniswapExchange exchange, - address tokenAddress, - uint256 minimumAllowance - ) - private - { - LibERC20Token.approveIfBelow( - tokenAddress, - address(exchange), - minimumAllowance - ); - } - - /// @dev Retrieves the uniswap exchange for a given token pair. - /// In the case of a WETH-token exchange, this will be the non-WETH token. - /// In th ecase of a token-token exchange, this will be the first token. - /// @param fromTokenAddress The address of the token we are converting from. - /// @param toTokenAddress The address of the token we are converting to. - /// @return exchange The uniswap exchange. - function _getUniswapExchangeForTokenPair( - address fromTokenAddress, - address toTokenAddress - ) - private - view - returns (IUniswapExchange exchange) - { - address exchangeTokenAddress = fromTokenAddress; - // Whichever isn't WETH is the exchange token. - if (fromTokenAddress == _getWethAddress()) { - exchangeTokenAddress = toTokenAddress; - } - exchange = IUniswapExchange( - IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress()) - .getExchange(exchangeTokenAddress) - ); - require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN"); - return exchange; - } -} diff --git a/contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol b/contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol deleted file mode 100644 index 4a40546406..0000000000 --- a/contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol +++ /dev/null @@ -1,135 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; -import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "../interfaces/IUniswapV2Router01.sol"; -import "../interfaces/IERC20Bridge.sol"; - - -// solhint-disable space-after-comma -// solhint-disable not-rely-on-time -contract UniswapV2Bridge is - IERC20Bridge, - IWallet, - DeploymentConstants -{ - struct TransferState { - address[] path; - uint256 fromTokenBalance; - } - - /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of - /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` - /// token encoded in the bridge data. - /// @param toTokenAddress The token to buy and transfer to `to`. - /// @param from The maker (this contract). - /// @param to The recipient of the bought tokens. - /// @param amount Minimum amount of `toTokenAddress` tokens to buy. - /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress - /// @return success The magic bytes if successful. - function bridgeTransferFrom( - address toTokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success) - { - // hold variables to get around stack depth limitations - TransferState memory state; - - // Decode the bridge data to get the `fromTokenAddress`. - // solhint-disable indent - state.path = abi.decode(bridgeData, (address[])); - // solhint-enable indent - - require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); - require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); - - // Just transfer the tokens if they're the same. - if (state.path[0] == toTokenAddress) { - LibERC20Token.transfer(state.path[0], to, amount); - return BRIDGE_SUCCESS; - } - - // Get our balance of `fromTokenAddress` token. - state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); - - // Grant the Uniswap router an allowance. - LibERC20Token.approveIfBelow( - state.path[0], - _getUniswapV2Router01Address(), - state.fromTokenBalance - ); - - // Buy as much `toTokenAddress` token with `fromTokenAddress` token - // and transfer it to `to`. - IUniswapV2Router01 router = IUniswapV2Router01(_getUniswapV2Router01Address()); - uint[] memory amounts = router.swapExactTokensForTokens( - // Sell all tokens we hold. - state.fromTokenBalance, - // Minimum buy amount. - amount, - // Convert `fromTokenAddress` to `toTokenAddress`. - state.path, - // Recipient is `to`. - to, - // Expires after this block. - block.timestamp - ); - - emit ERC20BridgeTransfer( - // input token - state.path[0], - // output token - toTokenAddress, - // input token amount - state.fromTokenBalance, - // output token amount - amounts[amounts.length - 1], - from, - to - ); - - return BRIDGE_SUCCESS; - } - - /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker - /// and sign for itself in orders. Always succeeds. - /// @return magicValue Success bytes, always. - function isValidSignature( - bytes32, - bytes calldata - ) - external - view - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IAssetData.sol b/contracts/asset-proxy/contracts/src/interfaces/IAssetData.sol deleted file mode 100644 index e5caa7fdcb..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IAssetData.sol +++ /dev/null @@ -1,88 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -// @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 { - - /// @dev Function signature for encoding ERC20 assetData. - /// @param tokenAddress Address of ERC20Token contract. - function ERC20Token(address tokenAddress) - external; - - /// @dev Function signature for encoding ERC721 assetData. - /// @param tokenAddress Address of ERC721 token contract. - /// @param tokenId Id of ERC721 token to be transferred. - function ERC721Token( - address tokenAddress, - uint256 tokenId - ) - external; - - /// @dev Function signature for encoding ERC1155 assetData. - /// @param tokenAddress Address of ERC1155 token contract. - /// @param tokenIds Array of ids of tokens to be transferred. - /// @param values Array of values that correspond to each token id to be transferred. - /// Note that each value will be multiplied by the amount being filled in the order before transferring. - /// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function. - function ERC1155Assets( - address tokenAddress, - uint256[] calldata tokenIds, - uint256[] calldata values, - bytes calldata callbackData - ) - external; - - /// @dev Function signature for encoding MultiAsset assetData. - /// @param values Array of amounts that correspond to each asset to be transferred. - /// Note that each value will be multiplied by the amount being filled in the order before transferring. - /// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract. - function MultiAsset( - uint256[] calldata values, - bytes[] calldata nestedAssetData - ) - external; - - /// @dev Function signature for encoding StaticCall assetData. - /// @param staticCallTargetAddress Address that will execute the staticcall. - /// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress. - /// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data. - function StaticCall( - address staticCallTargetAddress, - bytes calldata staticCallData, - bytes32 expectedReturnDataHash - ) - external; - - /// @dev Function signature for encoding ERC20Bridge assetData. - /// @param tokenAddress Address of token to transfer. - /// @param bridgeAddress Address of the bridge contract. - /// @param bridgeData Arbitrary data to be passed to the bridge contract. - function ERC20Bridge( - address tokenAddress, - address bridgeAddress, - bytes calldata bridgeData - ) - external; -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IAssetProxy.sol b/contracts/asset-proxy/contracts/src/interfaces/IAssetProxy.sol deleted file mode 100644 index e2f381a9df..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IAssetProxy.sol +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract IAssetProxy { - - /// @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 calldata 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/contracts/asset-proxy/contracts/src/interfaces/IAssetProxyDispatcher.sol b/contracts/asset-proxy/contracts/src/interfaces/IAssetProxyDispatcher.sol deleted file mode 100644 index b675473c52..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IAssetProxyDispatcher.sol +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract IAssetProxyDispatcher { - - // Logs registration of new asset proxy - event AssetProxyRegistered( - bytes4 id, // Id of new registered AssetProxy. - address assetProxy // Address of new registered AssetProxy. - ); - - /// @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/contracts/asset-proxy/contracts/src/interfaces/IAuthorizable.sol b/contracts/asset-proxy/contracts/src/interfaces/IAuthorizable.sol deleted file mode 100644 index 5def85864b..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IAuthorizable.sol +++ /dev/null @@ -1,64 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol"; - - -contract IAuthorizable is - IOwnable -{ - // 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 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/contracts/asset-proxy/contracts/src/interfaces/IBalancerPool.sol b/contracts/asset-proxy/contracts/src/interfaces/IBalancerPool.sol deleted file mode 100644 index 8db7e0d7ce..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IBalancerPool.sol +++ /dev/null @@ -1,39 +0,0 @@ -/* - - Copyright 2020 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.5.9; - - -interface IBalancerPool { - /// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`. - /// @param tokenIn The token being sold - /// @param tokenAmountIn The amount of `tokenIn` to sell. - /// @param tokenOut The token being bought. - /// @param minAmountOut The minimum amount of `tokenOut` to buy. - /// @param maxPrice The maximum value for `spotPriceAfter`. - /// @return tokenAmountOut The amount of `tokenOut` bought. - /// @return spotPriceAfter The new marginal spot price of the given - /// token pair for this pool. - function swapExactAmountIn( - address tokenIn, - uint tokenAmountIn, - address tokenOut, - uint minAmountOut, - uint maxPrice - ) external returns (uint tokenAmountOut, uint spotPriceAfter); -} \ No newline at end of file diff --git a/contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol b/contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol deleted file mode 100644 index 7c1dfb6346..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol +++ /dev/null @@ -1,38 +0,0 @@ -/* - - Copyright 2020 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.5.9; - - -contract IContractRegistry { - function addressOf( - bytes32 contractName - ) external returns(address); -} - - -contract IBancorNetwork { - function convertByPath( - address[] calldata _path, - uint256 _amount, - uint256 _minReturn, - address _beneficiary, - address _affiliateAccount, - uint256 _affiliateFee - ) external payable returns (uint256); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IChai.sol b/contracts/asset-proxy/contracts/src/interfaces/IChai.sol deleted file mode 100644 index d1071dea7e..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IChai.sol +++ /dev/null @@ -1,66 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; - - -contract PotLike { - function chi() external returns (uint256); - function rho() external returns (uint256); - function drip() external returns (uint256); - function join(uint256) external; - function exit(uint256) external; -} - - -// The actual Chai contract can be found here: https://github.com/dapphub/chai -contract IChai is - IERC20Token -{ - /// @dev Withdraws Dai owned by `src` - /// @param src Address that owns Dai. - /// @param wad Amount of Dai to withdraw. - function draw( - address src, - uint256 wad - ) - external; - - /// @dev Queries Dai balance of Chai holder. - /// @param usr Address of Chai holder. - /// @return Dai balance. - function dai(address usr) - external - returns (uint256); - - /// @dev Queries the Pot contract used by the Chai contract. - function pot() - external - returns (PotLike); - - /// @dev Deposits Dai in exchange for Chai - /// @param dst Address to receive Chai. - /// @param wad Amount of Dai to deposit. - function join( - address dst, - uint256 wad - ) - external; -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/ICurve.sol b/contracts/asset-proxy/contracts/src/interfaces/ICurve.sol deleted file mode 100644 index 2f59939ce7..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/ICurve.sol +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -// solhint-disable func-name-mixedcase -interface ICurve { - - /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. - /// This function exists on later versions of Curve (USDC/DAI/USDT) - /// @param i The token index being sold. - /// @param j The token index being bought. - /// @param sellAmount The amount of token being bought. - /// @param minBuyAmount The minimum buy amount of the token being bought. - function exchange_underlying( - int128 i, - int128 j, - uint256 sellAmount, - uint256 minBuyAmount - ) - external; - - /// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken` - /// @param i The token index being sold. - /// @param j The token index being bought. - /// @param sellAmount The amount of token being bought. - function get_dy_underlying( - int128 i, - int128 j, - uint256 sellAmount - ) - external - returns (uint256 dy); - - /// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken` - /// @param i The token index being sold. - /// @param j The token index being bought. - /// @param buyAmount The amount of token being bought. - function get_dx_underlying( - int128 i, - int128 j, - uint256 buyAmount - ) - external - returns (uint256 dx); - - /// @dev Get the underlying token address from the token index - /// @param i The token index. - function underlying_coins( - int128 i - ) - external - returns (address tokenAddress); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IDydx.sol b/contracts/asset-proxy/contracts/src/interfaces/IDydx.sol deleted file mode 100644 index 1ec67a2dfe..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IDydx.sol +++ /dev/null @@ -1,192 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -interface IDydx { - - /// @dev Represents the unique key that specifies an account - struct AccountInfo { - address owner; // The address that owns the account - uint256 number; // A nonce that allows a single address to control many accounts - } - - enum ActionType { - Deposit, // supply tokens - Withdraw, // borrow tokens - Transfer, // transfer balance between accounts - Buy, // buy an amount of some token (externally) - Sell, // sell an amount of some token (externally) - Trade, // trade tokens against another account - Liquidate, // liquidate an undercollateralized or expiring account - Vaporize, // use excess tokens to zero-out a completely negative account - Call // send arbitrary data to an address - } - - /// @dev Arguments that are passed to Solo in an ordered list as part of a single operation. - /// Each ActionArgs has an actionType which specifies which action struct that this data will be - /// parsed into before being processed. - struct ActionArgs { - ActionType actionType; - uint256 accountIdx; - AssetAmount amount; - uint256 primaryMarketId; - uint256 secondaryMarketId; - address otherAddress; - uint256 otherAccountIdx; - bytes data; - } - - enum AssetDenomination { - Wei, // the amount is denominated in wei - Par // the amount is denominated in par - } - - enum AssetReference { - Delta, // the amount is given as a delta from the current value - Target // the amount is given as an exact number to end up at - } - - struct AssetAmount { - bool sign; // true if positive - AssetDenomination denomination; - AssetReference ref; - uint256 value; - } - - struct D256 { - uint256 value; - } - - struct Value { - uint256 value; - } - - struct Price { - uint256 value; - } - - struct OperatorArg { - address operator; - bool trusted; - } - - /// @dev The global risk parameters that govern the health and security of the system - struct RiskParams { - // Required ratio of over-collateralization - D256 marginRatio; - // Percentage penalty incurred by liquidated accounts - D256 liquidationSpread; - // Percentage of the borrower's interest fee that gets passed to the suppliers - D256 earningsRate; - // The minimum absolute borrow value of an account - // There must be sufficient incentivize to liquidate undercollateralized accounts - Value minBorrowedValue; - } - - /// @dev The main entry-point to Solo that allows users and contracts to manage accounts. - /// Take one or more actions on one or more accounts. The msg.sender must be the owner or - /// operator of all accounts except for those being liquidated, vaporized, or traded with. - /// One call to operate() is considered a singular "operation". Account collateralization is - /// ensured only after the completion of the entire operation. - /// @param accounts A list of all accounts that will be used in this operation. Cannot contain - /// duplicates. In each action, the relevant account will be referred-to by its - /// index in the list. - /// @param actions An ordered list of all actions that will be taken in this operation. The - /// actions will be processed in order. - function operate( - AccountInfo[] calldata accounts, - ActionArgs[] calldata actions - ) - external; - - // @dev Approves/disapproves any number of operators. An operator is an external address that has the - // same permissions to manipulate an account as the owner of the account. Operators are simply - // addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts. - // Operators are also able to act as AutoTrader contracts on behalf of the account owner if the - // operator is a smart contract and implements the IAutoTrader interface. - // @param args A list of OperatorArgs which have an address and a boolean. The boolean value - // denotes whether to approve (true) or revoke approval (false) for that address. - function setOperators(OperatorArg[] calldata args) external; - - /// @dev Return true if a particular address is approved as an operator for an owner's accounts. - /// Approved operators can act on the accounts of the owner as if it were the operator's own. - /// @param owner The owner of the accounts - /// @param operator The possible operator - /// @return isLocalOperator True if operator is approved for owner's accounts - function getIsLocalOperator( - address owner, - address operator - ) - external - view - returns (bool isLocalOperator); - - /// @dev Get the ERC20 token address for a market. - /// @param marketId The market to query - /// @return tokenAddress The token address - function getMarketTokenAddress( - uint256 marketId - ) - external - view - returns (address tokenAddress); - - /// @dev Get all risk parameters in a single struct. - /// @return riskParams All global risk parameters - function getRiskParams() - external - view - returns (RiskParams memory riskParams); - - /// @dev Get the price of the token for a market. - /// @param marketId The market to query - /// @return price The price of each atomic unit of the token - function getMarketPrice( - uint256 marketId - ) - external - view - returns (Price memory price); - - /// @dev Get the margin premium for a market. A margin premium makes it so that any positions that - /// include the market require a higher collateralization to avoid being liquidated. - /// @param marketId The market to query - /// @return premium The market's margin premium - function getMarketMarginPremium(uint256 marketId) - external - view - returns (D256 memory premium); - - /// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium - /// of each market. Supplied values are divided by (1 + marginPremium) for each market and - /// borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these - /// adjusted values gives the margin-ratio of the account which will be compared to the global - /// margin-ratio when determining if the account can be liquidated. - /// @param account The account to query - /// @return supplyValue The supplied value of the account (adjusted for marginPremium) - /// @return borrowValue The borrowed value of the account (adjusted for marginPremium) - function getAdjustedAccountValues( - AccountInfo calldata account - ) - external - view - returns (Value memory supplyValue, Value memory borrowValue); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol b/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol deleted file mode 100644 index 057f8ec4c0..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IDydxBridge.sol +++ /dev/null @@ -1,42 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IDydxBridge { - - /// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge. - enum BridgeActionType { - Deposit, // Deposit tokens into dydx account. - Withdraw // Withdraw tokens from dydx account. - } - - struct BridgeAction { - BridgeActionType actionType; // Action to run on dydx account. - uint256 accountIdx; // Index in `BridgeData.accountNumbers` for this action. - uint256 marketId; // Market to operate on. - uint256 conversionRateNumerator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). - uint256 conversionRateDenominator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator). - } - - struct BridgeData { - uint256[] accountNumbers; // Account number used to identify the owner's specific account. - BridgeAction[] actions; // Actions to carry out on the owner's accounts. - } -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IERC20Bridge.sol b/contracts/asset-proxy/contracts/src/interfaces/IERC20Bridge.sol deleted file mode 100644 index bcd1e47381..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IERC20Bridge.sol +++ /dev/null @@ -1,59 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract IERC20Bridge { - - /// @dev Result of a successful bridge call. - bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3; - - /// @dev Emitted when a trade occurs. - /// @param inputToken The token the bridge is converting from. - /// @param outputToken The token the bridge is converting to. - /// @param inputTokenAmount Amount of input token. - /// @param outputTokenAmount Amount of output token. - /// @param from The `from` address in `bridgeTransferFrom()` - /// @param to The `to` address in `bridgeTransferFrom()` - event ERC20BridgeTransfer( - address inputToken, - address outputToken, - uint256 inputTokenAmount, - uint256 outputTokenAmount, - address from, - address to - ); - - /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`. - /// @param tokenAddress The address of the ERC20 token to transfer. - /// @param from Address to transfer asset from. - /// @param to Address to transfer asset to. - /// @param amount Amount of asset to transfer. - /// @param bridgeData Arbitrary asset data needed by the bridge contract. - /// @return success The magic bytes `0xdc1600f3` if successful. - function bridgeTransferFrom( - address tokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4 success); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol b/contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol deleted file mode 100644 index 38fab155b6..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol +++ /dev/null @@ -1,38 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IEth2Dai { - - /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token. - /// @param fromToken The token being sold. - /// @param sellAmount The amount of `fromToken` token being sold. - /// @param toToken The token being bought. - /// @param minFillAmount Minimum amount of `toToken` token to buy. - /// @return fillAmount Amount of `toToken` bought. - function sellAllAmount( - address fromToken, - uint256 sellAmount, - address toToken, - uint256 minFillAmount - ) - external - returns (uint256 fillAmount); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol b/contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol deleted file mode 100644 index a05426e2a4..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol +++ /dev/null @@ -1,40 +0,0 @@ -/* - - Copyright 2019 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.5.15; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; - - -contract IGasToken is IERC20Token { - - /// @dev Frees up to `value` sub-tokens - /// @param value The amount of tokens to free - /// @return How many tokens were freed - function freeUpTo(uint256 value) external returns (uint256 freed); - - /// @dev Frees up to `value` sub-tokens owned by `from` - /// @param from The owner of tokens to spend - /// @param value The amount of tokens to free - /// @return How many tokens were freed - function freeFromUpTo(address from, uint256 value) external returns (uint256 freed); - - /// @dev Mints `value` amount of tokens - /// @param value The amount of tokens to mint - function mint(uint256 value) external; -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IKyberNetworkProxy.sol b/contracts/asset-proxy/contracts/src/interfaces/IKyberNetworkProxy.sol deleted file mode 100644 index 7078c28521..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IKyberNetworkProxy.sol +++ /dev/null @@ -1,72 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IKyberNetworkProxy { - - /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens. - /// @param sellTokenAddress Token to sell. - /// @param sellAmount Amount of tokens to sell. - /// @param buyTokenAddress Token to buy. - /// @param recipientAddress Address to send bought tokens to. - /// @param maxBuyTokenAmount A limit on the amount of tokens to buy. - /// @param minConversionRate The minimal conversion rate. If actual rate - /// is lower, trade is canceled. - /// @param walletId The wallet ID to send part of the fees - /// @return boughtAmount Amount of tokens bought. - function trade( - address sellTokenAddress, - uint256 sellAmount, - address buyTokenAddress, - address payable recipientAddress, - uint256 maxBuyTokenAmount, - uint256 minConversionRate, - address walletId - ) - external - payable - returns (uint256 boughtAmount); - - /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens - /// using a hint for the reserve. - /// @param sellTokenAddress Token to sell. - /// @param sellAmount Amount of tokens to sell. - /// @param buyTokenAddress Token to buy. - /// @param recipientAddress Address to send bought tokens to. - /// @param maxBuyTokenAmount A limit on the amount of tokens to buy. - /// @param minConversionRate The minimal conversion rate. If actual rate - /// is lower, trade is canceled. - /// @param walletId The wallet ID to send part of the fees - /// @param hint The hint for the selective inclusion (or exclusion) of reserves - /// @return boughtAmount Amount of tokens bought. - function tradeWithHint( - address sellTokenAddress, - uint256 sellAmount, - address buyTokenAddress, - address payable recipientAddress, - uint256 maxBuyTokenAmount, - uint256 minConversionRate, - address payable walletId, - bytes calldata hint - ) - external - payable - returns (uint256 boughtAmount); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IMStable.sol b/contracts/asset-proxy/contracts/src/interfaces/IMStable.sol deleted file mode 100644 index a6b0a2e2a5..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IMStable.sol +++ /dev/null @@ -1,32 +0,0 @@ -/* - - Copyright 2020 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.5.9; - - -interface IMStable { - - function swap( - address _input, - address _output, - uint256 _quantity, - address _recipient - ) - external - returns (uint256 output); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IMooniswap.sol b/contracts/asset-proxy/contracts/src/interfaces/IMooniswap.sol deleted file mode 100644 index daef84086c..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IMooniswap.sol +++ /dev/null @@ -1,40 +0,0 @@ -/* - - Copyright 2020 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.5.9; - - -interface IMooniswapRegistry { - - function pools(address token1, address token2) external view returns(address); -} - - -interface IMooniswap { - - function swap( - address fromToken, - address destToken, - uint256 amount, - uint256 minReturn, - address referral - ) - external - payable - returns(uint256 returnAmount); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IShell.sol b/contracts/asset-proxy/contracts/src/interfaces/IShell.sol deleted file mode 100644 index 91bc5f6315..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IShell.sol +++ /dev/null @@ -1,34 +0,0 @@ -/* - - Copyright 2020 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.5.9; - - -interface IShell { - - function originSwap( - address from, - address to, - uint256 fromAmount, - uint256 minTargetAmount, - uint256 deadline - ) - external - returns (uint256 toAmount); -} - diff --git a/contracts/asset-proxy/contracts/src/interfaces/IUniswapExchange.sol b/contracts/asset-proxy/contracts/src/interfaces/IUniswapExchange.sol deleted file mode 100644 index 7278da3978..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IUniswapExchange.sol +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IUniswapExchange { - - /// @dev Buys at least `minTokensBought` tokens with ETH and transfer them - /// to `recipient`. - /// @param minTokensBought The minimum number of tokens to buy. - /// @param deadline Time when this order expires. - /// @param recipient Who to transfer the tokens to. - /// @return tokensBought Amount of tokens bought. - function ethToTokenTransferInput( - uint256 minTokensBought, - uint256 deadline, - address recipient - ) - external - payable - returns (uint256 tokensBought); - - /// @dev Buys at least `minEthBought` ETH with tokens. - /// @param tokensSold Amount of tokens to sell. - /// @param minEthBought The minimum amount of ETH to buy. - /// @param deadline Time when this order expires. - /// @return ethBought Amount of tokens bought. - function tokenToEthSwapInput( - uint256 tokensSold, - uint256 minEthBought, - uint256 deadline - ) - external - returns (uint256 ethBought); - - /// @dev Buys at least `minTokensBought` tokens with the exchange token - /// and transfer them to `recipient`. - /// @param minTokensBought The minimum number of tokens to buy. - /// @param minEthBought The minimum amount of intermediate ETH to buy. - /// @param deadline Time when this order expires. - /// @param recipient Who to transfer the tokens to. - /// @param toTokenAddress The token being bought. - /// @return tokensBought Amount of tokens bought. - function tokenToTokenTransferInput( - uint256 tokensSold, - uint256 minTokensBought, - uint256 minEthBought, - uint256 deadline, - address recipient, - address toTokenAddress - ) - external - returns (uint256 tokensBought); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol b/contracts/asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol deleted file mode 100644 index d91c5319d5..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol +++ /dev/null @@ -1,32 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "./IUniswapExchange.sol"; - - -interface IUniswapExchangeFactory { - - /// @dev Get the exchange for a token. - /// @param tokenAddress The address of the token contract. - function getExchange(address tokenAddress) - external - view - returns (address); -} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IUniswapV2Router01.sol b/contracts/asset-proxy/contracts/src/interfaces/IUniswapV2Router01.sol deleted file mode 100644 index a50d77bba3..0000000000 --- a/contracts/asset-proxy/contracts/src/interfaces/IUniswapV2Router01.sol +++ /dev/null @@ -1,40 +0,0 @@ -/* - - Copyright 2020 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.5.9; - - -interface IUniswapV2Router01 { - - /// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path. - /// The first element of path is the input token, the last is the output token, and any intermediate elements represent - /// intermediate pairs to trade through (if, for example, a direct pair does not exist). - /// @param amountIn The amount of input tokens to send. - /// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert. - /// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity. - /// @param to Recipient of the output tokens. - /// @param deadline Unix timestamp after which the transaction will revert. - /// @return amounts The input token amount and all subsequent output token amounts. - function swapExactTokensForTokens( - uint amountIn, - uint amountOutMin, - address[] calldata path, - address to, - uint deadline - ) external returns (uint[] memory amounts); -} diff --git a/contracts/asset-proxy/contracts/test/TestBancorBridge.sol b/contracts/asset-proxy/contracts/test/TestBancorBridge.sol deleted file mode 100644 index aa0175eea5..0000000000 --- a/contracts/asset-proxy/contracts/test/TestBancorBridge.sol +++ /dev/null @@ -1,247 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; -import "../src/bridges/BancorBridge.sol"; -import "../src/interfaces/IBancorNetwork.sol"; - - -contract TestEventsRaiser { - - event TokenTransfer( - address token, - address from, - address to, - uint256 amount - ); - - event TokenApprove( - address spender, - uint256 allowance - ); - - event ConvertByPathInput( - uint amountIn, - uint amountOutMin, - address toTokenAddress, - address to, - address feeRecipient, - uint256 feeAmount - ); - - function raiseTokenTransfer( - address from, - address to, - uint256 amount - ) - external - { - emit TokenTransfer( - msg.sender, - from, - to, - amount - ); - } - - function raiseTokenApprove(address spender, uint256 allowance) external { - emit TokenApprove(spender, allowance); - } - - function raiseConvertByPathInput( - uint amountIn, - uint amountOutMin, - address toTokenAddress, - address to, - address feeRecipient, - uint256 feeAmount - ) external - { - emit ConvertByPathInput( - amountIn, - amountOutMin, - toTokenAddress, - to, - feeRecipient, - feeAmount - ); - } -} - - -/// @dev A minimalist ERC20 token. -contract TestToken { - - using LibSafeMath for uint256; - - mapping (address => uint256) public balances; - string private _nextRevertReason; - - /// @dev Set the balance for `owner`. - function setBalance(address owner, uint256 balance) - external - payable - { - balances[owner] = balance; - } - - /// @dev Just emits a TokenTransfer event on the caller - function transfer(address to, uint256 amount) - external - returns (bool) - { - TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); - return true; - } - - /// @dev Just emits a TokenApprove event on the caller - function approve(address spender, uint256 allowance) - external - returns (bool) - { - TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); - return true; - } - - function allowance(address, address) external view returns (uint256) { - return 0; - } - - /// @dev Retrieve the balance for `owner`. - function balanceOf(address owner) - external - view - returns (uint256) - { - return balances[owner]; - } -} - - -/// @dev Mock the BancorNetwork contract -contract TestBancorNetwork is - IBancorNetwork -{ - string private _nextRevertReason; - - /// @dev Set the revert reason for `swapExactTokensForTokens`. - function setRevertReason(string calldata reason) - external - { - _nextRevertReason = reason; - } - - function convertByPath( - address[] calldata _path, - uint256 _amount, - uint256 _minReturn, - address _beneficiary, - address _affiliateAccount, - uint256 _affiliateFee - ) external payable returns (uint256) - { - _revertIfReasonExists(); - - TestEventsRaiser(msg.sender).raiseConvertByPathInput( - // tokens sold - _amount, - // tokens bought - _minReturn, - // output token - _path[_path.length - 1], - // recipient - _beneficiary, - // fee recipient - _affiliateAccount, - // fee amount - _affiliateFee - ); - } - - function _revertIfReasonExists() - private - view - { - if (bytes(_nextRevertReason).length != 0) { - revert(_nextRevertReason); - } - } - -} - - -/// @dev BancorBridge overridden to mock tokens and BancorNetwork -contract TestBancorBridge is - BancorBridge, - TestEventsRaiser -{ - - // Token address to TestToken instance. - mapping (address => TestToken) private _testTokens; - // TestRouter instance. - TestBancorNetwork private _testNetwork; - - constructor() public { - _testNetwork = new TestBancorNetwork(); - } - - function setNetworkRevertReason(string calldata revertReason) - external - { - _testNetwork.setRevertReason(revertReason); - } - - /// @dev Sets the balance of this contract for an existing token. - function setTokenBalance(address tokenAddress, uint256 balance) - external - { - TestToken token = _testTokens[tokenAddress]; - token.setBalance(address(this), balance); - } - - /// @dev Create a new token - /// @param tokenAddress The token address. If zero, one will be created. - function createToken( - address tokenAddress - ) - external - returns (TestToken token) - { - token = TestToken(tokenAddress); - if (tokenAddress == address(0)) { - token = new TestToken(); - } - _testTokens[address(token)] = token; - - return token; - } - - function getNetworkAddress() - external - view - returns (address) - { - return address(_testNetwork); - } - -} diff --git a/contracts/asset-proxy/contracts/test/TestChaiBridge.sol b/contracts/asset-proxy/contracts/test/TestChaiBridge.sol deleted file mode 100644 index 3b2dc7f1bf..0000000000 --- a/contracts/asset-proxy/contracts/test/TestChaiBridge.sol +++ /dev/null @@ -1,80 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/bridges/ChaiBridge.sol"; -import "@0x/contracts-erc20/contracts/src/ERC20Token.sol"; - - -contract TestChaiDai is - ERC20Token -{ - address private constant ALWAYS_REVERT_ADDRESS = address(1); - - function draw( - address from, - uint256 amount - ) - external - { - if (from == ALWAYS_REVERT_ADDRESS) { - revert(); - } - balances[msg.sender] += amount; - } -} - - -contract TestChaiBridge is - ChaiBridge -{ - address public testChaiDai; - address private constant ALWAYS_REVERT_ADDRESS = address(1); - - constructor() - public - { - testChaiDai = address(new TestChaiDai()); - } - - function _getDaiAddress() - internal - view - returns (address) - { - return testChaiDai; - } - - function _getChaiAddress() - internal - view - returns (address) - { - return testChaiDai; - } - - function _getERC20BridgeProxyAddress() - internal - view - returns (address) - { - return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; - } -} diff --git a/contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol b/contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol deleted file mode 100644 index 21755ac591..0000000000 --- a/contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol +++ /dev/null @@ -1,244 +0,0 @@ -/* - - Copyright 2020 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/bridges/DexForwarderBridge.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; - - -interface ITestDexForwarderBridge { - event BridgeTransferFromCalled( - address caller, - uint256 inputTokenBalance, - address inputToken, - address outputToken, - address from, - address to, - uint256 amount - ); - - event TokenTransferCalled( - address from, - address to, - uint256 amount - ); - - function emitBridgeTransferFromCalled( - address caller, - uint256 inputTokenBalance, - address inputToken, - address outputToken, - address from, - address to, - uint256 amount - ) external; - - function emitTokenTransferCalled( - address from, - address to, - uint256 amount - ) external; -} - - -interface ITestDexForwarderBridgeTestToken { - - function transfer(address to, uint256 amount) - external - returns (bool); - - function mint(address to, uint256 amount) - external; - - function balanceOf(address owner) external view returns (uint256); -} - - -contract TestDexForwarderBridgeTestBridge { - - bytes4 private _returnCode; - string private _revertError; - uint256 private _transferAmount; - ITestDexForwarderBridge private _testContract; - - constructor(bytes4 returnCode, string memory revertError) public { - _testContract = ITestDexForwarderBridge(msg.sender); - _returnCode = returnCode; - _revertError = revertError; - } - - function setTransferAmount(uint256 amount) external { - _transferAmount = amount; - } - - function bridgeTransferFrom( - address outputToken, - address from, - address to, - uint256 amount, - bytes memory bridgeData - ) - public - returns (bytes4 success) - { - if (bytes(_revertError).length != 0) { - revert(_revertError); - } - address inputToken = abi.decode(bridgeData, (address)); - _testContract.emitBridgeTransferFromCalled( - msg.sender, - ITestDexForwarderBridgeTestToken(inputToken).balanceOf(address(this)), - inputToken, - outputToken, - from, - to, - amount - ); - ITestDexForwarderBridgeTestToken(outputToken).mint(to, _transferAmount); - return _returnCode; - } -} - - -contract TestDexForwarderBridgeTestToken { - - using LibSafeMath for uint256; - - mapping(address => uint256) public balanceOf; - ITestDexForwarderBridge private _testContract; - - constructor() public { - _testContract = ITestDexForwarderBridge(msg.sender); - } - - function transfer(address to, uint256 amount) - external - returns (bool) - { - balanceOf[msg.sender] = balanceOf[msg.sender].safeSub(amount); - balanceOf[to] = balanceOf[to].safeAdd(amount); - _testContract.emitTokenTransferCalled(msg.sender, to, amount); - return true; - } - - function mint(address owner, uint256 amount) - external - { - balanceOf[owner] = balanceOf[owner].safeAdd(amount); - } - - function setBalance(address owner, uint256 amount) - external - { - balanceOf[owner] = amount; - } -} - - -contract TestDexForwarderBridge is - ITestDexForwarderBridge, - DexForwarderBridge -{ - address private AUTHORIZED_ADDRESS; // solhint-disable-line var-name-mixedcase - - function setAuthorized(address authorized) - public - { - AUTHORIZED_ADDRESS = authorized; - } - - function createBridge( - bytes4 returnCode, - string memory revertError - ) - public - returns (address bridge) - { - return address(new TestDexForwarderBridgeTestBridge(returnCode, revertError)); - } - - function createToken() public returns (address token) { - return address(new TestDexForwarderBridgeTestToken()); - } - - function setTokenBalance(address token, address owner, uint256 amount) public { - TestDexForwarderBridgeTestToken(token).setBalance(owner, amount); - } - - function setBridgeTransferAmount(address bridge, uint256 amount) public { - TestDexForwarderBridgeTestBridge(bridge).setTransferAmount(amount); - } - - function emitBridgeTransferFromCalled( - address caller, - uint256 inputTokenBalance, - address inputToken, - address outputToken, - address from, - address to, - uint256 amount - ) - public - { - emit BridgeTransferFromCalled( - caller, - inputTokenBalance, - inputToken, - outputToken, - from, - to, - amount - ); - } - - function emitTokenTransferCalled( - address from, - address to, - uint256 amount - ) - public - { - emit TokenTransferCalled( - from, - to, - amount - ); - } - - function balanceOf(address token, address owner) public view returns (uint256) { - return TestDexForwarderBridgeTestToken(token).balanceOf(owner); - } - - function _getGstAddress() - internal - view - returns (address gst) - { - return address(0); - } - - function _getERC20BridgeProxyAddress() - internal - view - returns (address erc20BridgeProxyAddress) - { - return AUTHORIZED_ADDRESS; - } -} diff --git a/contracts/asset-proxy/contracts/test/TestDydxBridge.sol b/contracts/asset-proxy/contracts/test/TestDydxBridge.sol deleted file mode 100644 index d23425b865..0000000000 --- a/contracts/asset-proxy/contracts/test/TestDydxBridge.sol +++ /dev/null @@ -1,246 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "../src/bridges/DydxBridge.sol"; - - -// solhint-disable no-empty-blocks -contract TestDydxBridgeToken { - - uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens - mapping (address => uint256) private _balances; - - /// @dev Sets initial balance of token holders. - constructor(address[] memory holders) - public - { - for (uint256 i = 0; i != holders.length; ++i) { - _balances[holders[i]] = INIT_HOLDER_BALANCE; - } - _balances[msg.sender] = INIT_HOLDER_BALANCE; - } - - /// @dev Basic transferFrom implementation. - function transferFrom(address from, address to, uint256 amount) - external - returns (bool) - { - if (_balances[from] < amount || _balances[to] + amount < _balances[to]) { - return false; - } - _balances[from] -= amount; - _balances[to] += amount; - return true; - } - - /// @dev Returns balance of `holder`. - function balanceOf(address holder) - external - view - returns (uint256) - { - return _balances[holder]; - } -} - - -// solhint-disable space-after-comma -contract TestDydxBridge is - IDydx, - DydxBridge -{ - - address private constant ALWAYS_REVERT_ADDRESS = address(1); - address private _testTokenAddress; - bool private _shouldRevertOnOperate; - - event OperateAccount( - address owner, - uint256 number - ); - - event OperateAction( - ActionType actionType, - uint256 accountIdx, - bool amountSign, - AssetDenomination amountDenomination, - AssetReference amountRef, - uint256 amountValue, - uint256 primaryMarketId, - uint256 secondaryMarketId, - address otherAddress, - uint256 otherAccountId, - bytes data - ); - - constructor(address[] memory holders) - public - { - // Deploy a test token. This represents the asset being deposited/withdrawn from dydx. - _testTokenAddress = address(new TestDydxBridgeToken(holders)); - } - - /// @dev Simulates `operate` in dydx contract. - /// Emits events so that arguments can be validated client-side. - function operate( - AccountInfo[] calldata accounts, - ActionArgs[] calldata actions - ) - external - { - if (_shouldRevertOnOperate) { - revert("TestDydxBridge/SHOULD_REVERT_ON_OPERATE"); - } - - for (uint i = 0; i < accounts.length; ++i) { - emit OperateAccount( - accounts[i].owner, - accounts[i].number - ); - } - - for (uint i = 0; i < actions.length; ++i) { - emit OperateAction( - actions[i].actionType, - actions[i].accountIdx, - actions[i].amount.sign, - actions[i].amount.denomination, - actions[i].amount.ref, - actions[i].amount.value, - actions[i].primaryMarketId, - actions[i].secondaryMarketId, - actions[i].otherAddress, - actions[i].otherAccountIdx, - actions[i].data - ); - - if (actions[i].actionType == IDydx.ActionType.Withdraw) { - require( - IERC20Token(_testTokenAddress).transferFrom( - address(this), - actions[i].otherAddress, - actions[i].amount.value - ), - "TestDydxBridge/WITHDRAW_FAILED" - ); - } else if (actions[i].actionType == IDydx.ActionType.Deposit) { - require( - IERC20Token(_testTokenAddress).transferFrom( - actions[i].otherAddress, - address(this), - actions[i].amount.value - ), - "TestDydxBridge/DEPOSIT_FAILED" - ); - } else { - revert("TestDydxBridge/UNSUPPORTED_ACTION"); - } - } - } - - /// @dev If `true` then subsequent calls to `operate` will revert. - function setRevertOnOperate(bool shouldRevert) - external - { - _shouldRevertOnOperate = shouldRevert; - } - - /// @dev Returns test token. - function getTestToken() - external - returns (address) - { - return _testTokenAddress; - } - - /// @dev Unused. - function setOperators(OperatorArg[] calldata args) external {} - - /// @dev Unused. - function getIsLocalOperator( - address owner, - address operator - ) - external - view - returns (bool isLocalOperator) - {} - - /// @dev Unused. - function getMarketTokenAddress( - uint256 marketId - ) - external - view - returns (address tokenAddress) - {} - - /// @dev Unused. - function getRiskParams() - external - view - returns (RiskParams memory riskParams) - {} - - /// @dev Unsused. - function getMarketPrice( - uint256 marketId - ) - external - view - returns (Price memory price) - {} - - /// @dev Unsused - function getMarketMarginPremium(uint256 marketId) - external - view - returns (IDydx.D256 memory premium) - {} - - /// @dev Unused. - function getAdjustedAccountValues( - AccountInfo calldata account - ) - external - view - returns (Value memory supplyValue, Value memory borrowValue) - {} - - /// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address. - function _getDydxAddress() - internal - view - returns (address) - { - return address(this); - } - - /// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing. - function _getERC20BridgeProxyAddress() - internal - view - returns (address) - { - return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; - } -} diff --git a/contracts/asset-proxy/contracts/test/TestERC20Bridge.sol b/contracts/asset-proxy/contracts/test/TestERC20Bridge.sol deleted file mode 100644 index b65f666475..0000000000 --- a/contracts/asset-proxy/contracts/test/TestERC20Bridge.sol +++ /dev/null @@ -1,108 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IERC20Bridge.sol"; - - -/// @dev Test bridge token -contract TestERC20BridgeToken { - mapping (address => uint256) private _balances; - - function addBalance(address owner, int256 amount) - external - { - setBalance(owner, uint256(int256(balanceOf(owner)) + amount)); - } - - function setBalance(address owner, uint256 balance) - public - { - _balances[owner] = balance; - } - - function balanceOf(address owner) - public - view - returns (uint256) - { - return _balances[owner]; - } -} - - -/// @dev Test bridge contract. -contract TestERC20Bridge is - IERC20Bridge -{ - TestERC20BridgeToken public testToken; - - event BridgeWithdrawTo( - address tokenAddress, - address from, - address to, - uint256 amount, - bytes bridgeData - ); - - constructor() public { - testToken = new TestERC20BridgeToken(); - } - - function setTestTokenBalance(address owner, uint256 balance) - external - { - testToken.setBalance(owner, balance); - } - - function bridgeTransferFrom( - address tokenAddress, - address from, - address to, - uint256 amount, - bytes calldata bridgeData - ) - external - returns (bytes4) - { - emit BridgeWithdrawTo( - tokenAddress, - from, - to, - amount, - bridgeData - ); - // Unpack the bridgeData. - ( - int256 transferAmount, - bytes memory revertData, - bytes memory returnData - ) = abi.decode(bridgeData, (int256, bytes, bytes)); - - // If `revertData` is set, revert. - if (revertData.length != 0) { - assembly { revert(add(revertData, 0x20), mload(revertData)) } - } - // Increase `to`'s balance by `transferAmount`. - TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount); - // Return `returnData`. - assembly { return(add(returnData, 0x20), mload(returnData)) } - } -} diff --git a/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol b/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol deleted file mode 100644 index ee249278b1..0000000000 --- a/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol +++ /dev/null @@ -1,206 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "../src/bridges/Eth2DaiBridge.sol"; -import "../src/interfaces/IEth2Dai.sol"; - - -// solhint-disable no-simple-event-func-name -contract TestEvents { - - event TokenTransfer( - address token, - address from, - address to, - uint256 amount - ); - - event TokenApprove( - address token, - address spender, - uint256 allowance - ); - - function raiseTokenTransfer( - address from, - address to, - uint256 amount - ) - external - { - emit TokenTransfer( - msg.sender, - from, - to, - amount - ); - } - - function raiseTokenApprove(address spender, uint256 allowance) - external - { - emit TokenApprove(msg.sender, spender, allowance); - } -} - - -/// @dev A minimalist ERC20 token. -contract TestToken { - - mapping (address => uint256) public balances; - string private _nextTransferRevertReason; - bytes private _nextTransferReturnData; - - /// @dev Just calls `raiseTokenTransfer()` on the caller. - function transfer(address to, uint256 amount) - external - returns (bool) - { - TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount); - if (bytes(_nextTransferRevertReason).length != 0) { - revert(_nextTransferRevertReason); - } - bytes memory returnData = _nextTransferReturnData; - assembly { return(add(returnData, 0x20), mload(returnData)) } - } - - /// @dev Set the balance for `owner`. - function setBalance(address owner, uint256 balance) - external - { - balances[owner] = balance; - } - - /// @dev Set the behavior of the `transfer()` call. - function setTransferBehavior( - string calldata revertReason, - bytes calldata returnData - ) - external - { - _nextTransferRevertReason = revertReason; - _nextTransferReturnData = returnData; - } - - /// @dev Just calls `raiseTokenApprove()` on the caller. - function approve(address spender, uint256 allowance) - external - returns (bool) - { - TestEvents(msg.sender).raiseTokenApprove(spender, allowance); - return true; - } - - function allowance(address, address) external view returns (uint256) { - return 0; - } - - /// @dev Retrieve the balance for `owner`. - function balanceOf(address owner) - external - view - returns (uint256) - { - return balances[owner]; - } -} - - -/// @dev Eth2DaiBridge overridden to mock tokens and -/// implement IEth2Dai. -contract TestEth2DaiBridge is - TestEvents, - IEth2Dai, - Eth2DaiBridge -{ - event SellAllAmount( - address sellToken, - uint256 sellTokenAmount, - address buyToken, - uint256 minimumFillAmount - ); - - mapping (address => TestToken) public testTokens; - string private _nextRevertReason; - uint256 private _nextFillAmount; - - /// @dev Create a token and set this contract's balance. - function createToken(uint256 balance) - external - returns (address tokenAddress) - { - TestToken token = new TestToken(); - testTokens[address(token)] = token; - token.setBalance(address(this), balance); - return address(token); - } - - /// @dev Set the behavior for `IEth2Dai.sellAllAmount()`. - function setFillBehavior(string calldata revertReason, uint256 fillAmount) - external - { - _nextRevertReason = revertReason; - _nextFillAmount = fillAmount; - } - - /// @dev Set the behavior of a token's `transfer()`. - function setTransferBehavior( - address tokenAddress, - string calldata revertReason, - bytes calldata returnData - ) - external - { - testTokens[tokenAddress].setTransferBehavior(revertReason, returnData); - } - - /// @dev Implementation of `IEth2Dai.sellAllAmount()` - function sellAllAmount( - address sellTokenAddress, - uint256 sellTokenAmount, - address buyTokenAddress, - uint256 minimumFillAmount - ) - external - returns (uint256 fillAmount) - { - emit SellAllAmount( - sellTokenAddress, - sellTokenAmount, - buyTokenAddress, - minimumFillAmount - ); - if (bytes(_nextRevertReason).length != 0) { - revert(_nextRevertReason); - } - return _nextFillAmount; - } - - // @dev This contract will double as the Eth2Dai contract. - function _getEth2DaiAddress() - internal - view - returns (address) - { - return address(this); - } -} diff --git a/contracts/asset-proxy/contracts/test/TestKyberBridge.sol b/contracts/asset-proxy/contracts/test/TestKyberBridge.sol deleted file mode 100644 index 26f87071d1..0000000000 --- a/contracts/asset-proxy/contracts/test/TestKyberBridge.sol +++ /dev/null @@ -1,355 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "../src/bridges/KyberBridge.sol"; -import "../src/interfaces/IKyberNetworkProxy.sol"; - - -// solhint-disable no-simple-event-func-name -interface ITestContract { - - function wethWithdraw( - address payable ownerAddress, - uint256 amount - ) - external; - - function wethDeposit( - address ownerAddress - ) - external - payable; - - function tokenTransfer( - address ownerAddress, - address recipientAddress, - uint256 amount - ) - external - returns (bool success); - - function tokenApprove( - address ownerAddress, - address spenderAddress, - uint256 allowance - ) - external - returns (bool success); - - function tokenBalanceOf( - address ownerAddress - ) - external - view - returns (uint256 balance); -} - - -/// @dev A minimalist ERC20/WETH token. -contract TestToken { - - uint8 public decimals; - ITestContract private _testContract; - - constructor(uint8 decimals_) public { - decimals = decimals_; - _testContract = ITestContract(msg.sender); - } - - function approve(address spender, uint256 allowance) - external - returns (bool) - { - return _testContract.tokenApprove( - msg.sender, - spender, - allowance - ); - } - - function transfer(address recipient, uint256 amount) - external - returns (bool) - { - return _testContract.tokenTransfer( - msg.sender, - recipient, - amount - ); - } - - function withdraw(uint256 amount) - external - { - return _testContract.wethWithdraw(msg.sender, amount); - } - - function deposit() - external - payable - { - return _testContract.wethDeposit.value(msg.value)(msg.sender); - } - - function allowance(address, address) external view returns (uint256) { - return 0; - } - - function balanceOf(address owner) - external - view - returns (uint256) - { - return _testContract.tokenBalanceOf(owner); - } -} - - -/// @dev KyberBridge overridden to mock tokens and implement IKyberBridge. -contract TestKyberBridge is - KyberBridge, - ITestContract, - IKyberNetworkProxy -{ - event KyberBridgeTrade( - uint256 msgValue, - address sellTokenAddress, - uint256 sellAmount, - address buyTokenAddress, - address payable recipientAddress, - uint256 maxBuyTokenAmount, - uint256 minConversionRate, - address walletId - ); - - event KyberBridgeWethWithdraw( - address ownerAddress, - uint256 amount - ); - - event KyberBridgeWethDeposit( - uint256 msgValue, - address ownerAddress, - uint256 amount - ); - - event KyberBridgeTokenApprove( - address tokenAddress, - address ownerAddress, - address spenderAddress, - uint256 allowance - ); - - event KyberBridgeTokenTransfer( - address tokenAddress, - address ownerAddress, - address recipientAddress, - uint256 amount - ); - - IEtherToken public weth; - mapping (address => mapping (address => uint256)) private _tokenBalances; - uint256 private _nextFillAmount; - - constructor() public { - weth = IEtherToken(address(new TestToken(18))); - } - - /// @dev Implementation of `IKyberNetworkProxy.trade()` - function trade( - address sellTokenAddress, - uint256 sellAmount, - address buyTokenAddress, - address payable recipientAddress, - uint256 maxBuyTokenAmount, - uint256 minConversionRate, - address walletId - ) - external - payable - returns(uint256 boughtAmount) - { - emit KyberBridgeTrade( - msg.value, - sellTokenAddress, - sellAmount, - buyTokenAddress, - recipientAddress, - maxBuyTokenAmount, - minConversionRate, - walletId - ); - return _nextFillAmount; - } - - function tradeWithHint( - address sellTokenAddress, - uint256 sellAmount, - address buyTokenAddress, - address payable recipientAddress, - uint256 maxBuyTokenAmount, - uint256 minConversionRate, - address payable walletId, - bytes calldata hint - ) - external - payable - returns (uint256 boughtAmount) - { - emit KyberBridgeTrade( - msg.value, - sellTokenAddress, - sellAmount, - buyTokenAddress, - recipientAddress, - maxBuyTokenAmount, - minConversionRate, - walletId - ); - return _nextFillAmount; - } - - function createToken(uint8 decimals) - external - returns (address tokenAddress) - { - return address(new TestToken(decimals)); - } - - function setNextFillAmount(uint256 amount) - external - payable - { - if (msg.value != 0) { - require(amount == msg.value, "VALUE_AMOUNT_MISMATCH"); - grantTokensTo(address(weth), address(this), msg.value); - } - _nextFillAmount = amount; - } - - function wethDeposit( - address ownerAddress - ) - external - payable - { - require(msg.sender == address(weth), "ONLY_WETH"); - grantTokensTo(address(weth), ownerAddress, msg.value); - emit KyberBridgeWethDeposit( - msg.value, - ownerAddress, - msg.value - ); - } - - function wethWithdraw( - address payable ownerAddress, - uint256 amount - ) - external - { - require(msg.sender == address(weth), "ONLY_WETH"); - _tokenBalances[address(weth)][ownerAddress] -= amount; - ownerAddress.transfer(amount); - emit KyberBridgeWethWithdraw( - ownerAddress, - amount - ); - } - - function tokenApprove( - address ownerAddress, - address spenderAddress, - uint256 allowance - ) - external - returns (bool success) - { - emit KyberBridgeTokenApprove( - msg.sender, - ownerAddress, - spenderAddress, - allowance - ); - return true; - } - - function tokenTransfer( - address ownerAddress, - address recipientAddress, - uint256 amount - ) - external - returns (bool success) - { - _tokenBalances[msg.sender][ownerAddress] -= amount; - _tokenBalances[msg.sender][recipientAddress] += amount; - emit KyberBridgeTokenTransfer( - msg.sender, - ownerAddress, - recipientAddress, - amount - ); - return true; - } - - function tokenBalanceOf( - address ownerAddress - ) - external - view - returns (uint256 balance) - { - return _tokenBalances[msg.sender][ownerAddress]; - } - - function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount) - public - payable - { - _tokenBalances[tokenAddress][ownerAddress] += amount; - if (tokenAddress != address(weth)) { - // Send back ether if not WETH. - msg.sender.transfer(msg.value); - } else { - require(msg.value == amount, "VALUE_AMOUNT_MISMATCH"); - } - } - - // @dev overridden to point to this contract. - function _getKyberNetworkProxyAddress() - internal - view - returns (address) - { - return address(this); - } - - // @dev overridden to point to test WETH. - function _getWethAddress() - internal - view - returns (address) - { - return address(weth); - } -} diff --git a/contracts/asset-proxy/contracts/test/TestStaticCallTarget.sol b/contracts/asset-proxy/contracts/test/TestStaticCallTarget.sol deleted file mode 100644 index 2dd7929c71..0000000000 --- a/contracts/asset-proxy/contracts/test/TestStaticCallTarget.sol +++ /dev/null @@ -1,82 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -contract TestStaticCallTarget { - - using LibBytes for bytes; - - uint256 internal _state; - - function updateState() - external - { - _state++; - } - - function assertEvenNumber(uint256 target) - external - pure - { - require( - target % 2 == 0, - "TARGET_NOT_EVEN" - ); - } - - function isOddNumber(uint256 target) - external - pure - returns (bool isOdd) - { - isOdd = target % 2 == 1; - return isOdd; - } - - function noInputFunction() - external - pure - { - assert(msg.data.length == 4 && msg.data.readBytes4(0) == bytes4(keccak256("noInputFunction()"))); - } - - function dynamicInputFunction(bytes calldata a) - external - pure - { - bytes memory abiEncodedData = abi.encodeWithSignature("dynamicInputFunction(bytes)", a); - assert(msg.data.equals(abiEncodedData)); - } - - function returnComplexType(uint256 a, uint256 b) - external - view - returns (bytes memory result) - { - result = abi.encodePacked( - address(this), - a, - b - ); - return result; - } -} \ No newline at end of file diff --git a/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol b/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol deleted file mode 100644 index bc9b53b650..0000000000 --- a/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol +++ /dev/null @@ -1,436 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../src/bridges/UniswapBridge.sol"; -import "../src/interfaces/IUniswapExchangeFactory.sol"; -import "../src/interfaces/IUniswapExchange.sol"; - - -// solhint-disable no-simple-event-func-name -contract TestEventsRaiser { - - event TokenTransfer( - address token, - address from, - address to, - uint256 amount - ); - - event TokenApprove( - address spender, - uint256 allowance - ); - - event WethDeposit( - uint256 amount - ); - - event WethWithdraw( - uint256 amount - ); - - event EthToTokenTransferInput( - address exchange, - uint256 minTokensBought, - uint256 deadline, - address recipient - ); - - event TokenToEthSwapInput( - address exchange, - uint256 tokensSold, - uint256 minEthBought, - uint256 deadline - ); - - event TokenToTokenTransferInput( - address exchange, - uint256 tokensSold, - uint256 minTokensBought, - uint256 minEthBought, - uint256 deadline, - address recipient, - address toTokenAddress - ); - - function raiseEthToTokenTransferInput( - uint256 minTokensBought, - uint256 deadline, - address recipient - ) - external - { - emit EthToTokenTransferInput( - msg.sender, - minTokensBought, - deadline, - recipient - ); - } - - function raiseTokenToEthSwapInput( - uint256 tokensSold, - uint256 minEthBought, - uint256 deadline - ) - external - { - emit TokenToEthSwapInput( - msg.sender, - tokensSold, - minEthBought, - deadline - ); - } - - function raiseTokenToTokenTransferInput( - uint256 tokensSold, - uint256 minTokensBought, - uint256 minEthBought, - uint256 deadline, - address recipient, - address toTokenAddress - ) - external - { - emit TokenToTokenTransferInput( - msg.sender, - tokensSold, - minTokensBought, - minEthBought, - deadline, - recipient, - toTokenAddress - ); - } - - function raiseTokenTransfer( - address from, - address to, - uint256 amount - ) - external - { - emit TokenTransfer( - msg.sender, - from, - to, - amount - ); - } - - function raiseTokenApprove(address spender, uint256 allowance) - external - { - emit TokenApprove(spender, allowance); - } - - function raiseWethDeposit(uint256 amount) - external - { - emit WethDeposit(amount); - } - - function raiseWethWithdraw(uint256 amount) - external - { - emit WethWithdraw(amount); - } -} - - -/// @dev A minimalist ERC20/WETH token. -contract TestToken { - - using LibSafeMath for uint256; - - mapping (address => uint256) public balances; - string private _nextRevertReason; - - /// @dev Set the balance for `owner`. - function setBalance(address owner) - external - payable - { - balances[owner] = msg.value; - } - - /// @dev Set the revert reason for `transfer()`, - /// `deposit()`, and `withdraw()`. - function setRevertReason(string calldata reason) - external - { - _nextRevertReason = reason; - } - - /// @dev Just calls `raiseTokenTransfer()` on the caller. - function transfer(address to, uint256 amount) - external - returns (bool) - { - _revertIfReasonExists(); - TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); - return true; - } - - /// @dev Just calls `raiseTokenApprove()` on the caller. - function approve(address spender, uint256 allowance) - external - returns (bool) - { - TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); - return true; - } - - /// @dev `IWETH.deposit()` that increases balances and calls - /// `raiseWethDeposit()` on the caller. - function deposit() - external - payable - { - _revertIfReasonExists(); - balances[msg.sender] += balances[msg.sender].safeAdd(msg.value); - TestEventsRaiser(msg.sender).raiseWethDeposit(msg.value); - } - - /// @dev `IWETH.withdraw()` that just reduces balances and calls - /// `raiseWethWithdraw()` on the caller. - function withdraw(uint256 amount) - external - { - _revertIfReasonExists(); - balances[msg.sender] = balances[msg.sender].safeSub(amount); - msg.sender.transfer(amount); - TestEventsRaiser(msg.sender).raiseWethWithdraw(amount); - } - - function allowance(address, address) external view returns (uint256) { - return 0; - } - - /// @dev Retrieve the balance for `owner`. - function balanceOf(address owner) - external - view - returns (uint256) - { - return balances[owner]; - } - - function _revertIfReasonExists() - private - view - { - if (bytes(_nextRevertReason).length != 0) { - revert(_nextRevertReason); - } - } -} - - -contract TestExchange is - IUniswapExchange -{ - address public tokenAddress; - string private _nextRevertReason; - - constructor(address _tokenAddress) public { - tokenAddress = _tokenAddress; - } - - function setFillBehavior( - string calldata revertReason - ) - external - payable - { - _nextRevertReason = revertReason; - } - - function ethToTokenTransferInput( - uint256 minTokensBought, - uint256 deadline, - address recipient - ) - external - payable - returns (uint256 tokensBought) - { - TestEventsRaiser(msg.sender).raiseEthToTokenTransferInput( - minTokensBought, - deadline, - recipient - ); - _revertIfReasonExists(); - return address(this).balance; - } - - function tokenToEthSwapInput( - uint256 tokensSold, - uint256 minEthBought, - uint256 deadline - ) - external - returns (uint256 ethBought) - { - TestEventsRaiser(msg.sender).raiseTokenToEthSwapInput( - tokensSold, - minEthBought, - deadline - ); - _revertIfReasonExists(); - uint256 fillAmount = address(this).balance; - msg.sender.transfer(fillAmount); - return fillAmount; - } - - function tokenToTokenTransferInput( - uint256 tokensSold, - uint256 minTokensBought, - uint256 minEthBought, - uint256 deadline, - address recipient, - address toTokenAddress - ) - external - returns (uint256 tokensBought) - { - TestEventsRaiser(msg.sender).raiseTokenToTokenTransferInput( - tokensSold, - minTokensBought, - minEthBought, - deadline, - recipient, - toTokenAddress - ); - _revertIfReasonExists(); - return address(this).balance; - } - - function toTokenAddress() - external - view - returns (address _tokenAddress) - { - return tokenAddress; - } - - function _revertIfReasonExists() - private - view - { - if (bytes(_nextRevertReason).length != 0) { - revert(_nextRevertReason); - } - } -} - - -/// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory. -contract TestUniswapBridge is - IUniswapExchangeFactory, - TestEventsRaiser, - UniswapBridge -{ - TestToken public wethToken; - // Token address to TestToken instance. - mapping (address => TestToken) private _testTokens; - // Token address to TestExchange instance. - mapping (address => TestExchange) private _testExchanges; - - constructor() public { - wethToken = new TestToken(); - _testTokens[address(wethToken)] = wethToken; - } - - /// @dev Sets the balance of this contract for an existing token. - /// The wei attached will be the balance. - function setTokenBalance(address tokenAddress) - external - payable - { - TestToken token = _testTokens[tokenAddress]; - token.deposit.value(msg.value)(); - } - - /// @dev Sets the revert reason for an existing token. - function setTokenRevertReason(address tokenAddress, string calldata revertReason) - external - { - TestToken token = _testTokens[tokenAddress]; - token.setRevertReason(revertReason); - } - - /// @dev Create a token and exchange (if they don't exist) for a new token - /// and sets the exchange revert and fill behavior. The wei attached - /// will be the fill amount for the exchange. - /// @param tokenAddress The token address. If zero, one will be created. - /// @param revertReason The revert reason for exchange operations. - function createTokenAndExchange( - address tokenAddress, - string calldata revertReason - ) - external - payable - returns (TestToken token, TestExchange exchange) - { - token = TestToken(tokenAddress); - if (tokenAddress == address(0)) { - token = new TestToken(); - } - _testTokens[address(token)] = token; - exchange = _testExchanges[address(token)]; - if (address(exchange) == address(0)) { - _testExchanges[address(token)] = exchange = new TestExchange(address(token)); - } - exchange.setFillBehavior.value(msg.value)(revertReason); - return (token, exchange); - } - - /// @dev `IUniswapExchangeFactory.getExchange` - function getExchange(address tokenAddress) - external - view - returns (address) - { - return address(_testExchanges[tokenAddress]); - } - - // @dev Use `wethToken`. - function _getWethAddress() - internal - view - returns (address) - { - return address(wethToken); - } - - // @dev This contract will double as the Uniswap contract. - function _getUniswapExchangeFactoryAddress() - internal - view - returns (address) - { - return address(this); - } -} diff --git a/contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol b/contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol deleted file mode 100644 index 04126f22e0..0000000000 --- a/contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol +++ /dev/null @@ -1,253 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; -import "../src/bridges/UniswapV2Bridge.sol"; -import "../src/interfaces/IUniswapV2Router01.sol"; - - -contract TestEventsRaiser { - - event TokenTransfer( - address token, - address from, - address to, - uint256 amount - ); - - event TokenApprove( - address spender, - uint256 allowance - ); - - event SwapExactTokensForTokensInput( - uint amountIn, - uint amountOutMin, - address toTokenAddress, - address to, - uint deadline - ); - - function raiseTokenTransfer( - address from, - address to, - uint256 amount - ) - external - { - emit TokenTransfer( - msg.sender, - from, - to, - amount - ); - } - - function raiseTokenApprove(address spender, uint256 allowance) external { - emit TokenApprove(spender, allowance); - } - - function raiseSwapExactTokensForTokensInput( - uint amountIn, - uint amountOutMin, - address toTokenAddress, - address to, - uint deadline - ) external - { - emit SwapExactTokensForTokensInput( - amountIn, - amountOutMin, - toTokenAddress, - to, - deadline - ); - } -} - - -/// @dev A minimalist ERC20 token. -contract TestToken { - - using LibSafeMath for uint256; - - mapping (address => uint256) public balances; - string private _nextRevertReason; - - /// @dev Set the balance for `owner`. - function setBalance(address owner, uint256 balance) - external - payable - { - balances[owner] = balance; - } - - /// @dev Just emits a TokenTransfer event on the caller - function transfer(address to, uint256 amount) - external - returns (bool) - { - TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); - return true; - } - - /// @dev Just emits a TokenApprove event on the caller - function approve(address spender, uint256 allowance) - external - returns (bool) - { - TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); - return true; - } - - function allowance(address, address) external view returns (uint256) { - return 0; - } - - /// @dev Retrieve the balance for `owner`. - function balanceOf(address owner) - external - view - returns (uint256) - { - return balances[owner]; - } -} - - -/// @dev Mock the UniswapV2Router01 contract -contract TestRouter is - IUniswapV2Router01 -{ - string private _nextRevertReason; - - /// @dev Set the revert reason for `swapExactTokensForTokens`. - function setRevertReason(string calldata reason) - external - { - _nextRevertReason = reason; - } - - function swapExactTokensForTokens( - uint amountIn, - uint amountOutMin, - address[] calldata path, - address to, - uint deadline - ) external returns (uint[] memory amounts) - { - _revertIfReasonExists(); - - amounts = new uint[](path.length); - amounts[0] = amountIn; - amounts[amounts.length - 1] = amountOutMin; - - TestEventsRaiser(msg.sender).raiseSwapExactTokensForTokensInput( - // tokens sold - amountIn, - // tokens bought - amountOutMin, - // output token (toTokenAddress) - path[path.length - 1], - // recipient - to, - // deadline - deadline - ); - } - - function _revertIfReasonExists() - private - view - { - if (bytes(_nextRevertReason).length != 0) { - revert(_nextRevertReason); - } - } - -} - - -/// @dev UniswapV2Bridge overridden to mock tokens and Uniswap router -contract TestUniswapV2Bridge is - UniswapV2Bridge, - TestEventsRaiser -{ - - // Token address to TestToken instance. - mapping (address => TestToken) private _testTokens; - // TestRouter instance. - TestRouter private _testRouter; - - constructor() public { - _testRouter = new TestRouter(); - } - - function setRouterRevertReason(string calldata revertReason) - external - { - _testRouter.setRevertReason(revertReason); - } - - /// @dev Sets the balance of this contract for an existing token. - /// The wei attached will be the balance. - function setTokenBalance(address tokenAddress, uint256 balance) - external - { - TestToken token = _testTokens[tokenAddress]; - token.setBalance(address(this), balance); - } - - /// @dev Create a new token - /// @param tokenAddress The token address. If zero, one will be created. - function createToken( - address tokenAddress - ) - external - returns (TestToken token) - { - token = TestToken(tokenAddress); - if (tokenAddress == address(0)) { - token = new TestToken(); - } - _testTokens[address(token)] = token; - - return token; - } - - function getRouterAddress() - external - view - returns (address) - { - return address(_testRouter); - } - - function _getUniswapV2Router01Address() - internal - view - returns (address) - { - return address(_testRouter); - } -} diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json deleted file mode 100644 index f2dc759d46..0000000000 --- a/contracts/asset-proxy/package.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "name": "@0x/contracts-asset-proxy", - "version": "3.7.19", - "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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CryptoComBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contract-wrappers": "^13.17.4", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "ethereumjs-util": "^7.0.10", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/contracts-erc1155": "^2.1.37", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-erc721": "^3.1.37", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/order-utils": "^10.4.28", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "ethereum-types": "^3.5.0", - "lodash": "^4.17.11" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts deleted file mode 100644 index 00b95798dc..0000000000 --- a/contracts/asset-proxy/src/artifacts.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json'; -import * as BancorBridge from '../generated-artifacts/BancorBridge.json'; -import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json'; -import * as CreamBridge from '../generated-artifacts/CreamBridge.json'; -import * as CryptoComBridge from '../generated-artifacts/CryptoComBridge.json'; -import * as CurveBridge from '../generated-artifacts/CurveBridge.json'; -import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json'; -import * as DODOBridge from '../generated-artifacts/DODOBridge.json'; -import * as DydxBridge from '../generated-artifacts/DydxBridge.json'; -import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; -import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; -import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; -import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json'; -import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json'; -import * as IAssetData from '../generated-artifacts/IAssetData.json'; -import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json'; -import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json'; -import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; -import * as IBalancerPool from '../generated-artifacts/IBalancerPool.json'; -import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.json'; -import * as IChai from '../generated-artifacts/IChai.json'; -import * as ICurve from '../generated-artifacts/ICurve.json'; -import * as IDydx from '../generated-artifacts/IDydx.json'; -import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json'; -import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json'; -import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json'; -import * as IGasToken from '../generated-artifacts/IGasToken.json'; -import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json'; -import * as IMooniswap from '../generated-artifacts/IMooniswap.json'; -import * as IMStable from '../generated-artifacts/IMStable.json'; -import * as IShell from '../generated-artifacts/IShell.json'; -import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json'; -import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json'; -import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.json'; -import * as KyberBridge from '../generated-artifacts/KyberBridge.json'; -import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json'; -import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; -import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json'; -import * as MooniswapBridge from '../generated-artifacts/MooniswapBridge.json'; -import * as MStableBridge from '../generated-artifacts/MStableBridge.json'; -import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; -import * as Ownable from '../generated-artifacts/Ownable.json'; -import * as ShellBridge from '../generated-artifacts/ShellBridge.json'; -import * as SnowSwapBridge from '../generated-artifacts/SnowSwapBridge.json'; -import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; -import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json'; -import * as SwerveBridge from '../generated-artifacts/SwerveBridge.json'; -import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json'; -import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; -import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json'; -import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json'; -import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json'; -import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json'; -import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json'; -import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json'; -import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json'; -import * as TestUniswapV2Bridge from '../generated-artifacts/TestUniswapV2Bridge.json'; -import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json'; -import * as UniswapV2Bridge from '../generated-artifacts/UniswapV2Bridge.json'; -export const artifacts = { - MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, - MixinAuthorizable: MixinAuthorizable as ContractArtifact, - Ownable: Ownable as ContractArtifact, - ERC1155Proxy: ERC1155Proxy as ContractArtifact, - ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, - ERC20Proxy: ERC20Proxy as ContractArtifact, - ERC721Proxy: ERC721Proxy as ContractArtifact, - MultiAssetProxy: MultiAssetProxy as ContractArtifact, - StaticCallProxy: StaticCallProxy as ContractArtifact, - BalancerBridge: BalancerBridge as ContractArtifact, - BancorBridge: BancorBridge as ContractArtifact, - ChaiBridge: ChaiBridge as ContractArtifact, - CreamBridge: CreamBridge as ContractArtifact, - CryptoComBridge: CryptoComBridge as ContractArtifact, - CurveBridge: CurveBridge as ContractArtifact, - DODOBridge: DODOBridge as ContractArtifact, - DexForwarderBridge: DexForwarderBridge as ContractArtifact, - DydxBridge: DydxBridge as ContractArtifact, - Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, - KyberBridge: KyberBridge as ContractArtifact, - MStableBridge: MStableBridge as ContractArtifact, - MixinGasToken: MixinGasToken as ContractArtifact, - MooniswapBridge: MooniswapBridge as ContractArtifact, - ShellBridge: ShellBridge as ContractArtifact, - SnowSwapBridge: SnowSwapBridge as ContractArtifact, - SushiSwapBridge: SushiSwapBridge as ContractArtifact, - SwerveBridge: SwerveBridge as ContractArtifact, - UniswapBridge: UniswapBridge as ContractArtifact, - UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, - IAssetData: IAssetData as ContractArtifact, - IAssetProxy: IAssetProxy as ContractArtifact, - IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, - IAuthorizable: IAuthorizable as ContractArtifact, - IBalancerPool: IBalancerPool as ContractArtifact, - IBancorNetwork: IBancorNetwork as ContractArtifact, - IChai: IChai as ContractArtifact, - ICurve: ICurve as ContractArtifact, - IDydx: IDydx as ContractArtifact, - IDydxBridge: IDydxBridge as ContractArtifact, - IERC20Bridge: IERC20Bridge as ContractArtifact, - IEth2Dai: IEth2Dai as ContractArtifact, - IGasToken: IGasToken as ContractArtifact, - IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, - IMStable: IMStable as ContractArtifact, - IMooniswap: IMooniswap as ContractArtifact, - IShell: IShell as ContractArtifact, - IUniswapExchange: IUniswapExchange as ContractArtifact, - IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, - IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, - TestBancorBridge: TestBancorBridge as ContractArtifact, - TestChaiBridge: TestChaiBridge as ContractArtifact, - TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact, - TestDydxBridge: TestDydxBridge as ContractArtifact, - TestERC20Bridge: TestERC20Bridge as ContractArtifact, - TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, - TestKyberBridge: TestKyberBridge as ContractArtifact, - TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, - TestUniswapBridge: TestUniswapBridge as ContractArtifact, - TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact, -}; diff --git a/contracts/asset-proxy/src/asset_data.ts b/contracts/asset-proxy/src/asset_data.ts deleted file mode 100644 index fef2030fef..0000000000 --- a/contracts/asset-proxy/src/asset_data.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { AssetProxyId } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; - -import { IAssetDataContract } from './wrappers'; - -const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any); - -/** - * Get the proxy ID from encoded asset data. - */ -export function getAssetDataProxyId(encoded: string): AssetProxyId { - // tslint:disable-next-line: no-unnecessary-type-assertion - return hexUtils.slice(encoded, 0, 4) as AssetProxyId; -} - -/** - * Decode ERC20 asset data. - */ -export function decodeERC20AssetData(encoded: string): string { - return assetDataIface.getABIDecodedTransactionData('ERC20Token', encoded); -} - -/** - * Decode ERC721 asset data. - */ -export function decodeERC721AssetData(encoded: string): [string, BigNumber] { - return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded); -} - -/** - * Decode ERC1155 asset data. - */ -export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] { - return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>( - 'ERC1155Assets', - encoded, - ); -} - -/** - * Decode MultiAsset asset data. - */ -export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] { - return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded); -} - -/** - * Decode StaticCall asset data. - */ -export function decodeStaticCallAssetData(encoded: string): [string, string, string] { - return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded); -} - -/** - * Decode ERC20Bridge asset data. - */ -export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] { - return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded); -} - -/** - * Encode ERC20 asset data. - */ -export function encodeERC20AssetData(tokenAddress: string): string { - return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData(); -} - -/** - * Encode ERC721 asset data. - */ -export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { - return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData(); -} - -/** - * Encode ERC1155 asset data. - */ -export function encodeERC1155AssetData( - tokenAddress: string, - tokenIds: BigNumber[], - values: BigNumber[], - callbackData: string, -): string { - return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData(); -} - -/** - * Encode MultiAsset asset data. - */ -export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string { - return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData(); -} - -/** - * Encode StaticCall asset data. - */ -export function encodeStaticCallAssetData( - staticCallTargetAddress: string, - staticCallData: string, - expectedReturnDataHash: string, -): string { - return assetDataIface - .StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash) - .getABIEncodedTransactionData(); -} - -/** - * Encode ERC20Bridge asset data. - */ -export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string { - return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData(); -} diff --git a/contracts/asset-proxy/src/dex_forwarder_bridge.ts b/contracts/asset-proxy/src/dex_forwarder_bridge.ts deleted file mode 100644 index bb155cb214..0000000000 --- a/contracts/asset-proxy/src/dex_forwarder_bridge.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { AbiEncoder, BigNumber } from '@0x/utils'; - -export interface DexForwarderBridgeCall { - target: string; - inputTokenAmount: BigNumber; - outputTokenAmount: BigNumber; - bridgeData: string; -} - -export interface DexForwaderBridgeData { - inputToken: string; - calls: DexForwarderBridgeCall[]; -} - -export const dexForwarderBridgeDataEncoder = AbiEncoder.create([ - { name: 'inputToken', type: 'address' }, - { - name: 'calls', - type: 'tuple[]', - components: [ - { name: 'target', type: 'address' }, - { name: 'inputTokenAmount', type: 'uint256' }, - { name: 'outputTokenAmount', type: 'uint256' }, - { name: 'bridgeData', type: 'bytes' }, - ], - }, -]); diff --git a/contracts/asset-proxy/src/dydx_bridge_encoder.ts b/contracts/asset-proxy/src/dydx_bridge_encoder.ts deleted file mode 100644 index 63dcade973..0000000000 --- a/contracts/asset-proxy/src/dydx_bridge_encoder.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { AbiEncoder, BigNumber } from '@0x/utils'; - -export enum DydxBridgeActionType { - Deposit, - Withdraw, -} - -export interface DydxBridgeAction { - actionType: DydxBridgeActionType; - accountIdx: BigNumber; - marketId: BigNumber; - conversionRateNumerator: BigNumber; - conversionRateDenominator: BigNumber; -} - -export interface DydxBridgeData { - accountNumbers: BigNumber[]; - actions: DydxBridgeAction[]; -} - -export const dydxBridgeDataEncoder = AbiEncoder.create([ - { - name: 'bridgeData', - type: 'tuple', - components: [ - { name: 'accountNumbers', type: 'uint256[]' }, - { - name: 'actions', - type: 'tuple[]', - components: [ - { name: 'actionType', type: 'uint8' }, - { name: 'accountIdx', type: 'uint256' }, - { name: 'marketId', type: 'uint256' }, - { name: 'conversionRateNumerator', type: 'uint256' }, - { name: 'conversionRateDenominator', type: 'uint256' }, - ], - }, - ], - }, -]); diff --git a/contracts/asset-proxy/src/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/src/erc1155_proxy_wrapper.ts deleted file mode 100644 index 7b68190dd3..0000000000 --- a/contracts/asset-proxy/src/erc1155_proxy_wrapper.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; -import { - constants, - ERC1155FungibleHoldingsByOwner, - ERC1155HoldingsByOwner, - ERC1155NonFungibleHoldingsByOwner, - LogDecoder, - txDefaults, -} from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers'; - -export class ERC1155ProxyWrapper { - private readonly _tokenOwnerAddresses: string[]; - private readonly _fungibleTokenIds: string[]; - private readonly _nonFungibleTokenIds: string[]; - private readonly _nfts: Array<{ id: BigNumber; tokenId: BigNumber }>; - private readonly _contractOwnerAddress: string; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _provider: Provider; - private readonly _logDecoder: LogDecoder; - private readonly _dummyTokenWrappers: Erc1155Wrapper[]; - private readonly _assetProxyInterface: IAssetProxyContract; - private readonly _assetDataInterface: IAssetDataContract; - private _proxyContract?: ERC1155ProxyContract; - private _proxyIdIfExists?: string; - private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; - - constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { - this._web3Wrapper = new Web3Wrapper(provider); - this._provider = provider; - const allArtifacts = _.merge(artifacts, erc1155Artifacts); - this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts); - this._dummyTokenWrappers = []; - this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); - this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); - this._tokenOwnerAddresses = tokenOwnerAddresses; - this._contractOwnerAddress = contractOwnerAddress; - this._fungibleTokenIds = []; - this._nonFungibleTokenIds = []; - this._nfts = []; - } - /** - * @dev Deploys dummy ERC1155 contracts - * @return An array of ERC1155 wrappers; one for each deployed contract. - */ - public async deployDummyContractsAsync(): Promise { - // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) { - const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( - erc1155Artifacts.ERC1155Mintable, - this._provider, - txDefaults, - artifacts, - ); - const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress); - this._dummyTokenWrappers.push(erc1155Wrapper); - } - return this._dummyTokenWrappers; - } - /** - * @dev Deploys the ERC1155 proxy - * @return Deployed ERC1155 proxy contract instance - */ - public async deployProxyAsync(): Promise { - this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC1155Proxy, - this._provider, - txDefaults, - artifacts, - ); - this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); - return this._proxyContract; - } - /** - * @dev Gets the ERC1155 proxy id - */ - public getProxyId(): string { - this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as string; - } - /** - * @dev generates abi-encoded tx data for transferring erc1155 fungible/non-fungible tokens. - * @param from source address - * @param to destination address - * @param contractAddress address of erc155 contract - * @param tokensToTransfer array of erc1155 tokens to transfer - * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer - * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this - * @param receiverCallbackData callback data if `to` is a contract - * @param authorizedSender sender of `transferFrom` transaction - * @param extraData extra data to append to `transferFrom` transaction. Optional. - * @return abi encoded tx data. - */ - public async getTransferFromAbiEncodedTxDataAsync( - from: string, - to: string, - contractAddress: string, - tokensToTransfer: BigNumber[], - valuesToTransfer: BigNumber[], - valueMultiplier: BigNumber, - receiverCallbackData: string, - authorizedSender: string, - assetData_?: string, - ): Promise { - this._validateProxyContractExistsOrThrow(); - const assetData = - assetData_ === undefined - ? this._assetDataInterface - .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData() - : assetData_; - const data = this._assetProxyInterface - .transferFrom(assetData, from, to, valueMultiplier) - .getABIEncodedTransactionData(); - return data; - } - /** - * @dev transfers erc1155 fungible/non-fungible tokens. - * @param txData: abi-encoded tx data - * @param authorizedSender sender of `transferFrom` transaction - */ - public async transferFromRawAsync( - txData: string, - authorizedSender: string, - ): Promise { - const txHash = await this._web3Wrapper.sendTransactionAsync({ - to: (this._proxyContract as ERC1155ProxyContract).address, - data: txData, - from: authorizedSender, - gas: 300000, - }); - const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return txReceipt; - } - /** - * @dev transfers erc1155 fungible/non-fungible tokens. - * @param from source address - * @param to destination address - * @param contractAddress address of erc155 contract - * @param tokensToTransfer array of erc1155 tokens to transfer - * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer - * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this - * @param receiverCallbackData callback data if `to` is a contract - * @param authorizedSender sender of `transferFrom` transaction - * @param extraData extra data to append to `transferFrom` transaction. Optional. - * @return tranasction hash. - */ - public async transferFromAsync( - from: string, - to: string, - contractAddress: string, - tokensToTransfer: BigNumber[], - valuesToTransfer: BigNumber[], - valueMultiplier: BigNumber, - receiverCallbackData: string, - authorizedSender: string, - assetData_?: string, - ): Promise { - this._validateProxyContractExistsOrThrow(); - const assetData = - assetData_ === undefined - ? this._assetDataInterface - .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData() - : assetData_; - const data = this._assetProxyInterface - .transferFrom(assetData, from, to, valueMultiplier) - .getABIEncodedTransactionData(); - const txHash = await this._web3Wrapper.sendTransactionAsync({ - to: (this._proxyContract as ERC1155ProxyContract).address, - data, - from: authorizedSender, - gas: 300000, - }); - const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return txReceipt; - } - /** - * @dev For each deployed ERC1155 contract, this function mints a set of fungible/non-fungible - * tokens for each token owner address (`_tokenOwnerAddresses`). - * @return Balances of each token owner, across all ERC1155 contracts and tokens. - */ - public async setBalancesAndAllowancesAsync(): Promise { - this._validateDummyTokenContractsExistOrThrow(); - this._validateProxyContractExistsOrThrow(); - this._initialTokenIdsByOwner = { - fungible: {}, - nonFungible: {}, - }; - const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; - const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; - // Set balances accordingly - for (const dummyWrapper of this._dummyTokenWrappers) { - const dummyAddress = dummyWrapper.getContract().address; - // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) { - // Create a fungible token - const tokenId = await dummyWrapper.mintFungibleTokensAsync( - this._tokenOwnerAddresses, - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - ); - const tokenIdAsString = tokenId.toString(); - this._fungibleTokenIds.push(tokenIdAsString); - // Mint tokens for each owner for this token - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - // tslint:disable-next-line:no-unused-variable - if (fungibleHoldingsByOwner[tokenOwnerAddress] === undefined) { - fungibleHoldingsByOwner[tokenOwnerAddress] = {}; - } - if (fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) { - fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; - } - fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - await dummyWrapper.setApprovalForAllAsync( - tokenOwnerAddress, - (this._proxyContract as ERC1155ProxyContract).address, - true, - ); - } - } - // Non-fungible tokens - // tslint:disable-next-line:no-unused-variable - for (const j of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { - const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses); - const tokenIdAsString = tokenId.toString(); - this._nonFungibleTokenIds.push(tokenIdAsString); - _.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => { - if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) { - nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; - } - if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; - } - if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] === undefined) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = []; - } - this._nfts.push({ id: nftIds[i], tokenId }); - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]); - await dummyWrapper.setApprovalForAllAsync( - tokenOwnerAddress, - (this._proxyContract as ERC1155ProxyContract).address, - true, - ); - }); - } - } - this._initialTokenIdsByOwner = { - fungible: fungibleHoldingsByOwner, - nonFungible: nonFungibleHoldingsByOwner, - }; - return this._initialTokenIdsByOwner; - } - /** - * @dev For each deployed ERC1155 contract, this function quieries the set of fungible/non-fungible - * tokens for each token owner address (`_tokenOwnerAddresses`). - * @return Balances of each token owner, across all ERC1155 contracts and tokens. - */ - public async getBalancesAsync(): Promise { - this._validateDummyTokenContractsExistOrThrow(); - this._validateBalancesAndAllowancesSetOrThrow(); - const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; - const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; - for (const dummyTokenWrapper of this._dummyTokenWrappers) { - const tokenContract = dummyTokenWrapper.getContract(); - const tokenAddress = tokenContract.address; - // Construct batch balance call - const tokenOwners: string[] = []; - const tokenIds: BigNumber[] = []; - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - for (const tokenId of this._fungibleTokenIds) { - tokenOwners.push(tokenOwnerAddress); - tokenIds.push(new BigNumber(tokenId)); - } - for (const nft of this._nfts) { - tokenOwners.push(tokenOwnerAddress); - tokenIds.push(nft.id); - } - } - const balances = await dummyTokenWrapper.getBalancesAsync(tokenOwners, tokenIds); - // Parse out balances into fungible / non-fungible token holdings - let i = 0; - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - // Fungible tokens - for (const tokenId of this._fungibleTokenIds) { - if (tokenHoldingsByOwner[tokenOwnerAddress] === undefined) { - tokenHoldingsByOwner[tokenOwnerAddress] = {}; - } - if (tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) { - tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; - } - tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++]; - } - // Non-fungible tokens - for (const nft of this._nfts) { - if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) { - nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; - } - if (nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; - } - if ( - nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] === - undefined - ) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = []; - } - const isOwner = balances[i++]; - if (isOwner.isEqualTo(1)) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push( - nft.id, - ); - } - } - } - } - const holdingsByOwner = { - fungible: tokenHoldingsByOwner, - nonFungible: nonFungibleHoldingsByOwner, - }; - return holdingsByOwner; - } - /** - * @dev Set the approval for the proxy on behalf of `userAddress` . - * @param userAddress owner of ERC1155 tokens. - * @param contractAddress address of ERC1155 contract. - * @param isApproved Whether to approve the proxy for all or not. - */ - public async setProxyAllowanceForAllAsync( - userAddress: string, - contractAddress: string, - isApproved: boolean, - ): Promise { - this._validateProxyContractExistsOrThrow(); - const tokenWrapper = this.getContractWrapper(contractAddress); - const operator = (this._proxyContract as ERC1155ProxyContract).address; - await tokenWrapper.setApprovalForAllAsync(userAddress, operator, isApproved); - } - /** - * @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`. - * @param userAddress owner of ERC1155 tokens. - * @param contractAddress address of ERC1155 contract. - * @return True iff the proxy is approved for all. False otherwise. - */ - public async isProxyApprovedForAllAsync(userAddress: string, contractAddress: string): Promise { - this._validateProxyContractExistsOrThrow(); - const tokenContract = this._getContractFromAddress(contractAddress); - const operator = (this._proxyContract as ERC1155ProxyContract).address; - const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); - return didApproveAll; - } - public getFungibleTokenIds(): BigNumber[] { - const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => { - return new BigNumber(tokenIdAsString); - }); - return fungibleTokenIds; - } - public getNonFungibleTokenIds(): BigNumber[] { - const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => { - return new BigNumber(tokenIdAsString); - }); - return nonFungibleTokenIds; - } - public getTokenOwnerAddresses(): string[] { - return this._tokenOwnerAddresses; - } - public getContractWrapper(contractAddress: string): Erc1155Wrapper { - const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => { - return wrapper.getContract().address === contractAddress; - }); - if (tokenWrapper === undefined) { - throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`); - } - return tokenWrapper; - } - private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract { - const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress); - if (tokenContractIfExists === undefined) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`); - } - return tokenContractIfExists.getContract(); - } - private _validateDummyTokenContractsExistOrThrow(): void { - if (this._dummyTokenWrappers === undefined) { - throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"'); - } - } - private _validateProxyContractExistsOrThrow(): void { - if (this._proxyContract === undefined) { - throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"'); - } - } - private _validateBalancesAndAllowancesSetOrThrow(): void { - if ( - _.keys(this._initialTokenIdsByOwner.fungible).length === 0 || - _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0 - ) { - throw new Error( - 'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', - ); - } - } -} diff --git a/contracts/asset-proxy/src/erc20_wrapper.ts b/contracts/asset-proxy/src/erc20_wrapper.ts deleted file mode 100644 index a473cb0b37..0000000000 --- a/contracts/asset-proxy/src/erc20_wrapper.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { ZeroExProvider } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { ERC20ProxyContract, IAssetDataContract } from './wrappers'; - -export class ERC20Wrapper { - private readonly _tokenOwnerAddresses: string[]; - private readonly _contractOwnerAddress: string; - private readonly _provider: ZeroExProvider; - private readonly _dummyTokenContracts: DummyERC20TokenContract[]; - private readonly _assetDataInterface: IAssetDataContract; - 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: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { - this._dummyTokenContracts = []; - this._provider = provider; - this._tokenOwnerAddresses = tokenOwnerAddresses; - this._contractOwnerAddress = contractOwnerAddress; - this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); - } - public async deployDummyTokensAsync( - numberToDeploy: number, - decimals: BigNumber, - ): Promise { - for (let i = 0; i < numberToDeploy; i++) { - this._dummyTokenContracts.push( - await DummyERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyERC20Token, - this._provider, - txDefaults, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - decimals, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ), - ); - } - return this._dummyTokenContracts; - } - public async deployProxyAsync(): Promise { - this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC20Proxy, - this._provider, - txDefaults, - artifacts, - ); - this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); - return this._proxyContract; - } - public getProxyId(): string { - this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as string; - } - public async setBalancesAndAllowancesAsync(): Promise { - this._validateDummyTokenContractsExistOrThrow(); - this._validateProxyContractExistsOrThrow(); - for (const dummyTokenContract of this._dummyTokenContracts) { - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - await dummyTokenContract - .setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE) - .awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); - await dummyTokenContract - .approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE) - .awaitTransactionSuccessAsync({ from: tokenOwnerAddress }); - } - } - } - public async getBalanceAsync(userAddress: string, assetData: string): Promise { - const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); - const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync()); - return balance; - } - public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise { - const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); - await tokenContract - .setBalance(userAddress, amount) - .awaitTransactionSuccessAsync( - { from: this._contractOwnerAddress }, - { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS }, - ); - } - public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { - const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); - const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; - const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync()); - return allowance; - } - public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise { - const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData); - const proxyAddress = (this._proxyContract as ERC20ProxyContract).address; - await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress }); - } - public async getBalancesAsync(): Promise { - 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(tokenOwnerAddress).callAsync()); - balanceInfo.push({ - tokenOwnerAddress, - tokenAddress: dummyTokenContract.address, - }); - } - } - _.forEach(balances, (balance, balanceIndex) => { - const tokenAddress = balanceInfo[balanceIndex].tokenAddress; - const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress; - if (balancesByOwner[tokenOwnerAddress] === undefined) { - balancesByOwner[tokenOwnerAddress] = {}; - } - const wrappedBalance = new BigNumber(balance); - balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance; - }); - return balancesByOwner; - } - public addDummyTokenContract(dummy: DummyERC20TokenContract): void { - if (this._dummyTokenContracts !== undefined) { - 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 async _getTokenContractFromAssetDataAsync(assetData: string): Promise { - const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData('ERC20Token', assetData); // tslint:disable-line:no-unused-variable - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); - if (tokenContractIfExists === undefined) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); - } - return tokenContractIfExists; - } - private _validateDummyTokenContractsExistOrThrow(): void { - if (this._dummyTokenContracts === undefined) { - throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"'); - } - } - private _validateProxyContractExistsOrThrow(): void { - if (this._proxyContract === undefined) { - throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"'); - } - } -} diff --git a/contracts/asset-proxy/src/erc721_wrapper.ts b/contracts/asset-proxy/src/erc721_wrapper.ts deleted file mode 100644 index da6fa4aa22..0000000000 --- a/contracts/asset-proxy/src/erc721_wrapper.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils'; -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; -import { ZeroExProvider } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { ERC721ProxyContract } from './wrappers'; - -export class ERC721Wrapper { - private readonly _tokenOwnerAddresses: string[]; - private readonly _contractOwnerAddress: string; - private readonly _provider: ZeroExProvider; - private readonly _dummyTokenContracts: DummyERC721TokenContract[]; - private _proxyContract?: ERC721ProxyContract; - private _proxyIdIfExists?: string; - private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; - constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { - this._provider = provider; - this._dummyTokenContracts = []; - this._tokenOwnerAddresses = tokenOwnerAddresses; - this._contractOwnerAddress = contractOwnerAddress; - } - public async deployDummyTokensAsync(): Promise { - // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) { - this._dummyTokenContracts.push( - await DummyERC721TokenContract.deployFrom0xArtifactAsync( - erc721Artifacts.DummyERC721Token, - this._provider, - txDefaults, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ), - ); - } - return this._dummyTokenContracts; - } - public async deployProxyAsync(): Promise { - this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC721Proxy, - this._provider, - txDefaults, - artifacts, - ); - this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync(); - return this._proxyContract; - } - public getProxyId(): string { - this._validateProxyContractExistsOrThrow(); - return this._proxyIdIfExists as string; - } - public async setBalancesAndAllowancesAsync(): Promise { - this._validateDummyTokenContractsExistOrThrow(); - this._validateProxyContractExistsOrThrow(); - this._initialTokenIdsByOwner = {}; - for (const dummyTokenContract of this._dummyTokenContracts) { - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { - // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) { - const tokenId = generatePseudoRandomSalt(); - await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); - if (this._initialTokenIdsByOwner[tokenOwnerAddress] === undefined) { - this._initialTokenIdsByOwner[tokenOwnerAddress] = { - [dummyTokenContract.address]: [], - }; - } - if (this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] === undefined) { - this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = []; - } - this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); - - await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true); - } - } - } - } - public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const owner = await tokenContract.ownerOf(tokenId).callAsync(); - const doesExist = owner !== constants.NULL_ADDRESS; - return doesExist; - } - public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise { - const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; - await this.approveAsync(proxyAddress, tokenAddress, tokenId); - } - public async approveProxyForAllAsync( - tokenAddress: string, - ownerAddress: string, - isApproved: boolean, - ): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; - await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - } - public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId); - await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner }); - } - public async transferFromAsync( - tokenAddress: string, - tokenId: BigNumber, - currentOwner: string, - userAddress: string, - ): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({ - from: currentOwner, - }); - } - public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({ - from: this._contractOwnerAddress, - }); - } - public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress }); - } - public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const owner = await tokenContract.ownerOf(tokenId).callAsync(); - return owner; - } - public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync(); - const isOwner = tokenOwner === userAddress; - return isOwner; - } - public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise { - this._validateProxyContractExistsOrThrow(); - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const operator = (this._proxyContract as ERC721ProxyContract).address; - const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync(); - return didApproveAll; - } - public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise { - this._validateProxyContractExistsOrThrow(); - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const approvedAddress = await tokenContract.getApproved(tokenId).callAsync(); - const proxyAddress = (this._proxyContract as ERC721ProxyContract).address; - const isProxyAnApprovedOperator = approvedAddress === proxyAddress; - return isProxyAnApprovedOperator; - } - public async getBalancesAsync(): Promise { - 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(tokenId).callAsync()); - tokenInfo.push({ - tokenId, - tokenAddress: dummyTokenContract.address, - }); - } - } - } - _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => { - const tokenAddress = tokenInfo[ownerIndex].tokenAddress; - const tokenId = tokenInfo[ownerIndex].tokenId; - if (tokenIdsByOwner[tokenOwnerAddress] === undefined) { - tokenIdsByOwner[tokenOwnerAddress] = { - [tokenAddress]: [], - }; - } - if (tokenIdsByOwner[tokenOwnerAddress][tokenAddress] === undefined) { - 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 (tokenContractIfExists === undefined) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`); - } - return tokenContractIfExists; - } - private _validateDummyTokenContractsExistOrThrow(): void { - if (this._dummyTokenContracts === undefined) { - throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"'); - } - } - private _validateProxyContractExistsOrThrow(): void { - if (this._proxyContract === undefined) { - 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/contracts/asset-proxy/src/index.ts b/contracts/asset-proxy/src/index.ts deleted file mode 100644 index 7e31c510b3..0000000000 --- a/contracts/asset-proxy/src/index.ts +++ /dev/null @@ -1,93 +0,0 @@ -export { artifacts } from './artifacts'; -export { - BalancerBridgeContract, - ChaiBridgeContract, - ERC1155ProxyContract, - ERC20BridgeProxyContract, - ERC20ProxyContract, - ERC721ProxyContract, - Eth2DaiBridgeContract, - DydxBridgeContract, - IAssetDataContract, - IAssetProxyContract, - IChaiContract, - IDydxContract, - KyberBridgeContract, - MultiAssetProxyContract, - StaticCallProxyContract, - TestDydxBridgeContract, - TestStaticCallTargetContract, - UniswapBridgeContract, - DexForwarderBridgeContract, -} from './wrappers'; - -export { ERC20Wrapper } from './erc20_wrapper'; -export { ERC721Wrapper } from './erc721_wrapper'; -export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper'; -export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; -export { DummyERC20TokenContract } from '@0x/contracts-erc20'; -export { DummyERC721TokenContract } from '@0x/contracts-erc721'; -export { AssetProxyId } from '@0x/types'; -export { - ERC1155HoldingsByOwner, - ERC20BalancesByOwner, - ERC721TokenIdsByOwner, - ERC1155FungibleHoldingsByOwner, - ERC1155NonFungibleHoldingsByOwner, -} from '@0x/contracts-test-utils'; -export { - TransactionReceiptWithDecodedLogs, - Provider, - ZeroExProvider, - JSONRPCRequestPayload, - JSONRPCErrorCallback, - TransactionReceiptStatus, - JSONRPCResponsePayload, - JSONRPCResponseError, - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; - -export { - decodeERC1155AssetData, - decodeERC20AssetData, - decodeERC20BridgeAssetData, - decodeERC721AssetData, - decodeMultiAssetData, - decodeStaticCallAssetData, - encodeERC1155AssetData, - encodeERC20AssetData, - encodeERC20BridgeAssetData, - encodeERC721AssetData, - encodeMultiAssetData, - encodeStaticCallAssetData, - getAssetDataProxyId, -} from './asset_data'; - -export * from './dydx_bridge_encoder'; -export * from './dex_forwarder_bridge'; diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts deleted file mode 100644 index e51d91096e..0000000000 --- a/contracts/asset-proxy/src/wrappers.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/balancer_bridge'; -export * from '../generated-wrappers/bancor_bridge'; -export * from '../generated-wrappers/chai_bridge'; -export * from '../generated-wrappers/cream_bridge'; -export * from '../generated-wrappers/crypto_com_bridge'; -export * from '../generated-wrappers/curve_bridge'; -export * from '../generated-wrappers/d_o_d_o_bridge'; -export * from '../generated-wrappers/dex_forwarder_bridge'; -export * from '../generated-wrappers/dydx_bridge'; -export * from '../generated-wrappers/erc1155_proxy'; -export * from '../generated-wrappers/erc20_bridge_proxy'; -export * from '../generated-wrappers/erc20_proxy'; -export * from '../generated-wrappers/erc721_proxy'; -export * from '../generated-wrappers/eth2_dai_bridge'; -export * from '../generated-wrappers/i_asset_data'; -export * from '../generated-wrappers/i_asset_proxy'; -export * from '../generated-wrappers/i_asset_proxy_dispatcher'; -export * from '../generated-wrappers/i_authorizable'; -export * from '../generated-wrappers/i_balancer_pool'; -export * from '../generated-wrappers/i_bancor_network'; -export * from '../generated-wrappers/i_chai'; -export * from '../generated-wrappers/i_curve'; -export * from '../generated-wrappers/i_dydx'; -export * from '../generated-wrappers/i_dydx_bridge'; -export * from '../generated-wrappers/i_erc20_bridge'; -export * from '../generated-wrappers/i_eth2_dai'; -export * from '../generated-wrappers/i_gas_token'; -export * from '../generated-wrappers/i_kyber_network_proxy'; -export * from '../generated-wrappers/i_m_stable'; -export * from '../generated-wrappers/i_mooniswap'; -export * from '../generated-wrappers/i_shell'; -export * from '../generated-wrappers/i_uniswap_exchange'; -export * from '../generated-wrappers/i_uniswap_exchange_factory'; -export * from '../generated-wrappers/i_uniswap_v2_router01'; -export * from '../generated-wrappers/kyber_bridge'; -export * from '../generated-wrappers/m_stable_bridge'; -export * from '../generated-wrappers/mixin_asset_proxy_dispatcher'; -export * from '../generated-wrappers/mixin_authorizable'; -export * from '../generated-wrappers/mixin_gas_token'; -export * from '../generated-wrappers/mooniswap_bridge'; -export * from '../generated-wrappers/multi_asset_proxy'; -export * from '../generated-wrappers/ownable'; -export * from '../generated-wrappers/shell_bridge'; -export * from '../generated-wrappers/snow_swap_bridge'; -export * from '../generated-wrappers/static_call_proxy'; -export * from '../generated-wrappers/sushi_swap_bridge'; -export * from '../generated-wrappers/swerve_bridge'; -export * from '../generated-wrappers/test_bancor_bridge'; -export * from '../generated-wrappers/test_chai_bridge'; -export * from '../generated-wrappers/test_dex_forwarder_bridge'; -export * from '../generated-wrappers/test_dydx_bridge'; -export * from '../generated-wrappers/test_erc20_bridge'; -export * from '../generated-wrappers/test_eth2_dai_bridge'; -export * from '../generated-wrappers/test_kyber_bridge'; -export * from '../generated-wrappers/test_static_call_target'; -export * from '../generated-wrappers/test_uniswap_bridge'; -export * from '../generated-wrappers/test_uniswap_v2_bridge'; -export * from '../generated-wrappers/uniswap_bridge'; -export * from '../generated-wrappers/uniswap_v2_bridge'; diff --git a/contracts/asset-proxy/test/artifacts.ts b/contracts/asset-proxy/test/artifacts.ts deleted file mode 100644 index 2ccc9699e8..0000000000 --- a/contracts/asset-proxy/test/artifacts.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json'; -import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json'; -import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json'; -import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json'; -import * as CryptoComBridge from '../test/generated-artifacts/CryptoComBridge.json'; -import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json'; -import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json'; -import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json'; -import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json'; -import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json'; -import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json'; -import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json'; -import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json'; -import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json'; -import * as IAssetData from '../test/generated-artifacts/IAssetData.json'; -import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; -import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; -import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; -import * as IBalancerPool from '../test/generated-artifacts/IBalancerPool.json'; -import * as IBancorNetwork from '../test/generated-artifacts/IBancorNetwork.json'; -import * as IChai from '../test/generated-artifacts/IChai.json'; -import * as ICurve from '../test/generated-artifacts/ICurve.json'; -import * as IDydx from '../test/generated-artifacts/IDydx.json'; -import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json'; -import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; -import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; -import * as IGasToken from '../test/generated-artifacts/IGasToken.json'; -import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json'; -import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json'; -import * as IMStable from '../test/generated-artifacts/IMStable.json'; -import * as IShell from '../test/generated-artifacts/IShell.json'; -import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json'; -import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json'; -import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json'; -import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json'; -import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json'; -import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json'; -import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json'; -import * as MooniswapBridge from '../test/generated-artifacts/MooniswapBridge.json'; -import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json'; -import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; -import * as Ownable from '../test/generated-artifacts/Ownable.json'; -import * as ShellBridge from '../test/generated-artifacts/ShellBridge.json'; -import * as SnowSwapBridge from '../test/generated-artifacts/SnowSwapBridge.json'; -import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; -import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json'; -import * as SwerveBridge from '../test/generated-artifacts/SwerveBridge.json'; -import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json'; -import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; -import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json'; -import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json'; -import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json'; -import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json'; -import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json'; -import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json'; -import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json'; -import * as TestUniswapV2Bridge from '../test/generated-artifacts/TestUniswapV2Bridge.json'; -import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json'; -import * as UniswapV2Bridge from '../test/generated-artifacts/UniswapV2Bridge.json'; -export const artifacts = { - MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, - MixinAuthorizable: MixinAuthorizable as ContractArtifact, - Ownable: Ownable as ContractArtifact, - ERC1155Proxy: ERC1155Proxy as ContractArtifact, - ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact, - ERC20Proxy: ERC20Proxy as ContractArtifact, - ERC721Proxy: ERC721Proxy as ContractArtifact, - MultiAssetProxy: MultiAssetProxy as ContractArtifact, - StaticCallProxy: StaticCallProxy as ContractArtifact, - BalancerBridge: BalancerBridge as ContractArtifact, - BancorBridge: BancorBridge as ContractArtifact, - ChaiBridge: ChaiBridge as ContractArtifact, - CreamBridge: CreamBridge as ContractArtifact, - CryptoComBridge: CryptoComBridge as ContractArtifact, - CurveBridge: CurveBridge as ContractArtifact, - DODOBridge: DODOBridge as ContractArtifact, - DexForwarderBridge: DexForwarderBridge as ContractArtifact, - DydxBridge: DydxBridge as ContractArtifact, - Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, - KyberBridge: KyberBridge as ContractArtifact, - MStableBridge: MStableBridge as ContractArtifact, - MixinGasToken: MixinGasToken as ContractArtifact, - MooniswapBridge: MooniswapBridge as ContractArtifact, - ShellBridge: ShellBridge as ContractArtifact, - SnowSwapBridge: SnowSwapBridge as ContractArtifact, - SushiSwapBridge: SushiSwapBridge as ContractArtifact, - SwerveBridge: SwerveBridge as ContractArtifact, - UniswapBridge: UniswapBridge as ContractArtifact, - UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, - IAssetData: IAssetData as ContractArtifact, - IAssetProxy: IAssetProxy as ContractArtifact, - IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, - IAuthorizable: IAuthorizable as ContractArtifact, - IBalancerPool: IBalancerPool as ContractArtifact, - IBancorNetwork: IBancorNetwork as ContractArtifact, - IChai: IChai as ContractArtifact, - ICurve: ICurve as ContractArtifact, - IDydx: IDydx as ContractArtifact, - IDydxBridge: IDydxBridge as ContractArtifact, - IERC20Bridge: IERC20Bridge as ContractArtifact, - IEth2Dai: IEth2Dai as ContractArtifact, - IGasToken: IGasToken as ContractArtifact, - IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, - IMStable: IMStable as ContractArtifact, - IMooniswap: IMooniswap as ContractArtifact, - IShell: IShell as ContractArtifact, - IUniswapExchange: IUniswapExchange as ContractArtifact, - IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, - IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, - TestBancorBridge: TestBancorBridge as ContractArtifact, - TestChaiBridge: TestChaiBridge as ContractArtifact, - TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact, - TestDydxBridge: TestDydxBridge as ContractArtifact, - TestERC20Bridge: TestERC20Bridge as ContractArtifact, - TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, - TestKyberBridge: TestKyberBridge as ContractArtifact, - TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, - TestUniswapBridge: TestUniswapBridge as ContractArtifact, - TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact, -}; diff --git a/contracts/asset-proxy/test/authorizable.ts b/contracts/asset-proxy/test/authorizable.ts deleted file mode 100644 index d531bdd59c..0000000000 --- a/contracts/asset-proxy/test/authorizable.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { artifacts } from './artifacts'; - -import { MixinAuthorizableContract } from './wrappers'; - -blockchainTests.resets('Authorizable', () => { - let owner: string; - let notOwner: string; - let address: string; - let authorizable: MixinAuthorizableContract; - - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - [owner, address, notOwner] = accounts.slice(0, 3); - authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync( - artifacts.MixinAuthorizable, - provider, - txDefaults, - artifacts, - ); - }); - - describe('addAuthorizedAddress', () => { - it('should revert if not called by owner', async () => { - const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }); - return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); - }); - - it('should allow owner to add an authorized address', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const isAuthorized = await authorizable.authorized(address).callAsync(); - expect(isAuthorized).to.be.true(); - }); - - it('should revert if owner attempts to authorize a duplicate address', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized); - }); - }); - - describe('removeAuthorizedAddress', () => { - it('should revert if not called by owner', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }); - return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); - }); - - it('should allow owner to remove an authorized address', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const isAuthorized = await authorizable.authorized(address).callAsync(); - expect(isAuthorized).to.be.false(); - }); - - it('should revert if owner attempts to remove an address that is not authorized', async () => { - const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); - }); - }); - - describe('removeAuthorizedAddressAtIndex', () => { - it('should revert if not called by owner', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const index = new BigNumber(0); - const tx = authorizable - .removeAuthorizedAddressAtIndex(address, index) - .sendTransactionAsync({ from: notOwner }); - return expect(tx).to.revertWith(RevertReason.OnlyContractOwner); - }); - - it('should revert if index is >= authorities.length', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const index = new BigNumber(1); - const tx = authorizable - .removeAuthorizedAddressAtIndex(address, index) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds); - }); - - it('should revert if owner attempts to remove an address that is not authorized', async () => { - const index = new BigNumber(0); - const tx = authorizable - .removeAuthorizedAddressAtIndex(address, index) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized); - }); - - it('should revert if address at index does not match target', async () => { - const address1 = address; - const address2 = notOwner; - await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner }); - await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner }); - const address1Index = new BigNumber(0); - const tx = authorizable - .removeAuthorizedAddressAtIndex(address2, address1Index) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch); - }); - - it('should allow owner to remove an authorized address', async () => { - await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const index = new BigNumber(0); - await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({ - from: owner, - }); - const isAuthorized = await authorizable.authorized(address).callAsync(); - 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 authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const afterAdd = await authorizable.getAuthorizedAddresses().callAsync(); - expect(afterAdd).to.have.length(1); - expect(afterAdd).to.include(address); - await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner }); - const afterRemove = await authorizable.getAuthorizedAddresses().callAsync(); - expect(afterRemove).to.have.length(0); - }); - }); -}); diff --git a/contracts/asset-proxy/test/bancor_bridge.ts b/contracts/asset-proxy/test/bancor_bridge.ts deleted file mode 100644 index da1549c0f3..0000000000 --- a/contracts/asset-proxy/test/bancor_bridge.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { - blockchainTests, - constants, - expect, - filterLogsToArguments, - getRandomInteger, - randomAddress, -} from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils'; -import { DecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { TestBancorBridgeContract } from './generated-wrappers/test_bancor_bridge'; -import { - TestBancorBridgeConvertByPathInputEventArgs as ConvertByPathArgs, - TestBancorBridgeEvents as ContractEvents, - TestBancorBridgeTokenApproveEventArgs as TokenApproveArgs, -} from './wrappers'; - -blockchainTests.resets('Bancor unit tests', env => { - const FROM_TOKEN_DECIMALS = 6; - const TO_TOKEN_DECIMALS = 18; - const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); - const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); - let testContract: TestBancorBridgeContract; - - before(async () => { - testContract = await TestBancorBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestBancorBridge, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('isValidSignature()', () => { - it('returns success bytes', async () => { - const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; - const result = await testContract - .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) - .callAsync(); - expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); - }); - }); - - describe('bridgeTransferFrom()', () => { - interface TransferFromOpts { - tokenAddressesPath: string[]; - toAddress: string; - // Amount to pass into `bridgeTransferFrom()` - amount: BigNumber; - // Token balance of the bridge. - fromTokenBalance: BigNumber; - // Router reverts with this reason - routerRevertReason: string; - } - - interface TransferFromResult { - opts: TransferFromOpts; - result: string; - logs: DecodedLogs; - blocktime: number; - } - - function createTransferFromOpts(opts?: Partial): TransferFromOpts { - const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); - return { - tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS), - amount, - toAddress: randomAddress(), - fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), - routerRevertReason: '', - ...opts, - }; - } - - const bridgeDataEncoder = AbiEncoder.create('(address[], address)'); - - async function transferFromAsync(opts?: Partial): Promise { - const _opts = createTransferFromOpts(opts); - - for (let i = 0; i < _opts.tokenAddressesPath.length; i++) { - const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]); - _opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync(); - await createFromTokenFn.awaitTransactionSuccessAsync(); - } - - // Set the token balance for the token we're converting from. - await testContract - .setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance) - .awaitTransactionSuccessAsync(); - - // Set revert reason for the router. - await testContract.setNetworkRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync(); - - // Call bridgeTransferFrom(). - const bridgeTransferFromFn = testContract.bridgeTransferFrom( - // Output token - _opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1], - // Random maker address. - randomAddress(), - // Recipient address. - _opts.toAddress, - // Transfer amount. - _opts.amount, - // ABI-encode the input token address as the bridge data. - bridgeDataEncoder.encode([ - _opts.tokenAddressesPath, - await testContract.getNetworkAddress().callAsync(), - ]), - ); - const result = await bridgeTransferFromFn.callAsync(); - const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); - return { - opts: _opts, - result, - logs: (receipt.logs as any) as DecodedLogs, - blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), - }; - } - - it('returns magic bytes on success', async () => { - const { result } = await transferFromAsync(); - expect(result).to.eq(AssetProxyId.ERC20Bridge); - }); - - describe('token -> token', async () => { - it('calls BancorNetwork.convertByPath()', async () => { - const { opts, result, logs } = await transferFromAsync(); - expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); - const transfers = filterLogsToArguments(logs, ContractEvents.ConvertByPathInput); - - expect(transfers.length).to.eq(1); - expect(transfers[0].toTokenAddress).to.eq( - opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], - 'output token address', - ); - expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); - expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); - expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); - expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS); - expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0)); - }); - - it('sets allowance for "from" token', async () => { - const { logs } = await transferFromAsync(); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const networkAddress = await testContract.getNetworkAddress().callAsync(); - expect(approvals.length).to.eq(1); - expect(approvals[0].spender).to.eq(networkAddress); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('fails if the router fails', async () => { - const revertReason = 'FOOBAR'; - const tx = transferFromAsync({ - routerRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - }); - describe('token -> token -> token', async () => { - it('calls BancorNetwork.convertByPath()', async () => { - const { opts, result, logs } = await transferFromAsync({ - tokenAddressesPath: Array(5).fill(constants.NULL_ADDRESS), - }); - expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); - const transfers = filterLogsToArguments(logs, ContractEvents.ConvertByPathInput); - - expect(transfers.length).to.eq(1); - expect(transfers[0].toTokenAddress).to.eq( - opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], - 'output token address', - ); - expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); - expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); - expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); - expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS); - expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0)); - }); - }); - }); -}); diff --git a/contracts/asset-proxy/test/chai_bridge.ts b/contracts/asset-proxy/test/chai_bridge.ts deleted file mode 100644 index 9bed1f9864..0000000000 --- a/contracts/asset-proxy/test/chai_bridge.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; -import { AssetProxyId, RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { artifacts } from './artifacts'; -import { TestChaiBridgeContract } from './wrappers'; - -blockchainTests.resets('ChaiBridge unit tests', env => { - let chaiBridgeContract: TestChaiBridgeContract; - let testDaiContract: ERC20TokenContract; - let fromAddress: string; - let toAddress: string; - - const alwaysRevertAddress = '0x0000000000000000000000000000000000000001'; - const amount = new BigNumber(1); - - before(async () => { - [fromAddress, toAddress] = await env.getAccountAddressesAsync(); - chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestChaiBridge, - env.provider, - env.txDefaults, - artifacts, - ); - const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync(); - testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults); - }); - - describe('bridgeTransferFrom()', () => { - it('fails if not called by ERC20BridgeProxy', async () => { - return expect( - chaiBridgeContract - .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) - .awaitTransactionSuccessAsync({ from: alwaysRevertAddress }), - ).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy); - }); - it('returns magic bytes upon success', async () => { - const magicBytes = await chaiBridgeContract - .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) - .callAsync(); - expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge); - }); - it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => { - const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync(); - await chaiBridgeContract - .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const endBalance = await testDaiContract.balanceOf(toAddress).callAsync(); - expect(endBalance).to.bignumber.eq(initialBalance.plus(amount)); - }); - it('fails if the `chai.draw` call fails', async () => { - return expect( - chaiBridgeContract - .bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(), - ).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed); - }); - }); -}); diff --git a/contracts/asset-proxy/test/dydx_bridge.ts b/contracts/asset-proxy/test/dydx_bridge.ts deleted file mode 100644 index 3377ddfce4..0000000000 --- a/contracts/asset-proxy/test/dydx_bridge.ts +++ /dev/null @@ -1,399 +0,0 @@ -import { LibMathRevertErrors } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; -import { AssetProxyId, RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { DydxBridgeActionType, DydxBridgeData, dydxBridgeDataEncoder } from '../src/dydx_bridge_encoder'; -import { ERC20BridgeProxyContract, IAssetDataContract } from '../src/wrappers'; - -import { artifacts } from './artifacts'; -import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers'; - -blockchainTests.resets('DydxBridge unit tests', env => { - const defaultAccountNumber = new BigNumber(1); - const marketId = new BigNumber(2); - const defaultAmount = new BigNumber(4); - const notAuthorized = '0x0000000000000000000000000000000000000001'; - const defaultDepositAction = { - actionType: DydxBridgeActionType.Deposit, - accountIdx: constants.ZERO_AMOUNT, - marketId, - conversionRateNumerator: constants.ZERO_AMOUNT, - conversionRateDenominator: constants.ZERO_AMOUNT, - }; - const defaultWithdrawAction = { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: constants.ZERO_AMOUNT, - marketId, - conversionRateNumerator: constants.ZERO_AMOUNT, - conversionRateDenominator: constants.ZERO_AMOUNT, - }; - let testContract: TestDydxBridgeContract; - let testProxyContract: ERC20BridgeProxyContract; - let assetDataEncoder: IAssetDataContract; - let owner: string; - let authorized: string; - let accountOwner: string; - let receiver: string; - - before(async () => { - // Get accounts - const accounts = await env.web3Wrapper.getAvailableAddressesAsync(); - [owner, authorized, accountOwner, receiver] = accounts; - - // Deploy dydx bridge - testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestDydxBridge, - env.provider, - env.txDefaults, - artifacts, - [accountOwner, receiver], - ); - - // Deploy test erc20 bridge proxy - testProxyContract = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC20BridgeProxy, - env.provider, - env.txDefaults, - artifacts, - ); - await testProxyContract.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - - // Setup asset data encoder - assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider); - }); - - describe('bridgeTransferFrom()', () => { - const callBridgeTransferFrom = async ( - from: string, - to: string, - amount: BigNumber, - bridgeData: DydxBridgeData, - sender: string, - ): Promise => { - const returnValue = await testContract - .bridgeTransferFrom( - constants.NULL_ADDRESS, - from, - to, - amount, - dydxBridgeDataEncoder.encode({ bridgeData }), - ) - .callAsync({ from: sender }); - return returnValue; - }; - const executeBridgeTransferFromAndVerifyEvents = async ( - from: string, - to: string, - amount: BigNumber, - bridgeData: DydxBridgeData, - sender: string, - ): Promise => { - // Execute transaction. - const txReceipt = await testContract - .bridgeTransferFrom( - constants.NULL_ADDRESS, - from, - to, - amount, - dydxBridgeDataEncoder.encode({ bridgeData }), - ) - .awaitTransactionSuccessAsync({ from: sender }); - - // Verify `OperateAccount` event. - const expectedOperateAccountEvents = []; - for (const accountNumber of bridgeData.accountNumbers) { - expectedOperateAccountEvents.push({ - owner: accountOwner, - number: accountNumber, - }); - } - verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount); - - // Verify `OperateAction` event. - const weiDenomination = 0; - const deltaAmountRef = 0; - const expectedOperateActionEvents = []; - for (const action of bridgeData.actions) { - expectedOperateActionEvents.push({ - actionType: action.actionType as number, - accountIdx: action.accountIdx, - amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false, - amountDenomination: weiDenomination, - amountRef: deltaAmountRef, - amountValue: action.conversionRateDenominator.gt(0) - ? amount - .times(action.conversionRateNumerator) - .dividedToIntegerBy(action.conversionRateDenominator) - : amount, - primaryMarketId: marketId, - secondaryMarketId: constants.ZERO_AMOUNT, - otherAddress: action.actionType === DydxBridgeActionType.Deposit ? from : to, - otherAccountId: constants.ZERO_AMOUNT, - data: '0x', - }); - } - verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction); - }; - it('succeeds when calling with zero amount', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultDepositAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - constants.ZERO_AMOUNT, - bridgeData, - authorized, - ); - }); - it('succeeds when calling with no accounts', async () => { - const bridgeData = { - accountNumbers: [], - actions: [defaultDepositAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling with no actions', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling `operate` with the `deposit` action and a single account', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultDepositAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], - actions: [defaultDepositAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultWithdrawAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], - actions: [defaultWithdrawAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], - actions: [defaultWithdrawAction, defaultDepositAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when calling `operate` with multiple actions under a single account', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultWithdrawAction, defaultDepositAction], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when scaling the `amount` to deposit', async () => { - const conversionRateNumerator = new BigNumber(1); - const conversionRateDenominator = new BigNumber(2); - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [ - defaultWithdrawAction, - { - ...defaultDepositAction, - conversionRateNumerator, - conversionRateDenominator, - }, - ], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('succeeds when scaling the `amount` to withdraw', async () => { - const conversionRateNumerator = new BigNumber(1); - const conversionRateDenominator = new BigNumber(2); - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [ - defaultDepositAction, - { - ...defaultWithdrawAction, - conversionRateNumerator, - conversionRateDenominator, - }, - ], - }; - await executeBridgeTransferFromAndVerifyEvents( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - }); - it('reverts if not called by the ERC20 Bridge Proxy', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultDepositAction], - }; - const callBridgeTransferFromPromise = callBridgeTransferFrom( - accountOwner, - receiver, - defaultAmount, - bridgeData, - notAuthorized, - ); - const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy; - return expect(callBridgeTransferFromPromise).to.revertWith(expectedError); - }); - it('should return magic bytes if call succeeds', async () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultDepositAction], - }; - const returnValue = await callBridgeTransferFrom( - accountOwner, - receiver, - defaultAmount, - bridgeData, - authorized, - ); - expect(returnValue).to.equal(AssetProxyId.ERC20Bridge); - }); - it('should revert when `Operate` reverts', async () => { - // Set revert flag. - await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync(); - - // Execute transfer. - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultDepositAction], - }; - const tx = callBridgeTransferFrom(accountOwner, receiver, defaultAmount, bridgeData, authorized); - const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE'; - return expect(tx).to.revertWith(expectedError); - }); - it('should revert when there is a rounding error', async () => { - // Setup a rounding error - const conversionRateNumerator = new BigNumber(5318); - const conversionRateDenominator = new BigNumber(47958); - const amount = new BigNumber(9000); - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [ - defaultDepositAction, - { - ...defaultWithdrawAction, - conversionRateNumerator, - conversionRateDenominator, - }, - ], - }; - - // Execute transfer and assert error. - const tx = callBridgeTransferFrom(accountOwner, receiver, amount, bridgeData, authorized); - const expectedError = new LibMathRevertErrors.RoundingError( - conversionRateNumerator, - conversionRateDenominator, - amount, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('ERC20BridgeProxy.transferFrom()', () => { - const bridgeData = { - accountNumbers: [defaultAccountNumber], - actions: [defaultWithdrawAction], - }; - let assetData: string; - - before(async () => { - const testTokenAddress = await testContract.getTestToken().callAsync(); - assetData = assetDataEncoder - .ERC20Bridge(testTokenAddress, testContract.address, dydxBridgeDataEncoder.encode({ bridgeData })) - .getABIEncodedTransactionData(); - }); - - it('should succeed if `bridgeTransferFrom` succeeds', async () => { - await testProxyContract - .transferFrom(assetData, accountOwner, receiver, defaultAmount) - .awaitTransactionSuccessAsync({ from: authorized }); - }); - it('should revert if `bridgeTransferFrom` reverts', async () => { - // Set revert flag. - await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync(); - const tx = testProxyContract - .transferFrom(assetData, accountOwner, receiver, defaultAmount) - .awaitTransactionSuccessAsync({ from: authorized }); - const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE'; - return expect(tx).to.revertWith(expectedError); - }); - }); -}); diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts deleted file mode 100644 index 42e07a499e..0000000000 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ /dev/null @@ -1,1849 +0,0 @@ -import { - artifacts as erc1155Artifacts, - DummyERC1155ReceiverBatchTokenReceivedEventArgs, - DummyERC1155ReceiverContract, - ERC1155MintableContract, - Erc1155Wrapper, -} from '@0x/contracts-erc1155'; -import { - chaiSetup, - constants, - expectTransactionFailedAsync, - expectTransactionFailedWithoutReasonAsync, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { AssetProxyId, RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper'; -import { ERC1155ProxyContract, IAssetDataContract } from '../src/wrappers'; - -import { artifacts } from './artifacts'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -// tslint:disable:no-unnecessary-type-assertion -describe('ERC1155Proxy', () => { - // constant values used in transfer tests - const nftOwnerBalance = new BigNumber(1); - const nftNotOwnerBalance = new BigNumber(0); - const spenderInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - const receiverInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - const receiverContractInitialFungibleBalance = new BigNumber(0); - const fungibleValueToTransferSmall = spenderInitialFungibleBalance.div(100); - const fungibleValueToTransferLarge = spenderInitialFungibleBalance.div(4); - const valueMultiplierSmall = new BigNumber(2); - const valueMultiplierNft = new BigNumber(1); - const nonFungibleValueToTransfer = nftOwnerBalance; - const receiverCallbackData = '0x01020304'; - // addresses - let owner: string; - let notAuthorized: string; - let authorized: string; - let spender: string; - let receiver: string; - let receiverContract: string; - // contracts & wrappers - let erc1155Proxy: ERC1155ProxyContract; - let erc1155Receiver: DummyERC1155ReceiverContract; - let erc1155ProxyWrapper: ERC1155ProxyWrapper; - let erc1155Contract: ERC1155MintableContract; - let erc1155Wrapper: Erc1155Wrapper; - // tokens - let fungibleTokens: BigNumber[]; - let nonFungibleTokensOwnedBySpender: BigNumber[]; - // IAssetData for encoding and decoding assetData - let assetDataContract: IAssetDataContract; - // tests - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - /// deploy & configure ERC1155Proxy - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5)); - erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); - erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); - await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - await erc1155Proxy.addAuthorizedAddress(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - // deploy & configure ERC1155 tokens and receiver - [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); - erc1155Contract = erc1155Wrapper.getContract(); - erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( - erc1155Artifacts.DummyERC1155Receiver, - provider, - txDefaults, - artifacts, - ); - receiverContract = erc1155Receiver.address; - await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); - fungibleTokens = erc1155ProxyWrapper.getFungibleTokenIds(); - const nonFungibleTokens = erc1155ProxyWrapper.getNonFungibleTokenIds(); - const tokenBalances = await erc1155ProxyWrapper.getBalancesAsync(); - nonFungibleTokensOwnedBySpender = []; - _.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => { - const nonFungibleTokenAsString = nonFungibleToken.toString(); - const nonFungibleTokenHeldBySpender = - tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; - nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); - }); - // set up assetDataContract - assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner }); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('general', () => { - it('should revert if undefined function is called', async () => { - const undefinedSelector = '0x01020304'; - await expectTransactionFailedWithoutReasonAsync( - web3Wrapper.sendTransactionAsync({ - from: owner, - to: erc1155Proxy.address, - value: constants.ZERO_AMOUNT, - data: undefinedSelector, - }), - ); - }); - it('should have an id of 0xa7cb5fb7', async () => { - const proxyId = await erc1155Proxy.getProxyId().callAsync(); - const expectedProxyId = AssetProxyId.ERC1155; - expect(proxyId).to.equal(expectedProxyId); - }); - }); - describe('transferFrom', () => { - it('should successfully transfer value for a single, fungible token', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const totalValueTransferred = valuesToTransfer[0].times(valueMultiplier); - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(totalValueTransferred), - receiverInitialFungibleBalance.plus(totalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value for the same fungible token several times', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = fungibleTokens[0]; - const tokensToTransfer = [tokenToTransfer, tokenToTransfer, tokenToTransfer]; - const valuesToTransfer = [ - fungibleValueToTransferSmall.plus(10), - fungibleValueToTransferSmall.plus(20), - fungibleValueToTransferSmall.plus(30), - ]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - // receiver - receiverInitialFungibleBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => { - return sum.plus(value); - }) as BigNumber; - totalValueTransferred = totalValueTransferred.times(valueMultiplier); - const expectedFinalBalances = [ - // spender - spenderInitialFungibleBalance.minus(totalValueTransferred), - // receiver - receiverInitialFungibleBalance.plus(totalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); - }); - it('should successfully transfer value for several fungible tokens', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 3); - const valuesToTransfer = [ - fungibleValueToTransferSmall.plus(10), - fungibleValueToTransferSmall.plus(20), - fungibleValueToTransferSmall.plus(30), - ]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - // receiver - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - const expectedFinalBalances = [ - // spender - spenderInitialFungibleBalance.minus(totalValuesTransferred[0]), - spenderInitialFungibleBalance.minus(totalValuesTransferred[1]), - spenderInitialFungibleBalance.minus(totalValuesTransferred[2]), - // receiver - receiverInitialFungibleBalance.plus(totalValuesTransferred[0]), - receiverInitialFungibleBalance.plus(totalValuesTransferred[1]), - receiverInitialFungibleBalance.plus(totalValuesTransferred[2]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer a non-fungible token', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [nonFungibleValueToTransfer]; - const valueMultiplier = valueMultiplierNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const expectedFinalBalances = [ - // spender - nftNotOwnerBalance, - // receiver - nftOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer multiple non-fungible tokens', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const valuesToTransfer = [ - nonFungibleValueToTransfer, - nonFungibleValueToTransfer, - nonFungibleValueToTransfer, - ]; - const valueMultiplier = valueMultiplierNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const expectedFinalBalances = [ - // spender - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - // receiver - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const fungibleTokensToTransfer = fungibleTokens.slice(0, 3); - const nonFungibleTokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 2); - const tokensToTransfer = fungibleTokensToTransfer.concat(nonFungibleTokensToTransfer); - const valuesToTransfer = [ - fungibleValueToTransferLarge, - fungibleValueToTransferSmall, - fungibleValueToTransferSmall, - nonFungibleValueToTransfer, - nonFungibleValueToTransfer, - ]; - const valueMultiplier = valueMultiplierNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - const expectedFinalBalances = [ - // spender - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].minus(totalValuesTransferred[1]), - expectedInitialBalances[2].minus(totalValuesTransferred[2]), - expectedInitialBalances[3].minus(totalValuesTransferred[3]), - expectedInitialBalances[4].minus(totalValuesTransferred[4]), - // receiver - expectedInitialBalances[5].plus(totalValuesTransferred[0]), - expectedInitialBalances[6].plus(totalValuesTransferred[1]), - expectedInitialBalances[7].plus(totalValuesTransferred[2]), - expectedInitialBalances[8].plus(totalValuesTransferred[3]), - expectedInitialBalances[9].plus(totalValuesTransferred[4]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value to a smart contract and trigger its callback', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value to a smart contract and trigger its callback, when callback `data` is NULL', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const nullReceiverCallbackData = '0x'; - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - nullReceiverCallbackData, - authorized, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(nullReceiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value to a smart contract and trigger its callback, when callback `data` is one word', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // create word of callback data - const customReceiverCallbackData = '0x0102030405060708091001020304050607080910010203040506070809100102'; - const customReceiverCallbackDataAsBuffer = ethUtil.toBuffer(customReceiverCallbackData); - const oneWordInBytes = 32; - expect(customReceiverCallbackDataAsBuffer.byteLength).to.be.equal(oneWordInBytes); - // execute transfer - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - customReceiverCallbackData, - authorized, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(customReceiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value to a smart contract and trigger its callback, when callback `data` is multiple words', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // create word of callback data - const scalar = 5; - const customReceiverCallbackData = `0x${'0102030405060708091001020304050607080910010203040506070809100102'.repeat( - scalar, - )}`; - const customReceiverCallbackDataAsBuffer = ethUtil.toBuffer(customReceiverCallbackData); - const oneWordInBytes = 32; - expect(customReceiverCallbackDataAsBuffer.byteLength).to.be.equal(oneWordInBytes * scalar); - // execute transfer - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - customReceiverCallbackData, - authorized, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(customReceiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value to a smart contract and trigger its callback, when callback `data` is multiple words but not word-aligned', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // create word of callback data - const scalar = 5; - const customReceiverCallbackData = `0x${'0102030405060708091001020304050607080910010203040506070809100102'.repeat( - scalar, - )}090807`; - const customReceiverCallbackDataAsBuffer = ethUtil.toBuffer(customReceiverCallbackData); - const oneWordInBytes = 32; - expect(customReceiverCallbackDataAsBuffer.byteLength).to.be.greaterThan(oneWordInBytes * scalar); - expect(customReceiverCallbackDataAsBuffer.byteLength).to.be.lessThan(oneWordInBytes * (scalar + 1)); - // execute transfer - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - customReceiverCallbackData, - authorized, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(customReceiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value and ignore extra assetData', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier); - }); - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - const extraData = '0102030405060708091001020304050607080910010203040506070809100102'; - const assetDataWithExtraData = `${assetData}${extraData}`; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithExtraData, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer if token ids and values are abi encoded to same entry in calldata', async () => { - /** - * Suppose the `tokensToTransfer` and `valuesToTransfer` are identical; their offsets in - * the ABI-encoded asset data may be the same. E.g. token IDs [1, 2] and values [1, 2]. - * Suppose we scale by a factor of 2, then we expect to trade token IDs [1, 2] and values [2, 4]. - * This test ensures that scaling the values does not simultaneously scale the token IDs. - */ - ///// Step 1/5 ///// - // Create tokens with ids [1, 2, 3, 4] and mint a balance of 4 for the `spender` - const tokensToCreate = [new BigNumber(1), new BigNumber(2), new BigNumber(3), new BigNumber(4)]; - const spenderInitialBalance = new BigNumber(4); - const receiverInitialBalance = new BigNumber(0); - const tokenUri = ''; - for (const tokenToCreate of tokensToCreate) { - // create token - await erc1155Wrapper - .getContract() - .createWithType(tokenToCreate, tokenUri) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // mint balance for spender - await erc1155Wrapper - .getContract() - .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) - .awaitTransactionSuccessAsync({ - from: owner, - }); - } - ///// Step 2/5 ///// - // Check balances before transfer - const balanceHolders = [spender, spender, spender, spender, receiver, receiver, receiver, receiver]; - const balanceTokens = tokensToCreate.concat(tokensToCreate); - const initialBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens); - const expectedInitialBalances = [ - spenderInitialBalance, // Token ID 1 / Spender Balance - spenderInitialBalance, // Token ID 2 / Spender Balance - spenderInitialBalance, // Token ID 3 / Spender Balance - spenderInitialBalance, // Token ID 4 / Spender Balance - receiverInitialBalance, // Token ID 1 / Receiver Balance - receiverInitialBalance, // Token ID 2 / Receiver Balance - receiverInitialBalance, // Token ID 3 / Receiver Balance - receiverInitialBalance, // Token ID 4 / Receiver Balance - ]; - expect(initialBalances).to.be.deep.equal(expectedInitialBalances); - ///// Step 3/5 ///// - // Create optimized calldata. We expect it to be formatted like the table below. - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 // ERC1155 contract address - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token IDs - // 0x40 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token values (same as IDs) - // 0x60 00000000000000000000000000000000000000000000000000000000000000e0 // Offset to data - // 0x80 0000000000000000000000000000000000000000000000000000000000000002 // Length of token Ids / token values - // 0xA0 0000000000000000000000000000000000000000000000000000000000000001 // First Token ID / Token value - // 0xC0 0000000000000000000000000000000000000000000000000000000000000002 // Second Token ID / Token value - // 0xE0 0000000000000000000000000000000000000000000000000000000000000004 // Length of callback data - // 0x100 0102030400000000000000000000000000000000000000000000000000000000 // Callback data - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const tokensToTransfer = [new BigNumber(1), new BigNumber(2)]; - const valuesToTransfer = tokensToTransfer; - const valueMultiplier = new BigNumber(2); - - // hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding - const selector = assetDataContract.getSelector('ERC1155Assets'); - const assetDataWithoutContractAddress = - '0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000'; - const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr( - 2, - )}${assetDataWithoutContractAddress}`; - - ///// Step 4/5 ///// - // Transfer token IDs [1, 2] and amounts [1, 2] with a multiplier of 2; - // the expected trade will be token IDs [1, 2] and amounts [2, 4] - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetData, - ); - ///// Step 5/5 ///// - // Validate final balances - const finalBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens); - const expectedAmountsTransferred = _.map(valuesToTransfer, value => { - return value.times(valueMultiplier); - }); - const expectedFinalBalances = [ - spenderInitialBalance.minus(expectedAmountsTransferred[0]), // Token ID 1 / Spender Balance - spenderInitialBalance.minus(expectedAmountsTransferred[1]), // Token ID 2 / Spender Balance - spenderInitialBalance, // Token ID 3 / Spender Balance - spenderInitialBalance, // Token ID 4 / Spender Balance - receiverInitialBalance.plus(expectedAmountsTransferred[0]), // Token ID 1 / Receiver Balance - receiverInitialBalance.plus(expectedAmountsTransferred[1]), // Token ID 2 / Receiver Balance - receiverInitialBalance, // Token ID 3 / Receiver Balance - receiverInitialBalance, // Token ID 4 / Receiver Balance - ]; - expect(finalBalances).to.be.deep.equal(expectedFinalBalances); - }); - it('should successfully transfer if token values and data are abi encoded to same entry in calldata', async () => { - /** - * This test ensures that scaling the values does not simultaneously scale the data. - * Note that this test is slightly more contrived than the test above, as asset data must be - * intentionally hand-modified to produce this result: a functioning abi encoder will not produce it. - */ - ///// Step 1/5 ///// - // Create tokens with ids [1, 2, 3, 4] and mint a balance of 4 for the `spender` - const tokensToCreate = [new BigNumber(1), new BigNumber(2), new BigNumber(3), new BigNumber(4)]; - const spenderInitialBalance = new BigNumber(4); - const receiverInitialBalance = new BigNumber(0); - const tokenUri = ''; - for (const tokenToCreate of tokensToCreate) { - // create token - await erc1155Wrapper - .getContract() - .createWithType(tokenToCreate, tokenUri) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // mint balance for spender - await erc1155Wrapper - .getContract() - .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) - .awaitTransactionSuccessAsync({ - from: owner, - }); - } - ///// Step 2/5 ///// - // Check balances before transfer - const balanceHolders = [ - spender, - spender, - spender, - spender, - receiverContract, - receiverContract, - receiverContract, - receiverContract, - ]; - const balanceTokens = tokensToCreate.concat(tokensToCreate); - const initialBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens); - const expectedInitialBalances = [ - spenderInitialBalance, // Token ID 1 / Spender Balance - spenderInitialBalance, // Token ID 2 / Spender Balance - spenderInitialBalance, // Token ID 3 / Spender Balance - spenderInitialBalance, // Token ID 4 / Spender Balance - receiverInitialBalance, // Token ID 1 / Receiver Balance - receiverInitialBalance, // Token ID 2 / Receiver Balance - receiverInitialBalance, // Token ID 3 / Receiver Balance - receiverInitialBalance, // Token ID 4 / Receiver Balance - ]; - expect(initialBalances).to.be.deep.equal(expectedInitialBalances); - ///// Step 3/5 ///// - // Create optimized calldata. We format like the table below. - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 // ERC1155 contract address - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token IDs - // 0x40 00000000000000000000000000000000000000000000000000000000000000e0 // Offset to token values - // 0x60 00000000000000000000000000000000000000000000000000000000000000e0 // Offset to data (same as values) - // 0x80 0000000000000000000000000000000000000000000000000000000000000002 // Length of token Ids - // 0xA0 0000000000000000000000000000000000000000000000000000000000000001 // First Token ID - // 0xC0 0000000000000000000000000000000000000000000000000000000000000002 // Second Token ID - // 0xE0 0000000000000000000000000000000000000000000000000000000000000002 // Length of values (Length of data) - // 0x100 0000000000000000000000000000000000000000000000000000000000000002 // First Value - // 0x120 0000000000000000000000000000000000000000000000000000000000000002 // Second Value - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const tokensToTransfer = [new BigNumber(1), new BigNumber(2)]; - const valuesToTransfer = [new BigNumber(2), new BigNumber(2)]; - const valueMultiplier = new BigNumber(2); - // create callback data that is the encoded version of `valuesToTransfer` - const generatedAssetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // remove the function selector and contract address from check, as these change on each test - const offsetToTokenIds = 74; - const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); - const assetDataParameters = - '000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002'; - const assetData = `${assetDataSelectorAndContractAddress}${assetDataParameters}`; - ///// Step 4/5 ///// - // Transfer tokens - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetData, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(2); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenIds[1]).to.be.bignumber.equal(tokensToTransfer[1]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(2); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(valuesToTransfer[0].times(valueMultiplier)); - expect(receiverLog.args.tokenValues[1]).to.be.bignumber.equal(valuesToTransfer[1].times(valueMultiplier)); - expect(receiverLog.args.data).to.be.deep.equal('0x0000'); - ///// Step 5/5 ///// - // Validate final balances - const finalBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens); - const expectedAmountsTransferred = _.map(valuesToTransfer, value => { - return value.times(valueMultiplier); - }); - const expectedFinalBalances = [ - spenderInitialBalance.minus(expectedAmountsTransferred[0]), // Token ID 1 / Spender Balance - spenderInitialBalance.minus(expectedAmountsTransferred[1]), // Token ID 2 / Spender Balance - spenderInitialBalance, // Token ID 3 / Spender Balance - spenderInitialBalance, // Token ID 4 / Spender Balance - receiverInitialBalance.plus(expectedAmountsTransferred[0]), // Token ID 1 / Receiver Balance - receiverInitialBalance.plus(expectedAmountsTransferred[1]), // Token ID 2 / Receiver Balance - receiverInitialBalance, // Token ID 3 / Receiver Balance - receiverInitialBalance, // Token ID 4 / Receiver Balance - ]; - expect(finalBalances).to.be.deep.equal(expectedFinalBalances); - }); - it('should successfully transfer if token ids, values and data are abi encoded to same entry in calldata', async () => { - /** - * This test combines the two tests above. - * Similar to the test above, the asset data must be manually constructed. - */ - ///// Step 1/5 ///// - // Create tokens with ids [1, 2, 3, 4] and mint a balance of 4 for the `spender` - const tokensToCreate = [new BigNumber(1), new BigNumber(2), new BigNumber(3), new BigNumber(4)]; - const spenderInitialBalance = new BigNumber(4); - const receiverInitialBalance = new BigNumber(0); - const tokenUri = ''; - for (const tokenToCreate of tokensToCreate) { - // create token - await erc1155Wrapper - .getContract() - .createWithType(tokenToCreate, tokenUri) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // mint balance for spender - await erc1155Wrapper - .getContract() - .mintFungible(tokenToCreate, [spender], [spenderInitialBalance]) - .awaitTransactionSuccessAsync({ - from: owner, - }); - } - ///// Step 2/5 ///// - // Check balances before transfer - const balanceHolders = [ - spender, - spender, - spender, - spender, - receiverContract, - receiverContract, - receiverContract, - receiverContract, - ]; - const balanceTokens = tokensToCreate.concat(tokensToCreate); - const initialBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens); - const expectedInitialBalances = [ - spenderInitialBalance, // Token ID 1 / Spender Balance - spenderInitialBalance, // Token ID 2 / Spender Balance - spenderInitialBalance, // Token ID 3 / Spender Balance - spenderInitialBalance, // Token ID 4 / Spender Balance - receiverInitialBalance, // Token ID 1 / Receiver Balance - receiverInitialBalance, // Token ID 2 / Receiver Balance - receiverInitialBalance, // Token ID 3 / Receiver Balance - receiverInitialBalance, // Token ID 4 / Receiver Balance - ]; - expect(initialBalances).to.be.deep.equal(expectedInitialBalances); - ///// Step 3/5 ///// - // Create optimized calldata. We format like the table below. - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 // ERC1155 contract address - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token IDs - // 0x40 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token values - // 0x60 0000000000000000000000000000000000000000000000000000000000000080 // Offset to data (same as values) - // 0x80 0000000000000000000000000000000000000000000000000000000000000002 // Length of token Ids (Length of values / data) - // 0xA0 0000000000000000000000000000000000000000000000000000000000000001 // First Token ID (First Value) - // 0xC0 0000000000000000000000000000000000000000000000000000000000000002 // Second Token ID (Second Value) - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const tokensToTransfer = [new BigNumber(1), new BigNumber(2)]; - const valuesToTransfer = [new BigNumber(1), new BigNumber(2)]; - const valueMultiplier = new BigNumber(2); - // create callback data that is the encoded version of `valuesToTransfer` - const generatedAssetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // remove the function selector and contract address from check, as these change on each test - const offsetToTokenIds = 74; - const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds); - const assetDataParameters = - '000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'; - const assetData = `${assetDataSelectorAndContractAddress}${assetDataParameters}`; - ///// Step 4/5 ///// - // Transfer tokens - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetData, - ); - // check receiver log ignored extra asset data - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs< - DummyERC1155ReceiverBatchTokenReceivedEventArgs - >; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(spender); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(2); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenIds[1]).to.be.bignumber.equal(tokensToTransfer[1]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(2); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(valuesToTransfer[0].times(valueMultiplier)); - expect(receiverLog.args.tokenValues[1]).to.be.bignumber.equal(valuesToTransfer[1].times(valueMultiplier)); - expect(receiverLog.args.data).to.be.deep.equal('0x0000'); - ///// Step 5/5 ///// - // Validate final balances - const finalBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens); - const expectedAmountsTransferred = _.map(valuesToTransfer, value => { - return value.times(valueMultiplier); - }); - const expectedFinalBalances = [ - spenderInitialBalance.minus(expectedAmountsTransferred[0]), // Token ID 1 / Spender Balance - spenderInitialBalance.minus(expectedAmountsTransferred[1]), // Token ID 2 / Spender Balance - spenderInitialBalance, // Token ID 3 / Spender Balance - spenderInitialBalance, // Token ID 4 / Spender Balance - receiverInitialBalance.plus(expectedAmountsTransferred[0]), // Token ID 1 / Receiver Balance - receiverInitialBalance.plus(expectedAmountsTransferred[1]), // Token ID 2 / Receiver Balance - receiverInitialBalance, // Token ID 3 / Receiver Balance - receiverInitialBalance, // Token ID 4 / Receiver Balance - ]; - expect(finalBalances).to.be.deep.equal(expectedFinalBalances); - }); - it('should revert if token ids resolves to outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 // offset to token ids - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token ids to point outside the calldata. - const encodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000080'; - const badEncodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000180'; - const assetDataWithBadTokenIdsOffset = assetData.replace( - encodedOffsetToTokenIds, - badEncodedOffsetToTokenIds, - ); - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithBadTokenIdsOffset, - ), - ); - }); - it('should revert if an element of token ids lies to outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 // offset to token ids - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token ids to the end of calldata. - // Then we'll add an invalid length: we encode length of 2 but only add 1 element. - const encodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000080'; - const newEcodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000140'; - const assetDataWithNewTokenIdsOffset = assetData.replace( - encodedOffsetToTokenIds, - newEcodedOffsetToTokenIds, - ); - const encodedTokenIdsLength = '0000000000000000000000000000000000000000000000000000000000000002'; - const encodedTokenIdValues = '0000000000000000000000000000000000000000000000000000000000000001'; - const assetDataWithBadTokenIds = `${assetDataWithNewTokenIdsOffset}${encodedTokenIdsLength}${encodedTokenIdValues}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithBadTokenIds, - ), - ); - }); - it('should revert token ids length overflows', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 // offset to token ids - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token ids to point to the end of calldata - const encodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000080'; - const badEncodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000140'; - const assetDataWithBadTokenIdsOffset = assetData.replace( - encodedOffsetToTokenIds, - badEncodedOffsetToTokenIds, - ); - // We want a length that will overflow when converted to bytes - ie, multiplied by 32. - const encodedIdsLengthOverflow = '0800000000000000000000000000000000000000000000000000000000000001'; - const buffer = '0'.repeat(64 * 10); - const assetDataWithOverflow = `${assetDataWithBadTokenIdsOffset}${encodedIdsLengthOverflow}${buffer}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithOverflow, - ), - ); - }); - it('should revert token values length overflows', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 // offset to token values - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token values to point to the end of calldata - const encodedOffsetToTokenIds = '00000000000000000000000000000000000000000000000000000000000000c0'; - const badEncodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000140'; - const assetDataWithBadTokenIdsOffset = assetData.replace( - encodedOffsetToTokenIds, - badEncodedOffsetToTokenIds, - ); - // We want a length that will overflow when converted to bytes - ie, multiplied by 32. - const encodedIdsLengthOverflow = '0800000000000000000000000000000000000000000000000000000000000001'; - const buffer = '0'.repeat(64 * 10); - const assetDataWithOverflow = `${assetDataWithBadTokenIdsOffset}${encodedIdsLengthOverflow}${buffer}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithOverflow, - ), - ); - }); - it('should revert token data length overflows', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 // offset to token data - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token ids to point to the end of calldata, - // which we'll extend with a bad length. - const encodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000100'; - const badEncodedOffsetToTokenIds = '0000000000000000000000000000000000000000000000000000000000000140'; - const assetDataWithBadTokenIdsOffset = assetData.replace( - encodedOffsetToTokenIds, - badEncodedOffsetToTokenIds, - ); - // We want a length that will overflow when converted to bytes - ie, multiplied by 32. - const encodedIdsLengthOverflow = '0800000000000000000000000000000000000000000000000000000000000001'; - const buffer = '0'.repeat(64 * 10); - const assetDataWithOverflow = `${assetDataWithBadTokenIdsOffset}${encodedIdsLengthOverflow}${buffer}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithOverflow, - ), - ); - }); - it('should revert if token values resolves to outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 // offset to token values - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token values to point outside the calldata. - const encodedOffsetToTokenValues = '00000000000000000000000000000000000000000000000000000000000000c0'; - const badEncodedOffsetToTokenValues = '00000000000000000000000000000000000000000000000000000000000001c0'; - const assetDataWithBadTokenIdsOffset = assetData.replace( - encodedOffsetToTokenValues, - badEncodedOffsetToTokenValues, - ); - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithBadTokenIdsOffset, - ), - ); - }); - it('should revert if an element of token values lies to outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 // offset to token values - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token values to the end of calldata. - // Then we'll add an invalid length: we encode length of 2 but only add 1 element. - const encodedOffsetToTokenValues = '00000000000000000000000000000000000000000000000000000000000000c0'; - const newEcodedOffsetToTokenValues = '0000000000000000000000000000000000000000000000000000000000000140'; - const assetDataWithNewTokenValuesOffset = assetData.replace( - encodedOffsetToTokenValues, - newEcodedOffsetToTokenValues, - ); - const encodedTokenValuesLength = '0000000000000000000000000000000000000000000000000000000000000002'; - const encodedTokenValuesElements = '0000000000000000000000000000000000000000000000000000000000000001'; - const assetDataWithBadTokenIds = `${assetDataWithNewTokenValuesOffset}${encodedTokenValuesLength}${encodedTokenValuesElements}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithBadTokenIds, - ), - ); - }); - it('should revert if token data resolves to outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 // offset to token data - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token data to point outside the calldata. - const encodedOffsetToTokenData = '0000000000000000000000000000000000000000000000000000000000000100'; - const badEncodedOffsetToTokenData = '00000000000000000000000000000000000000000000000000000000000001c0'; - const assetDataWithBadTokenDataOffset = assetData.replace( - encodedOffsetToTokenData, - badEncodedOffsetToTokenData, - ); - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithBadTokenDataOffset, - ), - ); - }); - it('should revert if an element of token data lies to outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - // The asset data we just generated will look like this: - // a7cb5fb7 - // 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 - // 0x20 0000000000000000000000000000000000000000000000000000000000000080 - // 0x40 00000000000000000000000000000000000000000000000000000000000000c0 - // 0x60 0000000000000000000000000000000000000000000000000000000000000100 // offset to token data - // 0x80 0000000000000000000000000000000000000000000000000000000000000001 - // 0xA0 0000000000000000000000000000000100000000000000000000000000000000 - // 0xC0 0000000000000000000000000000000000000000000000000000000000000001 - // 0xE0 0000000000000000000000000000000000000000000000878678326eac900000 - // 0x100 0000000000000000000000000000000000000000000000000000000000000004 - // 0x120 0102030400000000000000000000000000000000000000000000000000000000 - // - // We want to change the offset to token data to the end of calldata. - // Then we'll add an invalid length: we encode length of 33 but only add 32 elements. - const encodedOffsetToTokenData = '0000000000000000000000000000000000000000000000000000000000000100'; - const newEcodedOffsetToTokenData = '0000000000000000000000000000000000000000000000000000000000000140'; - const assetDataWithNewTokenDataOffset = assetData.replace( - encodedOffsetToTokenData, - newEcodedOffsetToTokenData, - ); - const encodedTokenDataLength = '0000000000000000000000000000000000000000000000000000000000000021'; - const encodedTokenDataElements = '0000000000000000000000000000000000000000000000000000000000000001'; - const assetDataWithBadTokenData = `${assetDataWithNewTokenDataOffset}${encodedTokenDataLength}${encodedTokenDataElements}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetDataWithBadTokenData, - ), - ); - }); - it('should revert if asset data lies outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetData, - ); - const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; - const invalidOffsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000180'; - const badTxData = txData.replace(offsetToAssetData, invalidOffsetToAssetData); - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromRawAsync(badTxData, authorized), - ); - }); - it('should revert if asset data lies outside the bounds of calldata', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - const erc1155ContractAddress = erc1155Wrapper.getContract().address; - const assetData = assetDataContract - .ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .getABIEncodedTransactionData(); - const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetData, - ); - // append asset data to end of tx data with a length of 0x300 bytes, which will extend past actual calldata. - const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; - const invalidOffsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000200'; - const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304'; - const badTxData = `${txData.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromRawAsync(badTxData, authorized), - ); - }); - it('should revert if length of assetData is less than 132 bytes', async () => { - // setup test parameters - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - // we'll construct asset data that has a 4 byte selector plus - // 96 byte payload. This results in asset data that is 100 bytes - // long and will trigger the `invalid length` error. - // we must be sure to use a # of bytes that is still %32 - // so that we know the error is not triggered by another check in the code. - const zeros96Bytes = '0'.repeat(188); - const assetData131Bytes = `${AssetProxyId.ERC1155}${zeros96Bytes}`; - // execute transfer - await expectTransactionFailedWithoutReasonAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - assetData131Bytes, - ), - ); - }); - it('should transfer nothing if value is zero', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [new BigNumber(0)]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should transfer nothing if value multiplier is zero', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = new BigNumber(0); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should transfer nothing if there are no tokens in asset data', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer: BigNumber[] = []; - const valuesToTransfer: BigNumber[] = []; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - // check balances after transfer - const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should propagate revert reason from erc1155 contract failure', async () => { - // disable transfers - const shouldRejectTransfer = true; - await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).awaitTransactionSuccessAsync({ - from: owner, - }); - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiverContract, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ), - RevertReason.TransferRejected, - ); - }); - it('should revert if transferring the same non-fungible token more than once', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const nftToTransfer = nonFungibleTokensOwnedBySpender[0]; - const tokensToTransfer = [nftToTransfer, nftToTransfer]; - const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer]; - const valueMultiplier = valueMultiplierNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ), - RevertReason.NFTNotOwnedByFromAddress, - ); - }); - it('should revert if there is a multiplication overflow', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const maxUintValue = new BigNumber(2).pow(256).minus(1); - const valuesToTransfer = [nonFungibleValueToTransfer, maxUintValue, nonFungibleValueToTransfer]; - const valueMultiplier = new BigNumber(2); - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - maxUintValue, - valueMultiplier, - ); - // execute transfer - // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token - await expect( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ), - ).to.revertWith(expectedError); - }); - it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [nonFungibleValueToTransfer]; - const valueMultiplier = new BigNumber(2); - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ), - RevertReason.AmountEqualToOneRequired, - ); - }); - it('should revert if transferring > 1 instances of a non-fungible token (`valuesToTransfer` field >1)', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [new BigNumber(2)]; - const valueMultiplier = valueMultiplierNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ), - RevertReason.AmountEqualToOneRequired, - ); - }); - it('should revert if sender balance is insufficient', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valueGreaterThanSpenderBalance = spenderInitialFungibleBalance.plus(1); - const valuesToTransfer = [valueGreaterThanSpenderBalance]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - spenderInitialFungibleBalance, - valuesToTransfer[0].times(valueMultiplier), - ); - // execute transfer - const tx = erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if sender allowance is insufficient', async () => { - // dremove allowance for ERC1155 proxy - const wrapper = erc1155ProxyWrapper.getContractWrapper(erc1155Contract.address); - const isApproved = false; - await wrapper.setApprovalForAllAsync(spender, erc1155Proxy.address, isApproved); - const isApprovedActualValue = await wrapper.isApprovedForAllAsync(spender, erc1155Proxy.address); - expect(isApprovedActualValue).to.be.equal(isApproved); - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - authorized, - ), - RevertReason.InsufficientAllowance, - ); - }); - it('should revert if caller is not authorized', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const valueMultiplier = valueMultiplierSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - valueMultiplier, - receiverCallbackData, - notAuthorized, - ), - RevertReason.SenderNotAuthorized, - ); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion -// tslint:disable:max-file-line-count diff --git a/contracts/asset-proxy/test/erc20bridge_proxy.ts b/contracts/asset-proxy/test/erc20bridge_proxy.ts deleted file mode 100644 index b3a29c90ef..0000000000 --- a/contracts/asset-proxy/test/erc20bridge_proxy.ts +++ /dev/null @@ -1,287 +0,0 @@ -import { - blockchainTests, - constants, - expect, - getRandomInteger, - Numberish, - randomAddress, -} from '@0x/contracts-test-utils'; -import { AuthorizableRevertErrors } from '@0x/contracts-utils'; -import { AssetProxyId } from '@0x/types'; -import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils'; -import { DecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers'; - -blockchainTests.resets('ERC20BridgeProxy unit tests', env => { - const PROXY_ID = AssetProxyId.ERC20Bridge; - const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID); - let owner: string; - let badCaller: string; - let assetProxy: ERC20BridgeProxyContract; - let bridgeContract: TestERC20BridgeContract; - let testTokenAddress: string; - - before(async () => { - [owner, badCaller] = await env.getAccountAddressesAsync(); - assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC20BridgeProxy, - env.provider, - env.txDefaults, - artifacts, - ); - bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync( - artifacts.TestERC20Bridge, - env.provider, - env.txDefaults, - artifacts, - ); - testTokenAddress = await bridgeContract.testToken().callAsync(); - await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync(); - }); - - interface AssetDataOpts { - tokenAddress: string; - bridgeAddress: string; - bridgeData: BridgeDataOpts; - } - - interface BridgeDataOpts { - transferAmount: Numberish; - revertError?: string; - returnData: string; - } - - function createAssetData(opts?: Partial): AssetDataOpts { - return _.merge( - { - tokenAddress: testTokenAddress, - bridgeAddress: bridgeContract.address, - bridgeData: createBridgeData(), - }, - opts, - ); - } - - function createBridgeData(opts?: Partial): BridgeDataOpts { - return _.merge( - { - transferAmount: constants.ZERO_AMOUNT, - returnData: BRIDGE_SUCCESS_RETURN_DATA, - }, - opts, - ); - } - - function encodeAssetData(opts: AssetDataOpts): string { - const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [ - { name: 'tokenAddress', type: 'address' }, - { name: 'bridgeAddress', type: 'address' }, - { name: 'bridgeData', type: 'bytes' }, - ]); - return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]); - } - - function encodeBridgeData(opts: BridgeDataOpts): string { - const encoder = AbiEncoder.create([ - { name: 'transferAmount', type: 'int256' }, - { name: 'revertData', type: 'bytes' }, - { name: 'returnData', type: 'bytes' }, - ]); - const revertErrorBytes = - opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x'; - return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]); - } - - async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise { - await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync(); - } - - describe('transferFrom()', () => { - interface TransferFromOpts { - assetData: AssetDataOpts; - from: string; - to: string; - amount: Numberish; - } - - function createTransferFromOpts(opts?: Partial): TransferFromOpts { - const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber; - return _.merge( - { - assetData: createAssetData({ - bridgeData: createBridgeData({ - transferAmount, - }), - }), - from: randomAddress(), - to: randomAddress(), - amount: transferAmount, - }, - opts, - ); - } - - async function transferFromAsync(opts?: Partial, caller?: string): Promise { - const _opts = createTransferFromOpts(opts); - const { logs } = await assetProxy - .transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount)) - .awaitTransactionSuccessAsync({ from: caller }); - return (logs as any) as DecodedLogs; - } - - it('succeeds if the bridge succeeds and balance increases by `amount`', async () => { - const tx = transferFromAsync(); - return expect(tx).to.be.fulfilled(''); - }); - - it('succeeds if balance increases more than `amount`', async () => { - const amount = getRandomInteger(1, 100e18); - const tx = transferFromAsync({ - amount, - assetData: createAssetData({ - bridgeData: createBridgeData({ - transferAmount: amount.plus(1), - }), - }), - }); - return expect(tx).to.be.fulfilled(''); - }); - - it('passes the correct arguments to the bridge contract', async () => { - const opts = createTransferFromOpts(); - const logs = await transferFromAsync(opts); - expect(logs.length).to.eq(1); - const args = logs[0].args; - expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress); - expect(args.from).to.eq(opts.from); - expect(args.to).to.eq(opts.to); - expect(args.amount).to.bignumber.eq(opts.amount); - expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData)); - }); - - it('fails if not called by an authorized address', async () => { - const tx = transferFromAsync({}, badCaller); - return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller)); - }); - - it('fails if asset data is truncated', async () => { - const opts = createTransferFromOpts(); - const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1); - const tx = assetProxy - .transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount)) - .awaitTransactionSuccessAsync(); - return expect(tx).to.be.rejected(); - }); - - it('fails if bridge returns nothing', async () => { - const tx = transferFromAsync({ - assetData: createAssetData({ - bridgeData: createBridgeData({ - returnData: '0x', - }), - }), - }); - // This will actually revert when the AP tries to decode the return - // value. - return expect(tx).to.be.rejected(); - }); - - it('fails if bridge returns true', async () => { - const tx = transferFromAsync({ - assetData: createAssetData({ - bridgeData: createBridgeData({ - returnData: hexUtils.leftPad('0x1'), - }), - }), - }); - // This will actually revert when the AP tries to decode the return - // value. - return expect(tx).to.be.rejected(); - }); - - it('fails if bridge returns 0x1', async () => { - const tx = transferFromAsync({ - assetData: createAssetData({ - bridgeData: createBridgeData({ - returnData: hexUtils.rightPad('0x1'), - }), - }), - }); - return expect(tx).to.revertWith('BRIDGE_FAILED'); - }); - - it('fails if bridge is an EOA', async () => { - const tx = transferFromAsync({ - assetData: createAssetData({ - bridgeAddress: randomAddress(), - }), - }); - // This will actually revert when the AP tries to decode the return - // value. - return expect(tx).to.be.rejected(); - }); - - it('fails if bridge reverts', async () => { - const revertError = 'FOOBAR'; - const tx = transferFromAsync({ - assetData: createAssetData({ - bridgeData: createBridgeData({ - revertError, - }), - }), - }); - return expect(tx).to.revertWith(revertError); - }); - - it('fails if balance of `to` increases by less than `amount`', async () => { - const amount = getRandomInteger(1, 100e18); - const tx = transferFromAsync({ - amount, - assetData: createAssetData({ - bridgeData: createBridgeData({ - transferAmount: amount.minus(1), - }), - }), - }); - return expect(tx).to.revertWith('BRIDGE_UNDERPAY'); - }); - - it('fails if balance of `to` decreases', async () => { - const toAddress = randomAddress(); - await setTestTokenBalanceAsync(toAddress, 1e18); - const tx = transferFromAsync({ - to: toAddress, - assetData: createAssetData({ - bridgeData: createBridgeData({ - transferAmount: -1, - }), - }), - }); - return expect(tx).to.revertWith('BRIDGE_UNDERPAY'); - }); - }); - - describe('balanceOf()', () => { - it('retrieves the balance of the encoded token', async () => { - const _owner = randomAddress(); - const balance = getRandomInteger(1, 100e18); - await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync(); - const assetData = createAssetData({ - tokenAddress: testTokenAddress, - }); - const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync(); - expect(actualBalance).to.bignumber.eq(balance); - }); - }); - - describe('getProxyId()', () => { - it('returns the correct proxy ID', async () => { - const proxyId = await assetProxy.getProxyId().callAsync(); - expect(proxyId).to.eq(PROXY_ID); - }); - }); -}); diff --git a/contracts/asset-proxy/test/eth2dai_bridge.ts b/contracts/asset-proxy/test/eth2dai_bridge.ts deleted file mode 100644 index f102b146c6..0000000000 --- a/contracts/asset-proxy/test/eth2dai_bridge.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { - blockchainTests, - constants, - expect, - filterLogsToArguments, - getRandomInteger, - Numberish, - randomAddress, -} from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber, hexUtils, RawRevertError } from '@0x/utils'; -import { DecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { - TestEth2DaiBridgeContract, - TestEth2DaiBridgeEvents, - TestEth2DaiBridgeSellAllAmountEventArgs, - TestEth2DaiBridgeTokenApproveEventArgs, - TestEth2DaiBridgeTokenTransferEventArgs, -} from './wrappers'; - -blockchainTests.resets('Eth2DaiBridge unit tests', env => { - let testContract: TestEth2DaiBridgeContract; - - before(async () => { - testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestEth2DaiBridge, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('isValidSignature()', () => { - it('returns success bytes', async () => { - const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; - const result = await testContract - .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) - .callAsync(); - expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); - }); - }); - - describe('bridgeTransferFrom()', () => { - interface WithdrawToOpts { - toTokenAddress?: string; - fromTokenAddress?: string; - toAddress: string; - amount: Numberish; - fromTokenBalance: Numberish; - revertReason: string; - fillAmount: Numberish; - toTokentransferRevertReason: string; - toTokenTransferReturnData: string; - } - - interface WithdrawToResult { - opts: WithdrawToOpts; - result: string; - logs: DecodedLogs; - } - - function createWithdrawToOpts(opts?: Partial): WithdrawToOpts { - return { - toAddress: randomAddress(), - amount: getRandomInteger(1, 100e18), - revertReason: '', - fillAmount: getRandomInteger(1, 100e18), - fromTokenBalance: getRandomInteger(1, 100e18), - toTokentransferRevertReason: '', - toTokenTransferReturnData: hexUtils.leftPad(1), - ...opts, - }; - } - - async function withdrawToAsync(opts?: Partial): Promise { - const _opts = createWithdrawToOpts(opts); - // Set the fill behavior. - await testContract - .setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount)) - .awaitTransactionSuccessAsync(); - // Create tokens and balances. - if (_opts.fromTokenAddress === undefined) { - const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance)); - _opts.fromTokenAddress = await createTokenFn.callAsync(); - await createTokenFn.awaitTransactionSuccessAsync(); - } - if (_opts.toTokenAddress === undefined) { - const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT); - _opts.toTokenAddress = await createTokenFn.callAsync(); - await createTokenFn.awaitTransactionSuccessAsync(); - } - // Set the transfer behavior of `toTokenAddress`. - await testContract - .setTransferBehavior( - _opts.toTokenAddress, - _opts.toTokentransferRevertReason, - _opts.toTokenTransferReturnData, - ) - .awaitTransactionSuccessAsync(); - // Call bridgeTransferFrom(). - const bridgeTransferFromFn = testContract.bridgeTransferFrom( - // "to" token address - _opts.toTokenAddress, - // Random from address. - randomAddress(), - // To address. - _opts.toAddress, - new BigNumber(_opts.amount), - // ABI-encode the "from" token address as the bridge data. - hexUtils.leftPad(_opts.fromTokenAddress as string), - ); - const result = await bridgeTransferFromFn.callAsync(); - const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); - return { - opts: _opts, - result, - logs: (logs as any) as DecodedLogs, - }; - } - - it('returns magic bytes on success', async () => { - const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge; - const { result } = await withdrawToAsync(); - expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA); - }); - - it('calls `Eth2Dai.sellAllAmount()`', async () => { - const { opts, logs } = await withdrawToAsync(); - const transfers = filterLogsToArguments( - logs, - TestEth2DaiBridgeEvents.SellAllAmount, - ); - expect(transfers.length).to.eq(1); - expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress); - expect(transfers[0].buyToken).to.eq(opts.toTokenAddress); - expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance); - expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount); - }); - - it('sets an unlimited allowance on the `fromTokenAddress` token', async () => { - const { opts, logs } = await withdrawToAsync(); - const approvals = filterLogsToArguments( - logs, - TestEth2DaiBridgeEvents.TokenApprove, - ); - expect(approvals.length).to.eq(1); - expect(approvals[0].token).to.eq(opts.fromTokenAddress); - expect(approvals[0].spender).to.eq(testContract.address); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('transfers filled amount to `to`', async () => { - const { opts, logs } = await withdrawToAsync(); - const transfers = filterLogsToArguments( - logs, - TestEth2DaiBridgeEvents.TokenTransfer, - ); - expect(transfers.length).to.eq(1); - expect(transfers[0].token).to.eq(opts.toTokenAddress); - expect(transfers[0].from).to.eq(testContract.address); - expect(transfers[0].to).to.eq(opts.toAddress); - expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount); - }); - - it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => { - const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' }); - const tx = withdrawToAsync(opts); - return expect(tx).to.revertWith(opts.revertReason); - }); - - it('fails if `toTokenAddress.transfer()` reverts', async () => { - const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' }); - const tx = withdrawToAsync(opts); - return expect(tx).to.revertWith(opts.toTokentransferRevertReason); - }); - - it('fails if `toTokenAddress.transfer()` returns false', async () => { - const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) }); - const tx = withdrawToAsync(opts); - return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0))); - }); - - it('succeeds if `toTokenAddress.transfer()` returns true', async () => { - await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) }); - }); - }); -}); diff --git a/contracts/asset-proxy/test/global_hooks.ts b/contracts/asset-proxy/test/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/asset-proxy/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/asset-proxy/test/kyber_bridge.ts b/contracts/asset-proxy/test/kyber_bridge.ts deleted file mode 100644 index e46094d687..0000000000 --- a/contracts/asset-proxy/test/kyber_bridge.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { - blockchainTests, - constants, - expect, - getRandomInteger, - getRandomPortion, - randomAddress, - verifyEventsFromLogs, -} from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { DecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers'; - -// TODO(dorothy-zbornak): Tests need to be updated. -blockchainTests.resets.skip('KyberBridge unit tests', env => { - const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; - const FROM_TOKEN_DECIMALS = 6; - const TO_TOKEN_DECIMALS = 18; - const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); - const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); - const WETH_BASE = new BigNumber(10).pow(18); - const KYBER_RATE_BASE = WETH_BASE; - let testContract: TestKyberBridgeContract; - - before(async () => { - testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestKyberBridge, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('isValidSignature()', () => { - it('returns success bytes', async () => { - const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; - const result = await testContract - .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) - .callAsync(); - expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); - }); - }); - - describe('bridgeTransferFrom()', () => { - let fromTokenAddress: string; - let toTokenAddress: string; - let wethAddress: string; - - before(async () => { - wethAddress = await testContract.weth().callAsync(); - fromTokenAddress = await testContract.createToken(FROM_TOKEN_DECIMALS).callAsync(); - await testContract.createToken(FROM_TOKEN_DECIMALS).awaitTransactionSuccessAsync(); - toTokenAddress = await testContract.createToken(TO_TOKEN_DECIMALS).callAsync(); - await testContract.createToken(TO_TOKEN_DECIMALS).awaitTransactionSuccessAsync(); - }); - - const STATIC_KYBER_TRADE_ARGS = { - maxBuyTokenAmount: constants.MAX_UINT256, - walletId: constants.NULL_ADDRESS, - }; - - interface TransferFromOpts { - toTokenAddress: string; - fromTokenAddress: string; - toAddress: string; - // Amount to pass into `bridgeTransferFrom()` - amount: BigNumber; - // Amount to convert in `trade()`. - fillAmount: BigNumber; - // Token balance of the bridge. - fromTokenBalance: BigNumber; - } - - interface TransferFromResult { - opts: TransferFromOpts; - result: string; - logs: DecodedLogs; - } - - function createTransferFromOpts(opts?: Partial): TransferFromOpts { - const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); - return { - fromTokenAddress, - toTokenAddress, - amount, - toAddress: randomAddress(), - fillAmount: getRandomPortion(amount), - fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), - ...opts, - }; - } - - async function withdrawToAsync(opts?: Partial): Promise { - const _opts = createTransferFromOpts(opts); - // Fund the contract with input tokens. - await testContract - .grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance) - .awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance }); - // Fund the contract with output tokens. - await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({ - value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT, - }); - // Call bridgeTransferFrom(). - const bridgeTransferFromFn = testContract.bridgeTransferFrom( - // Output token - _opts.toTokenAddress, - // Random maker address. - randomAddress(), - // Recipient address. - _opts.toAddress, - // Transfer amount. - _opts.amount, - // ABI-encode the input token address as the bridge data. - hexUtils.concat(hexUtils.leftPad(_opts.fromTokenAddress), hexUtils.leftPad(32), hexUtils.leftPad(0)), - ); - const result = await bridgeTransferFromFn.callAsync(); - const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); - return { - opts: _opts, - result, - logs: (logs as any) as DecodedLogs, - }; - } - - function getMinimumConversionRate(opts: TransferFromOpts): BigNumber { - const fromBase = opts.fromTokenAddress === wethAddress ? WETH_BASE : FROM_TOKEN_BASE; - const toBase = opts.toTokenAddress === wethAddress ? WETH_BASE : TO_TOKEN_BASE; - return opts.amount - .div(toBase) - .div(opts.fromTokenBalance.div(fromBase)) - .times(KYBER_RATE_BASE) - .integerValue(BigNumber.ROUND_DOWN); - } - - it('returns magic bytes on success', async () => { - const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge; - const { result } = await withdrawToAsync(); - expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA); - }); - - it('can trade token -> token', async () => { - const { opts, logs } = await withdrawToAsync(); - verifyEventsFromLogs( - logs, - [ - { - sellTokenAddress: opts.fromTokenAddress, - buyTokenAddress: opts.toTokenAddress, - sellAmount: opts.fromTokenBalance, - recipientAddress: opts.toAddress, - minConversionRate: getMinimumConversionRate(opts), - msgValue: constants.ZERO_AMOUNT, - ...STATIC_KYBER_TRADE_ARGS, - }, - ], - TestKyberBridgeEvents.KyberBridgeTrade, - ); - }); - - it('can trade token -> ETH', async () => { - const { opts, logs } = await withdrawToAsync({ - toTokenAddress: wethAddress, - }); - verifyEventsFromLogs( - logs, - [ - { - sellTokenAddress: opts.fromTokenAddress, - buyTokenAddress: KYBER_ETH_ADDRESS, - sellAmount: opts.fromTokenBalance, - recipientAddress: testContract.address, - minConversionRate: getMinimumConversionRate(opts), - msgValue: constants.ZERO_AMOUNT, - ...STATIC_KYBER_TRADE_ARGS, - }, - ], - TestKyberBridgeEvents.KyberBridgeTrade, - ); - }); - - it('can trade ETH -> token', async () => { - const { opts, logs } = await withdrawToAsync({ - fromTokenAddress: wethAddress, - }); - verifyEventsFromLogs( - logs, - [ - { - sellTokenAddress: KYBER_ETH_ADDRESS, - buyTokenAddress: opts.toTokenAddress, - sellAmount: opts.fromTokenBalance, - recipientAddress: opts.toAddress, - minConversionRate: getMinimumConversionRate(opts), - msgValue: opts.fromTokenBalance, - ...STATIC_KYBER_TRADE_ARGS, - }, - ], - TestKyberBridgeEvents.KyberBridgeTrade, - ); - }); - - it('does nothing if bridge has no token balance', async () => { - const { logs } = await withdrawToAsync({ - fromTokenBalance: constants.ZERO_AMOUNT, - }); - expect(logs).to.be.length(0); - }); - - it('only transfers the token if trading the same token', async () => { - const { opts, logs } = await withdrawToAsync({ - toTokenAddress: fromTokenAddress, - }); - verifyEventsFromLogs( - logs, - [ - { - tokenAddress: fromTokenAddress, - ownerAddress: testContract.address, - recipientAddress: opts.toAddress, - amount: opts.fromTokenBalance, - }, - ], - TestKyberBridgeEvents.KyberBridgeTokenTransfer, - ); - }); - - it('grants Kyber an allowance when selling non-WETH', async () => { - const { opts, logs } = await withdrawToAsync(); - verifyEventsFromLogs( - logs, - [ - { - tokenAddress: opts.fromTokenAddress, - ownerAddress: testContract.address, - spenderAddress: testContract.address, - allowance: constants.MAX_UINT256, - }, - ], - TestKyberBridgeEvents.KyberBridgeTokenApprove, - ); - }); - - it('does not grant Kyber an allowance when selling WETH', async () => { - const { logs } = await withdrawToAsync({ - fromTokenAddress: wethAddress, - }); - verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove); - }); - - it('withdraws WETH and passes it to Kyber when selling WETH', async () => { - const { opts, logs } = await withdrawToAsync({ - fromTokenAddress: wethAddress, - }); - expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw); - expect(logs[0].args).to.deep.eq({ - ownerAddress: testContract.address, - amount: opts.fromTokenBalance, - }); - expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade); - expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance); - }); - - it('wraps WETH and transfers it to the recipient when buyng WETH', async () => { - const { opts, logs } = await withdrawToAsync({ - toTokenAddress: wethAddress, - }); - expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove); - expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress); - expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade); - expect(logs[1].args.recipientAddress).to.eq(testContract.address); - expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit); - expect(logs[2].args).to.deep.eq({ - msgValue: opts.fillAmount, - ownerAddress: testContract.address, - amount: opts.fillAmount, - }); - }); - }); -}); diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts deleted file mode 100644 index 7965f39546..0000000000 --- a/contracts/asset-proxy/test/proxies.ts +++ /dev/null @@ -1,1557 +0,0 @@ -import { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; -import { - artifacts as erc20Artifacts, - DummyERC20TokenContract, - DummyERC20TokenTransferEventArgs, - DummyMultipleReturnERC20TokenContract, - DummyNoReturnERC20TokenContract, -} from '@0x/contracts-erc20'; -import { - artifacts as erc721Artifacts, - DummyERC721ReceiverContract, - DummyERC721TokenContract, -} from '@0x/contracts-erc721'; -import { - chaiSetup, - constants, - expectTransactionFailedAsync, - expectTransactionFailedWithoutReasonAsync, - LogDecoder, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-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 { - encodeERC1155AssetData, - encodeERC20AssetData, - encodeERC721AssetData, - encodeMultiAssetData, -} from '../src/asset_data'; -import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper'; -import { ERC20Wrapper } from '../src/erc20_wrapper'; -import { ERC721Wrapper } from '../src/erc721_wrapper'; -import { ERC1155ProxyContract, ERC20ProxyContract, ERC721ProxyContract } from '../src/wrappers'; - -import { artifacts } from './artifacts'; -import { IAssetProxyContract, MultiAssetProxyContract } from './wrappers'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider); - -// tslint:disable:no-unnecessary-type-assertion -describe('Asset Transfer Proxies', () => { - let owner: string; - let notAuthorized: string; - let authorized: string; - let fromAddress: string; - let toAddress: string; - - let erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: DummyERC20TokenContract; - let erc721TokenA: DummyERC721TokenContract; - let erc721TokenB: DummyERC721TokenContract; - let erc721Receiver: DummyERC721ReceiverContract; - let erc20Proxy: ERC20ProxyContract; - let erc721Proxy: ERC721ProxyContract; - let noReturnErc20Token: DummyNoReturnERC20TokenContract; - let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract; - let multiAssetProxy: MultiAssetProxyContract; - - let erc20Wrapper: ERC20Wrapper; - let erc721Wrapper: ERC721Wrapper; - let erc721AFromTokenId: BigNumber; - let erc721BFromTokenId: BigNumber; - - let erc1155Proxy: ERC1155ProxyContract; - let erc1155ProxyWrapper: ERC1155ProxyWrapper; - let erc1155Contract: ERC1155MintableContract; - let erc1155Contract2: ERC1155MintableContract; - let erc1155Wrapper: Erc1155Wrapper; - let erc1155Wrapper2: Erc1155Wrapper; - let erc1155FungibleTokens: BigNumber[]; - let erc1155NonFungibleTokensOwnedBySpender: BigNumber[]; - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, notAuthorized, authorized, fromAddress, toAddress] = _.slice(accounts, 0, 5)); - - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - - // Deploy AssetProxies - erc20Proxy = await erc20Wrapper.deployProxyAsync(); - erc721Proxy = await erc721Wrapper.deployProxyAsync(); - multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( - artifacts.MultiAssetProxy, - provider, - txDefaults, - artifacts, - ); - - // Configure ERC20Proxy - await erc20Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - await erc20Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure ERC721Proxy - await erc721Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - await erc721Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure ERC115Proxy - erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); - erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); - await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - await erc1155Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure MultiAssetProxy - await multiAssetProxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - await multiAssetProxy.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - await multiAssetProxy.registerAssetProxy(erc721Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - await multiAssetProxy.registerAssetProxy(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Deploy and configure ERC20 tokens - const numDummyErc20ToDeploy = 2; - [erc20TokenA, erc20TokenB] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyNoReturnERC20Token, - provider, - txDefaults, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - multipleReturnErc20Token = await DummyMultipleReturnERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyMultipleReturnERC20Token, - provider, - txDefaults, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - - await erc20Wrapper.setBalancesAndAllowancesAsync(); - await noReturnErc20Token.setBalance(fromAddress, constants.INITIAL_ERC20_BALANCE).awaitTransactionSuccessAsync({ - from: owner, - }); - await noReturnErc20Token - .approve(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE) - .awaitTransactionSuccessAsync({ from: fromAddress }); - await multipleReturnErc20Token - .setBalance(fromAddress, constants.INITIAL_ERC20_BALANCE) - .awaitTransactionSuccessAsync({ - from: owner, - }); - await multipleReturnErc20Token - .approve(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE) - .awaitTransactionSuccessAsync({ from: fromAddress }); - - // Deploy and configure ERC721 tokens and receiver - [erc721TokenA, erc721TokenB] = await erc721Wrapper.deployDummyTokensAsync(); - erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync( - erc721Artifacts.DummyERC721Receiver, - provider, - txDefaults, - artifacts, - ); - - await erc721Wrapper.setBalancesAndAllowancesAsync(); - const erc721Balances = await erc721Wrapper.getBalancesAsync(); - erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0]; - erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0]; - - // Deploy & configure ERC1155 tokens and receiver - [erc1155Wrapper, erc1155Wrapper2] = await erc1155ProxyWrapper.deployDummyContractsAsync(); - erc1155Contract = erc1155Wrapper.getContract(); - erc1155Contract2 = erc1155Wrapper2.getContract(); - await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); - erc1155FungibleTokens = erc1155ProxyWrapper.getFungibleTokenIds(); - const nonFungibleTokens = erc1155ProxyWrapper.getNonFungibleTokenIds(); - const tokenBalances = await erc1155ProxyWrapper.getBalancesAsync(); - erc1155NonFungibleTokensOwnedBySpender = []; - _.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => { - const nonFungibleTokenAsString = nonFungibleToken.toString(); - const nonFungibleTokenHeldBySpender = - tokenBalances.nonFungible[fromAddress][erc1155Contract.address][nonFungibleTokenAsString][0]; - erc1155NonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); - }); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('ERC20Proxy', () => { - 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, - }), - ); - }); - it('should have an id of 0xf47261b0', async () => { - const proxyId = await erc20Proxy.getProxyId().callAsync(); - const expectedProxyId = '0xf47261b0'; - expect(proxyId).to.equal(expectedProxyId); - }); - describe('transferFrom', () => { - it('should successfully transfer tokens', async () => { - // Construct ERC20 asset data - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - // Perform a transfer from fromAddress to toAddress - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const amount = new BigNumber(10); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(amount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(amount), - ); - }); - - it('should successfully transfer tokens that do not return a value', async () => { - // Construct ERC20 asset data - const encodedAssetData = encodeERC20AssetData(noReturnErc20Token.address); - // Perform a transfer from fromAddress to toAddress - const initialFromBalance = await noReturnErc20Token.balanceOf(fromAddress).callAsync(); - const initialToBalance = await noReturnErc20Token.balanceOf(toAddress).callAsync(); - const amount = new BigNumber(10); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newFromBalance = await noReturnErc20Token.balanceOf(fromAddress).callAsync(); - const newToBalance = await noReturnErc20Token.balanceOf(toAddress).callAsync(); - expect(newFromBalance).to.be.bignumber.equal(initialFromBalance.minus(amount)); - expect(newToBalance).to.be.bignumber.equal(initialToBalance.plus(amount)); - }); - - it('should successfully transfer tokens and ignore extra assetData', async () => { - // Construct ERC20 asset data - const extraData = '0102030405060708'; - const encodedAssetData = `${encodeERC20AssetData(erc20TokenA.address)}${extraData}`; - // Perform a transfer from fromAddress to toAddress - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const amount = new BigNumber(10); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(amount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(amount), - ); - }); - - it('should do nothing if transferring 0 amount of a token', async () => { - // Construct ERC20 asset data - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - // Perform a transfer from fromAddress to toAddress - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const amount = new BigNumber(0); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address], - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address], - ); - }); - - it('should revert if allowances are too low', async () => { - // Construct ERC20 asset data - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - // Create allowance less than transfer amount. Set allowance on proxy. - const allowance = new BigNumber(0); - const amount = new BigNumber(10); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await erc20TokenA.approve(erc20Proxy.address, allowance).awaitTransactionSuccessAsync({ - from: fromAddress, - }); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - // Perform a transfer; expect this to fail. - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - RevertReason.TransferFailed, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances).to.deep.equal(erc20Balances); - }); - - it('should revert if allowances are too low and token does not return a value', async () => { - // Construct ERC20 asset data - const encodedAssetData = 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(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await noReturnErc20Token.approve(erc20Proxy.address, allowance).awaitTransactionSuccessAsync({ - from: fromAddress, - }); - const initialFromBalance = await noReturnErc20Token.balanceOf(fromAddress).callAsync(); - const initialToBalance = await noReturnErc20Token.balanceOf(toAddress).callAsync(); - // Perform a transfer; expect this to fail. - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - RevertReason.TransferFailed, - ); - const newFromBalance = await noReturnErc20Token.balanceOf(fromAddress).callAsync(); - const newToBalance = await noReturnErc20Token.balanceOf(toAddress).callAsync(); - expect(newFromBalance).to.be.bignumber.equal(initialFromBalance); - expect(newToBalance).to.be.bignumber.equal(initialToBalance); - }); - - it('should revert if caller is not authorized', async () => { - // Construct ERC20 asset data - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(10); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - 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 revert if token returns more than 32 bytes', async () => { - // Construct ERC20 asset data - const encodedAssetData = encodeERC20AssetData(multipleReturnErc20Token.address); - const amount = new BigNumber(10); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - const initialFromBalance = await multipleReturnErc20Token.balanceOf(fromAddress).callAsync(); - const initialToBalance = await multipleReturnErc20Token.balanceOf(toAddress).callAsync(); - // Perform a transfer; expect this to fail. - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc20Proxy.address, - data, - from: authorized, - }), - RevertReason.TransferFailed, - ); - const newFromBalance = await multipleReturnErc20Token.balanceOf(fromAddress).callAsync(); - const newToBalance = await multipleReturnErc20Token.balanceOf(toAddress).callAsync(); - expect(newFromBalance).to.be.bignumber.equal(initialFromBalance); - expect(newToBalance).to.be.bignumber.equal(initialToBalance); - }); - }); - }); - - describe('ERC721Proxy', () => { - 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, - }), - ); - }); - it('should have an id of 0x02571792', async () => { - const proxyId = await erc721Proxy.getProxyId().callAsync(); - const expectedProxyId = '0x02571792'; - expect(proxyId).to.equal(expectedProxyId); - }); - describe('transferFrom', () => { - it('should successfully transfer tokens', async () => { - // Construct ERC721 asset data - const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(1); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress); - }); - - it('should successfully transfer tokens and ignore extra assetData', async () => { - // Construct ERC721 asset data - const extraData = '0102030405060708'; - const encodedAssetData = `${encodeERC721AssetData( - erc721TokenA.address, - erc721AFromTokenId, - )}${extraData}`; - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(1); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.bignumber.equal(toAddress); - }); - - it('should not call onERC721Received when transferring to a smart contract', async () => { - // Construct ERC721 asset data - const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(1); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, erc721Receiver.address, amount) - .getABIEncodedTransactionData(); - const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...erc721Artifacts }); - const tx = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: authorized, - gas: constants.MAX_TRANSFER_FROM_GAS, - }), - ); - // Verify that no log was emitted by erc721 receiver - expect(tx.logs.length).to.be.equal(1); - // Verify transfer was successful - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.bignumber.equal(erc721Receiver.address); - }); - - it('should revert if transferring 0 amount of a token', async () => { - // Construct ERC721 asset data - const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(0); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: authorized, - }), - RevertReason.InvalidAmount, - ); - const newOwner = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwner).to.be.equal(ownerFromAsset); - }); - - it('should revert if transferring > 1 amount of a token', async () => { - // Construct ERC721 asset data - const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(500); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: authorized, - }), - RevertReason.InvalidAmount, - ); - const newOwner = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwner).to.be.equal(ownerFromAsset); - }); - - it('should revert if allowances are too low', async () => { - // Construct ERC721 asset data - const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Remove blanket transfer approval for fromAddress. - await erc721TokenA.setApprovalForAll(erc721Proxy.address, false).awaitTransactionSuccessAsync({ - from: fromAddress, - }); - // Remove token transfer approval for fromAddress. - await erc721TokenA.approve(constants.NULL_ADDRESS, erc721AFromTokenId).awaitTransactionSuccessAsync({ - from: fromAddress, - }); - // Perform a transfer; expect this to fail. - const amount = new BigNumber(1); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: authorized, - }), - RevertReason.TransferFailed, - ); - const newOwner = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwner).to.be.equal(ownerFromAsset); - }); - - it('should revert if caller is not authorized', async () => { - // Construct ERC721 asset data - const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - // Verify pre-condition - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const amount = new BigNumber(1); - const data = assetProxyInterface - .transferFrom(encodedAssetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc721Proxy.address, - data, - from: notAuthorized, - }), - RevertReason.SenderNotAuthorized, - ); - const newOwner = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwner).to.be.equal(ownerFromAsset); - }); - }); - }); - describe('MultiAssetProxy', () => { - it('should revert if undefined function is called', async () => { - const undefinedSelector = '0x01020304'; - await expectTransactionFailedWithoutReasonAsync( - web3Wrapper.sendTransactionAsync({ - from: owner, - to: multiAssetProxy.address, - value: constants.ZERO_AMOUNT, - data: undefinedSelector, - }), - ); - }); - it('should have an id of 0x94cfcdd7', async () => { - const proxyId = await multiAssetProxy.getProxyId().callAsync(); - // first 4 bytes of `keccak256('MultiAsset(uint256[],bytes[])')` - const expectedProxyId = '0x94cfcdd7'; - expect(proxyId).to.equal(expectedProxyId); - }); - describe('transferFrom', () => { - it('should transfer a single ERC20 token', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const amounts = [erc20Amount]; - const nestedAssetData = [erc20AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalAmount = inputAmount.times(erc20Amount); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount), - ); - }); - it('should dispatch an ERC20 transfer when input amount is 0', async () => { - const inputAmount = constants.ZERO_AMOUNT; - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const amounts = [erc20Amount]; - const nestedAssetData = [erc20AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...erc20Artifacts }); - const tx = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - ); - expect(tx.logs.length).to.be.equal(1); - const log = tx.logs[0] as LogWithDecodedArgs; - const transferEventName = 'Transfer'; - expect(log.event).to.equal(transferEventName); - expect(log.args._value).to.be.bignumber.equal(constants.ZERO_AMOUNT); - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances).to.deep.equal(erc20Balances); - }); - it('should successfully transfer multiple of the same ERC20 token', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount1 = new BigNumber(10); - const erc20Amount2 = new BigNumber(20); - const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); - const erc20AssetData2 = encodeERC20AssetData(erc20TokenA.address); - const amounts = [erc20Amount1, erc20Amount2]; - const nestedAssetData = [erc20AssetData1, erc20AssetData2]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalAmount = inputAmount.times(erc20Amount1).plus(inputAmount.times(erc20Amount2)); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount), - ); - }); - it('should successfully transfer multiple different ERC20 tokens', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount1 = new BigNumber(10); - const erc20Amount2 = new BigNumber(20); - const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); - const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address); - const amounts = [erc20Amount1, erc20Amount2]; - const nestedAssetData = [erc20AssetData1, erc20AssetData2]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalErc20AAmount = inputAmount.times(erc20Amount1); - const totalErc20BAmount = inputAmount.times(erc20Amount2); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalErc20AAmount), - ); - expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount), - ); - expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenB.address].plus(totalErc20BAmount), - ); - }); - it('should transfer a single ERC721 token', async () => { - const inputAmount = new BigNumber(1); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc721Amount]; - const nestedAssetData = [erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.equal(toAddress); - }); - it('should successfully transfer multiple of the same ERC721 token', async () => { - const erc721Balances = await erc721Wrapper.getBalancesAsync(); - const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1]; - const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const erc721AssetData2 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2); - const inputAmount = new BigNumber(1); - const erc721Amount = new BigNumber(1); - const amounts = [erc721Amount, erc721Amount]; - const nestedAssetData = [erc721AssetData1, erc721AssetData2]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const ownerFromAsset1 = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset1).to.be.equal(fromAddress); - const ownerFromAsset2 = await erc721TokenA.ownerOf(erc721AFromTokenId2).callAsync(); - expect(ownerFromAsset2).to.be.equal(fromAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - gas: constants.MAX_TRANSFER_FROM_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newOwnerFromAsset1 = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - const newOwnerFromAsset2 = await erc721TokenA.ownerOf(erc721AFromTokenId2).callAsync(); - expect(newOwnerFromAsset1).to.be.equal(toAddress); - expect(newOwnerFromAsset2).to.be.equal(toAddress); - }); - it('should successfully transfer multiple different ERC721 tokens', async () => { - const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const erc721AssetData2 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId); - const inputAmount = new BigNumber(1); - const erc721Amount = new BigNumber(1); - const amounts = [erc721Amount, erc721Amount]; - const nestedAssetData = [erc721AssetData1, erc721AssetData2]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const ownerFromAsset1 = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset1).to.be.equal(fromAddress); - const ownerFromAsset2 = await erc721TokenB.ownerOf(erc721BFromTokenId).callAsync(); - expect(ownerFromAsset2).to.be.equal(fromAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - gas: constants.MAX_TRANSFER_FROM_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newOwnerFromAsset1 = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - const newOwnerFromAsset2 = await erc721TokenB.ownerOf(erc721BFromTokenId).callAsync(); - expect(newOwnerFromAsset1).to.be.equal(toAddress); - expect(newOwnerFromAsset2).to.be.equal(toAddress); - }); - it('should transfer a fungible ERC1155 token', async () => { - // setup test parameters - const tokenHolders = [fromAddress, toAddress]; - const tokensToTransfer = erc1155FungibleTokens.slice(0, 1); - const valuesToTransfer = [new BigNumber(25)]; - const valueMultiplier = new BigNumber(23); - const receiverCallbackData = '0x0102030405'; - // check balances before transfer - const expectedInitialBalances = [ - // from - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - // to - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // encode erc1155 asset data - const erc1155AssetData = encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // encode multi-asset data - const multiAssetAmount = new BigNumber(5); - const amounts = [valueMultiplier]; - const nestedAssetData = [erc1155AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) - .getABIEncodedTransactionData(); - // execute transfer - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances - const totalValueTransferred = valuesToTransfer[0].times(valueMultiplier).times(multiAssetAmount); - const expectedFinalBalances = [ - // from - expectedInitialBalances[0].minus(totalValueTransferred), - // to - expectedInitialBalances[1].plus(totalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer multiple fungible tokens of the same ERC1155 contract', async () => { - // setup test parameters - const tokenHolders = [fromAddress, toAddress]; - const tokensToTransfer = erc1155FungibleTokens.slice(0, 3); - const valuesToTransfer = [new BigNumber(25), new BigNumber(35), new BigNumber(45)]; - const valueMultiplier = new BigNumber(23); - const receiverCallbackData = '0x0102030405'; - // check balances before transfer - const expectedInitialBalances = [ - // from - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - // to - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // encode erc1155 asset data - const erc1155AssetData = encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // encode multi-asset data - const multiAssetAmount = new BigNumber(5); - const amounts = [valueMultiplier]; - const nestedAssetData = [erc1155AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) - .getABIEncodedTransactionData(); - // execute transfer - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier).times(multiAssetAmount); - }); - const expectedFinalBalances = [ - // from - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].minus(totalValuesTransferred[1]), - expectedInitialBalances[2].minus(totalValuesTransferred[2]), - // to - expectedInitialBalances[3].plus(totalValuesTransferred[0]), - expectedInitialBalances[4].plus(totalValuesTransferred[1]), - expectedInitialBalances[5].plus(totalValuesTransferred[2]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer multiple fungible/non-fungible tokens of the same ERC1155 contract', async () => { - // setup test parameters - const tokenHolders = [fromAddress, toAddress]; - const fungibleTokensToTransfer = erc1155FungibleTokens.slice(0, 1); - const nonFungibleTokensToTransfer = erc1155NonFungibleTokensOwnedBySpender.slice(0, 1); - const tokensToTransfer = fungibleTokensToTransfer.concat(nonFungibleTokensToTransfer); - const valuesToTransfer = [new BigNumber(25), new BigNumber(1)]; - const valueMultiplier = new BigNumber(1); - const receiverCallbackData = '0x0102030405'; - // check balances before transfer - const nftOwnerBalance = new BigNumber(1); - const nftNotOwnerBalance = new BigNumber(0); - const expectedInitialBalances = [ - // from - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - nftOwnerBalance, - // to - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // encode erc1155 asset data - const erc1155AssetData = encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // encode multi-asset data - const multiAssetAmount = new BigNumber(1); - const amounts = [valueMultiplier]; - const nestedAssetData = [erc1155AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) - .getABIEncodedTransactionData(); - // execute transfer - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(valueMultiplier).times(multiAssetAmount); - }); - const expectedFinalBalances = [ - // from - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].minus(totalValuesTransferred[1]), - // to - expectedInitialBalances[2].plus(totalValuesTransferred[0]), - expectedInitialBalances[3].plus(totalValuesTransferred[1]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - // TODO(dorothy-zbornak): Figure out why this test fails. - it.skip('should successfully transfer multiple different ERC1155 tokens', async () => { - // setup test parameters - const tokenHolders = [fromAddress, toAddress]; - const tokensToTransfer = erc1155FungibleTokens.slice(0, 1); - const valuesToTransfer = [new BigNumber(25)]; - const valueMultiplier = new BigNumber(23); - const receiverCallbackData = '0x0102030405'; - // check balances before transfer - const expectedInitialBalances = [ - // from - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - // to - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - await erc1155Wrapper2.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // encode erc1155 asset data - const erc1155AssetData1 = encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const erc1155AssetData2 = encodeERC1155AssetData( - erc1155Contract2.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // encode multi-asset data - const multiAssetAmount = new BigNumber(5); - const amounts = [valueMultiplier, valueMultiplier]; - const nestedAssetData = [erc1155AssetData1, erc1155AssetData2]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, multiAssetAmount) - .getABIEncodedTransactionData(); - // execute transfer - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances - const totalValueTransferred = valuesToTransfer[0].times(valueMultiplier).times(multiAssetAmount); - const expectedFinalBalances = [ - // from - expectedInitialBalances[0].minus(totalValueTransferred), - // to - expectedInitialBalances[1].plus(totalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - await erc1155Wrapper2.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer a combination of ERC20, ERC721, and ERC1155 tokens', async () => { - // setup test parameters - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const erc1155TokenHolders = [fromAddress, toAddress]; - const erc1155TokensToTransfer = erc1155FungibleTokens.slice(0, 1); - const erc1155ValuesToTransfer = [new BigNumber(25)]; - const erc1155Amount = new BigNumber(23); - const erc1155ReceiverCallbackData = '0x0102030405'; - const erc1155AssetData = encodeERC1155AssetData( - erc1155Contract.address, - erc1155TokensToTransfer, - erc1155ValuesToTransfer, - erc1155ReceiverCallbackData, - ); - const amounts = [erc20Amount, erc721Amount, erc1155Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData, erc1155AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - // check balances before transfer - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - const erc1155ExpectedInitialBalances = [ - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, - ]; - await erc1155Wrapper.assertBalancesAsync( - erc1155TokenHolders, - erc1155TokensToTransfer, - erc1155ExpectedInitialBalances, - ); - // execute transfer - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - gas: 1000000, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalAmount = inputAmount.times(erc20Amount); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount), - ); - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.equal(toAddress); - const erc1155TotalValueTransferred = erc1155ValuesToTransfer[0].times(erc1155Amount).times(inputAmount); - const expectedFinalBalances = [ - erc1155ExpectedInitialBalances[0].minus(erc1155TotalValueTransferred), - erc1155ExpectedInitialBalances[1].plus(erc1155TotalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync( - erc1155TokenHolders, - erc1155TokensToTransfer, - expectedFinalBalances, - ); - }); - it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalAmount = inputAmount.times(erc20Amount); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount), - ); - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.equal(toAddress); - }); - // TODO(dorothy-zbornak): Figure out why this test fails. - it.skip('should successfully transfer tokens and ignore extra assetData', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const extraData = '0102030405060708090001020304050607080900010203040506070809000102'; - const assetData = `${encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`; - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset).to.be.equal(fromAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalAmount = inputAmount.times(erc20Amount); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalAmount), - ); - const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(newOwnerFromAsset).to.be.equal(toAddress); - }); - it('should successfully transfer correct amounts when the `amount` > 1', async () => { - const inputAmount = new BigNumber(100); - const erc20Amount1 = new BigNumber(10); - const erc20Amount2 = new BigNumber(20); - const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); - const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address); - const amounts = [erc20Amount1, erc20Amount2]; - const nestedAssetData = [erc20AssetData1, erc20AssetData2]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalErc20AAmount = inputAmount.times(erc20Amount1); - const totalErc20BAmount = inputAmount.times(erc20Amount2); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalErc20AAmount), - ); - expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount), - ); - expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenB.address].plus(totalErc20BAmount), - ); - }); - it('should successfully transfer a large amount of tokens', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount1 = new BigNumber(10); - const erc20Amount2 = new BigNumber(20); - const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address); - const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address); - const erc721Amount = new BigNumber(1); - const erc721Balances = await erc721Wrapper.getBalancesAsync(); - const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1]; - const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1]; - const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const erc721AssetData2 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2); - const erc721AssetData3 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId); - const erc721AssetData4 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId2); - const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount]; - const nestedAssetData = [ - erc721AssetData1, - erc20AssetData1, - erc721AssetData2, - erc20AssetData2, - erc721AssetData3, - erc721AssetData4, - ]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const ownerFromAsset1 = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - expect(ownerFromAsset1).to.be.equal(fromAddress); - const ownerFromAsset2 = await erc721TokenA.ownerOf(erc721AFromTokenId2).callAsync(); - expect(ownerFromAsset2).to.be.equal(fromAddress); - const ownerFromAsset3 = await erc721TokenB.ownerOf(erc721BFromTokenId).callAsync(); - expect(ownerFromAsset3).to.be.equal(fromAddress); - const ownerFromAsset4 = await erc721TokenB.ownerOf(erc721BFromTokenId2).callAsync(); - expect(ownerFromAsset4).to.be.equal(fromAddress); - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - gas: constants.MAX_EXECUTE_TRANSACTION_GAS, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - const newOwnerFromAsset1 = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync(); - const newOwnerFromAsset2 = await erc721TokenA.ownerOf(erc721AFromTokenId2).callAsync(); - const newOwnerFromAsset3 = await erc721TokenB.ownerOf(erc721BFromTokenId).callAsync(); - const newOwnerFromAsset4 = await erc721TokenB.ownerOf(erc721BFromTokenId2).callAsync(); - expect(newOwnerFromAsset1).to.be.equal(toAddress); - expect(newOwnerFromAsset2).to.be.equal(toAddress); - expect(newOwnerFromAsset3).to.be.equal(toAddress); - expect(newOwnerFromAsset4).to.be.equal(toAddress); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const totalErc20AAmount = inputAmount.times(erc20Amount1); - const totalErc20BAmount = inputAmount.times(erc20Amount2); - expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount), - ); - expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenA.address].plus(totalErc20AAmount), - ); - expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal( - erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount), - ); - expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal( - erc20Balances[toAddress][erc20TokenB.address].plus(totalErc20BAmount), - ); - }); - it('should revert if a single transfer fails', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - // 2 is an invalid erc721 amount - const erc721Amount = new BigNumber(2); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - RevertReason.InvalidAmount, - ); - }); - it('should revert if an AssetProxy is not registered', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const invalidProxyId = '0x12345678'; - const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`; - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, invalidErc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - RevertReason.AssetProxyDoesNotExist, - ); - }); - it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - RevertReason.LengthMismatch, - ); - }); - it('should revert if amounts multiplication results in an overflow', async () => { - const inputAmount = new BigNumber(2).pow(128); - const erc20Amount = new BigNumber(2).pow(128); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const amounts = [erc20Amount]; - const nestedAssetData = [erc20AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - RevertReason.Uint256Overflow, - ); - }); - it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = '0x123456'; - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: authorized, - }), - RevertReason.LengthGreaterThan3Required, - ); - }); - it('should revert if caller is not authorized', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data, - from: notAuthorized, - }), - RevertReason.SenderNotAuthorized, - ); - }); - it('should revert if asset data overflows beyond the bounds of calldata', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - // append asset data to end of tx data with a length of 0x300 bytes, which will extend past actual calldata. - const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; - const invalidOffsetToAssetData = '00000000000000000000000000000000000000000000000000000000000002a0'; - const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304'; - const badData = `${data.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`; - // execute transfer - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data: badData, - from: authorized, - }), - RevertReason.InvalidAssetDataEnd, - ); - }); - it('should revert if asset data resolves to a location beyond the bounds of calldata', async () => { - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const data = assetProxyInterface - .transferFrom(assetData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; - const invalidOffsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000400'; - const badData = data.replace(offsetToAssetData, invalidOffsetToAssetData); - // execute transfer - // note that this triggers `InvalidAssetDataLength` because the length is zero, otherwise it would - // trigger `InvalidAssetDataEnd`. - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data: badData, - from: authorized, - }), - RevertReason.InvalidAssetDataLength, - ); - }); - it('should revert if length of assetData, excluding the selector, is not a multiple of 32', async () => { - // setup test parameters - const inputAmount = new BigNumber(1); - const erc20Amount = new BigNumber(10); - const erc20AssetData = encodeERC20AssetData(erc20TokenA.address); - const erc721Amount = new BigNumber(1); - const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); - const amounts = [erc20Amount, erc721Amount]; - const nestedAssetData = [erc20AssetData, erc721AssetData]; - const assetData = encodeMultiAssetData(amounts, nestedAssetData); - const extraData = '01'; - const assetDataWithExtraData = `${assetData}${extraData}`; - const badData = assetProxyInterface - .transferFrom(assetDataWithExtraData, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - // execute transfer - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data: badData, - from: authorized, - }), - RevertReason.InvalidAssetDataLength, - ); - }); - it('should revert if length of assetData is less than 68 bytes', async () => { - // setup test parameters - const inputAmount = new BigNumber(1); - // we'll construct asset data that has a 4 byte selector plus - // 32 byte payload. This results in asset data that is 36 bytes - // long and will trigger the `invalid length` error. - // we must be sure to use a # of bytes that is still %32 - // so that we know the error is not triggered by another check in the code. - const zeros32Bytes = '0'.repeat(64); - const assetData36Bytes = `${AssetProxyId.MultiAsset}${zeros32Bytes}`; - const badData = assetProxyInterface - .transferFrom(assetData36Bytes, fromAddress, toAddress, inputAmount) - .getABIEncodedTransactionData(); - // execute transfer - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: multiAssetProxy.address, - data: badData, - from: authorized, - }), - RevertReason.InvalidAssetDataLength, - ); - }); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion -// tslint:disable:max-file-line-count diff --git a/contracts/asset-proxy/test/static_call_proxy.ts b/contracts/asset-proxy/test/static_call_proxy.ts deleted file mode 100644 index b7e776c18d..0000000000 --- a/contracts/asset-proxy/test/static_call_proxy.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { - chaiSetup, - constants, - expectTransactionFailedWithoutReasonAsync, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { AssetProxyId, RevertReason } from '@0x/types'; -import { AbiEncoder, BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import * as ethUtil from 'ethereumjs-util'; - -import { artifacts } from './artifacts'; - -import { - IAssetDataContract, - IAssetProxyContract, - StaticCallProxyContract, - TestStaticCallTargetContract, -} from './wrappers'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('StaticCallProxy', () => { - const amount = constants.ZERO_AMOUNT; - let fromAddress: string; - let toAddress: string; - - let assetDataInterface: IAssetDataContract; - let staticCallProxy: IAssetProxyContract; - let staticCallTarget: TestStaticCallTargetContract; - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - [fromAddress, toAddress] = accounts.slice(0, 2); - const staticCallProxyWithoutTransferFrom = await StaticCallProxyContract.deployFrom0xArtifactAsync( - artifacts.StaticCallProxy, - provider, - txDefaults, - artifacts, - ); - assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider); - staticCallProxy = new IAssetProxyContract( - staticCallProxyWithoutTransferFrom.address, - provider, - txDefaults, - {}, - StaticCallProxyContract.deployedBytecode, - ); - staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( - artifacts.TestStaticCallTarget, - provider, - txDefaults, - artifacts, - ); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('general', () => { - it('should revert if undefined function is called', async () => { - const undefinedSelector = '0x01020304'; - await expectTransactionFailedWithoutReasonAsync( - web3Wrapper.sendTransactionAsync({ - from: fromAddress, - to: staticCallProxy.address, - value: constants.ZERO_AMOUNT, - data: undefinedSelector, - }), - ); - }); - it('should have an id of 0xc339d10a', async () => { - const proxyId = await staticCallProxy.getProxyId().callAsync(); - const expectedProxyId = AssetProxyId.StaticCall; - expect(proxyId).to.equal(expectedProxyId); - }); - }); - describe('transferFrom', () => { - it('should revert if assetData lies outside the bounds of calldata', async () => { - const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - const txData = staticCallProxy - .transferFrom(assetData, fromAddress, toAddress, amount) - .getABIEncodedTransactionData(); - const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080'; - const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4); - const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32); - const invalidOffsetToAssetData = ethUtil.bufferToHex(paddedTxDataEndBuffer).slice(2); - const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304'; - const badTxData = `${txData.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`; - await expectTransactionFailedWithoutReasonAsync( - web3Wrapper.sendTransactionAsync({ - to: staticCallProxy.address, - from: fromAddress, - data: badTxData, - }), - ); - }); - it('should revert if the length of assetData is less than 100 bytes', async () => { - const staticCallData = constants.NULL_BYTES; - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData() - .slice(0, -128); - const assetDataByteLen = (assetData.length - 2) / 2; - expect((assetDataByteLen - 4) % 32).to.equal(0); - await expectTransactionFailedWithoutReasonAsync( - staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), - ); - }); - it('should revert if the offset to `staticCallData` points to outside of assetData', async () => { - const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060'; - const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4); - const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32); - const invalidOffsetToStaticCallData = ethUtil.bufferToHex(paddedAssetDataEndBuffer).slice(2); - const newStaticCallData = '0000000000000000000000000000000000000000000000000000000000000304'; - const badAssetData = `${assetData.replace( - offsetToStaticCallData, - invalidOffsetToStaticCallData, - )}${newStaticCallData}`; - await expectTransactionFailedWithoutReasonAsync( - staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(), - ); - }); - it('should revert if the callTarget attempts to write to state', async () => { - const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData(); - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - await expectTransactionFailedWithoutReasonAsync( - staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(), - ); - }); - it('should revert with data provided by the callTarget if the staticcall reverts', async () => { - const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - return expect( - staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), - ).to.revertWith(RevertReason.TargetNotEven); - }); - it('should revert if the hash of the output is different than expected expected', async () => { - const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData(); - const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); - const expectedResultHash = ethUtil.bufferToHex(ethUtil.keccak256(trueAsBuffer)); - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - return expect( - staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(), - ).to.revertWith(RevertReason.UnexpectedStaticCallResult); - }); - it('should be successful if a function call with no inputs and no outputs is successful', async () => { - const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData(); - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - await staticCallProxy - .transferFrom(assetData, fromAddress, toAddress, amount) - .awaitTransactionSuccessAsync(); - }); - it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => { - const staticCallData = '0x0102030405060708'; - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(toAddress, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - await staticCallProxy - .transferFrom(assetData, fromAddress, toAddress, amount) - .awaitTransactionSuccessAsync(); - }); - it('should be successful if a function call with one static input returns the correct value', async () => { - const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData(); - const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001'); - const expectedResultHash = ethUtil.bufferToHex(ethUtil.keccak256(trueAsBuffer)); - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - await staticCallProxy - .transferFrom(assetData, fromAddress, toAddress, amount) - .awaitTransactionSuccessAsync(); - }); - it('should be successful if a function with one dynamic input is successful', async () => { - const dynamicInput = '0x0102030405060708'; - const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData(); - const expectedResultHash = constants.KECCAK256_NULL; - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - await staticCallProxy - .transferFrom(assetData, fromAddress, toAddress, amount) - .awaitTransactionSuccessAsync(); - }); - it('should be successful if a function call returns a complex type', async () => { - const a = new BigNumber(1); - const b = new BigNumber(2); - const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData(); - const abiEncoder = new AbiEncoder.DynamicBytes({ - name: '', - type: 'bytes', - }); - const aHex = '0000000000000000000000000000000000000000000000000000000000000001'; - const bHex = '0000000000000000000000000000000000000000000000000000000000000002'; - const expectedResults = `${staticCallTarget.address}${aHex}${bHex}`; - const offset = '0000000000000000000000000000000000000000000000000000000000000020'; - const encodedExpectedResultWithOffset = `0x${offset}${abiEncoder.encode(expectedResults).slice(2)}`; - const expectedResultHash = ethUtil.bufferToHex( - ethUtil.keccak256(ethUtil.toBuffer(encodedExpectedResultWithOffset)), - ); - const assetData = assetDataInterface - .StaticCall(staticCallTarget.address, staticCallData, expectedResultHash) - .getABIEncodedTransactionData(); - await staticCallProxy - .transferFrom(assetData, fromAddress, toAddress, amount) - .awaitTransactionSuccessAsync(); - }); - }); -}); diff --git a/contracts/asset-proxy/test/uniswap_bridge.ts b/contracts/asset-proxy/test/uniswap_bridge.ts deleted file mode 100644 index 1b12c6caba..0000000000 --- a/contracts/asset-proxy/test/uniswap_bridge.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { - blockchainTests, - constants, - expect, - filterLogs, - filterLogsToArguments, - getRandomInteger, - Numberish, - randomAddress, -} from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { DecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { - TestUniswapBridgeContract, - TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs, - TestUniswapBridgeEvents as ContractEvents, - TestUniswapBridgeTokenApproveEventArgs as TokenApproveArgs, - TestUniswapBridgeTokenToEthSwapInputEventArgs as TokenToEthSwapInputArgs, - TestUniswapBridgeTokenToTokenTransferInputEventArgs as TokenToTokenTransferInputArgs, - TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs, - TestUniswapBridgeWethDepositEventArgs as WethDepositArgs, - TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs, -} from './wrappers'; - -blockchainTests.resets('UniswapBridge unit tests', env => { - let testContract: TestUniswapBridgeContract; - let wethTokenAddress: string; - - before(async () => { - testContract = await TestUniswapBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestUniswapBridge, - env.provider, - env.txDefaults, - artifacts, - ); - wethTokenAddress = await testContract.wethToken().callAsync(); - }); - - describe('isValidSignature()', () => { - it('returns success bytes', async () => { - const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; - const result = await testContract - .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) - .callAsync(); - expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); - }); - }); - - describe('bridgeTransferFrom()', () => { - interface WithdrawToOpts { - fromTokenAddress: string; - toTokenAddress: string; - fromTokenBalance: Numberish; - toAddress: string; - amount: Numberish; - exchangeRevertReason: string; - exchangeFillAmount: Numberish; - toTokenRevertReason: string; - fromTokenRevertReason: string; - } - - function createWithdrawToOpts(opts?: Partial): WithdrawToOpts { - return { - fromTokenAddress: constants.NULL_ADDRESS, - toTokenAddress: constants.NULL_ADDRESS, - fromTokenBalance: getRandomInteger(1, 1e18), - toAddress: randomAddress(), - amount: getRandomInteger(1, 1e18), - exchangeRevertReason: '', - exchangeFillAmount: getRandomInteger(1, 1e18), - toTokenRevertReason: '', - fromTokenRevertReason: '', - ...opts, - }; - } - - interface WithdrawToResult { - opts: WithdrawToOpts; - result: string; - logs: DecodedLogs; - blockTime: number; - } - - async function withdrawToAsync(opts?: Partial): Promise { - const _opts = createWithdrawToOpts(opts); - const callData = { value: new BigNumber(_opts.exchangeFillAmount) }; - // Create the "from" token and exchange. - const createFromTokenFn = testContract.createTokenAndExchange( - _opts.fromTokenAddress, - _opts.exchangeRevertReason, - ); - [_opts.fromTokenAddress] = await createFromTokenFn.callAsync(callData); - await createFromTokenFn.awaitTransactionSuccessAsync(callData); - - // Create the "to" token and exchange. - const createToTokenFn = testContract.createTokenAndExchange( - _opts.toTokenAddress, - _opts.exchangeRevertReason, - ); - [_opts.toTokenAddress] = await createToTokenFn.callAsync(callData); - await createToTokenFn.awaitTransactionSuccessAsync(callData); - - await testContract - .setTokenRevertReason(_opts.toTokenAddress, _opts.toTokenRevertReason) - .awaitTransactionSuccessAsync(); - await testContract - .setTokenRevertReason(_opts.fromTokenAddress, _opts.fromTokenRevertReason) - .awaitTransactionSuccessAsync(); - // Set the token balance for the token we're converting from. - await testContract.setTokenBalance(_opts.fromTokenAddress).awaitTransactionSuccessAsync({ - value: new BigNumber(_opts.fromTokenBalance), - }); - // Call bridgeTransferFrom(). - const bridgeTransferFromFn = testContract.bridgeTransferFrom( - // The "to" token address. - _opts.toTokenAddress, - // The "from" address. - randomAddress(), - // The "to" address. - _opts.toAddress, - // The amount to transfer to "to" - new BigNumber(_opts.amount), - // ABI-encoded "from" token address. - hexUtils.leftPad(_opts.fromTokenAddress), - ); - const result = await bridgeTransferFromFn.callAsync(); - const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); - return { - opts: _opts, - result, - logs: (receipt.logs as any) as DecodedLogs, - blockTime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), - }; - } - - async function getExchangeForTokenAsync(tokenAddress: string): Promise { - return testContract.getExchange(tokenAddress).callAsync(); - } - - it('returns magic bytes on success', async () => { - const { result } = await withdrawToAsync(); - expect(result).to.eq(AssetProxyId.ERC20Bridge); - }); - - it('just transfers tokens to `to` if the same tokens are in play', async () => { - const createTokenFn = await testContract.createTokenAndExchange(constants.NULL_ADDRESS, ''); - const [tokenAddress] = await createTokenFn.callAsync(); - await createTokenFn.awaitTransactionSuccessAsync(); - const { opts, result, logs } = await withdrawToAsync({ - fromTokenAddress: tokenAddress, - toTokenAddress: tokenAddress, - }); - expect(result).to.eq(AssetProxyId.ERC20Bridge); - const transfers = filterLogsToArguments(logs, ContractEvents.TokenTransfer); - expect(transfers.length).to.eq(1); - expect(transfers[0].token).to.eq(tokenAddress); - expect(transfers[0].from).to.eq(testContract.address); - expect(transfers[0].to).to.eq(opts.toAddress); - expect(transfers[0].amount).to.bignumber.eq(opts.amount); - }); - - describe('token -> token', () => { - it('calls `IUniswapExchange.tokenToTokenTransferInput()', async () => { - const { opts, logs, blockTime } = await withdrawToAsync(); - const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); - const calls = filterLogsToArguments( - logs, - ContractEvents.TokenToTokenTransferInput, - ); - expect(calls.length).to.eq(1); - expect(calls[0].exchange).to.eq(exchangeAddress); - expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance); - expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount); - expect(calls[0].minEthBought).to.bignumber.eq(1); - expect(calls[0].deadline).to.bignumber.eq(blockTime); - expect(calls[0].recipient).to.eq(opts.toAddress); - expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress); - }); - - it('sets allowance for "from" token', async () => { - const { opts, logs } = await withdrawToAsync(); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); - expect(approvals.length).to.eq(1); - expect(approvals[0].spender).to.eq(exchangeAddress); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('sets allowance for "from" token on subsequent calls', async () => { - const { opts } = await withdrawToAsync(); - const { logs } = await withdrawToAsync(opts); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); - expect(approvals.length).to.eq(1); - expect(approvals[0].spender).to.eq(exchangeAddress); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('fails if "from" token does not exist', async () => { - const tx = testContract - .bridgeTransferFrom( - randomAddress(), - randomAddress(), - randomAddress(), - getRandomInteger(1, 1e18), - hexUtils.leftPad(randomAddress()), - ) - .awaitTransactionSuccessAsync(); - return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); - }); - - it('fails if the exchange fails', async () => { - const revertReason = 'FOOBAR'; - const tx = withdrawToAsync({ - exchangeRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - }); - - describe('token -> ETH', () => { - it('calls `IUniswapExchange.tokenToEthSwapInput()`, `WETH.deposit()`, then `transfer()`', async () => { - const { opts, logs, blockTime } = await withdrawToAsync({ - toTokenAddress: wethTokenAddress, - }); - const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); - let calls: any = filterLogs(logs, ContractEvents.TokenToEthSwapInput); - expect(calls.length).to.eq(1); - expect(calls[0].args.exchange).to.eq(exchangeAddress); - expect(calls[0].args.tokensSold).to.bignumber.eq(opts.fromTokenBalance); - expect(calls[0].args.minEthBought).to.bignumber.eq(opts.amount); - expect(calls[0].args.deadline).to.bignumber.eq(blockTime); - calls = filterLogs( - logs.slice(calls[0].logIndex as number), - ContractEvents.WethDeposit, - ); - expect(calls.length).to.eq(1); - expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount); - calls = filterLogs( - logs.slice(calls[0].logIndex as number), - ContractEvents.TokenTransfer, - ); - expect(calls.length).to.eq(1); - expect(calls[0].args.token).to.eq(opts.toTokenAddress); - expect(calls[0].args.from).to.eq(testContract.address); - expect(calls[0].args.to).to.eq(opts.toAddress); - expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount); - }); - - it('sets allowance for "from" token', async () => { - const { opts, logs } = await withdrawToAsync({ - toTokenAddress: wethTokenAddress, - }); - const transfers = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); - expect(transfers.length).to.eq(1); - expect(transfers[0].spender).to.eq(exchangeAddress); - expect(transfers[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('sets allowance for "from" token on subsequent calls', async () => { - const { opts } = await withdrawToAsync({ - toTokenAddress: wethTokenAddress, - }); - const { logs } = await withdrawToAsync(opts); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress); - expect(approvals.length).to.eq(1); - expect(approvals[0].spender).to.eq(exchangeAddress); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('fails if "from" token does not exist', async () => { - const tx = testContract - .bridgeTransferFrom( - randomAddress(), - randomAddress(), - randomAddress(), - getRandomInteger(1, 1e18), - hexUtils.leftPad(wethTokenAddress), - ) - .awaitTransactionSuccessAsync(); - return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); - }); - - it('fails if `WETH.deposit()` fails', async () => { - const revertReason = 'FOOBAR'; - const tx = withdrawToAsync({ - toTokenAddress: wethTokenAddress, - toTokenRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - - it('fails if the exchange fails', async () => { - const revertReason = 'FOOBAR'; - const tx = withdrawToAsync({ - toTokenAddress: wethTokenAddress, - exchangeRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - }); - - describe('ETH -> token', () => { - it('calls `WETH.withdraw()`, then `IUniswapExchange.ethToTokenTransferInput()`', async () => { - const { opts, logs, blockTime } = await withdrawToAsync({ - fromTokenAddress: wethTokenAddress, - }); - const exchangeAddress = await getExchangeForTokenAsync(opts.toTokenAddress); - let calls: any = filterLogs(logs, ContractEvents.WethWithdraw); - expect(calls.length).to.eq(1); - expect(calls[0].args.amount).to.bignumber.eq(opts.fromTokenBalance); - calls = filterLogs( - logs.slice(calls[0].logIndex as number), - ContractEvents.EthToTokenTransferInput, - ); - expect(calls.length).to.eq(1); - expect(calls[0].args.exchange).to.eq(exchangeAddress); - expect(calls[0].args.minTokensBought).to.bignumber.eq(opts.amount); - expect(calls[0].args.deadline).to.bignumber.eq(blockTime); - expect(calls[0].args.recipient).to.eq(opts.toAddress); - }); - - it('does not set any allowance', async () => { - const { logs } = await withdrawToAsync({ - fromTokenAddress: wethTokenAddress, - }); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - expect(approvals).to.be.empty(''); - }); - - it('fails if "to" token does not exist', async () => { - const tx = testContract - .bridgeTransferFrom( - wethTokenAddress, - randomAddress(), - randomAddress(), - getRandomInteger(1, 1e18), - hexUtils.leftPad(randomAddress()), - ) - .awaitTransactionSuccessAsync(); - return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN'); - }); - - it('fails if the `WETH.withdraw()` fails', async () => { - const revertReason = 'FOOBAR'; - const tx = withdrawToAsync({ - fromTokenAddress: wethTokenAddress, - fromTokenRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - - it('fails if the exchange fails', async () => { - const revertReason = 'FOOBAR'; - const tx = withdrawToAsync({ - fromTokenAddress: wethTokenAddress, - exchangeRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - }); - }); -}); diff --git a/contracts/asset-proxy/test/uniswapv2_bridge.ts b/contracts/asset-proxy/test/uniswapv2_bridge.ts deleted file mode 100644 index 6e72b6115b..0000000000 --- a/contracts/asset-proxy/test/uniswapv2_bridge.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { - blockchainTests, - constants, - expect, - filterLogsToArguments, - getRandomInteger, - randomAddress, -} from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils'; -import { DecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; - -import { - TestUniswapV2BridgeContract, - TestUniswapV2BridgeEvents as ContractEvents, - TestUniswapV2BridgeSwapExactTokensForTokensInputEventArgs as SwapExactTokensForTokensArgs, - TestUniswapV2BridgeTokenApproveEventArgs as TokenApproveArgs, - TestUniswapV2BridgeTokenTransferEventArgs as TokenTransferArgs, -} from './wrappers'; - -blockchainTests.resets('UniswapV2 unit tests', env => { - const FROM_TOKEN_DECIMALS = 6; - const TO_TOKEN_DECIMALS = 18; - const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); - const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); - let testContract: TestUniswapV2BridgeContract; - - before(async () => { - testContract = await TestUniswapV2BridgeContract.deployFrom0xArtifactAsync( - artifacts.TestUniswapV2Bridge, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('isValidSignature()', () => { - it('returns success bytes', async () => { - const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; - const result = await testContract - .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) - .callAsync(); - expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); - }); - }); - - describe('bridgeTransferFrom()', () => { - interface TransferFromOpts { - tokenAddressesPath: string[]; - toAddress: string; - // Amount to pass into `bridgeTransferFrom()` - amount: BigNumber; - // Token balance of the bridge. - fromTokenBalance: BigNumber; - // Router reverts with this reason - routerRevertReason: string; - } - - interface TransferFromResult { - opts: TransferFromOpts; - result: string; - logs: DecodedLogs; - blocktime: number; - } - - function createTransferFromOpts(opts?: Partial): TransferFromOpts { - const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); - return { - tokenAddressesPath: Array(2).fill(constants.NULL_ADDRESS), - amount, - toAddress: randomAddress(), - fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), - routerRevertReason: '', - ...opts, - }; - } - - const bridgeDataEncoder = AbiEncoder.create('(address[])'); - - async function transferFromAsync(opts?: Partial): Promise { - const _opts = createTransferFromOpts(opts); - - for (let i = 0; i < _opts.tokenAddressesPath.length; i++) { - const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]); - _opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync(); - await createFromTokenFn.awaitTransactionSuccessAsync(); - } - - // Set the token balance for the token we're converting from. - await testContract - .setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance) - .awaitTransactionSuccessAsync(); - - // Set revert reason for the router. - await testContract.setRouterRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync(); - - // Call bridgeTransferFrom(). - const bridgeTransferFromFn = testContract.bridgeTransferFrom( - // Output token - _opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1], - // Random maker address. - randomAddress(), - // Recipient address. - _opts.toAddress, - // Transfer amount. - _opts.amount, - // ABI-encode the input token address as the bridge data. // FIXME - bridgeDataEncoder.encode([_opts.tokenAddressesPath]), - ); - const result = await bridgeTransferFromFn.callAsync(); - const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); - return { - opts: _opts, - result, - logs: (receipt.logs as any) as DecodedLogs, - blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), - }; - } - - it('returns magic bytes on success', async () => { - const { result } = await transferFromAsync(); - expect(result).to.eq(AssetProxyId.ERC20Bridge); - }); - - it('performs transfer when both tokens are the same', async () => { - const createTokenFn = testContract.createToken(constants.NULL_ADDRESS); - const tokenAddress = await createTokenFn.callAsync(); - await createTokenFn.awaitTransactionSuccessAsync(); - - const { opts, result, logs } = await transferFromAsync({ - tokenAddressesPath: [tokenAddress, tokenAddress], - }); - expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); - const transfers = filterLogsToArguments(logs, ContractEvents.TokenTransfer); - - expect(transfers.length).to.eq(1); - expect(transfers[0].token).to.eq(tokenAddress, 'input token address'); - expect(transfers[0].from).to.eq(testContract.address); - expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); - expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount'); - }); - - describe('token -> token', async () => { - it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => { - const { opts, result, logs, blocktime } = await transferFromAsync(); - expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); - const transfers = filterLogsToArguments( - logs, - ContractEvents.SwapExactTokensForTokensInput, - ); - - expect(transfers.length).to.eq(1); - expect(transfers[0].toTokenAddress).to.eq( - opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], - 'output token address', - ); - expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); - expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); - expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); - expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline'); - }); - - it('sets allowance for "from" token', async () => { - const { logs } = await transferFromAsync(); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const routerAddress = await testContract.getRouterAddress().callAsync(); - expect(approvals.length).to.eq(1); - expect(approvals[0].spender).to.eq(routerAddress); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('sets allowance for "from" token on subsequent calls', async () => { - const { opts } = await transferFromAsync(); - const { logs } = await transferFromAsync(opts); - const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); - const routerAddress = await testContract.getRouterAddress().callAsync(); - expect(approvals.length).to.eq(1); - expect(approvals[0].spender).to.eq(routerAddress); - expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('fails if the router fails', async () => { - const revertReason = 'FOOBAR'; - const tx = transferFromAsync({ - routerRevertReason: revertReason, - }); - return expect(tx).to.eventually.be.rejectedWith(revertReason); - }); - }); - describe('token -> token -> token', async () => { - it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => { - const { opts, result, logs, blocktime } = await transferFromAsync({ - tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS), - }); - expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); - const transfers = filterLogsToArguments( - logs, - ContractEvents.SwapExactTokensForTokensInput, - ); - - expect(transfers.length).to.eq(1); - expect(transfers[0].toTokenAddress).to.eq( - opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], - 'output token address', - ); - expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); - expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); - expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); - expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline'); - }); - }); - }); -}); diff --git a/contracts/asset-proxy/test/wrappers.ts b/contracts/asset-proxy/test/wrappers.ts deleted file mode 100644 index e289f39f64..0000000000 --- a/contracts/asset-proxy/test/wrappers.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/balancer_bridge'; -export * from '../test/generated-wrappers/bancor_bridge'; -export * from '../test/generated-wrappers/chai_bridge'; -export * from '../test/generated-wrappers/cream_bridge'; -export * from '../test/generated-wrappers/crypto_com_bridge'; -export * from '../test/generated-wrappers/curve_bridge'; -export * from '../test/generated-wrappers/d_o_d_o_bridge'; -export * from '../test/generated-wrappers/dex_forwarder_bridge'; -export * from '../test/generated-wrappers/dydx_bridge'; -export * from '../test/generated-wrappers/erc1155_proxy'; -export * from '../test/generated-wrappers/erc20_bridge_proxy'; -export * from '../test/generated-wrappers/erc20_proxy'; -export * from '../test/generated-wrappers/erc721_proxy'; -export * from '../test/generated-wrappers/eth2_dai_bridge'; -export * from '../test/generated-wrappers/i_asset_data'; -export * from '../test/generated-wrappers/i_asset_proxy'; -export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; -export * from '../test/generated-wrappers/i_authorizable'; -export * from '../test/generated-wrappers/i_balancer_pool'; -export * from '../test/generated-wrappers/i_bancor_network'; -export * from '../test/generated-wrappers/i_chai'; -export * from '../test/generated-wrappers/i_curve'; -export * from '../test/generated-wrappers/i_dydx'; -export * from '../test/generated-wrappers/i_dydx_bridge'; -export * from '../test/generated-wrappers/i_erc20_bridge'; -export * from '../test/generated-wrappers/i_eth2_dai'; -export * from '../test/generated-wrappers/i_gas_token'; -export * from '../test/generated-wrappers/i_kyber_network_proxy'; -export * from '../test/generated-wrappers/i_m_stable'; -export * from '../test/generated-wrappers/i_mooniswap'; -export * from '../test/generated-wrappers/i_shell'; -export * from '../test/generated-wrappers/i_uniswap_exchange'; -export * from '../test/generated-wrappers/i_uniswap_exchange_factory'; -export * from '../test/generated-wrappers/i_uniswap_v2_router01'; -export * from '../test/generated-wrappers/kyber_bridge'; -export * from '../test/generated-wrappers/m_stable_bridge'; -export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher'; -export * from '../test/generated-wrappers/mixin_authorizable'; -export * from '../test/generated-wrappers/mixin_gas_token'; -export * from '../test/generated-wrappers/mooniswap_bridge'; -export * from '../test/generated-wrappers/multi_asset_proxy'; -export * from '../test/generated-wrappers/ownable'; -export * from '../test/generated-wrappers/shell_bridge'; -export * from '../test/generated-wrappers/snow_swap_bridge'; -export * from '../test/generated-wrappers/static_call_proxy'; -export * from '../test/generated-wrappers/sushi_swap_bridge'; -export * from '../test/generated-wrappers/swerve_bridge'; -export * from '../test/generated-wrappers/test_bancor_bridge'; -export * from '../test/generated-wrappers/test_chai_bridge'; -export * from '../test/generated-wrappers/test_dex_forwarder_bridge'; -export * from '../test/generated-wrappers/test_dydx_bridge'; -export * from '../test/generated-wrappers/test_erc20_bridge'; -export * from '../test/generated-wrappers/test_eth2_dai_bridge'; -export * from '../test/generated-wrappers/test_kyber_bridge'; -export * from '../test/generated-wrappers/test_static_call_target'; -export * from '../test/generated-wrappers/test_uniswap_bridge'; -export * from '../test/generated-wrappers/test_uniswap_v2_bridge'; -export * from '../test/generated-wrappers/uniswap_bridge'; -export * from '../test/generated-wrappers/uniswap_v2_bridge'; diff --git a/contracts/asset-proxy/truffle-config.js b/contracts/asset-proxy/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/asset-proxy/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json deleted file mode 100644 index e6ee5945f4..0000000000 --- a/contracts/asset-proxy/tsconfig.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/BalancerBridge.json", - "generated-artifacts/BancorBridge.json", - "generated-artifacts/ChaiBridge.json", - "generated-artifacts/CreamBridge.json", - "generated-artifacts/CryptoComBridge.json", - "generated-artifacts/CurveBridge.json", - "generated-artifacts/DODOBridge.json", - "generated-artifacts/DexForwarderBridge.json", - "generated-artifacts/DydxBridge.json", - "generated-artifacts/ERC1155Proxy.json", - "generated-artifacts/ERC20BridgeProxy.json", - "generated-artifacts/ERC20Proxy.json", - "generated-artifacts/ERC721Proxy.json", - "generated-artifacts/Eth2DaiBridge.json", - "generated-artifacts/IAssetData.json", - "generated-artifacts/IAssetProxy.json", - "generated-artifacts/IAssetProxyDispatcher.json", - "generated-artifacts/IAuthorizable.json", - "generated-artifacts/IBalancerPool.json", - "generated-artifacts/IBancorNetwork.json", - "generated-artifacts/IChai.json", - "generated-artifacts/ICurve.json", - "generated-artifacts/IDydx.json", - "generated-artifacts/IDydxBridge.json", - "generated-artifacts/IERC20Bridge.json", - "generated-artifacts/IEth2Dai.json", - "generated-artifacts/IGasToken.json", - "generated-artifacts/IKyberNetworkProxy.json", - "generated-artifacts/IMStable.json", - "generated-artifacts/IMooniswap.json", - "generated-artifacts/IShell.json", - "generated-artifacts/IUniswapExchange.json", - "generated-artifacts/IUniswapExchangeFactory.json", - "generated-artifacts/IUniswapV2Router01.json", - "generated-artifacts/KyberBridge.json", - "generated-artifacts/MStableBridge.json", - "generated-artifacts/MixinAssetProxyDispatcher.json", - "generated-artifacts/MixinAuthorizable.json", - "generated-artifacts/MixinGasToken.json", - "generated-artifacts/MooniswapBridge.json", - "generated-artifacts/MultiAssetProxy.json", - "generated-artifacts/Ownable.json", - "generated-artifacts/ShellBridge.json", - "generated-artifacts/SnowSwapBridge.json", - "generated-artifacts/StaticCallProxy.json", - "generated-artifacts/SushiSwapBridge.json", - "generated-artifacts/SwerveBridge.json", - "generated-artifacts/TestBancorBridge.json", - "generated-artifacts/TestChaiBridge.json", - "generated-artifacts/TestDexForwarderBridge.json", - "generated-artifacts/TestDydxBridge.json", - "generated-artifacts/TestERC20Bridge.json", - "generated-artifacts/TestEth2DaiBridge.json", - "generated-artifacts/TestKyberBridge.json", - "generated-artifacts/TestStaticCallTarget.json", - "generated-artifacts/TestUniswapBridge.json", - "generated-artifacts/TestUniswapV2Bridge.json", - "generated-artifacts/UniswapBridge.json", - "generated-artifacts/UniswapV2Bridge.json", - "test/generated-artifacts/BalancerBridge.json", - "test/generated-artifacts/BancorBridge.json", - "test/generated-artifacts/ChaiBridge.json", - "test/generated-artifacts/CreamBridge.json", - "test/generated-artifacts/CryptoComBridge.json", - "test/generated-artifacts/CurveBridge.json", - "test/generated-artifacts/DODOBridge.json", - "test/generated-artifacts/DexForwarderBridge.json", - "test/generated-artifacts/DydxBridge.json", - "test/generated-artifacts/ERC1155Proxy.json", - "test/generated-artifacts/ERC20BridgeProxy.json", - "test/generated-artifacts/ERC20Proxy.json", - "test/generated-artifacts/ERC721Proxy.json", - "test/generated-artifacts/Eth2DaiBridge.json", - "test/generated-artifacts/IAssetData.json", - "test/generated-artifacts/IAssetProxy.json", - "test/generated-artifacts/IAssetProxyDispatcher.json", - "test/generated-artifacts/IAuthorizable.json", - "test/generated-artifacts/IBalancerPool.json", - "test/generated-artifacts/IBancorNetwork.json", - "test/generated-artifacts/IChai.json", - "test/generated-artifacts/ICurve.json", - "test/generated-artifacts/IDydx.json", - "test/generated-artifacts/IDydxBridge.json", - "test/generated-artifacts/IERC20Bridge.json", - "test/generated-artifacts/IEth2Dai.json", - "test/generated-artifacts/IGasToken.json", - "test/generated-artifacts/IKyberNetworkProxy.json", - "test/generated-artifacts/IMStable.json", - "test/generated-artifacts/IMooniswap.json", - "test/generated-artifacts/IShell.json", - "test/generated-artifacts/IUniswapExchange.json", - "test/generated-artifacts/IUniswapExchangeFactory.json", - "test/generated-artifacts/IUniswapV2Router01.json", - "test/generated-artifacts/KyberBridge.json", - "test/generated-artifacts/MStableBridge.json", - "test/generated-artifacts/MixinAssetProxyDispatcher.json", - "test/generated-artifacts/MixinAuthorizable.json", - "test/generated-artifacts/MixinGasToken.json", - "test/generated-artifacts/MooniswapBridge.json", - "test/generated-artifacts/MultiAssetProxy.json", - "test/generated-artifacts/Ownable.json", - "test/generated-artifacts/ShellBridge.json", - "test/generated-artifacts/SnowSwapBridge.json", - "test/generated-artifacts/StaticCallProxy.json", - "test/generated-artifacts/SushiSwapBridge.json", - "test/generated-artifacts/SwerveBridge.json", - "test/generated-artifacts/TestBancorBridge.json", - "test/generated-artifacts/TestChaiBridge.json", - "test/generated-artifacts/TestDexForwarderBridge.json", - "test/generated-artifacts/TestDydxBridge.json", - "test/generated-artifacts/TestERC20Bridge.json", - "test/generated-artifacts/TestEth2DaiBridge.json", - "test/generated-artifacts/TestKyberBridge.json", - "test/generated-artifacts/TestStaticCallTarget.json", - "test/generated-artifacts/TestUniswapBridge.json", - "test/generated-artifacts/TestUniswapV2Bridge.json", - "test/generated-artifacts/UniswapBridge.json", - "test/generated-artifacts/UniswapV2Bridge.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/asset-proxy/tslint.json b/contracts/asset-proxy/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/asset-proxy/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/asset-proxy/typedoc-tsconfig.json b/contracts/asset-proxy/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/asset-proxy/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/broker/.npmignore b/contracts/broker/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/broker/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/broker/CHANGELOG.json b/contracts/broker/CHANGELOG.json deleted file mode 100644 index 45c714712b..0000000000 --- a/contracts/broker/CHANGELOG.json +++ /dev/null @@ -1,373 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "1.1.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "1.1.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "1.1.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "1.1.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "1.1.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "1.1.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "1.1.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "1.1.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "1.1.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "1.1.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "1.1.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "1.1.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "1.1.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "1.1.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "1.1.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "1.1.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "1.1.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "1.1.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "1.1.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "1.1.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "1.1.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "1.1.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "1.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "1.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "1.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "1.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "1.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "1.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "1.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "1.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "1.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "1.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.5", - "changes": [ - { - "note": "Fix broken tests.", - "pr": 2591 - } - ], - "timestamp": 1592969527 - }, - { - "timestamp": 1583220306, - "version": "1.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "1.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "1.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "1.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Added decoders for broker data", - "pr": 2484 - } - ], - "timestamp": 1581748629 - }, - { - "timestamp": 1581204851, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580988106, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Created package", - "pr": "2455" - } - ] - } -] diff --git a/contracts/broker/CHANGELOG.md b/contracts/broker/CHANGELOG.md deleted file mode 100644 index 11f61097ed..0000000000 --- a/contracts/broker/CHANGELOG.md +++ /dev/null @@ -1,170 +0,0 @@ - - -CHANGELOG - -## v1.1.37 - _August 16, 2021_ - - * Dependencies updated - -## v1.1.36 - _August 11, 2021_ - - * Dependencies updated - -## v1.1.35 - _August 6, 2021_ - - * Dependencies updated - -## v1.1.34 - _June 22, 2021_ - - * Dependencies updated - -## v1.1.33 - _June 11, 2021_ - - * Dependencies updated - -## v1.1.32 - _June 2, 2021_ - - * Dependencies updated - -## v1.1.31 - _May 25, 2021_ - - * Dependencies updated - -## v1.1.30 - _May 21, 2021_ - - * Dependencies updated - -## v1.1.29 - _May 5, 2021_ - - * Dependencies updated - -## v1.1.28 - _April 28, 2021_ - - * Dependencies updated - -## v1.1.27 - _April 1, 2021_ - - * Dependencies updated - -## v1.1.26 - _March 17, 2021_ - - * Dependencies updated - -## v1.1.25 - _February 24, 2021_ - - * Dependencies updated - -## v1.1.24 - _February 10, 2021_ - - * Dependencies updated - -## v1.1.23 - _January 26, 2021_ - - * Dependencies updated - -## v1.1.22 - _January 13, 2021_ - - * Dependencies updated - -## v1.1.21 - _January 4, 2021_ - - * Dependencies updated - -## v1.1.20 - _December 23, 2020_ - - * Dependencies updated - -## v1.1.19 - _December 17, 2020_ - - * Dependencies updated - -## v1.1.18 - _December 16, 2020_ - - * Dependencies updated - -## v1.1.17 - _December 9, 2020_ - - * Dependencies updated - -## v1.1.16 - _December 7, 2020_ - - * Dependencies updated - -## v1.1.15 - _December 3, 2020_ - - * Dependencies updated - -## v1.1.14 - _November 19, 2020_ - - * Dependencies updated - -## v1.1.13 - _November 13, 2020_ - - * Dependencies updated - -## v1.1.12 - _November 3, 2020_ - - * Dependencies updated - -## v1.1.11 - _November 3, 2020_ - - * Dependencies updated - -## v1.1.10 - _November 2, 2020_ - - * Dependencies updated - -## v1.1.9 - _October 28, 2020_ - - * Dependencies updated - -## v1.1.8 - _October 27, 2020_ - - * Dependencies updated - -## v1.1.7 - _October 21, 2020_ - - * Dependencies updated - -## v1.1.6 - _July 15, 2020_ - - * Dependencies updated - -## v1.1.5 - _June 24, 2020_ - - * Fix broken tests. (#2591) - -## v1.1.4 - _March 3, 2020_ - - * Dependencies updated - -## v1.1.3 - _February 27, 2020_ - - * Dependencies updated - -## v1.1.2 - _February 26, 2020_ - - * Dependencies updated - -## v1.1.1 - _February 25, 2020_ - - * Dependencies updated - -## v1.1.0 - _February 15, 2020_ - - * Added decoders for broker data (#2484) - -## v1.0.2 - _February 8, 2020_ - - * Dependencies updated - -## v1.0.1 - _February 6, 2020_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Created package (#2455) diff --git a/contracts/broker/DEPLOYS.json b/contracts/broker/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/broker/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/broker/README.md b/contracts/broker/README.md deleted file mode 100644 index 0ad06fb3d4..0000000000 --- a/contracts/broker/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## Broker - -This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-broker --save -``` - -## Bug bounty - -A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-broker yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-broker yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/broker/compiler.json b/contracts/broker/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/broker/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/broker/contracts/src/Broker.sol b/contracts/broker/contracts/src/Broker.sol deleted file mode 100644 index 023c74a4cd..0000000000 --- a/contracts/broker/contracts/src/Broker.sol +++ /dev/null @@ -1,314 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; -import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./interfaces/IBroker.sol"; -import "./interfaces/IPropertyValidator.sol"; -import "./libs/LibBrokerRichErrors.sol"; - - -// solhint-disable space-after-comma, var-name-mixedcase -contract Broker is - IBroker, - MixinWethUtils -{ - // Contract addresses - - // Address of the 0x Exchange contract - address internal EXCHANGE; - // Address of the 0x ERC1155 Asset Proxy contract - address internal ERC1155_PROXY; - - // The following storage variables are used to cache data for the duration of the transcation. - // They should always cleared at the end of the transaction. - - // Token IDs specified by the taker to be used to fill property-based orders. - uint256[] internal _cachedTokenIds; - // An index to the above array keeping track of which assets have been transferred. - uint256 internal _cacheIndex; - // The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to - // and from this address as the effectual taker of the orders. - address internal _sender; - - using LibSafeMath for uint256; - using LibBytes for bytes; - using LibAssetDataTransfer for bytes; - - /// @param exchange Address of the 0x Exchange contract. - /// @param exchange Address of the Wrapped Ether contract. - /// @param exchange Address of the 0x ERC1155 Asset Proxy contract. - constructor ( - address exchange, - address weth - ) - public - MixinWethUtils( - exchange, - weth - ) - { - EXCHANGE = exchange; - ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); - } - - /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy - /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` - /// @param to This should be the maker of the order. - /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. - /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. - function safeBatchTransferFrom( - address from, - address to, - uint256[] calldata /* ids */, - uint256[] calldata amounts, - bytes calldata data - ) - external - { - // Only the ERC1155 asset proxy contract should be calling this function. - if (msg.sender != ERC1155_PROXY) { - LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError( - msg.sender - )); - } - // Only `takerAssetData` should be using Broker assets - if (from != address(this)) { - LibRichErrors.rrevert( - LibBrokerRichErrors.InvalidFromAddressError(from) - ); - } - // Only one asset amount should be specified. - if (amounts.length != 1) { - LibRichErrors.rrevert( - LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length) - ); - } - - uint256 cacheIndex = _cacheIndex; - uint256 remainingAmount = amounts[0]; - - // Verify that there are enough broker assets to transfer - if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) { - LibRichErrors.rrevert( - LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length) - ); - } - - // Decode validator and params from `data` - (address tokenAddress, address validator, bytes memory propertyData) = abi.decode( - data, - (address, address, bytes) - ); - - while (remainingAmount != 0) { - uint256 tokenId = _cachedTokenIds[cacheIndex]; - cacheIndex++; - - // Validate asset properties - IPropertyValidator(validator).checkBrokerAsset( - tokenId, - propertyData - ); - - // Perform the transfer - IERC721Token(tokenAddress).transferFrom( - _sender, - to, - tokenId - ); - - remainingAmount--; - } - // Update cache index in storage - _cacheIndex = cacheIndex; - } - - /// @dev Fills a single property-based order by the given amount using the given assets. - /// Pays protocol fees using either the ETH supplied by the taker to the transaction or - /// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. - /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. - /// @param order The property-based order to fill. The format of a property-based order is the - /// same as that of a normal order, except the takerAssetData. Instaed of specifying a - /// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the - /// underlying tokenAddress is this contract's address and the desired properties are - /// encoded in the extra data field. Also note that takerFees must be denominated in - /// WETH (or zero). - /// @param takerAssetFillAmount The amount to fill the order by. - /// @param signature The maker's signature of the given order. - /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return fillResults Amounts filled and fees paid by the maker and taker. - function brokerTrade( - uint256[] memory brokeredTokenIds, - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature, - bytes4 fillFunctionSelector, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns (LibFillResults.FillResults memory fillResults) - { - // Cache the taker-supplied asset data - _cachedTokenIds = brokeredTokenIds; - // Cache the sender's address - _sender = msg.sender; - - // Sanity-check the provided function selector - if ( - fillFunctionSelector != IExchange(address(0)).fillOrder.selector && - fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector - ) { - LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector); - } - - // Pay ETH affiliate fees to all feeRecipient addresses - _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); - - // Perform the fill - bytes memory fillCalldata = abi.encodeWithSelector( - fillFunctionSelector, - order, - takerAssetFillAmount, - signature - ); - // solhint-disable-next-line avoid-call-value - (bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata); - if (didSucceed) { - fillResults = abi.decode(returnData, (LibFillResults.FillResults)); - } else { - // Re-throw error - LibRichErrors.rrevert(returnData); - } - - // Transfer maker asset to taker - if (!order.makerAssetData.equals(WETH_ASSET_DATA)) { - order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount); - } - - // Refund remaining ETH to msg.sender. - _unwrapAndTransferEth(WETH.balanceOf(address(this))); - - _clearStorage(); - - return fillResults; - } - - /// @dev Fills multiple property-based orders by the given amounts using the given assets. - /// Pays protocol fees using either the ETH supplied by the taker to the transaction or - /// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. - /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. - /// @param orders The property-based orders to fill. The format of a property-based order is the - /// same as that of a normal order, except the takerAssetData. Instaed of specifying a - /// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the - /// underlying tokenAddress is this contract's address and the desired properties are - /// encoded in the extra data field. Also note that takerFees must be denominated in - /// WETH (or zero). - /// @param takerAssetFillAmounts The amounts to fill the orders by. - /// @param signatures The makers' signatures for the given orders. - /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, - /// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return fillResults Amounts filled and fees paid by the makers and taker. - function batchBrokerTrade( - uint256[] memory brokeredTokenIds, - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures, - bytes4 batchFillFunctionSelector, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns (LibFillResults.FillResults[] memory fillResults) - { - // Cache the taker-supplied asset data - _cachedTokenIds = brokeredTokenIds; - // Cache the sender's address - _sender = msg.sender; - - // Sanity-check the provided function selector - if ( - batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector && - batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector && - batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector - ) { - LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector); - } - - // Pay ETH affiliate fees to all feeRecipient addresses - _transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients); - - // Perform the batch fill - bytes memory batchFillCalldata = abi.encodeWithSelector( - batchFillFunctionSelector, - orders, - takerAssetFillAmounts, - signatures - ); - // solhint-disable-next-line avoid-call-value - (bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata); - if (didSucceed) { - // solhint-disable-next-line indent - fillResults = abi.decode(returnData, (LibFillResults.FillResults[])); - } else { - // Re-throw error - LibRichErrors.rrevert(returnData); - } - - // Transfer maker assets to taker - for (uint256 i = 0; i < orders.length; i++) { - if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) { - orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount); - } - } - - // Refund remaining ETH to msg.sender. - _unwrapAndTransferEth(WETH.balanceOf(address(this))); - - _clearStorage(); - - return fillResults; - } - - function _clearStorage() - private - { - delete _cachedTokenIds; - _cacheIndex = 0; - _sender = address(0); - } -} diff --git a/contracts/broker/contracts/src/interfaces/IBroker.sol b/contracts/broker/contracts/src/interfaces/IBroker.sol deleted file mode 100644 index 10bf8e7a97..0000000000 --- a/contracts/broker/contracts/src/interfaces/IBroker.sol +++ /dev/null @@ -1,101 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; - - -// solhint-disable space-after-comma -interface IBroker { - - /// @dev Fills a single property-based order by the given amount using the given assets. - /// Pays protocol fees using either the ETH supplied by the taker to the transaction or - /// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. - /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. - /// @param order The property-based order to fill. The format of a property-based order is the - /// same as that of a normal order, except the takerAssetData. Instaed of specifying a - /// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the - /// underlying tokenAddress is this contract's address and the desired properties are - /// encoded in the extra data field. Also note that takerFees must be denominated in - /// WETH (or zero). - /// @param takerAssetFillAmount The amount to fill the order by. - /// @param signature The maker's signature of the given order. - /// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return fillResults Amounts filled and fees paid by the maker and taker. - function brokerTrade( - uint256[] calldata brokeredTokenIds, - LibOrder.Order calldata order, - uint256 takerAssetFillAmount, - bytes calldata signature, - bytes4 fillFunctionSelector, - uint256[] calldata ethFeeAmounts, - address payable[] calldata feeRecipients - ) - external - payable - returns (LibFillResults.FillResults memory fillResults); - - /// @dev Fills multiple property-based orders by the given amounts using the given assets. - /// Pays protocol fees using either the ETH supplied by the taker to the transaction or - /// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker. - /// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders. - /// @param orders The property-based orders to fill. The format of a property-based order is the - /// same as that of a normal order, except the takerAssetData. Instaed of specifying a - /// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the - /// underlying tokenAddress is this contract's address and the desired properties are - /// encoded in the extra data field. Also note that takerFees must be denominated in - /// WETH (or zero). - /// @param takerAssetFillAmounts The amounts to fill the orders by. - /// @param signatures The makers' signatures for the given orders. - /// @param batchFillFunctionSelector The selector for either `batchFillOrders`, - /// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return fillResults Amounts filled and fees paid by the makers and taker. - function batchBrokerTrade( - uint256[] calldata brokeredTokenIds, - LibOrder.Order[] calldata orders, - uint256[] calldata takerAssetFillAmounts, - bytes[] calldata signatures, - bytes4 batchFillFunctionSelector, - uint256[] calldata ethFeeAmounts, - address payable[] calldata feeRecipients - ) - external - payable - returns (LibFillResults.FillResults[] memory fillResults); - - /// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy - /// @param from Since the Broker serves as the taker of the order, this should equal `address(this)` - /// @param to This should be the maker of the order. - /// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer. - /// @param data Encodes the validator contract address and any auxiliary data it needs for property validation. - function safeBatchTransferFrom( - address from, - address to, - uint256[] calldata /* ids */, - uint256[] calldata amounts, - bytes calldata data - ) - external; -} diff --git a/contracts/broker/contracts/src/interfaces/IGodsUnchained.sol b/contracts/broker/contracts/src/interfaces/IGodsUnchained.sol deleted file mode 100644 index b8276b787a..0000000000 --- a/contracts/broker/contracts/src/interfaces/IGodsUnchained.sol +++ /dev/null @@ -1,33 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -interface IGodsUnchained { - - /// @dev Returns the proto and quality for a particular card given its token id - /// @param tokenId The id of the card to query. - /// @return proto The proto of the given card. - /// @return quality The quality of the given card - function getDetails(uint256 tokenId) - external - view - returns (uint16 proto, uint8 quality); -} diff --git a/contracts/broker/contracts/src/interfaces/IPropertyValidator.sol b/contracts/broker/contracts/src/interfaces/IPropertyValidator.sol deleted file mode 100644 index 5316d3934d..0000000000 --- a/contracts/broker/contracts/src/interfaces/IPropertyValidator.sol +++ /dev/null @@ -1,35 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -interface IPropertyValidator { - - /// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`. - /// Should revert if the asset does not satisfy the specified properties. - /// @param tokenId The ERC721 tokenId of the asset to check. - /// @param propertyData Encoded properties or auxiliary data needed to perform the check. - function checkBrokerAsset( - uint256 tokenId, - bytes calldata propertyData - ) - external - view; -} diff --git a/contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol b/contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol deleted file mode 100644 index 7963fa637c..0000000000 --- a/contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol +++ /dev/null @@ -1,109 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -library LibBrokerRichErrors { - - // bytes4(keccak256("InvalidFromAddressError(address)")) - bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR = - 0x906bfb3c; - - // bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)")) - bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR = - 0xba9be200; - - // bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)")) - bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR = - 0x55272586; - - // bytes4(keccak256("InvalidFunctionSelectorError(bytes4)")) - bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR = - 0x540943f1; - - // bytes4(keccak256("OnlyERC1155ProxyError(address)")) - bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR = - 0xccc529af; - - // solhint-disable func-name-mixedcase - function InvalidFromAddressError( - address from - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INVALID_FROM_ADDRESS_ERROR_SELECTOR, - from - ); - } - - function AmountsLengthMustEqualOneError( - uint256 amountsLength - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR, - amountsLength - ); - } - - function TooFewBrokerAssetsProvidedError( - uint256 numBrokeredAssets - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR, - numBrokeredAssets - ); - } - - function InvalidFunctionSelectorError( - bytes4 selector - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR, - selector - ); - } - - function OnlyERC1155ProxyError( - address sender - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ONLY_ERC_1155_PROXY_ERROR_SELECTOR, - sender - ); - } -} diff --git a/contracts/broker/contracts/src/validators/GodsUnchainedValidator.sol b/contracts/broker/contracts/src/validators/GodsUnchainedValidator.sol deleted file mode 100644 index 1b4e6e8ddf..0000000000 --- a/contracts/broker/contracts/src/validators/GodsUnchainedValidator.sol +++ /dev/null @@ -1,61 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "../interfaces/IGodsUnchained.sol"; -import "../interfaces/IPropertyValidator.sol"; - - -contract GodsUnchainedValidator is - IPropertyValidator -{ - IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase - - using LibBytes for bytes; - - constructor(address _godsUnchained) - public - { - GODS_UNCHAINED = IGodsUnchained(_godsUnchained); - } - - /// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`. - /// Reverts if the card doesn't match the specified proto and quality. - /// @param tokenId The ERC721 tokenId of the card to check. - /// @param propertyData Encoded proto and quality that the card is expected to have. - function checkBrokerAsset( - uint256 tokenId, - bytes calldata propertyData - ) - external - view - { - (uint16 expectedProto, uint8 expectedQuality) = abi.decode( - propertyData, - (uint16, uint8) - ); - - // Validate card properties. - (uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId); - require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH"); - require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH"); - } -} diff --git a/contracts/broker/contracts/test/TestGodsUnchained.sol b/contracts/broker/contracts/test/TestGodsUnchained.sol deleted file mode 100644 index 8c0c289efb..0000000000 --- a/contracts/broker/contracts/test/TestGodsUnchained.sol +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol"; -import "../src/interfaces/IGodsUnchained.sol"; - - -contract TestGodsUnchained is - IGodsUnchained, - DummyERC721Token -{ - mapping (uint256 => uint16) internal _protoByTokenId; - mapping (uint256 => uint8) internal _qualityByTokenId; - - constructor ( - string memory _name, - string memory _symbol - ) - public - DummyERC721Token(_name, _symbol) - {} // solhint-disable-line no-empty-blocks - - function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality) - external - { - _protoByTokenId[tokenId] = proto; - _qualityByTokenId[tokenId] = quality; - } - - function getDetails(uint256 tokenId) - external - view - returns (uint16 proto, uint8 quality) - { - return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]); - } -} diff --git a/contracts/broker/package.json b/contracts/broker/package.json deleted file mode 100644 index 3164184004..0000000000 --- a/contracts/broker/package.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "name": "@0x/contracts-broker", - "version": "1.1.37", - "engines": { - "node": ">=6.12" - }, - "description": "Extension of 0x protocol for property-based orders", - "main": "lib/src/index.js", - "directories": { - "test": "test" - }, - "scripts": { - "build": "yarn build:contracts && yarn build:ts", - "build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", - "build:ts": "tsc -b", - "build:ci": "yarn build", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-erc721": "^3.1.37", - "@0x/contracts-exchange": "^3.2.38", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/order-utils": "^10.4.28", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "ethereum-types": "^3.5.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/broker/src/artifacts.ts b/contracts/broker/src/artifacts.ts deleted file mode 100644 index 3bb32b942c..0000000000 --- a/contracts/broker/src/artifacts.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Broker from '../generated-artifacts/Broker.json'; -import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json'; -import * as IBroker from '../generated-artifacts/IBroker.json'; -import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json'; -import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json'; -import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json'; -import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json'; -export const artifacts = { - Broker: Broker as ContractArtifact, - IBroker: IBroker as ContractArtifact, - IGodsUnchained: IGodsUnchained as ContractArtifact, - IPropertyValidator: IPropertyValidator as ContractArtifact, - LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact, - GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact, - TestGodsUnchained: TestGodsUnchained as ContractArtifact, -}; diff --git a/contracts/broker/src/gods_unchained_utils.ts b/contracts/broker/src/gods_unchained_utils.ts deleted file mode 100644 index d644812007..0000000000 --- a/contracts/broker/src/gods_unchained_utils.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { assetDataUtils } from '@0x/order-utils'; -import { ERC1155AssetData } from '@0x/types'; -import { AbiEncoder, BigNumber } from '@0x/utils'; - -export interface GodsUnchainedProperties { - proto: BigNumber | number; - quality: BigNumber | number; -} - -const propertyDataEncoder = AbiEncoder.create([ - { name: 'proto', type: 'uint16' }, - { name: 'quality', type: 'uint8' }, -]); -const brokerDataEncoder = AbiEncoder.create([ - { name: 'godsUnchainedAddress', type: 'address' }, - { name: 'validatorAddress', type: 'address' }, - { name: 'propertyData', type: 'bytes' }, -]); - -/** - * Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator. - */ -export function encodePropertyData(properties: GodsUnchainedProperties): string { - return propertyDataEncoder.encode(properties); -} - -/** - * Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData - * of a property-based GodsUnchained order. Must also provide the addresses of the Broker, - * GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies - * how many cards are expected for each "unit" of the takerAssetAmount. For example, If the - * takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards - * with the given proto and quality to fill the order. If an odd number is provided, the fill fails. - */ -export function encodeBrokerAssetData( - brokerAddress: string, - godsUnchainedAddress: string, - validatorAddress: string, - properties: GodsUnchainedProperties, - bundleSize: number = 1, -): string { - const propertyData = propertyDataEncoder.encode(properties); - const brokerData = brokerDataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData }); - return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], brokerData); -} - -/** - * Decodes proto and quality from the bytes format expected by the GodsUnchainedValidator. - */ -export function decodePropertyData(propertyData: string): GodsUnchainedProperties { - return propertyDataEncoder.decode(propertyData); -} - -/** - * Decodes proto and quality from the ERC1155 takerAssetData of a property-based GodsUnchained order. - */ -export function decodeBrokerAssetData(brokerAssetData: string): GodsUnchainedProperties { - // tslint:disable-next-line:no-unnecessary-type-assertion - const { callbackData: brokerData } = assetDataUtils.decodeAssetDataOrThrow(brokerAssetData) as ERC1155AssetData; - const { propertyData } = brokerDataEncoder.decode(brokerData); - return decodePropertyData(propertyData); -} diff --git a/contracts/broker/src/index.ts b/contracts/broker/src/index.ts deleted file mode 100644 index 1f13b98d10..0000000000 --- a/contracts/broker/src/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -export { artifacts } from './artifacts'; -export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers'; -export * from './gods_unchained_utils'; -export { BrokerRevertErrors } from '@0x/utils'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/broker/src/wrappers.ts b/contracts/broker/src/wrappers.ts deleted file mode 100644 index c231b37fbf..0000000000 --- a/contracts/broker/src/wrappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/broker'; -export * from '../generated-wrappers/gods_unchained_validator'; -export * from '../generated-wrappers/i_broker'; -export * from '../generated-wrappers/i_gods_unchained'; -export * from '../generated-wrappers/i_property_validator'; -export * from '../generated-wrappers/lib_broker_rich_errors'; -export * from '../generated-wrappers/test_gods_unchained'; diff --git a/contracts/broker/test/artifacts.ts b/contracts/broker/test/artifacts.ts deleted file mode 100644 index 6db14b6c9a..0000000000 --- a/contracts/broker/test/artifacts.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Broker from '../test/generated-artifacts/Broker.json'; -import * as GodsUnchainedValidator from '../test/generated-artifacts/GodsUnchainedValidator.json'; -import * as IBroker from '../test/generated-artifacts/IBroker.json'; -import * as IGodsUnchained from '../test/generated-artifacts/IGodsUnchained.json'; -import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json'; -import * as LibBrokerRichErrors from '../test/generated-artifacts/LibBrokerRichErrors.json'; -import * as TestGodsUnchained from '../test/generated-artifacts/TestGodsUnchained.json'; -export const artifacts = { - Broker: Broker as ContractArtifact, - IBroker: IBroker as ContractArtifact, - IGodsUnchained: IGodsUnchained as ContractArtifact, - IPropertyValidator: IPropertyValidator as ContractArtifact, - LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact, - GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact, - TestGodsUnchained: TestGodsUnchained as ContractArtifact, -}; diff --git a/contracts/broker/test/gods_unchained_validator_test.ts b/contracts/broker/test/gods_unchained_validator_test.ts deleted file mode 100644 index 965d6a977a..0000000000 --- a/contracts/broker/test/gods_unchained_validator_test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { encodePropertyData } from '../src/gods_unchained_utils'; - -import { artifacts } from './artifacts'; -import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers'; - -blockchainTests.resets('GodsUnchainedValidator unit tests', env => { - let godsUnchained: TestGodsUnchainedContract; - let validator: GodsUnchainedValidatorContract; - - before(async () => { - godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync( - artifacts.TestGodsUnchained, - env.provider, - env.txDefaults, - artifacts, - 'Gods Unchained Cards', - 'GU', - ); - - validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync( - artifacts.GodsUnchainedValidator, - env.provider, - env.txDefaults, - artifacts, - godsUnchained.address, - ); - }); - - describe('checkBrokerAsset', () => { - const proto = new BigNumber(42); - const quality = new BigNumber(7); - const propertyData = encodePropertyData({ proto, quality }); - - it('succeeds if assetData proto and quality match propertyData', async () => { - const tokenId = getRandomInteger(0, constants.MAX_UINT256); - await godsUnchained.setTokenProperties(tokenId, proto, quality).awaitTransactionSuccessAsync(); - await validator.checkBrokerAsset(tokenId, propertyData).callAsync(); - }); - it("reverts if assetData proto doesn't match propertyData", async () => { - const tokenId = getRandomInteger(0, constants.MAX_UINT256); - await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync(); - const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync(); - expect(tx).to.revertWith('GodsUnchainedValidator/PROTO_MISMATCH'); - }); - it("reverts if assetData quality doesn't match proeprtyData", async () => { - const tokenId = getRandomInteger(0, constants.MAX_UINT256); - await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync(); - const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync(); - expect(tx).to.revertWith('GodsUnchainedValidator/QUALITY_MISMATCH'); - }); - }); -}); diff --git a/contracts/broker/test/wrappers.ts b/contracts/broker/test/wrappers.ts deleted file mode 100644 index a05b726463..0000000000 --- a/contracts/broker/test/wrappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/broker'; -export * from '../test/generated-wrappers/gods_unchained_validator'; -export * from '../test/generated-wrappers/i_broker'; -export * from '../test/generated-wrappers/i_gods_unchained'; -export * from '../test/generated-wrappers/i_property_validator'; -export * from '../test/generated-wrappers/lib_broker_rich_errors'; -export * from '../test/generated-wrappers/test_gods_unchained'; diff --git a/contracts/broker/truffle-config.js b/contracts/broker/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/broker/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/broker/tsconfig.json b/contracts/broker/tsconfig.json deleted file mode 100644 index 849374d53a..0000000000 --- a/contracts/broker/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/Broker.json", - "generated-artifacts/GodsUnchainedValidator.json", - "generated-artifacts/IBroker.json", - "generated-artifacts/IGodsUnchained.json", - "generated-artifacts/IPropertyValidator.json", - "generated-artifacts/LibBrokerRichErrors.json", - "generated-artifacts/TestGodsUnchained.json", - "test/generated-artifacts/Broker.json", - "test/generated-artifacts/GodsUnchainedValidator.json", - "test/generated-artifacts/IBroker.json", - "test/generated-artifacts/IGodsUnchained.json", - "test/generated-artifacts/IPropertyValidator.json", - "test/generated-artifacts/LibBrokerRichErrors.json", - "test/generated-artifacts/TestGodsUnchained.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/broker/tslint.json b/contracts/broker/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/broker/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/broker/typedoc-tsconfig.json b/contracts/broker/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/broker/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/coordinator/.npmignore b/contracts/coordinator/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/coordinator/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/coordinator/.solhintignore b/contracts/coordinator/.solhintignore deleted file mode 100644 index 7ba7eea62a..0000000000 --- a/contracts/coordinator/.solhintignore +++ /dev/null @@ -1,2 +0,0 @@ -# solhint can't parse `abi.decode` syntax. -contracts/src/MixinCoordinatorApprovalVerifier.sol diff --git a/contracts/coordinator/CHANGELOG.json b/contracts/coordinator/CHANGELOG.json deleted file mode 100644 index 11a2ad09e3..0000000000 --- a/contracts/coordinator/CHANGELOG.json +++ /dev/null @@ -1,720 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "3.1.38", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "3.1.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "3.1.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "3.1.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "3.1.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "3.1.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "3.1.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "3.1.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "3.1.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "3.1.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "3.1.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "3.1.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "3.1.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "3.1.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "3.1.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "3.1.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "3.1.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "3.1.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "3.1.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "3.1.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "3.1.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "3.1.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "3.1.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "3.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "3.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "3.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "3.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "3.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "3.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "3.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "3.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "3.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "3.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "3.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "3.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "3.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Update tests.", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "3.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "3.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "3.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export CoordinatorRevertErrors", - "pr": 2321 - }, - { - "note": "Added dependency on @0x/contracts-utils", - "pr": 2321 - }, - { - "note": "Add chainId to domain separator", - "pr": 1742 - }, - { - "note": "Inherit Exchange domain constants from `exchange-libs` to reduce code duplication", - "pr": 1742 - }, - { - "note": "Update domain separator", - "pr": 1742 - }, - { - "note": "Refactor contract to use new ITransactions interface", - "pr": 1753 - }, - { - "note": "Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor", - "pr": 1753 - }, - { - "note": "Remove LibZeroExTransaction contract", - "pr": 1753 - }, - { - "note": "Update tests for arbitrary fee tokens (ZEIP-28).", - "pr": 1819 - }, - { - "note": "Update for new `marketXOrders` consolidation.", - "pr": 2042 - }, - { - "note": "Use built in selectors instead of hard coded constants", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - } - ], - "timestamp": 1575296764 - }, - { - "version": "2.1.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "2.1.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "2.1.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export CoordinatorRevertErrors", - "pr": 2321 - }, - { - "note": "Added dependency on @0x/contracts-utils", - "pr": 2321 - } - ], - "timestamp": 1574030254 - }, - { - "version": "2.1.0-beta.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1573159180 - }, - { - "version": "2.1.0-beta.0", - "changes": [ - { - "note": "Add chainId to domain separator", - "pr": 1742 - }, - { - "note": "Inherit Exchange domain constants from `exchange-libs` to reduce code duplication", - "pr": 1742 - }, - { - "note": "Update domain separator", - "pr": 1742 - }, - { - "note": "Refactor contract to use new ITransactions interface", - "pr": 1753 - }, - { - "note": "Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor", - "pr": 1753 - }, - { - "note": "Remove LibZeroExTransaction contract", - "pr": 1753 - }, - { - "note": "Update tests for arbitrary fee tokens (ZEIP-28).", - "pr": 1819 - }, - { - "note": "Update for new `marketXOrders` consolidation.", - "pr": 2042 - }, - { - "note": "Use built in selectors instead of hard coded constants", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "2.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "2.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "2.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "2.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.9", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564607468 - }, - { - "timestamp": 1563957393, - "version": "2.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "2.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557799313, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557507213, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Make `decodeOrdersFromFillData`, `getCoordinatorApprovalHash`, and `getTransactionHash` public", - "pr": 1729 - }, - { - "note": "Make `assertValidTransactionOrdersApproval` internal", - "pr": 1729 - } - ], - "timestamp": 1554997931 - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Created Coordinator package" - }, - { - "note": "Use separate EIP712 domains for transactions and approvals", - "pr": 1705 - }, - { - "note": "Add `SignatureType.Invalid`", - "pr": 1705 - }, - { - "note": "Set `evmVersion` to `constantinople`", - "pr": 1707 - } - ], - "timestamp": 1553091633 - } -] diff --git a/contracts/coordinator/CHANGELOG.md b/contracts/coordinator/CHANGELOG.md deleted file mode 100644 index 31f1a8ddd5..0000000000 --- a/contracts/coordinator/CHANGELOG.md +++ /dev/null @@ -1,301 +0,0 @@ - - -CHANGELOG - -## v3.1.38 - _August 16, 2021_ - - * Dependencies updated - -## v3.1.37 - _August 11, 2021_ - - * Dependencies updated - -## v3.1.36 - _August 6, 2021_ - - * Dependencies updated - -## v3.1.35 - _June 22, 2021_ - - * Dependencies updated - -## v3.1.34 - _June 11, 2021_ - - * Dependencies updated - -## v3.1.33 - _June 2, 2021_ - - * Dependencies updated - -## v3.1.32 - _May 25, 2021_ - - * Dependencies updated - -## v3.1.31 - _May 21, 2021_ - - * Dependencies updated - -## v3.1.30 - _May 5, 2021_ - - * Dependencies updated - -## v3.1.29 - _April 28, 2021_ - - * Dependencies updated - -## v3.1.28 - _April 1, 2021_ - - * Dependencies updated - -## v3.1.27 - _March 17, 2021_ - - * Dependencies updated - -## v3.1.26 - _February 24, 2021_ - - * Dependencies updated - -## v3.1.25 - _February 10, 2021_ - - * Dependencies updated - -## v3.1.24 - _January 26, 2021_ - - * Dependencies updated - -## v3.1.23 - _January 13, 2021_ - - * Dependencies updated - -## v3.1.22 - _January 4, 2021_ - - * Dependencies updated - -## v3.1.21 - _December 23, 2020_ - - * Dependencies updated - -## v3.1.20 - _December 17, 2020_ - - * Dependencies updated - -## v3.1.19 - _December 16, 2020_ - - * Dependencies updated - -## v3.1.18 - _December 9, 2020_ - - * Dependencies updated - -## v3.1.17 - _December 7, 2020_ - - * Dependencies updated - -## v3.1.16 - _December 3, 2020_ - - * Dependencies updated - -## v3.1.15 - _November 19, 2020_ - - * Dependencies updated - -## v3.1.14 - _November 13, 2020_ - - * Dependencies updated - -## v3.1.13 - _November 3, 2020_ - - * Dependencies updated - -## v3.1.12 - _November 3, 2020_ - - * Dependencies updated - -## v3.1.11 - _November 2, 2020_ - - * Dependencies updated - -## v3.1.10 - _October 28, 2020_ - - * Dependencies updated - -## v3.1.9 - _October 27, 2020_ - - * Dependencies updated - -## v3.1.8 - _October 21, 2020_ - - * Dependencies updated - -## v3.1.7 - _July 15, 2020_ - - * Dependencies updated - -## v3.1.6 - _June 24, 2020_ - - * Dependencies updated - -## v3.1.5 - _March 3, 2020_ - - * Dependencies updated - -## v3.1.4 - _February 27, 2020_ - - * Dependencies updated - -## v3.1.3 - _February 26, 2020_ - - * Dependencies updated - -## v3.1.2 - _February 25, 2020_ - - * Dependencies updated - -## v3.1.1 - _February 15, 2020_ - - * Dependencies updated - -## v3.1.0 - _February 8, 2020_ - - * Update tests. (#2462) - -## v3.0.6 - _February 6, 2020_ - - * Dependencies updated - -## v3.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v3.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v3.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v3.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v3.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v3.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export CoordinatorRevertErrors (#2321) - * Added dependency on @0x/contracts-utils (#2321) - * Add chainId to domain separator (#1742) - * Inherit Exchange domain constants from `exchange-libs` to reduce code duplication (#1742) - * Update domain separator (#1742) - * Refactor contract to use new ITransactions interface (#1753) - * Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor (#1753) - * Remove LibZeroExTransaction contract (#1753) - * Update tests for arbitrary fee tokens (ZEIP-28). (#1819) - * Update for new `marketXOrders` consolidation. (#2042) - * Use built in selectors instead of hard coded constants (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - -## v2.1.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v2.1.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v2.1.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export CoordinatorRevertErrors (#2321) - * Added dependency on @0x/contracts-utils (#2321) - -## v2.1.0-beta.1 - _November 7, 2019_ - - * Dependencies updated - -## v2.1.0-beta.0 - _October 3, 2019_ - - * Add chainId to domain separator (#1742) - * Inherit Exchange domain constants from `exchange-libs` to reduce code duplication (#1742) - * Update domain separator (#1742) - * Refactor contract to use new ITransactions interface (#1753) - * Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor (#1753) - * Remove LibZeroExTransaction contract (#1753) - * Update tests for arbitrary fee tokens (ZEIP-28). (#1819) - * Update for new `marketXOrders` consolidation. (#2042) - * Use built in selectors instead of hard coded constants (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - -## v2.0.13 - _September 17, 2019_ - - * Dependencies updated - -## v2.0.12 - _September 3, 2019_ - - * Dependencies updated - -## v2.0.11 - _August 22, 2019_ - - * Dependencies updated - -## v2.0.10 - _August 8, 2019_ - - * Dependencies updated - -## v2.0.9 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v2.0.8 - _July 24, 2019_ - - * Dependencies updated - -## v2.0.7 - _July 15, 2019_ - - * Dependencies updated - -## v2.0.6 - _July 13, 2019_ - - * Dependencies updated - -## v2.0.5 - _July 13, 2019_ - - * Dependencies updated - -## v2.0.4 - _May 24, 2019_ - - * Dependencies updated - -## v2.0.3 - _May 15, 2019_ - - * Dependencies updated - -## v2.0.2 - _May 14, 2019_ - - * Dependencies updated - -## v2.0.1 - _May 10, 2019_ - - * Dependencies updated - -## v2.0.0 - _April 11, 2019_ - - * Make `decodeOrdersFromFillData`, `getCoordinatorApprovalHash`, and `getTransactionHash` public (#1729) - * Make `assertValidTransactionOrdersApproval` internal (#1729) - -## v1.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v1.0.0 - _March 20, 2019_ - - * Created Coordinator package - * Use separate EIP712 domains for transactions and approvals (#1705) - * Add `SignatureType.Invalid` (#1705) - * Set `evmVersion` to `constantinople` (#1707) diff --git a/contracts/coordinator/DEPLOYS.json b/contracts/coordinator/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/coordinator/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/coordinator/README.md b/contracts/coordinator/README.md deleted file mode 100644 index efd5d9571b..0000000000 --- a/contracts/coordinator/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## Coordinator - -This package contains a contract that allows users to call arbitrary functions on the Exchange contract with permission from one or more Coordinators. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-coordinator --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-coordinator yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-coordinator yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/coordinator/compiler.json b/contracts/coordinator/compiler.json deleted file mode 100644 index 0032db2c08..0000000000 --- a/contracts/coordinator/compiler.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/coordinator/contracts/src/Coordinator.sol b/contracts/coordinator/contracts/src/Coordinator.sol deleted file mode 100644 index ecfba59551..0000000000 --- a/contracts/coordinator/contracts/src/Coordinator.sol +++ /dev/null @@ -1,45 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "./libs/LibConstants.sol"; -import "./libs/LibEIP712CoordinatorDomain.sol"; -import "./MixinSignatureValidator.sol"; -import "./MixinCoordinatorApprovalVerifier.sol"; -import "./MixinCoordinatorCore.sol"; - - -// solhint-disable no-empty-blocks -contract Coordinator is - LibConstants, - MixinSignatureValidator, - MixinCoordinatorApprovalVerifier, - MixinCoordinatorCore -{ - /// @param exchange Address of the 0x Exchange contract. - /// @param chainId Chain ID of the network this contract is deployed on. - constructor (address exchange, uint256 chainId) - public - LibConstants(exchange) - LibEIP712CoordinatorDomain(chainId, address(0)) - LibEIP712ExchangeDomain(chainId, exchange) - {} -} diff --git a/contracts/coordinator/contracts/src/MixinCoordinatorApprovalVerifier.sol b/contracts/coordinator/contracts/src/MixinCoordinatorApprovalVerifier.sol deleted file mode 100644 index 9b542fc603..0000000000 --- a/contracts/coordinator/contracts/src/MixinCoordinatorApprovalVerifier.sol +++ /dev/null @@ -1,195 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "./libs/LibCoordinatorApproval.sol"; -import "./libs/LibCoordinatorRichErrors.sol"; -import "./interfaces/ICoordinatorSignatureValidator.sol"; -import "./interfaces/ICoordinatorApprovalVerifier.sol"; - - -// solhint-disable avoid-tx-origin -contract MixinCoordinatorApprovalVerifier is - LibCoordinatorApproval, - LibEIP712ExchangeDomain, - ICoordinatorSignatureValidator, - ICoordinatorApprovalVerifier -{ - using LibBytes for bytes; - using LibAddressArray for address[]; - - /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients - /// that correspond to each order in the transaction's Exchange calldata. - /// @param transaction 0x transaction containing salt, signerAddress, and data. - /// @param txOrigin Required signer of Ethereum transaction calling this function. - /// @param transactionSignature Proof that the transaction has been signed by the signer. - /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each - /// order in the transaction's Exchange calldata. - function assertValidCoordinatorApprovals( - LibZeroExTransaction.ZeroExTransaction memory transaction, - address txOrigin, - bytes memory transactionSignature, - bytes[] memory approvalSignatures - ) - public - view - { - // Get the orders from the the Exchange calldata in the 0x transaction - LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data); - - // No approval is required for non-fill methods - if (orders.length > 0) { - // Revert if approval is invalid for transaction orders - _assertValidTransactionOrdersApproval( - transaction, - orders, - txOrigin, - transactionSignature, - approvalSignatures - ); - } - } - - /// @dev Decodes the orders from Exchange calldata representing any fill method. - /// @param data Exchange calldata representing a fill method. - /// @return orders The orders from the Exchange calldata. - function decodeOrdersFromFillData(bytes memory data) - public - pure - returns (LibOrder.Order[] memory orders) - { - bytes4 selector = data.readBytes4(0); - if ( - selector == IExchange(address(0)).fillOrder.selector || - selector == IExchange(address(0)).fillOrKillOrder.selector - ) { - // Decode single order - (LibOrder.Order memory order) = abi.decode( - data.slice(4, data.length), - (LibOrder.Order) - ); - orders = new LibOrder.Order[](1); - orders[0] = order; - } else if ( - selector == IExchange(address(0)).batchFillOrders.selector || - selector == IExchange(address(0)).batchFillOrdersNoThrow.selector || - selector == IExchange(address(0)).batchFillOrKillOrders.selector || - selector == IExchange(address(0)).marketBuyOrdersNoThrow.selector || - selector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector || - selector == IExchange(address(0)).marketSellOrdersNoThrow.selector || - selector == IExchange(address(0)).marketSellOrdersFillOrKill.selector - ) { - // Decode all orders - // solhint-disable indent - (orders) = abi.decode( - data.slice(4, data.length), - (LibOrder.Order[]) - ); - } else if ( - selector == IExchange(address(0)).matchOrders.selector || - selector == IExchange(address(0)).matchOrdersWithMaximalFill.selector - ) { - // Decode left and right orders - (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode( - data.slice(4, data.length), - (LibOrder.Order, LibOrder.Order) - ); - - // Create array of orders - orders = new LibOrder.Order[](2); - orders[0] = leftOrder; - orders[1] = rightOrder; - } - return orders; - } - - /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction. - /// @param transaction 0x transaction containing salt, signerAddress, and data. - /// @param orders Array of order structs containing order specifications. - /// @param txOrigin Required signer of Ethereum transaction calling this function. - /// @param transactionSignature Proof that the transaction has been signed by the signer. - /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order. - function _assertValidTransactionOrdersApproval( - LibZeroExTransaction.ZeroExTransaction memory transaction, - LibOrder.Order[] memory orders, - address txOrigin, - bytes memory transactionSignature, - bytes[] memory approvalSignatures - ) - internal - view - { - // Verify that Ethereum tx signer is the same as the approved txOrigin - if (tx.origin != txOrigin) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.InvalidOriginError(txOrigin)); - } - - // Hash 0x transaction - bytes32 transactionHash = LibZeroExTransaction.getTypedDataHash(transaction, EIP712_EXCHANGE_DOMAIN_HASH); - - // Create empty list of approval signers - address[] memory approvalSignerAddresses = new address[](0); - - uint256 signaturesLength = approvalSignatures.length; - for (uint256 i = 0; i != signaturesLength; i++) { - // Create approval message - CoordinatorApproval memory approval = CoordinatorApproval({ - txOrigin: txOrigin, - transactionHash: transactionHash, - transactionSignature: transactionSignature - }); - - // Hash approval message and recover signer address - bytes32 approvalHash = getCoordinatorApprovalHash(approval); - address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]); - - // Add approval signer to list of signers - approvalSignerAddresses = approvalSignerAddresses.append(approvalSignerAddress); - } - - // Ethereum transaction signer gives implicit signature of approval - approvalSignerAddresses = approvalSignerAddresses.append(tx.origin); - - uint256 ordersLength = orders.length; - for (uint256 i = 0; i != ordersLength; i++) { - // Do not check approval if the order's senderAddress is null - if (orders[i].senderAddress == address(0)) { - continue; - } - - // Ensure feeRecipient of order has approved this 0x transaction - address approverAddress = orders[i].feeRecipientAddress; - bool isOrderApproved = approvalSignerAddresses.contains(approverAddress); - if (!isOrderApproved) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.InvalidApprovalSignatureError( - transactionHash, - approverAddress - )); - } - } - } -} diff --git a/contracts/coordinator/contracts/src/MixinCoordinatorCore.sol b/contracts/coordinator/contracts/src/MixinCoordinatorCore.sol deleted file mode 100644 index 6a128c7c4f..0000000000 --- a/contracts/coordinator/contracts/src/MixinCoordinatorCore.sol +++ /dev/null @@ -1,72 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-utils/contracts/src/Refundable.sol"; -import "./libs/LibConstants.sol"; -import "./interfaces/ICoordinatorCore.sol"; -import "./interfaces/ICoordinatorApprovalVerifier.sol"; - - -// solhint-disable no-empty-blocks -contract MixinCoordinatorCore is - Refundable, - LibConstants, - ICoordinatorApprovalVerifier, - ICoordinatorCore -{ - - /// @dev A payable fallback function that makes this contract "payable". This is necessary to allow - /// this contract to gracefully handle refunds from the Exchange. - function () - external - payable - {} - - /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to - /// each order in the transaction's Exchange calldata. - /// @param transaction 0x transaction containing salt, signerAddress, and data. - /// @param txOrigin Required signer of Ethereum transaction calling this function. - /// @param transactionSignature Proof that the transaction has been signed by the signer. - /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each - /// order in the transaction's Exchange calldata. - function executeTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - address txOrigin, - bytes memory transactionSignature, - bytes[] memory approvalSignatures - ) - public - payable - refundFinalBalance - { - // Validate that the 0x transaction has been approves by each feeRecipient - assertValidCoordinatorApprovals( - transaction, - txOrigin, - transactionSignature, - approvalSignatures - ); - - // Execute the transaction - EXCHANGE.executeTransaction.value(msg.value)(transaction, transactionSignature); - } -} diff --git a/contracts/coordinator/contracts/src/MixinSignatureValidator.sol b/contracts/coordinator/contracts/src/MixinSignatureValidator.sol deleted file mode 100644 index 8a3e79dac2..0000000000 --- a/contracts/coordinator/contracts/src/MixinSignatureValidator.sol +++ /dev/null @@ -1,142 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "./interfaces/ICoordinatorSignatureValidator.sol"; -import "./libs/LibCoordinatorRichErrors.sol"; - - -contract MixinSignatureValidator is - ICoordinatorSignatureValidator -{ - using LibBytes for bytes; - - /// @dev Recovers the address of a signer given a hash and signature. - /// @param hash Any 32 byte hash. - /// @param signature Proof that the hash has been signed by signer. - /// @return signerAddress Address of the signer. - function getSignerAddress(bytes32 hash, bytes memory signature) - public - pure - returns (address signerAddress) - { - uint256 signatureLength = signature.length; - if (signatureLength == 0) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signature - )); - } - - // Pop last byte off of signature byte array. - uint8 signatureTypeRaw = uint8(signature[signature.length - 1]); - - // Ensure signature is supported - if (signatureTypeRaw >= uint8(SignatureType.NSignatureTypes)) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.UNSUPPORTED, - hash, - signature - )); - } - - SignatureType signatureType = SignatureType(signatureTypeRaw); - - // 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) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.ILLEGAL, - hash, - signature - )); - - // 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) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.INVALID, - hash, - signature - )); - - // Signature using EIP712 - } else if (signatureType == SignatureType.EIP712) { - if (signatureLength != 66) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signature - )); - } - uint8 v = uint8(signature[0]); - bytes32 r = signature.readBytes32(1); - bytes32 s = signature.readBytes32(33); - signerAddress = ecrecover( - hash, - v, - r, - s - ); - return signerAddress; - - // Signed using web3.eth_sign - } else if (signatureType == SignatureType.EthSign) { - if (signatureLength != 66) { - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signature - )); - } - uint8 v = uint8(signature[0]); - bytes32 r = signature.readBytes32(1); - bytes32 s = signature.readBytes32(33); - signerAddress = ecrecover( - keccak256(abi.encodePacked( - "\x19Ethereum Signed Message:\n32", - hash - )), - v, - r, - s - ); - return signerAddress; - } - - // 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.) - LibRichErrors.rrevert(LibCoordinatorRichErrors.SignatureError( - LibCoordinatorRichErrors.SignatureErrorCodes.UNSUPPORTED, - hash, - signature - )); - } -} diff --git a/contracts/coordinator/contracts/src/interfaces/ICoordinatorApprovalVerifier.sol b/contracts/coordinator/contracts/src/interfaces/ICoordinatorApprovalVerifier.sol deleted file mode 100644 index 994ec04623..0000000000 --- a/contracts/coordinator/contracts/src/interfaces/ICoordinatorApprovalVerifier.sol +++ /dev/null @@ -1,51 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; - - -contract ICoordinatorApprovalVerifier { - - /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients - /// that correspond to each order in the transaction's Exchange calldata. - /// @param transaction 0x transaction containing salt, signerAddress, and data. - /// @param txOrigin Required signer of Ethereum transaction calling this function. - /// @param transactionSignature Proof that the transaction has been signed by the signer. - /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each - /// order in the transaction's Exchange calldata. - function assertValidCoordinatorApprovals( - LibZeroExTransaction.ZeroExTransaction memory transaction, - address txOrigin, - bytes memory transactionSignature, - bytes[] memory approvalSignatures - ) - public - view; - - /// @dev Decodes the orders from Exchange calldata representing any fill method. - /// @param data Exchange calldata representing a fill method. - /// @return orders The orders from the Exchange calldata. - function decodeOrdersFromFillData(bytes memory data) - public - pure - returns (LibOrder.Order[] memory orders); -} diff --git a/contracts/coordinator/contracts/src/interfaces/ICoordinatorCore.sol b/contracts/coordinator/contracts/src/interfaces/ICoordinatorCore.sol deleted file mode 100644 index 03d4ade319..0000000000 --- a/contracts/coordinator/contracts/src/interfaces/ICoordinatorCore.sol +++ /dev/null @@ -1,42 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; - - -contract ICoordinatorCore { - - /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to - /// each order in the transaction's Exchange calldata. - /// @param transaction 0x transaction containing salt, signerAddress, and data. - /// @param txOrigin Required signer of Ethereum transaction calling this function. - /// @param transactionSignature Proof that the transaction has been signed by the signer. - /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each - /// order in the transaction's Exchange calldata. - function executeTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - address txOrigin, - bytes memory transactionSignature, - bytes[] memory approvalSignatures - ) - public - payable; -} diff --git a/contracts/coordinator/contracts/src/interfaces/ICoordinatorSignatureValidator.sol b/contracts/coordinator/contracts/src/interfaces/ICoordinatorSignatureValidator.sol deleted file mode 100644 index 8152a4d5ec..0000000000 --- a/contracts/coordinator/contracts/src/interfaces/ICoordinatorSignatureValidator.sol +++ /dev/null @@ -1,45 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract ICoordinatorSignatureValidator { - - // Allowed signature types. - enum SignatureType { - Illegal, // 0x00, default value - Invalid, // 0x01 - EIP712, // 0x02 - EthSign, // 0x03 - Wallet, // 0x04 - Validator, // 0x05 - PreSigned, // 0x06 - EIP1271Wallet, // 0x07 - NSignatureTypes // 0x08, number of signature types. Always leave at end. - } - - /// @dev Recovers the address of a signer given a hash and signature. - /// @param hash Any 32 byte hash. - /// @param signature Proof that the hash has been signed by signer. - /// @return signerAddress Address of the signer. - function getSignerAddress(bytes32 hash, bytes memory signature) - public - pure - returns (address signerAddress); -} diff --git a/contracts/coordinator/contracts/src/libs/LibConstants.sol b/contracts/coordinator/contracts/src/libs/LibConstants.sol deleted file mode 100644 index 7f86b57b6a..0000000000 --- a/contracts/coordinator/contracts/src/libs/LibConstants.sol +++ /dev/null @@ -1,36 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-exchange/contracts/src/interfaces/ITransactions.sol"; - - -// solhint-disable var-name-mixedcase -contract LibConstants { - - // The 0x Exchange contract. - ITransactions internal EXCHANGE; - - /// @param exchange Address of the 0x Exchange contract. - constructor (address exchange) - public - { - EXCHANGE = ITransactions(exchange); - } -} diff --git a/contracts/coordinator/contracts/src/libs/LibCoordinatorApproval.sol b/contracts/coordinator/contracts/src/libs/LibCoordinatorApproval.sol deleted file mode 100644 index 3fdbb04afd..0000000000 --- a/contracts/coordinator/contracts/src/libs/LibCoordinatorApproval.sol +++ /dev/null @@ -1,98 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./LibEIP712CoordinatorDomain.sol"; - - -contract LibCoordinatorApproval is - LibEIP712CoordinatorDomain -{ - // Hash for the EIP712 Coordinator approval message - // keccak256(abi.encodePacked( - // "CoordinatorApproval(", - // "address txOrigin,", - // "bytes32 transactionHash,", - // "bytes transactionSignature", - // ")" - // )); - bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = - 0xa6511c04ca44625d50986f8c36bedc09366207a17b96e347094053a9f8507168; - - struct CoordinatorApproval { - address txOrigin; // Required signer of Ethereum transaction that is submitting approval. - bytes32 transactionHash; // EIP712 hash of the transaction. - bytes transactionSignature; // Signature of the 0x transaction. - } - - /// @dev Calculates the EIP712 hash of the Coordinator approval mesasage using the domain - /// separator of this contract. - /// @param approval Coordinator approval message containing the transaction hash, and transaction - /// signature. - /// @return approvalHash EIP712 hash of the Coordinator approval message with the domain - /// separator of this contract. - function getCoordinatorApprovalHash(CoordinatorApproval memory approval) - public - view - returns (bytes32 approvalHash) - { - approvalHash = _hashEIP712CoordinatorMessage(_hashCoordinatorApproval(approval)); - return approvalHash; - } - - /// @dev Calculates the EIP712 hash of the Coordinator approval mesasage with no domain separator. - /// @param approval Coordinator approval message containing the transaction hash, and transaction - // signature. - /// @return result EIP712 hash of the Coordinator approval message with no domain separator. - function _hashCoordinatorApproval(CoordinatorApproval memory approval) - internal - pure - returns (bytes32 result) - { - bytes32 schemaHash = EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH; - bytes memory transactionSignature = approval.transactionSignature; - address txOrigin = approval.txOrigin; - bytes32 transactionHash = approval.transactionHash; - - // Assembly for more efficiently computing: - // keccak256(abi.encodePacked( - // EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH, - // approval.txOrigin, - // approval.transactionHash, - // keccak256(approval.transactionSignature) - // )); - - assembly { - // Compute hash of transaction signature - let transactionSignatureHash := keccak256(add(transactionSignature, 32), mload(transactionSignature)) - - // Load free memory pointer - let memPtr := mload(64) - - mstore(memPtr, schemaHash) // hash of schema - mstore(add(memPtr, 32), txOrigin) // txOrigin - mstore(add(memPtr, 64), transactionHash) // transactionHash - mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash - // Compute hash - result := keccak256(memPtr, 128) - } - return result; - } -} diff --git a/contracts/coordinator/contracts/src/libs/LibCoordinatorRichErrors.sol b/contracts/coordinator/contracts/src/libs/LibCoordinatorRichErrors.sol deleted file mode 100644 index ad7dbcc430..0000000000 --- a/contracts/coordinator/contracts/src/libs/LibCoordinatorRichErrors.sol +++ /dev/null @@ -1,87 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -library LibCoordinatorRichErrors { - enum SignatureErrorCodes { - INVALID_LENGTH, - UNSUPPORTED, - ILLEGAL, - INVALID - } - - // bytes4(keccak256("SignatureError(uint8,bytes32,bytes)")) - bytes4 internal constant SIGNATURE_ERROR_SELECTOR = - 0x779c5223; - - // bytes4(keccak256("InvalidOriginError(address)")) - bytes4 internal constant INVALID_ORIGIN_ERROR_SELECTOR = - 0xa458d7ff; - - // bytes4(keccak256("InvalidApprovalSignatureError(bytes32,address)")) - bytes4 internal constant INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR = - 0xd789b640; - - // solhint-disable func-name-mixedcase - function SignatureError( - SignatureErrorCodes errorCode, - bytes32 hash, - bytes memory signature - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - SIGNATURE_ERROR_SELECTOR, - errorCode, - hash, - signature - ); - } - - function InvalidOriginError( - address expectedOrigin - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INVALID_ORIGIN_ERROR_SELECTOR, - expectedOrigin - ); - } - - function InvalidApprovalSignatureError( - bytes32 transactionHash, - address approverAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR, - transactionHash, - approverAddress - ); - } -} diff --git a/contracts/coordinator/contracts/src/libs/LibEIP712CoordinatorDomain.sol b/contracts/coordinator/contracts/src/libs/LibEIP712CoordinatorDomain.sol deleted file mode 100644 index 0025205c61..0000000000 --- a/contracts/coordinator/contracts/src/libs/LibEIP712CoordinatorDomain.sol +++ /dev/null @@ -1,66 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; - - -contract LibEIP712CoordinatorDomain { - - // EIP712 Domain Name value for the Coordinator - string constant public EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator"; - - // EIP712 Domain Version value for the Coordinator - string constant public EIP712_COORDINATOR_DOMAIN_VERSION = "3.0.0"; - - // Hash of the EIP712 Domain Separator data for the Coordinator - // solhint-disable-next-line var-name-mixedcase - bytes32 public EIP712_COORDINATOR_DOMAIN_HASH; - - /// @param chainId Chain ID of the network this contract is deployed on. - /// @param verifyingContractAddressIfExists Address of the verifying contract (null if the address of this contract) - constructor ( - uint256 chainId, - address verifyingContractAddressIfExists - ) - public - { - address verifyingContractAddress = verifyingContractAddressIfExists == address(0) - ? address(this) - : verifyingContractAddressIfExists; - EIP712_COORDINATOR_DOMAIN_HASH = LibEIP712.hashEIP712Domain( - EIP712_COORDINATOR_DOMAIN_NAME, - EIP712_COORDINATOR_DOMAIN_VERSION, - chainId, - verifyingContractAddress - ); - } - - /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain - /// of this contract. - /// @param hashStruct The EIP712 hash struct. - /// @return result EIP712 hash applied to this EIP712 Domain. - function _hashEIP712CoordinatorMessage(bytes32 hashStruct) - internal - view - returns (bytes32 result) - { - return LibEIP712.hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct); - } -} diff --git a/contracts/coordinator/contracts/src/registry/CoordinatorRegistry.sol b/contracts/coordinator/contracts/src/registry/CoordinatorRegistry.sol deleted file mode 100644 index acfd108028..0000000000 --- a/contracts/coordinator/contracts/src/registry/CoordinatorRegistry.sol +++ /dev/null @@ -1,32 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "./MixinCoordinatorRegistryCore.sol"; - - -// solhint-disable no-empty-blocks -contract CoordinatorRegistry is - MixinCoordinatorRegistryCore -{ - constructor () - public - MixinCoordinatorRegistryCore() - {} -} diff --git a/contracts/coordinator/contracts/src/registry/MixinCoordinatorRegistryCore.sol b/contracts/coordinator/contracts/src/registry/MixinCoordinatorRegistryCore.sol deleted file mode 100644 index 799c668e04..0000000000 --- a/contracts/coordinator/contracts/src/registry/MixinCoordinatorRegistryCore.sol +++ /dev/null @@ -1,49 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "./interfaces/ICoordinatorRegistryCore.sol"; - - -// solhint-disable no-empty-blocks -contract MixinCoordinatorRegistryCore is - ICoordinatorRegistryCore -{ - // mapping from `coordinatorOperator` -> `coordinatorEndpoint` - mapping (address => string) internal coordinatorEndpoints; - - /// @dev Called by a Coordinator operator to set the endpoint of their Coordinator. - /// @param coordinatorEndpoint Endpoint of the Coordinator as a string. - function setCoordinatorEndpoint(string calldata coordinatorEndpoint) external { - address coordinatorOperator = msg.sender; - coordinatorEndpoints[coordinatorOperator] = coordinatorEndpoint; - emit CoordinatorEndpointSet(coordinatorOperator, coordinatorEndpoint); - } - - /// @dev Gets the endpoint for a Coordinator. - /// @param coordinatorOperator Operator of the Coordinator endpoint. - /// @return coordinatorEndpoint Endpoint of the Coordinator as a string. - function getCoordinatorEndpoint(address coordinatorOperator) - external - view - returns (string memory coordinatorEndpoint) - { - return coordinatorEndpoints[coordinatorOperator]; - } -} diff --git a/contracts/coordinator/contracts/src/registry/interfaces/ICoordinatorRegistryCore.sol b/contracts/coordinator/contracts/src/registry/interfaces/ICoordinatorRegistryCore.sol deleted file mode 100644 index c562c4f159..0000000000 --- a/contracts/coordinator/contracts/src/registry/interfaces/ICoordinatorRegistryCore.sol +++ /dev/null @@ -1,42 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -// solhint-disable no-empty-blocks -contract ICoordinatorRegistryCore -{ - /// @dev Emitted when a Coordinator endpoint is set. - event CoordinatorEndpointSet( - address coordinatorOperator, - string coordinatorEndpoint - ); - - /// @dev Called by a Coordinator operator to set the endpoint of their Coordinator. - /// @param coordinatorEndpoint Endpoint of the Coordinator as a string. - function setCoordinatorEndpoint(string calldata coordinatorEndpoint) external; - - /// @dev Gets the endpoint for a Coordinator. - /// @param coordinatorOperator Operator of the Coordinator endpoint. - /// @return coordinatorEndpoint Endpoint of the Coordinator as a string. - function getCoordinatorEndpoint(address coordinatorOperator) - external - view - returns (string memory coordinatorEndpoint); -} diff --git a/contracts/coordinator/package.json b/contracts/coordinator/package.json deleted file mode 100644 index 482ab0b6ae..0000000000 --- a/contracts/coordinator/package.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "name": "@0x/contracts-coordinator", - "version": "3.1.38", - "engines": { - "node": ">=6.12" - }, - "description": "Smart contract extensions 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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "Coordinator,CoordinatorRegistry,LibCoordinatorApproval,LibCoordinatorRichErrors,LibEIP712CoordinatorDomain,LibConstants", - "abis": "./test/generated-artifacts/@(Coordinator|CoordinatorRegistry|ICoordinatorApprovalVerifier|ICoordinatorCore|ICoordinatorRegistryCore|ICoordinatorSignatureValidator|LibConstants|LibCoordinatorApproval|LibCoordinatorRichErrors|LibEIP712CoordinatorDomain|MixinCoordinatorApprovalVerifier|MixinCoordinatorCore|MixinCoordinatorRegistryCore|MixinSignatureValidator).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-dev-utils": "^1.3.36", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-gen": "^2.0.38", - "@0x/dev-utils": "^4.2.7", - "@0x/order-utils": "^10.4.28", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/assert": "^3.0.27", - "@0x/base-contract": "^6.4.0", - "@0x/contract-addresses": "^6.6.0", - "@0x/contracts-exchange": "^3.2.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/json-schemas": "^6.1.3", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "ethereum-types": "^3.5.0", - "http-status-codes": "^1.3.2" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/coordinator/src/approval_factory.ts b/contracts/coordinator/src/approval_factory.ts deleted file mode 100644 index 11fc7f5846..0000000000 --- a/contracts/coordinator/src/approval_factory.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { signingUtils } from '@0x/contracts-test-utils'; -import { SignatureType, SignedZeroExTransaction } from '@0x/types'; -import { hexUtils } from '@0x/utils'; - -import { hashUtils } from './hash_utils'; -import { SignedCoordinatorApproval } from './types'; - -export class ApprovalFactory { - private readonly _privateKey: Buffer; - private readonly _verifyingContractAddress: string; - - constructor(privateKey: Buffer, verifyingContract: string) { - this._privateKey = privateKey; - this._verifyingContractAddress = verifyingContract; - } - - public newSignedApproval( - transaction: SignedZeroExTransaction, - txOrigin: string, - signatureType: SignatureType = SignatureType.EthSign, - ): SignedCoordinatorApproval { - const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, this._verifyingContractAddress, txOrigin); - const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType); - const signedApproval = { - txOrigin, - transaction, - signature: hexUtils.concat(signatureBuff), - }; - return signedApproval; - } -} diff --git a/contracts/coordinator/src/artifacts.ts b/contracts/coordinator/src/artifacts.ts deleted file mode 100644 index 61e478dc39..0000000000 --- a/contracts/coordinator/src/artifacts.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Coordinator from '../generated-artifacts/Coordinator.json'; -import * as CoordinatorRegistry from '../generated-artifacts/CoordinatorRegistry.json'; -import * as LibConstants from '../generated-artifacts/LibConstants.json'; -import * as LibCoordinatorApproval from '../generated-artifacts/LibCoordinatorApproval.json'; -import * as LibCoordinatorRichErrors from '../generated-artifacts/LibCoordinatorRichErrors.json'; -import * as LibEIP712CoordinatorDomain from '../generated-artifacts/LibEIP712CoordinatorDomain.json'; -export const artifacts = { - Coordinator: Coordinator as ContractArtifact, - CoordinatorRegistry: CoordinatorRegistry as ContractArtifact, - LibCoordinatorApproval: LibCoordinatorApproval as ContractArtifact, - LibCoordinatorRichErrors: LibCoordinatorRichErrors as ContractArtifact, - LibEIP712CoordinatorDomain: LibEIP712CoordinatorDomain as ContractArtifact, - LibConstants: LibConstants as ContractArtifact, -}; diff --git a/contracts/coordinator/src/client/index.ts b/contracts/coordinator/src/client/index.ts deleted file mode 100644 index 22a3cf4372..0000000000 --- a/contracts/coordinator/src/client/index.ts +++ /dev/null @@ -1,820 +0,0 @@ -import { SendTransactionOpts } from '@0x/base-contract'; -import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { ExchangeContract } from '@0x/contracts-exchange'; -import { ExchangeFunctionName } from '@0x/contracts-test-utils'; -import { devConstants } from '@0x/dev-utils'; -import { schemas } from '@0x/json-schemas'; -import { generatePseudoRandomSalt, signatureUtils } from '@0x/order-utils'; -import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; -import { BigNumber, fetchAsync } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { CallData, ContractAbi, SupportedProvider, TxData } from 'ethereum-types'; -import * as HttpStatus from 'http-status-codes'; -import { flatten } from 'lodash'; - -import { artifacts } from '../artifacts'; -import { CoordinatorContract, CoordinatorRegistryContract } from '../wrappers'; - -import { assert } from './utils/assert'; -import { - CoordinatorServerApprovalResponse, - CoordinatorServerCancellationResponse, - CoordinatorServerError, - CoordinatorServerErrorMsg, - CoordinatorServerResponse, -} from './utils/coordinator_server_types'; - -import { decorators } from './utils/decorators'; - -export { CoordinatorServerErrorMsg, CoordinatorServerCancellationResponse }; - -const DEFAULT_TX_DATA = { - gas: devConstants.GAS_LIMIT, - gasPrice: new BigNumber(1), - value: new BigNumber(150000), // DEFAULT_PROTOCOL_FEE_MULTIPLIER -}; - -// tx expiration time will be set to (now + default_approval - time_buffer) -const DEFAULT_APPROVAL_EXPIRATION_TIME_SECONDS = 90; -const DEFAULT_EXPIRATION_TIME_BUFFER_SECONDS = 30; - -/** - * This class includes all the functionality related to filling or cancelling orders through - * the 0x V2 Coordinator extension contract. - */ -export class CoordinatorClient { - public abi: ContractAbi = artifacts.Coordinator.compilerOutput.abi; - public chainId: number; - public address: string; - public exchangeAddress: string; - public registryAddress: string; - - private readonly _web3Wrapper: Web3Wrapper; - private readonly _contractInstance: CoordinatorContract; - private readonly _registryInstance: CoordinatorRegistryContract; - private readonly _exchangeInstance: ExchangeContract; - private readonly _feeRecipientToEndpoint: { [feeRecipient: string]: string } = {}; - private readonly _txDefaults: CallData = DEFAULT_TX_DATA; - - /** - * Validates that the 0x transaction has been approved by all of the feeRecipients that correspond to each order in the transaction's Exchange calldata. - * Throws an error if the transaction approvals are not valid. Will not detect failures that would occur when the transaction is executed on the Exchange contract. - * @param transaction 0x transaction containing salt, signerAddress, and data. - * @param txOrigin Required signer of Ethereum transaction calling this function. - * @param transactionSignature Proof that the transaction has been signed by the signer. - * @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata. - */ - @decorators.asyncZeroExErrorHandler - public async assertValidCoordinatorApprovalsOrThrowAsync( - transaction: ZeroExTransaction, - txOrigin: string, - transactionSignature: string, - approvalSignatures: string[], - ): Promise { - assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema); - assert.isETHAddressHex('txOrigin', txOrigin); - assert.isHexString('transactionSignature', transactionSignature); - for (const approvalSignature of approvalSignatures) { - assert.isHexString('approvalSignature', approvalSignature); - } - return this._contractInstance - .assertValidCoordinatorApprovals(transaction, txOrigin, transactionSignature, approvalSignatures) - .callAsync(); - } - /** - * Instantiate CoordinatorClient - * @param web3Wrapper Web3Wrapper instance to use. - * @param chainId Desired chainId. - * @param address The address of the Coordinator contract. If undefined, will - * default to the known address corresponding to the chainId. - * @param exchangeAddress The address of the Exchange contract. If undefined, will - * default to the known address corresponding to the chainId. - * @param registryAddress The address of the CoordinatorRegistry contract. If undefined, will - * default to the known address corresponding to the chainId. - */ - constructor( - address: string, - provider: SupportedProvider, - chainId: number, - txDefaults?: Partial, - exchangeAddress?: string, - registryAddress?: string, - ) { - this.chainId = chainId; - const contractAddresses = getContractAddressesForChainOrThrow(this.chainId); - this.address = address === undefined ? contractAddresses.coordinator : address; - this.exchangeAddress = exchangeAddress === undefined ? contractAddresses.exchange : exchangeAddress; - this.registryAddress = registryAddress === undefined ? contractAddresses.coordinatorRegistry : registryAddress; - this._web3Wrapper = new Web3Wrapper(provider); - this._txDefaults = { ...txDefaults, ...DEFAULT_TX_DATA }; - this._contractInstance = new CoordinatorContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._registryInstance = new CoordinatorRegistryContract( - this.registryAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._exchangeInstance = new ExchangeContract( - this.exchangeAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - } - - /** - * Fills a signed order with an amount denominated in baseUnits of the taker asset. Under-the-hood, this - * method uses the `feeRecipientAddress` of the order to look up the coordinator server endpoint registered in the - * coordinator registry contract. It requests an approval from that coordinator server before - * submitting the order and approval as a 0x transaction to the coordinator extension contract. The coordinator extension - * contract validates approvals and then fills the order via the Exchange contract. - * @param order An object that conforms to the Order interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @param signature Signature corresponding to the order. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async fillOrderAsync( - order: Order, - takerAssetFillAmount: BigNumber, - signature: string, - txData: TxData, - sendTxOpts: Partial = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - return this._executeTxThroughCoordinatorAsync( - ExchangeFunctionName.FillOrder, - txData, - sendTxOpts, - [order], - order, - takerAssetFillAmount, - signature, - ); - } - - /** - * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled, - * the fill order is abandoned. - * @param order An object that conforms to the Order interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @param signature Signature corresponding to the order. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async fillOrKillOrderAsync( - order: Order, - takerAssetFillAmount: BigNumber, - signature: string, - txData: TxData, - sendTxOpts: Partial = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - return this._executeTxThroughCoordinatorAsync( - ExchangeFunctionName.FillOrKillOrder, - txData, - sendTxOpts, - [order], - order, - takerAssetFillAmount, - signature, - ); - } - - /** - * Batch version of fillOrderAsync. Executes multiple fills atomically in a single transaction. - * If any `feeRecipientAddress` in the batch is not registered to a coordinator server through the CoordinatorRegistryContract, the whole batch fails. - * @param orders An array of orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @param signatures Signatures corresponding to the orders. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchFillOrdersAsync( - orders: Order[], - takerAssetFillAmounts: BigNumber[], - signatures: string[], - txData: TxData, - sendTxOpts?: Partial, - ): Promise { - return this._batchFillAsync( - ExchangeFunctionName.BatchFillOrders, - orders, - takerAssetFillAmounts, - signatures, - txData, - sendTxOpts, - ); - } - /** - * No throw version of batchFillOrdersAsync - * @param orders An array of orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @param signatures Signatures corresponding to the orders. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - - public async batchFillOrdersNoThrowAsync( - orders: Order[], - takerAssetFillAmounts: BigNumber[], - signatures: string[], - txData: TxData, - sendTxOpts?: Partial, - ): Promise { - return this._batchFillAsync( - ExchangeFunctionName.BatchFillOrdersNoThrow, - orders, - takerAssetFillAmounts, - signatures, - txData, - sendTxOpts, - ); - } - /** - * Batch version of fillOrKillOrderAsync. Executes multiple fills atomically in a single transaction. - * @param orders An array of orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @param signatures Signatures corresponding to the orders. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchFillOrKillOrdersAsync( - orders: Order[], - takerAssetFillAmounts: BigNumber[], - signatures: string[], - txData: TxData, - sendTxOpts?: Partial, - ): Promise { - return this._batchFillAsync( - ExchangeFunctionName.BatchFillOrKillOrders, - orders, - takerAssetFillAmounts, - signatures, - txData, - sendTxOpts, - ); - } - - /** - * Executes multiple calls of fillOrder until total amount of makerAsset is bought by taker. - * If any fill reverts, the error is caught and ignored. Finally, reverts if < makerAssetFillAmount has been bought. - * NOTE: This function does not enforce that the makerAsset is the same for each order. - * @param orders Array of order specifications. - * @param makerAssetFillAmount Desired amount of makerAsset to buy. - * @param signatures Proofs that orders have been signed by makers. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketBuyOrdersFillOrKillAsync( - orders: Order[], - makerAssetFillAmount: BigNumber, - signatures: string[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - return this._marketBuySellOrdersAsync( - ExchangeFunctionName.MarketBuyOrdersFillOrKill, - orders, - makerAssetFillAmount, - signatures, - txData, - sendTxOpts, - ); - } - - /** - * No throw version of marketBuyOrdersFillOrKillAsync - * @param orders An array of orders to fill. - * @param makerAssetFillAmount Maker asset fill amount. - * @param signatures Signatures corresponding to the orders. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketBuyOrdersNoThrowAsync( - orders: Order[], - makerAssetFillAmount: BigNumber, - signatures: string[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - return this._marketBuySellOrdersAsync( - ExchangeFunctionName.MarketBuyOrdersNoThrow, - orders, - makerAssetFillAmount, - signatures, - txData, - sendTxOpts, - ); - } - /** - * Executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. - * If any fill reverts, the error is caught and ignored. Finally, reverts if < takerAssetFillAmount has been sold. - * NOTE: This function does not enforce that the takerAsset is the same for each order. - * @param orders Array of order specifications. - * @param takerAssetFillAmount Desired amount of takerAsset to sell. - * @param signatures Proofs that orders have been signed by makers. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketSellOrdersFillOrKillAsync( - orders: Order[], - takerAssetFillAmount: BigNumber, - signatures: string[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - return this._marketBuySellOrdersAsync( - ExchangeFunctionName.MarketSellOrdersFillOrKill, - orders, - takerAssetFillAmount, - signatures, - txData, - sendTxOpts, - ); - } - - /** - * No throw version of marketSellOrdersAsync - * @param orders An array of orders to fill. - * @param takerAssetFillAmount Taker asset fill amount. - * @param signatures Signatures corresponding to the orders. - * @param txData Transaction data. The `from` field should be the user Ethereum address who would like - * to fill these orders. Must be available via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketSellOrdersNoThrowAsync( - orders: Order[], - takerAssetFillAmount: BigNumber, - signatures: string[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - return this._marketBuySellOrdersAsync( - ExchangeFunctionName.MarketSellOrdersNoThrow, - orders, - takerAssetFillAmount, - signatures, - txData, - sendTxOpts, - ); - } - - /** - * Cancels an order on-chain by submitting an Ethereum transaction. - * @param order An object that conforms to the Order interface. The order you would like to cancel. - * @param txData Transaction data. The `from` field should be the maker's Ethereum address. Must be available - * via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async hardCancelOrderAsync( - order: Order, - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema); - return this._executeTxThroughCoordinatorAsync( - ExchangeFunctionName.CancelOrder, - txData, - sendTxOpts, - [order], - order, - ); - } - - /** - * Batch version of hardCancelOrderAsync. Cancels orders on-chain by submitting an Ethereum transaction. - * Executes multiple cancels atomically in a single transaction. - * @param orders An array of orders to cancel. - * @param txData Transaction data. The `from` field should be the maker's Ethereum address. Must be available - * via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchHardCancelOrdersAsync( - orders: Order[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - return this._executeTxThroughCoordinatorAsync( - ExchangeFunctionName.BatchCancelOrders, - txData, - sendTxOpts, - orders, - orders, - ); - } - - /** - * Cancels orders on-chain by submitting an Ethereum transaction. - * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch - * and senderAddress equal to coordinator extension contract address. - * @param targetOrderEpoch Target order epoch. - * @param txData Transaction data. The `from` field should be the maker's Ethereum address. Must be available - * via the Provider supplied at instantiation. - * @param sendTxOpts Optional arguments for sending the transaction. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async hardCancelOrdersUpToAsync( - targetOrderEpoch: BigNumber, - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); - return this._executeTxThroughCoordinatorAsync( - ExchangeFunctionName.CancelOrdersUpTo, - txData, - sendTxOpts, - [], - targetOrderEpoch, - ); - } - /** - * Soft cancel a given order. - * Soft cancels are recorded only on coordinator operator servers and do not involve an Ethereum transaction. - * See [soft cancels](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#soft-cancels). - * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. - * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). - */ - @decorators.asyncZeroExErrorHandler - public async softCancelAsync(order: Order): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema); - assert.isETHAddressHex('feeRecipientAddress', order.feeRecipientAddress); - assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); - - const data = this._exchangeInstance.cancelOrder(order).getABIEncodedTransactionData(); - const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); - const endpoint = await this._getServerEndpointOrThrowAsync(order); - - const response = await this._executeServerRequestAsync(transaction, order.makerAddress, endpoint); - if (response.isError) { - const approvedOrders = new Array(); - const cancellations = new Array(); - const errors = [ - { - ...response, - orders: [order], - }, - ]; - throw new CoordinatorServerError( - CoordinatorServerErrorMsg.CancellationFailed, - approvedOrders, - cancellations, - errors, - ); - } else { - return response.body as CoordinatorServerCancellationResponse; - } - } - /** - * Batch version of softCancelOrderAsync. Requests multiple soft cancels - * @param orders An array of orders to cancel. - * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). - */ - @decorators.asyncZeroExErrorHandler - public async batchSoftCancelAsync(orders: SignedOrder[]): Promise { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - const makerAddress = getMakerAddressOrThrow(orders); - assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); - const data = this._exchangeInstance.batchCancelOrders(orders).getABIEncodedTransactionData(); - const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); - - // make server requests - const errorResponses: CoordinatorServerResponse[] = []; - const successResponses: CoordinatorServerCancellationResponse[] = []; - const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(orders); - for (const endpoint of Object.keys(serverEndpointsToOrders)) { - const response = await this._executeServerRequestAsync(transaction, makerAddress, endpoint); - if (response.isError) { - errorResponses.push(response); - } else { - successResponses.push(response.body as CoordinatorServerCancellationResponse); - } - } - - // if no errors - if (errorResponses.length === 0) { - return successResponses; - } else { - // lookup orders with errors - const errorsWithOrders = errorResponses.map(resp => { - const endpoint = resp.coordinatorOperator; - const _orders = serverEndpointsToOrders[endpoint]; - return { - ...resp, - orders: _orders, - }; - }); - - const approvedOrders = new Array(); - const cancellations = successResponses; - // return errors and approvals - throw new CoordinatorServerError( - CoordinatorServerErrorMsg.CancellationFailed, - approvedOrders, - cancellations, - errorsWithOrders, - ); - } - } - - /** - * Recovers the address of a signer given a hash and signature. - * @param hash Any 32 byte hash. - * @param signature Proof that the hash has been signed by signer. - * @returns Signer address. - */ - @decorators.asyncZeroExErrorHandler - public async getSignerAddressAsync(hash: string, signature: string): Promise { - assert.isHexString('hash', hash); - assert.isHexString('signature', signature); - const signerAddress = await this._contractInstance.getSignerAddress(hash, signature).callAsync(); - return signerAddress; - } - - private async _marketBuySellOrdersAsync( - exchangeFn: ExchangeFunctionName, - orders: Order[], - assetFillAmount: BigNumber, - signatures: string[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - assert.isBigNumber('assetFillAmount', assetFillAmount); - return this._executeTxThroughCoordinatorAsync( - exchangeFn, - txData, - sendTxOpts, - orders, - orders, - assetFillAmount, - signatures, - ); - } - - private async _batchFillAsync( - exchangeFn: ExchangeFunctionName, - orders: Order[], - takerAssetFillAmounts: BigNumber[], - signatures: string[], - txData: TxData, - sendTxOpts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - takerAssetFillAmounts.forEach(takerAssetFillAmount => - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount), - ); - return this._executeTxThroughCoordinatorAsync( - exchangeFn, - txData, - sendTxOpts, - orders, - orders, - takerAssetFillAmounts, - signatures, - ); - } - - private async _executeTxThroughCoordinatorAsync( - exchangeFn: ExchangeFunctionName, - txData: TxData, - sendTxOpts: Partial, - ordersNeedingApprovals: Order[], - ...args: any[] // tslint:disable-line:trailing-comma - ): Promise { - assert.isETHAddressHex('takerAddress', txData.from); - await assert.isSenderAddressAsync('takerAddress', txData.from, this._web3Wrapper); - - // get ABI encoded transaction data for the desired exchange method - const data = (this._exchangeInstance as any)[exchangeFn](...args).getABIEncodedTransactionData(); - - // generate and sign a ZeroExTransaction - const signedZrxTx = await this._generateSignedZeroExTransactionAsync(data, txData.from, txData.gasPrice); - - // get approval signatures from registered coordinator operators - const approvalSignatures = await this._getApprovalsAsync(signedZrxTx, ordersNeedingApprovals, txData.from); - - // execute the transaction through the Coordinator Contract - const txDataWithDefaults = { - ...this._txDefaults, - ...txData, // override defaults - }; - const txHash = this._contractInstance - .executeTransaction(signedZrxTx, txData.from, signedZrxTx.signature, approvalSignatures) - .sendTransactionAsync(txDataWithDefaults, sendTxOpts); - return txHash; - } - - private async _generateSignedZeroExTransactionAsync( - data: string, - signerAddress: string, - gasPrice?: BigNumber | string | number, - ): Promise { - const transaction: ZeroExTransaction = { - salt: generatePseudoRandomSalt(), - signerAddress, - data, - domain: { - verifyingContract: this.exchangeAddress, - chainId: await this._web3Wrapper.getChainIdAsync(), - }, - expirationTimeSeconds: new BigNumber( - Math.floor(Date.now() / 1000) + - DEFAULT_APPROVAL_EXPIRATION_TIME_SECONDS - - DEFAULT_EXPIRATION_TIME_BUFFER_SECONDS, - ), - gasPrice: gasPrice ? new BigNumber(gasPrice) : new BigNumber(1), - }; - const signedZrxTx = await signatureUtils.ecSignTransactionAsync( - this._web3Wrapper.getProvider(), - transaction, - transaction.signerAddress, - ); - return signedZrxTx; - } - - private async _getApprovalsAsync( - transaction: SignedZeroExTransaction, - orders: Order[], - txOrigin: string, - ): Promise { - const coordinatorOrders = orders.filter(o => o.senderAddress === this.address); - if (coordinatorOrders.length === 0) { - return []; - } - const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(coordinatorOrders); - - // make server requests - const errorResponses: CoordinatorServerResponse[] = []; - const approvalResponses: CoordinatorServerResponse[] = []; - for (const endpoint of Object.keys(serverEndpointsToOrders)) { - const response = await this._executeServerRequestAsync(transaction, txOrigin, endpoint); - if (response.isError) { - errorResponses.push(response); - } else { - approvalResponses.push(response); - } - } - - // if no errors - if (errorResponses.length === 0) { - // concatenate all approval responses - return approvalResponses.reduce( - (accumulator, response) => - accumulator.concat((response.body as CoordinatorServerApprovalResponse).signatures), - [] as string[], - ); - } else { - // format errors and approvals - // concatenate approvals - const notCoordinatorOrders = orders.filter(o => o.senderAddress !== this.address); - const approvedOrdersNested = approvalResponses.map(resp => { - const endpoint = resp.coordinatorOperator; - return serverEndpointsToOrders[endpoint]; - }); - const approvedOrders = flatten(approvedOrdersNested.concat(notCoordinatorOrders)); - - // lookup orders with errors - const errorsWithOrders = errorResponses.map(resp => { - const endpoint = resp.coordinatorOperator; - return { - ...resp, - orders: serverEndpointsToOrders[endpoint], - }; - }); - - // throw informative error - const cancellations = new Array(); - throw new CoordinatorServerError( - CoordinatorServerErrorMsg.FillFailed, - approvedOrders, - cancellations, - errorsWithOrders, - ); - } - } - - private async _getServerEndpointOrThrowAsync(order: Order): Promise { - const cached = this._feeRecipientToEndpoint[order.feeRecipientAddress]; - const endpoint = - cached !== undefined - ? cached - : await _fetchServerEndpointOrThrowAsync(order.feeRecipientAddress, this._registryInstance); - return endpoint; - - async function _fetchServerEndpointOrThrowAsync( - feeRecipient: string, - registryInstance: CoordinatorRegistryContract, - ): Promise { - const coordinatorOperatorEndpoint = await registryInstance.getCoordinatorEndpoint(feeRecipient).callAsync(); - if (coordinatorOperatorEndpoint === '' || coordinatorOperatorEndpoint === undefined) { - throw new Error( - `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipient}. Registry contract address: [${ - registryInstance.address - }] Order: [${JSON.stringify(order)}]`, - ); - } - return coordinatorOperatorEndpoint; - } - } - - private async _executeServerRequestAsync( - signedTransaction: SignedZeroExTransaction, - txOrigin: string, - endpoint: string, - ): Promise { - const requestPayload = { - signedTransaction, - txOrigin, - }; - const response = await fetchAsync(`${endpoint}/v2/request_transaction?chainId=${this.chainId}`, { - body: JSON.stringify(requestPayload), - method: 'POST', - headers: { - 'Content-Type': 'application/json; charset=utf-8', - }, - }); - - const isError = response.status !== HttpStatus.OK; - const isValidationError = response.status === HttpStatus.BAD_REQUEST; - const json = isError && !isValidationError ? undefined : await response.json(); - - const result = { - isError, - status: response.status, - body: isError ? undefined : json, - error: isError ? json : undefined, - request: requestPayload, - coordinatorOperator: endpoint, - }; - - return result; - } - - private async _mapServerEndpointsToOrdersAsync( - coordinatorOrders: Order[], - ): Promise<{ [endpoint: string]: Order[] }> { - const groupByFeeRecipient: { [feeRecipient: string]: Order[] } = {}; - for (const order of coordinatorOrders) { - const feeRecipient = order.feeRecipientAddress; - if (groupByFeeRecipient[feeRecipient] === undefined) { - groupByFeeRecipient[feeRecipient] = [] as Order[]; - } - groupByFeeRecipient[feeRecipient].push(order); - } - const serverEndpointsToOrders: { [endpoint: string]: Order[] } = {}; - for (const orders of Object.values(groupByFeeRecipient)) { - const endpoint = await this._getServerEndpointOrThrowAsync(orders[0]); - if (serverEndpointsToOrders[endpoint] === undefined) { - serverEndpointsToOrders[endpoint] = []; - } - serverEndpointsToOrders[endpoint] = serverEndpointsToOrders[endpoint].concat(orders); - } - return serverEndpointsToOrders; - } -} - -function getMakerAddressOrThrow(orders: Array): string { - const uniqueMakerAddresses = new Set(orders.map(o => o.makerAddress)); - if (uniqueMakerAddresses.size > 1) { - throw new Error(`All orders in a batch must have the same makerAddress`); - } - return orders[0].makerAddress; -} - -// tslint:disable:max-file-line-count diff --git a/contracts/coordinator/src/client/utils/assert.ts b/contracts/coordinator/src/client/utils/assert.ts deleted file mode 100644 index 719b9dae3c..0000000000 --- a/contracts/coordinator/src/client/utils/assert.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { assert as sharedAssert } from '@0x/assert'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -export const assert = { - ...sharedAssert, - async isSenderAddressAsync( - variableName: string, - senderAddressHex: string, - web3Wrapper: Web3Wrapper, - ): Promise { - sharedAssert.isETHAddressHex(variableName, senderAddressHex); - const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex); - sharedAssert.assert( - isSenderAddressAvailable, - `Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`, - ); - }, -}; diff --git a/contracts/coordinator/src/client/utils/coordinator_server_types.ts b/contracts/coordinator/src/client/utils/coordinator_server_types.ts deleted file mode 100644 index dd3833aeeb..0000000000 --- a/contracts/coordinator/src/client/utils/coordinator_server_types.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Order, SignedOrder, SignedZeroExTransaction } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -export interface CoordinatorServerApprovalResponse { - signatures: string[]; - expirationTimeSeconds: BigNumber; -} - -export interface CoordinatorServerCancellationResponse { - outstandingFillSignatures: CoordinatorOutstandingFillSignatures[]; - cancellationSignatures: string[]; -} -export interface CoordinatorOutstandingFillSignatures { - orderHash: string; - approvalSignatures: string[]; - expirationTimeSeconds: BigNumber; - takerAssetFillAmount: BigNumber; -} - -export interface CoordinatorServerResponse { - isError: boolean; - status: number; - body?: CoordinatorServerCancellationResponse | CoordinatorServerApprovalResponse; - error?: any; - request: CoordinatorServerRequest; - coordinatorOperator: string; - orders?: Array; -} - -export interface CoordinatorServerRequest { - signedTransaction: SignedZeroExTransaction; - txOrigin: string; -} - -export class CoordinatorServerError extends Error { - public message: CoordinatorServerErrorMsg; - public approvedOrders?: Order[] = []; - public cancellations?: CoordinatorServerCancellationResponse[] = []; - public errors: CoordinatorServerResponse[]; - constructor( - message: CoordinatorServerErrorMsg, - approvedOrders: Order[], - cancellations: CoordinatorServerCancellationResponse[], - errors: CoordinatorServerResponse[], - ) { - super(); - this.message = message; - this.approvedOrders = approvedOrders; - this.cancellations = cancellations; - this.errors = errors; - } -} - -export enum CoordinatorServerErrorMsg { - CancellationFailed = 'Failed to cancel with some coordinator server(s). See errors for more info. See cancellations for successful cancellations.', - FillFailed = 'Failed to obtain approval signatures from some coordinator server(s). See errors for more info. Current transaction has been abandoned but you may resubmit with only approvedOrders (a new ZeroEx transaction will have to be signed).', -} diff --git a/contracts/coordinator/src/client/utils/decorators.ts b/contracts/coordinator/src/client/utils/decorators.ts deleted file mode 100644 index d3ddf8267d..0000000000 --- a/contracts/coordinator/src/client/utils/decorators.ts +++ /dev/null @@ -1,133 +0,0 @@ -import * as _ from 'lodash'; - -export enum ContractError { - ContractNotDeployedOnChain = 'CONTRACT_NOT_DEPLOYED_ON_CHAIN', - InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', - InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER', - InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT', - InsufficientWEthBalanceForWithdrawal = 'INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL', - InvalidJump = 'INVALID_JUMP', - OutOfGas = 'OUT_OF_GAS', - SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND', - SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT', - ERC721OwnerNotFound = 'ERC_721_OWNER_NOT_FOUND', - ERC721NoApproval = 'ERC_721_NO_APPROVAL', - SignatureRequestDenied = 'SIGNATURE_REQUEST_DENIED', -} - -export type AsyncMethod = (...args: any[]) => Promise; -export type SyncMethod = (...args: any[]) => any; - -const constants = { - INVALID_JUMP_PATTERN: 'invalid JUMP at', - REVERT: 'revert', - OUT_OF_GAS_PATTERN: 'out of gas', - INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string', - METAMASK_USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature', - TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN: 'cancelled', -}; - -type ErrorTransformer = (err: Error) => Error; - -const contractCallErrorTransformer = (error: Error) => { - if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) { - return new Error(ContractError.InvalidJump); - } - if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) { - return new Error(ContractError.OutOfGas); - } - if (_.includes(error.message, constants.REVERT)) { - const revertReason = error.message.split(constants.REVERT)[1].trim(); - return new Error(revertReason); - } - return error; -}; - -const schemaErrorTransformer = (error: Error) => { - if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) { - const errMsg = - 'Order taker must be of type string. If you want anyone to be able to fill an order - pass NULL_ADDRESS'; - return new Error(errMsg); - } - return error; -}; - -const signatureRequestErrorTransformer = (error: Error) => { - if ( - _.includes(error.message, constants.METAMASK_USER_DENIED_SIGNATURE_PATTERN) || - _.includes(error.message, constants.TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN) - ) { - const errMsg = ContractError.SignatureRequestDenied; - return new Error(errMsg); - } - return error; -}; - -/** - * Source: https://stackoverflow.com/a/29837695/3546986 - */ -const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { - const asyncErrorHandlingDecorator = ( - _target: object, - _key: string | symbol, - descriptor: TypedPropertyDescriptor, - ) => { - const originalMethod = descriptor.value as AsyncMethod; - - // Do not use arrow syntax here. Use a function expression in - // order to use the correct value of `this` in this method - // tslint:disable-next-line:only-arrow-functions - descriptor.value = async function(...args: any[]): Promise { - try { - const result = await originalMethod.apply(this, args); // tslint:disable-line:no-invalid-this - return result; - } catch (error) { - const transformedError = errorTransformer(error); - throw transformedError; - } - }; - - return descriptor; - }; - - return asyncErrorHandlingDecorator; -}; - -const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { - const syncErrorHandlingDecorator = ( - _target: object, - _key: string | symbol, - descriptor: TypedPropertyDescriptor, - ) => { - const originalMethod = descriptor.value as SyncMethod; - - // Do not use arrow syntax here. Use a function expression in - // order to use the correct value of `this` in this method - // tslint:disable-next-line:only-arrow-functions - descriptor.value = function(...args: any[]): any { - try { - const result = originalMethod.apply(this, args); // tslint:disable-line:no-invalid-this - return result; - } catch (error) { - const transformedError = errorTransformer(error); - throw transformedError; - } - }; - - return descriptor; - }; - - return syncErrorHandlingDecorator; -}; - -// _.flow(f, g) = f ∘ g -const zeroExErrorTransformer = _.flow( - schemaErrorTransformer, - contractCallErrorTransformer, - signatureRequestErrorTransformer, -); - -export const decorators = { - asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer), - syncZeroExErrorHandler: syncErrorHandlerFactory(zeroExErrorTransformer), -}; diff --git a/contracts/coordinator/src/hash_utils.ts b/contracts/coordinator/src/hash_utils.ts deleted file mode 100644 index 9c8980ae25..0000000000 --- a/contracts/coordinator/src/hash_utils.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { eip712Utils } from '@0x/order-utils'; -import { SignedZeroExTransaction } from '@0x/types'; -import { hexUtils, signTypedDataUtils } from '@0x/utils'; - -export const hashUtils = { - getApprovalHashBuffer(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): Buffer { - const typedData = eip712Utils.createCoordinatorApprovalTypedData(transaction, verifyingContract, txOrigin); - const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData); - return hashBuffer; - }, - getApprovalHashHex(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): string { - const hashHex = hexUtils.toHex(hashUtils.getApprovalHashBuffer(transaction, verifyingContract, txOrigin)); - return hashHex; - }, -}; diff --git a/contracts/coordinator/src/index.ts b/contracts/coordinator/src/index.ts deleted file mode 100644 index 99fe02d373..0000000000 --- a/contracts/coordinator/src/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -export { artifacts } from './artifacts'; -export { - CoordinatorContract, - CoordinatorRegistryContract, - LibConstantsContract, - LibCoordinatorApprovalContract, - LibCoordinatorRichErrorsContract, - LibEIP712CoordinatorDomainContract, -} from './wrappers'; -export { CoordinatorRevertErrors } from '@0x/utils'; -export { CoordinatorServerCancellationResponse } from './client/index'; -export { ApprovalFactory } from './approval_factory'; -export { SignedCoordinatorApproval } from './types'; -export { - Order, - SignedOrder, - SignatureType, - SignedZeroExTransaction, - EIP712DomainWithDefaultSchema, - ZeroExTransaction, -} from '@0x/types'; -export { AwaitTransactionSuccessOpts, SendTransactionOpts } from '@0x/base-contract'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, - SupportedProvider, - TxData, - TxDataPayable, - Web3JsProvider, - GanacheProvider, - EIP1193Provider, - ZeroExProvider, - EIP1193Event, - JSONRPCRequestPayload, - JSONRPCErrorCallback, - Web3JsV1Provider, - Web3JsV2Provider, - Web3JsV3Provider, - JSONRPCResponsePayload, - JSONRPCResponseError, -} from 'ethereum-types'; -export { CoordinatorClient, CoordinatorServerErrorMsg } from './client/index'; diff --git a/contracts/coordinator/src/types.ts b/contracts/coordinator/src/types.ts deleted file mode 100644 index 6ff7ee7b3d..0000000000 --- a/contracts/coordinator/src/types.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { SignedZeroExTransaction } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -export interface CoordinatorApproval { - transaction: SignedZeroExTransaction; - txOrigin: string; -} - -export interface SignedCoordinatorApproval extends CoordinatorApproval { - signature: string; -} - -export interface CoordinatorTransaction { - salt: BigNumber; - signerAddress: string; - data: string; -} diff --git a/contracts/coordinator/src/wrappers.ts b/contracts/coordinator/src/wrappers.ts deleted file mode 100644 index 53905d57a5..0000000000 --- a/contracts/coordinator/src/wrappers.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/coordinator'; -export * from '../generated-wrappers/coordinator_registry'; -export * from '../generated-wrappers/lib_constants'; -export * from '../generated-wrappers/lib_coordinator_approval'; -export * from '../generated-wrappers/lib_coordinator_rich_errors'; -export * from '../generated-wrappers/lib_e_i_p712_coordinator_domain'; diff --git a/contracts/coordinator/test/artifacts.ts b/contracts/coordinator/test/artifacts.ts deleted file mode 100644 index d432f86b29..0000000000 --- a/contracts/coordinator/test/artifacts.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Coordinator from '../test/generated-artifacts/Coordinator.json'; -import * as CoordinatorRegistry from '../test/generated-artifacts/CoordinatorRegistry.json'; -import * as ICoordinatorApprovalVerifier from '../test/generated-artifacts/ICoordinatorApprovalVerifier.json'; -import * as ICoordinatorCore from '../test/generated-artifacts/ICoordinatorCore.json'; -import * as ICoordinatorRegistryCore from '../test/generated-artifacts/ICoordinatorRegistryCore.json'; -import * as ICoordinatorSignatureValidator from '../test/generated-artifacts/ICoordinatorSignatureValidator.json'; -import * as LibConstants from '../test/generated-artifacts/LibConstants.json'; -import * as LibCoordinatorApproval from '../test/generated-artifacts/LibCoordinatorApproval.json'; -import * as LibCoordinatorRichErrors from '../test/generated-artifacts/LibCoordinatorRichErrors.json'; -import * as LibEIP712CoordinatorDomain from '../test/generated-artifacts/LibEIP712CoordinatorDomain.json'; -import * as MixinCoordinatorApprovalVerifier from '../test/generated-artifacts/MixinCoordinatorApprovalVerifier.json'; -import * as MixinCoordinatorCore from '../test/generated-artifacts/MixinCoordinatorCore.json'; -import * as MixinCoordinatorRegistryCore from '../test/generated-artifacts/MixinCoordinatorRegistryCore.json'; -import * as MixinSignatureValidator from '../test/generated-artifacts/MixinSignatureValidator.json'; -export const artifacts = { - Coordinator: Coordinator as ContractArtifact, - MixinCoordinatorApprovalVerifier: MixinCoordinatorApprovalVerifier as ContractArtifact, - MixinCoordinatorCore: MixinCoordinatorCore as ContractArtifact, - MixinSignatureValidator: MixinSignatureValidator as ContractArtifact, - ICoordinatorApprovalVerifier: ICoordinatorApprovalVerifier as ContractArtifact, - ICoordinatorCore: ICoordinatorCore as ContractArtifact, - ICoordinatorSignatureValidator: ICoordinatorSignatureValidator as ContractArtifact, - LibConstants: LibConstants as ContractArtifact, - LibCoordinatorApproval: LibCoordinatorApproval as ContractArtifact, - LibCoordinatorRichErrors: LibCoordinatorRichErrors as ContractArtifact, - LibEIP712CoordinatorDomain: LibEIP712CoordinatorDomain as ContractArtifact, - CoordinatorRegistry: CoordinatorRegistry as ContractArtifact, - MixinCoordinatorRegistryCore: MixinCoordinatorRegistryCore as ContractArtifact, - ICoordinatorRegistryCore: ICoordinatorRegistryCore as ContractArtifact, -}; diff --git a/contracts/coordinator/test/coordinator_registry.ts b/contracts/coordinator/test/coordinator_registry.ts deleted file mode 100644 index 8a1ede6009..0000000000 --- a/contracts/coordinator/test/coordinator_registry.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { blockchainTests, expect, verifyEvents } from '@0x/contracts-test-utils'; - -import { artifacts } from './artifacts'; - -import { CoordinatorRegistryContract, CoordinatorRegistryCoordinatorEndpointSetEventArgs } from './wrappers'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Coordinator Registry tests', env => { - let coordinatorRegistry: CoordinatorRegistryContract; - let coordinatorOperator: string; - const coordinatorEndpoint = 'http://sometec.0x.org'; - const nilCoordinatorEndpoint = ''; - // tests - before(async () => { - // setup accounts (skip owner) - const accounts = await env.getAccountAddressesAsync(); - [, coordinatorOperator] = accounts; - // deploy coordinator registry - coordinatorRegistry = await CoordinatorRegistryContract.deployFrom0xArtifactAsync( - artifacts.CoordinatorRegistry, - env.provider, - env.txDefaults, - artifacts, - ); - }); - describe('core', () => { - it('Should successfully set a Coordinator endpoint', async () => { - await coordinatorRegistry.setCoordinatorEndpoint(coordinatorEndpoint).awaitTransactionSuccessAsync({ - from: coordinatorOperator, - }); - const recordedCoordinatorEndpoint = await coordinatorRegistry - .getCoordinatorEndpoint(coordinatorOperator) - .callAsync(); - expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); - }); - it('Should successfully unset a Coordinator endpoint', async () => { - // set Coordinator endpoint - await coordinatorRegistry.setCoordinatorEndpoint(coordinatorEndpoint).awaitTransactionSuccessAsync({ - from: coordinatorOperator, - }); - let recordedCoordinatorEndpoint = await coordinatorRegistry - .getCoordinatorEndpoint(coordinatorOperator) - .callAsync(); - expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); - // unset Coordinator endpoint - await coordinatorRegistry.setCoordinatorEndpoint(nilCoordinatorEndpoint).awaitTransactionSuccessAsync({ - from: coordinatorOperator, - }); - recordedCoordinatorEndpoint = await coordinatorRegistry - .getCoordinatorEndpoint(coordinatorOperator) - .callAsync(); - expect(recordedCoordinatorEndpoint).to.be.equal(nilCoordinatorEndpoint); - }); - it('Should emit an event when setting Coordinator endpoint', async () => { - // set Coordinator endpoint - const txReceipt = await coordinatorRegistry - .setCoordinatorEndpoint(coordinatorEndpoint) - .awaitTransactionSuccessAsync({ - from: coordinatorOperator, - }); - const recordedCoordinatorEndpoint = await coordinatorRegistry - .getCoordinatorEndpoint(coordinatorOperator) - .callAsync(); - expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); - // validate event - const expectedEvent: CoordinatorRegistryCoordinatorEndpointSetEventArgs = { - coordinatorOperator, - coordinatorEndpoint, - }; - verifyEvents(txReceipt, [expectedEvent], 'CoordinatorEndpointSet'); - }); - }); -}); diff --git a/contracts/coordinator/test/global_hooks.ts b/contracts/coordinator/test/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/coordinator/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/coordinator/test/libs.ts b/contracts/coordinator/test/libs.ts deleted file mode 100644 index ab21f15e15..0000000000 --- a/contracts/coordinator/test/libs.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { blockchainTests, constants, expect, randomAddress, transactionHashUtils } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { hashUtils } from '../src/hash_utils'; - -import { artifacts } from './artifacts'; - -import { CoordinatorContract } from './wrappers'; - -blockchainTests.resets('Libs tests', env => { - let coordinatorContract: CoordinatorContract; - let chainId: number; - const exchangeAddress = randomAddress(); - - before(async () => { - chainId = await env.getChainIdAsync(); - coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( - artifacts.Coordinator, - env.provider, - env.txDefaults, - artifacts, - exchangeAddress, - new BigNumber(chainId), - ); - }); - - describe('getApprovalHash', () => { - it('should return the correct approval hash', async () => { - const signedTx = { - salt: constants.ZERO_AMOUNT, - gasPrice: constants.ZERO_AMOUNT, - expirationTimeSeconds: constants.ZERO_AMOUNT, - signerAddress: constants.NULL_ADDRESS, - data: '0x1234', - signature: '0x5678', - domain: { - verifyingContract: exchangeAddress, - chainId, - }, - }; - const txOrigin = constants.NULL_ADDRESS; - const approval = { - txOrigin, - transactionHash: transactionHashUtils.getTransactionHashHex(signedTx), - transactionSignature: signedTx.signature, - }; - const expectedApprovalHash = hashUtils.getApprovalHashHex(signedTx, coordinatorContract.address, txOrigin); - const approvalHash = await coordinatorContract.getCoordinatorApprovalHash(approval).callAsync(); - expect(expectedApprovalHash).to.eq(approvalHash); - }); - }); -}); diff --git a/contracts/coordinator/test/mixins.ts b/contracts/coordinator/test/mixins.ts deleted file mode 100644 index 9a514cd0a8..0000000000 --- a/contracts/coordinator/test/mixins.ts +++ /dev/null @@ -1,534 +0,0 @@ -import { exchangeDataEncoder } from '@0x/contracts-exchange'; -import { - blockchainTests, - constants, - ExchangeFunctionName, - expect, - randomAddress, - TransactionFactory, - transactionHashUtils, -} from '@0x/contracts-test-utils'; -import { LibBytesRevertErrors } from '@0x/contracts-utils'; -import { SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber, CoordinatorRevertErrors, hexUtils } from '@0x/utils'; - -import { ApprovalFactory } from '../src/approval_factory'; - -import { artifacts } from './artifacts'; - -import { CoordinatorContract } from './wrappers'; - -blockchainTests.resets('Mixins tests', env => { - let chainId: number; - let transactionSignerAddress: string; - let approvalSignerAddress1: string; - let approvalSignerAddress2: string; - let mixins: CoordinatorContract; - let transactionFactory: TransactionFactory; - let approvalFactory1: ApprovalFactory; - let approvalFactory2: ApprovalFactory; - let defaultOrder: SignedOrder; - const exchangeAddress = randomAddress(); - - before(async () => { - chainId = await env.getChainIdAsync(); - mixins = await CoordinatorContract.deployFrom0xArtifactAsync( - artifacts.Coordinator, - env.provider, - env.txDefaults, - artifacts, - exchangeAddress, - new BigNumber(chainId), - ); - const accounts = await env.getAccountAddressesAsync(); - [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts; - defaultOrder = { - makerAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - senderAddress: mixins.address, - feeRecipientAddress: approvalSignerAddress1, - makerAssetData: constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - makerAssetAmount: constants.ZERO_AMOUNT, - takerAssetAmount: constants.ZERO_AMOUNT, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - expirationTimeSeconds: constants.ZERO_AMOUNT, - salt: constants.ZERO_AMOUNT, - signature: constants.NULL_BYTES, - exchangeAddress: constants.NULL_ADDRESS, - chainId, - }; - const transactionSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)]; - const approvalSignerPrivateKey1 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)]; - const approvalSignerPrivateKey2 = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)]; - transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress, chainId); - approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); - approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); - }); - - describe('getSignerAddress', () => { - it('should return the correct address using the EthSign signature type', async () => { - const data = constants.NULL_BYTES; - const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EthSign); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const signerAddress = await mixins.getSignerAddress(transactionHash, transaction.signature).callAsync(); - expect(transaction.signerAddress).to.eq(signerAddress); - }); - it('should return the correct address using the EIP712 signature type', async () => { - const data = constants.NULL_BYTES; - const transaction = await transactionFactory.newSignedTransactionAsync({ data }, SignatureType.EIP712); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const signerAddress = await mixins.getSignerAddress(transactionHash, transaction.signature).callAsync(); - expect(transaction.signerAddress).to.eq(signerAddress); - }); - it('should revert with with the Illegal signature type', async () => { - const data = constants.NULL_BYTES; - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - transaction.signature = hexUtils.concat( - hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1), - SignatureType.Illegal, - ); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( - new CoordinatorRevertErrors.SignatureError( - CoordinatorRevertErrors.SignatureErrorCodes.Illegal, - transactionHash, - transaction.signature, - ), - ); - }); - it('should revert with with the Invalid signature type', async () => { - const data = constants.NULL_BYTES; - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - transaction.signature = hexUtils.concat(SignatureType.Invalid); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( - new CoordinatorRevertErrors.SignatureError( - CoordinatorRevertErrors.SignatureErrorCodes.Invalid, - transactionHash, - transaction.signature, - ), - ); - }); - it('should revert with with a signature type that equals `NSignatureTypes`', async () => { - const data = constants.NULL_BYTES; - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - transaction.signature = hexUtils.concat( - hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1), - SignatureType.NSignatureTypes, - ); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( - new CoordinatorRevertErrors.SignatureError( - CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, - transactionHash, - transaction.signature, - ), - ); - }); - it("should revert with with a signature type that isn't supported", async () => { - const data = constants.NULL_BYTES; - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - transaction.signature = hexUtils.concat( - hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1), - SignatureType.Wallet, - ); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith( - new CoordinatorRevertErrors.SignatureError( - CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, - transactionHash, - transaction.signature, - ), - ); - }); - }); - - describe('decodeOrdersFromFillData', () => { - for (const fnName of constants.SINGLE_FILL_FN_NAMES) { - it(`should correctly decode the orders for ${fnName} data`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); - const decodedSignedOrders = decodedOrders.map(order => ({ - ...order, - signature: constants.NULL_BYTES, - exchangeAddress: constants.NULL_ADDRESS, - chainId, - })); - expect(orders).to.deep.eq(decodedSignedOrders); - }); - } - for (const fnName of constants.BATCH_FILL_FN_NAMES) { - it(`should correctly decode the orders for ${fnName} data`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); - const decodedSignedOrders = decodedOrders.map(order => ({ - ...order, - signature: constants.NULL_BYTES, - exchangeAddress: constants.NULL_ADDRESS, - chainId, - })); - expect(orders).to.deep.eq(decodedSignedOrders); - }); - } - for (const fnName of constants.MARKET_FILL_FN_NAMES) { - it(`should correctly decode the orders for ${fnName} data`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); - const decodedSignedOrders = decodedOrders.map(order => ({ - ...order, - signature: constants.NULL_BYTES, - exchangeAddress: constants.NULL_ADDRESS, - chainId, - })); - expect(orders).to.deep.eq(decodedSignedOrders); - }); - } - for (const fnName of constants.MATCH_ORDER_FN_NAMES) { - it(`should correctly decode the orders for ${fnName} data`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); - const decodedSignedOrders = decodedOrders.map(order => ({ - ...order, - signature: constants.NULL_BYTES, - exchangeAddress: constants.NULL_ADDRESS, - chainId, - })); - expect(orders).to.deep.eq(decodedSignedOrders); - }); - } - for (const fnName of constants.CANCEL_ORDER_FN_NAMES) { - it(`should correctly decode the orders for ${fnName} data`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); - const emptyArray: any[] = []; - expect(emptyArray).to.deep.eq(decodedOrders); - }); - } - it('should decode an empty array for invalid data', async () => { - const data = '0x0123456789'; - const decodedOrders = await mixins.decodeOrdersFromFillData(data).callAsync(); - const emptyArray: any[] = []; - expect(emptyArray).to.deep.eq(decodedOrders); - }); - it('should revert if data is less than 4 bytes long', async () => { - const data = '0x010203'; - const expectedError = new LibBytesRevertErrors.InvalidByteOperationError( - LibBytesRevertErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsFourRequired, - new BigNumber(3), // the length of data - new BigNumber(4), - ); - return expect(mixins.decodeOrdersFromFillData(data).callAsync()).to.revertWith(expectedError); - }); - }); - - describe('Single order approvals', () => { - for (const fnName of constants.SINGLE_FILL_FN_NAMES) { - it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1]`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1]`, async () => { - const order = { - ...defaultOrder, - senderAddress: constants.NULL_ADDRESS, - }; - const orders = [order]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) - .callAsync({ - from: approvalSignerAddress1, - }); - }); - it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1]`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: approvalSignerAddress1 }); - }); - it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) - .callAsync({ - from: approvalSignerAddress1, - }); - }); - it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid]`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - const signature = hexUtils.concat( - hexUtils.slice(approval.signature, 0, 2), - '0xFFFFFFFF', - hexUtils.slice(approval.signature, 6), - ); - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - signature, - ]) - .callAsync({ from: transactionSignerAddress }); - - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(tx).to.revertWith( - new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), - ); - }); - it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1]`, async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: approvalSignerAddress2 }); - expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); - }); - } - }); - describe('Batch order approvals', () => { - for (const fnName of [ - ...constants.BATCH_FILL_FN_NAMES, - ...constants.MARKET_FILL_FN_NAMES, - ...constants.MATCH_ORDER_FN_NAMES, - ]) { - it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { - const orders = [defaultOrder, defaultOrder].map(order => ({ - ...order, - senderAddress: constants.NULL_ADDRESS, - })); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => { - const orders = [defaultOrder, defaultOrder].map(order => ({ - ...order, - senderAddress: constants.NULL_ADDRESS, - })); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => { - const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval.signature, - ]) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2]`, async () => { - const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval1.signature, - approval2.signature, - ]) - .callAsync({ from: transactionSignerAddress }); - }); - it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, []) - .callAsync({ from: approvalSignerAddress1 }); - }); - it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2]`, async () => { - const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); - - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval2.signature, - ]) - .callAsync({ from: approvalSignerAddress1 }); - expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); - }); - it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[]`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) - .callAsync({ from: transactionSignerAddress }); - - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(tx).to.revertWith( - new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), - ); - }); - it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid]`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - const signature = hexUtils.concat( - hexUtils.slice(approval.signature, 0, 2), - '0xFFFFFFFF', - hexUtils.slice(approval.signature, 6), - ); - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - signature, - ]) - .callAsync({ from: transactionSignerAddress }); - - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(tx).to.revertWith( - new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), - ); - }); - it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid]`, async () => { - const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); - const approvalSignature2 = hexUtils.concat( - hexUtils.slice(approval2.signature, 0, 2), - '0xFFFFFFFF', - hexUtils.slice(approval2.signature, 6), - ); - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval1.signature, - approvalSignature2, - ]) - .callAsync({ from: transactionSignerAddress }); - - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(tx).to.revertWith( - new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), - ); - }); - it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid]`, async () => { - const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress); - const approvalSignature2 = hexUtils.concat( - hexUtils.slice(approval2.signature, 0, 2), - '0xFFFFFFFF', - hexUtils.slice(approval2.signature, 6), - ); - const tx = mixins - .assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [ - approvalSignature2, - ]) - .callAsync({ from: approvalSignerAddress1 }); - - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(tx).to.revertWith( - new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), - ); - }); - it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid]`, async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress); - - const tx = mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [ - approval1.signature, - ]) - .callAsync({ from: approvalSignerAddress2 }); - expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); - }); - } - }); - describe('cancels', () => { - it('should allow the tx signer to call `cancelOrder` without approval', async () => { - const orders = [defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) - .callAsync({ from: transactionSignerAddress }); - }); - it('should allow the tx signer to call `batchCancelOrders` without approval', async () => { - const orders = [defaultOrder, defaultOrder]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) - .callAsync({ from: transactionSignerAddress }); - }); - it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => { - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo); - const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - await mixins - .assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, []) - .callAsync({ from: transactionSignerAddress }); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/coordinator/test/wrappers.ts b/contracts/coordinator/test/wrappers.ts deleted file mode 100644 index cfc1187fb8..0000000000 --- a/contracts/coordinator/test/wrappers.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/coordinator'; -export * from '../test/generated-wrappers/coordinator_registry'; -export * from '../test/generated-wrappers/i_coordinator_approval_verifier'; -export * from '../test/generated-wrappers/i_coordinator_core'; -export * from '../test/generated-wrappers/i_coordinator_registry_core'; -export * from '../test/generated-wrappers/i_coordinator_signature_validator'; -export * from '../test/generated-wrappers/lib_constants'; -export * from '../test/generated-wrappers/lib_coordinator_approval'; -export * from '../test/generated-wrappers/lib_coordinator_rich_errors'; -export * from '../test/generated-wrappers/lib_e_i_p712_coordinator_domain'; -export * from '../test/generated-wrappers/mixin_coordinator_approval_verifier'; -export * from '../test/generated-wrappers/mixin_coordinator_core'; -export * from '../test/generated-wrappers/mixin_coordinator_registry_core'; -export * from '../test/generated-wrappers/mixin_signature_validator'; diff --git a/contracts/coordinator/truffle-config.js b/contracts/coordinator/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/coordinator/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/coordinator/tsconfig.json b/contracts/coordinator/tsconfig.json deleted file mode 100644 index cd6b5d948f..0000000000 --- a/contracts/coordinator/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/Coordinator.json", - "generated-artifacts/CoordinatorRegistry.json", - "generated-artifacts/LibConstants.json", - "generated-artifacts/LibCoordinatorApproval.json", - "generated-artifacts/LibCoordinatorRichErrors.json", - "generated-artifacts/LibEIP712CoordinatorDomain.json", - "test/generated-artifacts/Coordinator.json", - "test/generated-artifacts/CoordinatorRegistry.json", - "test/generated-artifacts/ICoordinatorApprovalVerifier.json", - "test/generated-artifacts/ICoordinatorCore.json", - "test/generated-artifacts/ICoordinatorRegistryCore.json", - "test/generated-artifacts/ICoordinatorSignatureValidator.json", - "test/generated-artifacts/LibConstants.json", - "test/generated-artifacts/LibCoordinatorApproval.json", - "test/generated-artifacts/LibCoordinatorRichErrors.json", - "test/generated-artifacts/LibEIP712CoordinatorDomain.json", - "test/generated-artifacts/MixinCoordinatorApprovalVerifier.json", - "test/generated-artifacts/MixinCoordinatorCore.json", - "test/generated-artifacts/MixinCoordinatorRegistryCore.json", - "test/generated-artifacts/MixinSignatureValidator.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/coordinator/tslint.json b/contracts/coordinator/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/coordinator/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/coordinator/typedoc-tsconfig.json b/contracts/coordinator/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/coordinator/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/dev-utils/.npmignore b/contracts/dev-utils/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/dev-utils/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/dev-utils/CHANGELOG.json b/contracts/dev-utils/CHANGELOG.json deleted file mode 100644 index 0a388924aa..0000000000 --- a/contracts/dev-utils/CHANGELOG.json +++ /dev/null @@ -1,665 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "1.3.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "1.3.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "1.3.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "1.3.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "1.3.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "1.3.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "1.3.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "1.3.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "1.3.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "1.3.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "1.3.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "1.3.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "1.3.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "1.3.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "1.3.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "1.3.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "1.3.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "1.3.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "1.3.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "1.3.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "1.3.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "1.3.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "1.3.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "1.3.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "1.3.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "1.3.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "1.3.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "1.3.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "1.3.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "1.3.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "1.3.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "1.3.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "1.3.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "1.3.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "1.3.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "1.3.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.3.0", - "changes": [ - { - "note": "Update `DevUtils` addresses in `DeploymentConstants`", - "pr": 2493 - } - ], - "timestamp": 1582623685 - }, - { - "version": "1.2.0", - "changes": [ - { - "note": "Add `DydxBridge` order validation", - "pr": 2466 - } - ] - }, - { - "timestamp": 1581748629, - "version": "1.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Refactor mixins into public libraries.", - "pr": 2464 - }, - { - "note": "Remove `LibTransactionDecoder` export", - "pr": 2464 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Fixed ERC721 duplicate token ID bug", - "pr": 2400 - } - ], - "timestamp": 1578272714 - }, - { - "timestamp": 1576540892, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Add new method getOrderHash() to DevUtils contract", - "pr": 2321 - }, - { - "note": "Add new method getTransactionHash() to DevUtils contract", - "pr": 2321 - }, - { - "note": "Add `encodeStaticCallAssetData` and `decodeStaticCallAssetData` in LibAssetData", - "pr": 2034 - }, - { - "note": "Add `revertIfInvalidAssetData` in LibAssetData", - "pr": 2034 - }, - { - "note": "Use built in selectors instead of hard coded constants", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`.", - "pr": 2075 - }, - { - "note": "`run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable.", - "pr": 2075 - } - ], - "timestamp": 1575296764 - }, - { - "version": "0.1.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "0.1.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "0.1.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Add new method getOrderHash() to DevUtils contract", - "pr": 2321 - }, - { - "note": "Add new method getTransactionHash() to DevUtils contract", - "pr": 2321 - } - ], - "timestamp": 1574030254 - }, - { - "version": "0.1.0-beta.1", - "changes": [ - { - "note": "Add `encodeStaticCallAssetData` and `decodeStaticCallAssetData` in LibAssetData", - "pr": 2034 - }, - { - "note": "Add `revertIfInvalidAssetData` in LibAssetData", - "pr": 2034 - } - ], - "timestamp": 1573159180 - }, - { - "version": "0.1.0-beta.0", - "changes": [ - { - "note": "Use built in selectors instead of hard coded constants", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`.", - "pr": 2075 - }, - { - "note": "`run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable.", - "pr": 2075 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "0.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "0.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "0.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "0.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1564607468, - "version": "0.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.5", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564604963 - }, - { - "timestamp": 1563957393, - "version": "0.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "0.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "0.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "0.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.1", - "changes": [ - { - "note": "Create dev-utils package", - "pr": 1848 - }, - { - "note": "Add `LibAssetData` and `LibTransactionDecoder` contracts", - "pr": 1848 - }, - { - "note": "Refactor `LibAssetData` to only check 0x-specific allowances", - "pr": 1848 - }, - { - "note": "Refactor `LibAssetData` balance/allowance checks to never revert", - "pr": 1848 - }, - { - "note": "Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount`", - "pr": 1848 - }, - { - "note": "Add support for StaticCallProxy", - "pr": 1863 - }, - { - "note": "Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain", - "pr": 1868 - }, - { - "note": "Updated to use the new rich error pattern from @0x/contracts-exchange", - "pr": 1913 - } - ] - } -] diff --git a/contracts/dev-utils/CHANGELOG.md b/contracts/dev-utils/CHANGELOG.md deleted file mode 100644 index ac6ff5a527..0000000000 --- a/contracts/dev-utils/CHANGELOG.md +++ /dev/null @@ -1,280 +0,0 @@ - - -CHANGELOG - -## v1.3.36 - _August 16, 2021_ - - * Dependencies updated - -## v1.3.35 - _August 11, 2021_ - - * Dependencies updated - -## v1.3.34 - _August 6, 2021_ - - * Dependencies updated - -## v1.3.33 - _June 22, 2021_ - - * Dependencies updated - -## v1.3.32 - _June 11, 2021_ - - * Dependencies updated - -## v1.3.31 - _June 2, 2021_ - - * Dependencies updated - -## v1.3.30 - _May 25, 2021_ - - * Dependencies updated - -## v1.3.29 - _May 21, 2021_ - - * Dependencies updated - -## v1.3.28 - _May 5, 2021_ - - * Dependencies updated - -## v1.3.27 - _April 28, 2021_ - - * Dependencies updated - -## v1.3.26 - _April 1, 2021_ - - * Dependencies updated - -## v1.3.25 - _March 17, 2021_ - - * Dependencies updated - -## v1.3.24 - _February 24, 2021_ - - * Dependencies updated - -## v1.3.23 - _February 10, 2021_ - - * Dependencies updated - -## v1.3.22 - _January 26, 2021_ - - * Dependencies updated - -## v1.3.21 - _January 13, 2021_ - - * Dependencies updated - -## v1.3.20 - _January 4, 2021_ - - * Dependencies updated - -## v1.3.19 - _December 23, 2020_ - - * Dependencies updated - -## v1.3.18 - _December 17, 2020_ - - * Dependencies updated - -## v1.3.17 - _December 16, 2020_ - - * Dependencies updated - -## v1.3.16 - _December 9, 2020_ - - * Dependencies updated - -## v1.3.15 - _December 7, 2020_ - - * Dependencies updated - -## v1.3.14 - _December 3, 2020_ - - * Dependencies updated - -## v1.3.13 - _November 19, 2020_ - - * Dependencies updated - -## v1.3.12 - _November 13, 2020_ - - * Dependencies updated - -## v1.3.11 - _November 3, 2020_ - - * Dependencies updated - -## v1.3.10 - _November 3, 2020_ - - * Dependencies updated - -## v1.3.9 - _November 2, 2020_ - - * Dependencies updated - -## v1.3.8 - _October 28, 2020_ - - * Dependencies updated - -## v1.3.7 - _October 27, 2020_ - - * Dependencies updated - -## v1.3.6 - _October 21, 2020_ - - * Dependencies updated - -## v1.3.5 - _July 15, 2020_ - - * Dependencies updated - -## v1.3.4 - _June 24, 2020_ - - * Dependencies updated - -## v1.3.3 - _March 3, 2020_ - - * Dependencies updated - -## v1.3.2 - _February 27, 2020_ - - * Dependencies updated - -## v1.3.1 - _February 26, 2020_ - - * Dependencies updated - -## v1.3.0 - _February 25, 2020_ - - * Update `DevUtils` addresses in `DeploymentConstants` (#2493) - -## v1.2.0 - _Invalid date_ - - * Add `DydxBridge` order validation (#2466) - -## v1.1.1 - _February 15, 2020_ - - * Dependencies updated - -## v1.1.0 - _February 8, 2020_ - - * Refactor mixins into public libraries. (#2464) - * Remove `LibTransactionDecoder` export (#2464) - -## v1.0.6 - _February 6, 2020_ - - * Dependencies updated - -## v1.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v1.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v1.0.3 - _January 6, 2020_ - - * Fixed ERC721 duplicate token ID bug (#2400) - -## v1.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v1.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v1.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Add new method getOrderHash() to DevUtils contract (#2321) - * Add new method getTransactionHash() to DevUtils contract (#2321) - * Add `encodeStaticCallAssetData` and `decodeStaticCallAssetData` in LibAssetData (#2034) - * Add `revertIfInvalidAssetData` in LibAssetData (#2034) - * Use built in selectors instead of hard coded constants (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`. (#2075) - * `run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable. (#2075) - -## v0.1.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v0.1.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v0.1.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Add new method getOrderHash() to DevUtils contract (#2321) - * Add new method getTransactionHash() to DevUtils contract (#2321) - -## v0.1.0-beta.1 - _November 7, 2019_ - - * Add `encodeStaticCallAssetData` and `decodeStaticCallAssetData` in LibAssetData (#2034) - * Add `revertIfInvalidAssetData` in LibAssetData (#2034) - -## v0.1.0-beta.0 - _October 3, 2019_ - - * Use built in selectors instead of hard coded constants (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`. (#2075) - * `run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable. (#2075) - -## v0.0.10 - _September 17, 2019_ - - * Dependencies updated - -## v0.0.9 - _September 3, 2019_ - - * Dependencies updated - -## v0.0.8 - _August 22, 2019_ - - * Dependencies updated - -## v0.0.7 - _August 8, 2019_ - - * Dependencies updated - -## v0.0.6 - _July 31, 2019_ - - * Dependencies updated - -## v0.0.5 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v0.0.5 - _July 24, 2019_ - - * Dependencies updated - -## v0.0.4 - _July 15, 2019_ - - * Dependencies updated - -## v0.0.3 - _July 13, 2019_ - - * Dependencies updated - -## v0.0.2 - _July 13, 2019_ - - * Dependencies updated - -## v0.0.1 - _Invalid date_ - - * Create dev-utils package (#1848) - * Add `LibAssetData` and `LibTransactionDecoder` contracts (#1848) - * Refactor `LibAssetData` to only check 0x-specific allowances (#1848) - * Refactor `LibAssetData` balance/allowance checks to never revert (#1848) - * Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848) - * Add support for StaticCallProxy (#1863) - * Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain (#1868) - * Updated to use the new rich error pattern from @0x/contracts-exchange (#1913) diff --git a/contracts/dev-utils/DEPLOYS.json b/contracts/dev-utils/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/dev-utils/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/dev-utils/README.md b/contracts/dev-utils/README.md deleted file mode 100644 index 05ac1aee92..0000000000 --- a/contracts/dev-utils/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## Dev-Utils - -This package implements various utilities for developers. For example, the `DevUtils` contract can query batches of balances or allowances given some `assetData`, can validate batches of orders, and can decode 0x-specific calldata. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-dev-utils --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-dev-utils yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-dev-utils yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/dev-utils/compiler.json b/contracts/dev-utils/compiler.json deleted file mode 100644 index 9fda7deacb..0000000000 --- a/contracts/dev-utils/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 5000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/dev-utils/contracts/src/Addresses.sol b/contracts/dev-utils/contracts/src/Addresses.sol deleted file mode 100644 index 12e58284fb..0000000000 --- a/contracts/dev-utils/contracts/src/Addresses.sol +++ /dev/null @@ -1,54 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; - - -// solhint-disable no-empty-blocks -contract Addresses is - DeploymentConstants -{ - address public exchangeAddress; - address public erc20ProxyAddress; - address public erc721ProxyAddress; - address public erc1155ProxyAddress; - address public staticCallProxyAddress; - address public chaiBridgeAddress; - address public dydxBridgeAddress; - - constructor ( - address exchange_, - address chaiBridge_, - address dydxBridge_ - ) - public - { - exchangeAddress = exchange_; - chaiBridgeAddress = chaiBridge_; - dydxBridgeAddress = dydxBridge_; - erc20ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC20Token.selector); - erc721ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC721Token.selector); - erc1155ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); - staticCallProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).StaticCall.selector); - } -} diff --git a/contracts/dev-utils/contracts/src/AssetBalance.sol b/contracts/dev-utils/contracts/src/AssetBalance.sol deleted file mode 100644 index a71d116ffb..0000000000 --- a/contracts/dev-utils/contracts/src/AssetBalance.sol +++ /dev/null @@ -1,388 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; -import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "./Addresses.sol"; -import "./LibDydxBalance.sol"; - - -contract AssetBalance is - Addresses -{ - // 2^256 - 1 - uint256 constant internal _MAX_UINT256 = uint256(-1); - - using LibBytes for bytes; - - /// @dev Returns the owner's balance of the assets(s) specified in - /// assetData. When the asset data contains multiple assets (eg in - /// ERC1155 or Multi-Asset), the return value indicates how many - /// complete "baskets" of those assets are owned by owner. - /// @param ownerAddress Owner of the assets specified by assetData. - /// @param assetData Details of asset, encoded per the AssetProxy contract specification. - /// @return Number of assets (or asset baskets) held by owner. - function getBalance(address ownerAddress, bytes memory assetData) - public - returns (uint256 balance) - { - // Get id of AssetProxy contract - bytes4 assetProxyId = assetData.readBytes4(0); - - if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { - // Get ERC20 token address - address tokenAddress = assetData.readAddress(16); - balance = LibERC20Token.balanceOf(tokenAddress, ownerAddress); - - } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { - // Get ERC721 token address and id - (, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData); - - // Check if id is owned by ownerAddress - bytes memory ownerOfCalldata = abi.encodeWithSelector( - IERC721Token(address(0)).ownerOf.selector, - tokenId - ); - - (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); - address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); - balance = currentOwnerAddress == ownerAddress ? 1 : 0; - - } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { - // Get ERC1155 token address, array of ids, and array of values - (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = LibAssetData.decodeERC1155AssetData(assetData); - - uint256 length = tokenIds.length; - for (uint256 i = 0; i != length; i++) { - // Skip over the token if the corresponding value is 0. - if (tokenValues[i] == 0) { - continue; - } - - // Encode data for `balanceOf(ownerAddress, tokenIds[i]) - bytes memory balanceOfData = abi.encodeWithSelector( - IERC1155(address(0)).balanceOf.selector, - ownerAddress, - tokenIds[i] - ); - - // Query balance - (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData); - uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; - - // Scale total balance down by corresponding value in assetData - uint256 scaledBalance = totalBalance / tokenValues[i]; - if (scaledBalance == 0) { - return 0; - } - if (scaledBalance < balance || balance == 0) { - balance = scaledBalance; - } - } - - } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { - // Encode data for `staticCallProxy.transferFrom(assetData,...)` - bytes memory transferFromData = abi.encodeWithSelector( - IAssetProxy(address(0)).transferFrom.selector, - assetData, - address(0), // `from` address is not used - address(0), // `to` address is not used - 0 // `amount` is not used - ); - - // Check if staticcall would be successful - (bool success,) = staticCallProxyAddress.staticcall(transferFromData); - - // Success means that the staticcall can be made an unlimited amount of times - balance = success ? _MAX_UINT256 : 0; - - } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { - // Get address of ERC20 token and bridge contract - (, address tokenAddress, address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(assetData); - if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) { - uint256 chaiBalance = LibERC20Token.balanceOf(_getChaiAddress(), ownerAddress); - // Calculate Dai balance - balance = _convertChaiToDaiAmount(chaiBalance); - } - // Balance will be 0 if bridge is not supported - - } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { - // Get array of values and array of assetDatas - (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData); - - uint256 length = nestedAssetData.length; - for (uint256 i = 0; i != length; i++) { - // Skip over the asset if the corresponding amount is 0. - if (assetAmounts[i] == 0) { - continue; - } - - // Query balance of individual assetData - uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]); - - // Scale total balance down by corresponding value in assetData - uint256 scaledBalance = totalBalance / assetAmounts[i]; - if (scaledBalance == 0) { - return 0; - } - if (scaledBalance < balance || balance == 0) { - balance = scaledBalance; - } - } - } - - // Balance will be 0 if assetProxyId is unknown - return balance; - } - - /// @dev Calls getBalance() for each element of assetData. - /// @param ownerAddress Owner of the assets specified by assetData. - /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. - /// @return Array of asset balances from getBalance(), with each element - /// corresponding to the same-indexed element in the assetData input. - function getBatchBalances(address ownerAddress, bytes[] memory assetData) - public - returns (uint256[] memory balances) - { - uint256 length = assetData.length; - balances = new uint256[](length); - for (uint256 i = 0; i != length; i++) { - balances[i] = getBalance(ownerAddress, assetData[i]); - } - return balances; - } - - /// @dev Returns the number of asset(s) (described by assetData) that - /// the corresponding AssetProxy contract is authorized to spend. When the asset data contains - /// multiple assets (eg for Multi-Asset), the return value indicates - /// how many complete "baskets" of those assets may be spent by all of the corresponding - /// AssetProxy contracts. - /// @param ownerAddress Owner of the assets specified by assetData. - /// @param assetData Details of asset, encoded per the AssetProxy contract specification. - /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. - function getAssetProxyAllowance(address ownerAddress, bytes memory assetData) - public - returns (uint256 allowance) - { - // Get id of AssetProxy contract - bytes4 assetProxyId = assetData.readBytes4(0); - - if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { - // Get array of values and array of assetDatas - (, uint256[] memory amounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData); - - uint256 length = nestedAssetData.length; - for (uint256 i = 0; i != length; i++) { - // Skip over the asset if the corresponding amount is 0. - if (amounts[i] == 0) { - continue; - } - - // Query allowance of individual assetData - uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]); - - // Scale total allowance down by corresponding value in assetData - uint256 scaledAllowance = totalAllowance / amounts[i]; - if (scaledAllowance == 0) { - return 0; - } - if (scaledAllowance < allowance || allowance == 0) { - allowance = scaledAllowance; - } - } - return allowance; - } - - if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { - // Get ERC20 token address - address tokenAddress = assetData.readAddress(16); - allowance = LibERC20Token.allowance(tokenAddress, ownerAddress, erc20ProxyAddress); - - } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { - // Get ERC721 token address and id - (, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData); - - // Encode data for `isApprovedForAll(ownerAddress, erc721ProxyAddress)` - bytes memory isApprovedForAllData = abi.encodeWithSelector( - IERC721Token(address(0)).isApprovedForAll.selector, - ownerAddress, - erc721ProxyAddress - ); - - (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); - - // If not approved for all, call `getApproved(tokenId)` - if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) { - // Encode data for `getApproved(tokenId)` - bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId); - (success, returnData) = tokenAddress.staticcall(getApprovedData); - - // Allowance is 1 if successful and the approved address is the ERC721Proxy - allowance = success && returnData.length == 32 && returnData.readAddress(12) == erc721ProxyAddress ? 1 : 0; - } else { - // Allowance is 2^256 - 1 if `isApprovedForAll` returned true - allowance = _MAX_UINT256; - } - - } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { - // Get ERC1155 token address - (, address tokenAddress, , , ) = LibAssetData.decodeERC1155AssetData(assetData); - - // Encode data for `isApprovedForAll(ownerAddress, erc1155ProxyAddress)` - bytes memory isApprovedForAllData = abi.encodeWithSelector( - IERC1155(address(0)).isApprovedForAll.selector, - ownerAddress, - erc1155ProxyAddress - ); - - // Query allowance - (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); - allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0; - - } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { - // The StaticCallProxy does not require any approvals - allowance = _MAX_UINT256; - - } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { - // Get address of ERC20 token and bridge contract - (, address tokenAddress, address bridgeAddress,) = - LibAssetData.decodeERC20BridgeAssetData(assetData); - if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) { - uint256 chaiAllowance = LibERC20Token.allowance(_getChaiAddress(), ownerAddress, chaiBridgeAddress); - // Dai allowance is unlimited if Chai allowance is unlimited - allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance); - } else if (bridgeAddress == dydxBridgeAddress) { - allowance = LibDydxBalance.getDydxMakerAllowance(ownerAddress, bridgeAddress, _getDydxAddress()); - } - // Allowance will be 0 if bridge is not supported - } - - // Allowance will be 0 if the assetProxyId is unknown - return allowance; - } - - /// @dev Calls getAssetProxyAllowance() for each element of assetData. - /// @param ownerAddress Owner of the assets specified by assetData. - /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. - /// @return An array of asset allowances from getAllowance(), with each - /// element corresponding to the same-indexed element in the assetData input. - function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) - public - returns (uint256[] memory allowances) - { - uint256 length = assetData.length; - allowances = new uint256[](length); - for (uint256 i = 0; i != length; i++) { - allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]); - } - return allowances; - } - - /// @dev Calls getBalance() and getAllowance() for assetData. - /// @param ownerAddress Owner of the assets specified by assetData. - /// @param assetData Details of asset, encoded per the AssetProxy contract specification. - /// @return Number of assets (or asset baskets) held by owner, and number - /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. - function getBalanceAndAssetProxyAllowance( - address ownerAddress, - bytes memory assetData - ) - public - returns (uint256 balance, uint256 allowance) - { - balance = getBalance(ownerAddress, assetData); - allowance = getAssetProxyAllowance(ownerAddress, assetData); - return (balance, allowance); - } - - /// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData. - /// @param ownerAddress Owner of the assets specified by assetData. - /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. - /// @return An array of asset balances from getBalance(), and an array of - /// asset allowances from getAllowance(), with each element - /// corresponding to the same-indexed element in the assetData input. - function getBatchBalancesAndAssetProxyAllowances( - address ownerAddress, - bytes[] memory assetData - ) - public - returns (uint256[] memory balances, uint256[] memory allowances) - { - balances = getBatchBalances(ownerAddress, assetData); - allowances = getBatchAssetProxyAllowances(ownerAddress, assetData); - return (balances, allowances); - } - - /// @dev Converts an amount of Chai into its equivalent Dai amount. - /// Also accumulates Dai from DSR if called after the last time it was collected. - /// @param chaiAmount Amount of Chai to converts. - function _convertChaiToDaiAmount(uint256 chaiAmount) - internal - returns (uint256 daiAmount) - { - PotLike pot = IChai(_getChaiAddress()).pot(); - // Accumulate savings if called after last time savings were collected - // solhint-disable-next-line not-rely-on-time - uint256 chiMultiplier = (now > pot.rho()) - ? pot.drip() - : pot.chi(); - daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount); - return daiAmount; - } - - /// @dev Returns an order MAKER's balance of the assets(s) specified in - /// makerAssetData. Unlike `getBalanceAndAssetProxyAllowance()`, this - /// can handle maker asset types that depend on taker tokens being - /// transferred to the maker first. - /// @param order The order. - /// @return balance Quantity of assets transferrable from maker to taker. - function _getConvertibleMakerBalanceAndAssetProxyAllowance( - LibOrder.Order memory order - ) - internal - returns (uint256 balance, uint256 allowance) - { - if (order.makerAssetData.length < 4) { - return (0, 0); - } - bytes4 assetProxyId = order.makerAssetData.readBytes4(0); - // Handle dydx bridge assets. - if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { - (, , address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData); - if (bridgeAddress == dydxBridgeAddress) { - return ( - LibDydxBalance.getDydxMakerBalance(order, _getDydxAddress()), - getAssetProxyAllowance(order.makerAddress, order.makerAssetData) - ); - } - } - return ( - getBalance(order.makerAddress, order.makerAssetData), - getAssetProxyAllowance(order.makerAddress, order.makerAssetData) - ); - } -} diff --git a/contracts/dev-utils/contracts/src/DevUtils.sol b/contracts/dev-utils/contracts/src/DevUtils.sol deleted file mode 100644 index b275b3ccb1..0000000000 --- a/contracts/dev-utils/contracts/src/DevUtils.sol +++ /dev/null @@ -1,84 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "./Addresses.sol"; -import "./OrderValidationUtils.sol"; -import "./EthBalanceChecker.sol"; -import "./ExternalFunctions.sol"; - - -// solhint-disable no-empty-blocks -contract DevUtils is - Addresses, - OrderValidationUtils, - LibEIP712ExchangeDomain, - EthBalanceChecker, - ExternalFunctions -{ - constructor ( - address exchange_, - address chaiBridge_, - address dydxBridge_ - ) - public - Addresses( - exchange_, - chaiBridge_, - dydxBridge_ - ) - LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants - {} - - function getOrderHash( - LibOrder.Order memory order, - uint256 chainId, - address exchange - ) - public - pure - returns (bytes32 orderHash) - { - return LibOrder.getTypedDataHash( - order, - LibEIP712.hashEIP712Domain(_EIP712_EXCHANGE_DOMAIN_NAME, _EIP712_EXCHANGE_DOMAIN_VERSION, chainId, exchange) - ); - } - - function getTransactionHash( - LibZeroExTransaction.ZeroExTransaction memory transaction, - uint256 chainId, - address exchange - ) - public - pure - returns (bytes32 transactionHash) - { - return LibZeroExTransaction.getTypedDataHash( - transaction, - LibEIP712.hashEIP712Domain(_EIP712_EXCHANGE_DOMAIN_NAME, _EIP712_EXCHANGE_DOMAIN_VERSION, chainId, exchange) - ); - } -} diff --git a/contracts/dev-utils/contracts/src/EthBalanceChecker.sol b/contracts/dev-utils/contracts/src/EthBalanceChecker.sol deleted file mode 100644 index 48e0215692..0000000000 --- a/contracts/dev-utils/contracts/src/EthBalanceChecker.sol +++ /dev/null @@ -1,39 +0,0 @@ -/* - - Copyright 2019 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.5.16; - - -contract EthBalanceChecker { - - /// @dev Batch fetches ETH balances - /// @param addresses Array of addresses. - /// @return Array of ETH balances. - function getEthBalances(address[] memory addresses) - public - view - returns (uint256[] memory) - { - uint256[] memory balances = new uint256[](addresses.length); - for (uint256 i = 0; i != addresses.length; i++) { - balances[i] = addresses[i].balance; - } - return balances; - } - -} diff --git a/contracts/dev-utils/contracts/src/ExternalFunctions.sol b/contracts/dev-utils/contracts/src/ExternalFunctions.sol deleted file mode 100644 index e9e1443404..0000000000 --- a/contracts/dev-utils/contracts/src/ExternalFunctions.sol +++ /dev/null @@ -1,322 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "./Addresses.sol"; -import "./LibAssetData.sol"; -import "./LibTransactionDecoder.sol"; -import "./LibOrderTransferSimulation.sol"; - - -contract ExternalFunctions is - Addresses -{ - - /// @dev Decodes the call data for an Exchange contract method call. - /// @param transactionData ABI-encoded calldata for an Exchange - /// contract method call. - /// @return The name of the function called, and the parameters it was - /// given. For single-order fills and cancels, the arrays will have - /// just one element. - function decodeZeroExTransactionData(bytes memory transactionData) - public - pure - returns( - string memory functionName, - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - { - return LibTransactionDecoder.decodeZeroExTransactionData(transactionData); - } - - /// @dev Decode AssetProxy identifier - /// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset. - /// @return The AssetProxy identifier - function decodeAssetProxyId(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId - ) - { - return LibAssetData.decodeAssetProxyId(assetData); - } - - /// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification. - /// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded. - /// @return AssetProxy-compliant data describing the asset. - function encodeERC20AssetData(address tokenAddress) - public - pure - returns (bytes memory assetData) - { - return LibAssetData.encodeERC20AssetData(tokenAddress); - } - - /// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset. - /// @return The AssetProxy identifier, and the address of the ERC-20 - /// contract hosting this asset. - function decodeERC20AssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress - ) - { - return LibAssetData.decodeERC20AssetData(assetData); - } - - /// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification. - /// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded. - /// @param tokenId The identifier of the specific asset to be traded. - /// @return AssetProxy-compliant asset data describing the asset. - function encodeERC721AssetData(address tokenAddress, uint256 tokenId) - public - pure - returns (bytes memory assetData) - { - return LibAssetData.encodeERC721AssetData(tokenAddress, tokenId); - } - - /// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset. - /// @return The ERC-721 AssetProxy identifier, the address of the ERC-721 - /// contract hosting this asset, and the identifier of the specific - /// asset to be traded. - function decodeERC721AssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress, - uint256 tokenId - ) - { - return LibAssetData.decodeERC721AssetData(assetData); - } - - /// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification. - /// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded. - /// @param tokenIds The identifiers of the specific assets to be traded. - /// @param tokenValues The amounts of each asset to be traded. - /// @param callbackData Data to be passed to receiving contracts when a transfer is performed. - /// @return AssetProxy-compliant asset data describing the set of assets. - function encodeERC1155AssetData( - address tokenAddress, - uint256[] memory tokenIds, - uint256[] memory tokenValues, - bytes memory callbackData - ) - public - pure - returns (bytes memory assetData) - { - return LibAssetData.encodeERC1155AssetData( - tokenAddress, - tokenIds, - tokenValues, - callbackData - ); - } - - /// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets. - /// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155 - /// contract hosting the assets, an array of the identifiers of the - /// assets to be traded, an array of asset amounts to be traded, and - /// callback data. Each element of the arrays corresponds to the - /// same-indexed element of the other array. Return values specified as - /// `memory` are returned as pointers to locations within the memory of - /// the input parameter `assetData`. - function decodeERC1155AssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress, - uint256[] memory tokenIds, - uint256[] memory tokenValues, - bytes memory callbackData - ) - { - return LibAssetData.decodeERC1155AssetData(assetData); - } - - /// @dev Encode data for multiple assets, per the AssetProxy contract specification. - /// @param amounts The amounts of each asset to be traded. - /// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded. - /// @return AssetProxy-compliant data describing the set of assets. - function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData) - public - pure - returns (bytes memory assetData) - { - return LibAssetData.encodeMultiAssetData(amounts, nestedAssetData); - } - - /// @dev Decode multi-asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant data describing a multi-asset basket. - /// @return The Multi-Asset AssetProxy identifier, an array of the amounts - /// of the assets to be traded, and an array of the - /// AssetProxy-compliant data describing each asset to be traded. Each - /// element of the arrays corresponds to the same-indexed element of the other array. - function decodeMultiAssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - uint256[] memory amounts, - bytes[] memory nestedAssetData - ) - { - return LibAssetData.decodeMultiAssetData(assetData); - } - - /// @dev Encode StaticCall asset data into the format described in the AssetProxy contract specification. - /// @param staticCallTargetAddress Target address of StaticCall. - /// @param staticCallData Data that will be passed to staticCallTargetAddress in the StaticCall. - /// @param expectedReturnDataHash Expected Keccak-256 hash of the StaticCall return data. - /// @return AssetProxy-compliant asset data describing the set of assets. - function encodeStaticCallAssetData( - address staticCallTargetAddress, - bytes memory staticCallData, - bytes32 expectedReturnDataHash - ) - public - pure - returns (bytes memory assetData) - { - return LibAssetData.encodeStaticCallAssetData( - staticCallTargetAddress, - staticCallData, - expectedReturnDataHash - ); - } - - /// @dev Decode StaticCall asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing a StaticCall asset - /// @return The StaticCall AssetProxy identifier, the target address of the StaticCAll, the data to be - /// passed to the target address, and the expected Keccak-256 hash of the static call return data. - function decodeStaticCallAssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address staticCallTargetAddress, - bytes memory staticCallData, - bytes32 expectedReturnDataHash - ) - { - return LibAssetData.decodeStaticCallAssetData(assetData); - } - - /// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset - /// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address - /// of the bridge contract, and extra data to be passed to the bridge contract. - function decodeERC20BridgeAssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress, - address bridgeAddress, - bytes memory bridgeData - ) - { - return LibAssetData.decodeERC20BridgeAssetData(assetData); - } - - /// @dev Reverts if assetData is not of a valid format for its given proxy id. - /// @param assetData AssetProxy compliant asset data. - function revertIfInvalidAssetData(bytes memory assetData) - public - pure - { - return LibAssetData.revertIfInvalidAssetData(assetData); - } - - /// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer. - /// @param order The order to simulate transfers for. - /// @param takerAddress The address of the taker that will fill the order. - /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. - /// @return The index of the first failed transfer (or 4 if all transfers are successful). - function getSimulatedOrderMakerTransferResults( - LibOrder.Order memory order, - address takerAddress, - uint256 takerAssetFillAmount - ) - public - returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults) - { - return LibOrderTransferSimulation.getSimulatedOrderMakerTransferResults( - exchangeAddress, - order, - takerAddress, - takerAssetFillAmount - ); - } - - /// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. - /// @param order The order to simulate transfers for. - /// @param takerAddress The address of the taker that will fill the order. - /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. - /// @return The index of the first failed transfer (or 4 if all transfers are successful). - function getSimulatedOrderTransferResults( - LibOrder.Order memory order, - address takerAddress, - uint256 takerAssetFillAmount - ) - public - returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults) - { - return LibOrderTransferSimulation.getSimulatedOrderTransferResults( - exchangeAddress, - order, - takerAddress, - takerAssetFillAmount - ); - } - - /// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. - /// @param orders Array of orders to individually simulate transfers for. - /// @param takerAddresses Array of addresses of takers that will fill each order. - /// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. - /// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. - function getSimulatedOrdersTransferResults( - LibOrder.Order[] memory orders, - address[] memory takerAddresses, - uint256[] memory takerAssetFillAmounts - ) - public - returns (LibOrderTransferSimulation.OrderTransferResults[] memory orderTransferResults) - { - return LibOrderTransferSimulation.getSimulatedOrdersTransferResults( - exchangeAddress, - orders, - takerAddresses, - takerAssetFillAmounts - ); - } -} diff --git a/contracts/dev-utils/contracts/src/LibAssetData.sol b/contracts/dev-utils/contracts/src/LibAssetData.sol deleted file mode 100644 index 2408c9dae4..0000000000 --- a/contracts/dev-utils/contracts/src/LibAssetData.sol +++ /dev/null @@ -1,354 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; - - -library LibAssetData { - - using LibBytes for bytes; - - /// @dev Decode AssetProxy identifier - /// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset. - /// @return The AssetProxy identifier - function decodeAssetProxyId(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).ERC20Token.selector || - assetProxyId == IAssetData(address(0)).ERC721Token.selector || - assetProxyId == IAssetData(address(0)).ERC1155Assets.selector || - assetProxyId == IAssetData(address(0)).MultiAsset.selector || - assetProxyId == IAssetData(address(0)).StaticCall.selector, - "WRONG_PROXY_ID" - ); - return assetProxyId; - } - - /// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification. - /// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded. - /// @return AssetProxy-compliant data describing the asset. - function encodeERC20AssetData(address tokenAddress) - public - pure - returns (bytes memory assetData) - { - assetData = abi.encodeWithSelector(IAssetData(address(0)).ERC20Token.selector, tokenAddress); - return assetData; - } - - /// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset. - /// @return The AssetProxy identifier, and the address of the ERC-20 - /// contract hosting this asset. - function decodeERC20AssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).ERC20Token.selector, - "WRONG_PROXY_ID" - ); - - tokenAddress = assetData.readAddress(16); - return (assetProxyId, tokenAddress); - } - - /// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification. - /// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded. - /// @param tokenId The identifier of the specific asset to be traded. - /// @return AssetProxy-compliant asset data describing the asset. - function encodeERC721AssetData(address tokenAddress, uint256 tokenId) - public - pure - returns (bytes memory assetData) - { - assetData = abi.encodeWithSelector( - IAssetData(address(0)).ERC721Token.selector, - tokenAddress, - tokenId - ); - return assetData; - } - - /// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset. - /// @return The ERC-721 AssetProxy identifier, the address of the ERC-721 - /// contract hosting this asset, and the identifier of the specific - /// asset to be traded. - function decodeERC721AssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress, - uint256 tokenId - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).ERC721Token.selector, - "WRONG_PROXY_ID" - ); - - tokenAddress = assetData.readAddress(16); - tokenId = assetData.readUint256(36); - return (assetProxyId, tokenAddress, tokenId); - } - - /// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification. - /// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded. - /// @param tokenIds The identifiers of the specific assets to be traded. - /// @param tokenValues The amounts of each asset to be traded. - /// @param callbackData Data to be passed to receiving contracts when a transfer is performed. - /// @return AssetProxy-compliant asset data describing the set of assets. - function encodeERC1155AssetData( - address tokenAddress, - uint256[] memory tokenIds, - uint256[] memory tokenValues, - bytes memory callbackData - ) - public - pure - returns (bytes memory assetData) - { - assetData = abi.encodeWithSelector( - IAssetData(address(0)).ERC1155Assets.selector, - tokenAddress, - tokenIds, - tokenValues, - callbackData - ); - return assetData; - } - - /// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets. - /// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155 - /// contract hosting the assets, an array of the identifiers of the - /// assets to be traded, an array of asset amounts to be traded, and - /// callback data. Each element of the arrays corresponds to the - /// same-indexed element of the other array. Return values specified as - /// `memory` are returned as pointers to locations within the memory of - /// the input parameter `assetData`. - function decodeERC1155AssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress, - uint256[] memory tokenIds, - uint256[] memory tokenValues, - bytes memory callbackData - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).ERC1155Assets.selector, - "WRONG_PROXY_ID" - ); - - assembly { - // Skip selector and length to get to the first parameter: - assetData := add(assetData, 36) - // Read the value of the first parameter: - tokenAddress := mload(assetData) - // Point to the next parameter's data: - tokenIds := add(assetData, mload(add(assetData, 32))) - // Point to the next parameter's data: - tokenValues := add(assetData, mload(add(assetData, 64))) - // Point to the next parameter's data: - callbackData := add(assetData, mload(add(assetData, 96))) - } - - return ( - assetProxyId, - tokenAddress, - tokenIds, - tokenValues, - callbackData - ); - } - - /// @dev Encode data for multiple assets, per the AssetProxy contract specification. - /// @param amounts The amounts of each asset to be traded. - /// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded. - /// @return AssetProxy-compliant data describing the set of assets. - function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData) - public - pure - returns (bytes memory assetData) - { - assetData = abi.encodeWithSelector( - IAssetData(address(0)).MultiAsset.selector, - amounts, - nestedAssetData - ); - return assetData; - } - - /// @dev Decode multi-asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant data describing a multi-asset basket. - /// @return The Multi-Asset AssetProxy identifier, an array of the amounts - /// of the assets to be traded, and an array of the - /// AssetProxy-compliant data describing each asset to be traded. Each - /// element of the arrays corresponds to the same-indexed element of the other array. - function decodeMultiAssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - uint256[] memory amounts, - bytes[] memory nestedAssetData - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).MultiAsset.selector, - "WRONG_PROXY_ID" - ); - - // solhint-disable indent - (amounts, nestedAssetData) = abi.decode( - assetData.slice(4, assetData.length), - (uint256[], bytes[]) - ); - // solhint-enable indent - } - - /// @dev Encode StaticCall asset data into the format described in the AssetProxy contract specification. - /// @param staticCallTargetAddress Target address of StaticCall. - /// @param staticCallData Data that will be passed to staticCallTargetAddress in the StaticCall. - /// @param expectedReturnDataHash Expected Keccak-256 hash of the StaticCall return data. - /// @return AssetProxy-compliant asset data describing the set of assets. - function encodeStaticCallAssetData( - address staticCallTargetAddress, - bytes memory staticCallData, - bytes32 expectedReturnDataHash - ) - public - pure - returns (bytes memory assetData) - { - assetData = abi.encodeWithSelector( - IAssetData(address(0)).StaticCall.selector, - staticCallTargetAddress, - staticCallData, - expectedReturnDataHash - ); - return assetData; - } - - /// @dev Decode StaticCall asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing a StaticCall asset - /// @return The StaticCall AssetProxy identifier, the target address of the StaticCAll, the data to be - /// passed to the target address, and the expected Keccak-256 hash of the static call return data. - function decodeStaticCallAssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address staticCallTargetAddress, - bytes memory staticCallData, - bytes32 expectedReturnDataHash - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).StaticCall.selector, - "WRONG_PROXY_ID" - ); - - (staticCallTargetAddress, staticCallData, expectedReturnDataHash) = abi.decode( - assetData.slice(4, assetData.length), - (address, bytes, bytes32) - ); - } - - /// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification. - /// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset - /// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address - /// of the bridge contract, and extra data to be passed to the bridge contract. - function decodeERC20BridgeAssetData(bytes memory assetData) - public - pure - returns ( - bytes4 assetProxyId, - address tokenAddress, - address bridgeAddress, - bytes memory bridgeData - ) - { - assetProxyId = assetData.readBytes4(0); - - require( - assetProxyId == IAssetData(address(0)).ERC20Bridge.selector, - "WRONG_PROXY_ID" - ); - - (tokenAddress, bridgeAddress, bridgeData) = abi.decode( - assetData.slice(4, assetData.length), - (address, address, bytes) - ); - } - - /// @dev Reverts if assetData is not of a valid format for its given proxy id. - /// @param assetData AssetProxy compliant asset data. - function revertIfInvalidAssetData(bytes memory assetData) - public - pure - { - bytes4 assetProxyId = assetData.readBytes4(0); - - if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { - decodeERC20AssetData(assetData); - } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { - decodeERC721AssetData(assetData); - } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { - decodeERC1155AssetData(assetData); - } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { - decodeMultiAssetData(assetData); - } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { - decodeStaticCallAssetData(assetData); - } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) { - decodeERC20BridgeAssetData(assetData); - } else { - revert("WRONG_PROXY_ID"); - } - } -} diff --git a/contracts/dev-utils/contracts/src/LibDydxBalance.sol b/contracts/dev-utils/contracts/src/LibDydxBalance.sol deleted file mode 100644 index 4ca815e4b8..0000000000 --- a/contracts/dev-utils/contracts/src/LibDydxBalance.sol +++ /dev/null @@ -1,436 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydxBridge.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/D18.sol"; -import "./LibAssetData.sol"; - - -library LibDydxBalance { - - using LibBytes for bytes; - using LibSafeMath for uint256; - - /// @dev Padding % added to the minimum collateralization ratio to - /// prevent withdrawing exactly the amount that would make an account - /// insolvent. 1 bps. - int256 private constant MARGIN_RATIO_PADDING = 0.0001e18; - - /// @dev Structure that holds all pertinent info needed to perform a balance - /// check. - struct BalanceCheckInfo { - IDydx dydx; - address bridgeAddress; - address makerAddress; - address makerTokenAddress; - address takerTokenAddress; - int256 orderMakerToTakerRate; - uint256[] accounts; - IDydxBridge.BridgeAction[] actions; - } - - /// @dev Gets the maker asset allowance for a Dydx bridge order. - /// @param makerAddress The maker of the order. - /// @param bridgeAddress The address of the Dydx bridge. - /// @param dydx The Dydx contract address. - /// @return allowance The maker asset allowance. - function getDydxMakerAllowance(address makerAddress, address bridgeAddress, address dydx) - public - view - returns (uint256 allowance) - { - // Allowance is infinite if the dydx bridge is an operator for the maker. - return IDydx(dydx).getIsLocalOperator(makerAddress, bridgeAddress) - ? uint256(-1) : 0; - } - - /// @dev Gets the maker allowance for a - /// @dev Get the maker asset balance of an order with a `DydxBridge` maker asset. - /// @param order An order with a dydx maker asset. - /// @param dydx The address of the dydx contract. - /// @return balance The maker asset balance. - function getDydxMakerBalance(LibOrder.Order memory order, address dydx) - public - view - returns (uint256 balance) - { - BalanceCheckInfo memory info = _getBalanceCheckInfo(order, dydx); - // Actions must be well-formed. - if (!_areActionsWellFormed(info)) { - return 0; - } - // If the rate we withdraw maker tokens is less than one, the asset - // proxy will throw because we will always transfer less maker tokens - // than asked. - if (_getMakerTokenWithdrawRate(info) < D18.one()) { - return 0; - } - // The maker balance is the smaller of: - return LibSafeMath.min256( - // How many times we can execute all the deposit actions. - _getDepositableMakerAmount(info), - // How many times we can execute all the actions before the an - // account becomes undercollateralized. - _getSolventMakerAmount(info) - ); - } - - /// @dev Checks that: - /// 1. Actions are arranged as [...deposits, withdraw]. - /// 2. There is only one deposit for each market ID. - /// 3. Every action has a valid account index. - /// 4. There is exactly one withdraw at the end and it is for the - /// maker token. - /// @param info State from `_getBalanceCheckInfo()`. - /// @return areWellFormed Whether the actions are well-formed. - function _areActionsWellFormed(BalanceCheckInfo memory info) - internal - view - returns (bool areWellFormed) - { - if (info.actions.length == 0) { - return false; - } - uint256 depositCount = 0; - // Count the number of deposits. - for (; depositCount < info.actions.length; ++depositCount) { - IDydxBridge.BridgeAction memory action = info.actions[depositCount]; - if (action.actionType != IDydxBridge.BridgeActionType.Deposit) { - break; - } - // Search all prior actions for the same market ID. - uint256 marketId = action.marketId; - for (uint256 j = 0; j < depositCount; ++j) { - if (info.actions[j].marketId == marketId) { - // Market ID is not unique. - return false; - } - } - // Check that the account index is within the valid range. - if (action.accountIdx >= info.accounts.length) { - return false; - } - } - // There must be exactly one withdraw action at the end. - if (depositCount + 1 != info.actions.length) { - return false; - } - IDydxBridge.BridgeAction memory withdraw = info.actions[depositCount]; - if (withdraw.actionType != IDydxBridge.BridgeActionType.Withdraw) { - return false; - } - // And it must be for the maker token. - if (info.dydx.getMarketTokenAddress(withdraw.marketId) != info.makerTokenAddress) { - return false; - } - // Check the account index. - return withdraw.accountIdx < info.accounts.length; - } - - /// @dev Returns the rate at which we withdraw maker tokens. - /// @param info State from `_getBalanceCheckInfo()`. - /// @return makerTokenWithdrawRate Maker token withdraw rate. - function _getMakerTokenWithdrawRate(BalanceCheckInfo memory info) - internal - pure - returns (int256 makerTokenWithdrawRate) - { - // The last action is always a withdraw for the maker token. - IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1]; - return _getActionRate(withdraw); - } - - /// @dev Get how much maker asset we can transfer before a deposit fails. - /// @param info State from `_getBalanceCheckInfo()`. - function _getDepositableMakerAmount(BalanceCheckInfo memory info) - internal - view - returns (uint256 depositableMakerAmount) - { - depositableMakerAmount = uint256(-1); - // Take the minimum maker amount from all deposits. - for (uint256 i = 0; i < info.actions.length; ++i) { - IDydxBridge.BridgeAction memory action = info.actions[i]; - // Only looking at deposit actions. - if (action.actionType != IDydxBridge.BridgeActionType.Deposit) { - continue; - } - // `depositRate` is the rate at which we convert a maker token into - // a taker token for deposit. - int256 depositRate = _getActionRate(action); - // Taker tokens will be transferred to the maker for every fill, so - // we reduce the effective deposit rate if we're depositing the taker - // token. - address depositToken = info.dydx.getMarketTokenAddress(action.marketId); - if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) { - depositRate = D18.sub(depositRate, info.orderMakerToTakerRate); - } - // If the deposit rate is > 0, we are limited by the transferrable - // token balance of the maker. - if (depositRate > 0) { - uint256 supply = _getTransferabeTokenAmount( - depositToken, - info.makerAddress, - address(info.dydx) - ); - depositableMakerAmount = LibSafeMath.min256( - depositableMakerAmount, - uint256(D18.div(supply, depositRate)) - ); - } - } - } - - /// @dev Get how much maker asset we can transfer before an account - /// becomes insolvent. - /// @param info State from `_getBalanceCheckInfo()`. - function _getSolventMakerAmount(BalanceCheckInfo memory info) - internal - view - returns (uint256 solventMakerAmount) - { - solventMakerAmount = uint256(-1); - assert(info.actions.length >= 1); - IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1]; - assert(withdraw.actionType == IDydxBridge.BridgeActionType.Withdraw); - int256 minCr = D18.add(_getMinimumCollateralizationRatio(info.dydx), MARGIN_RATIO_PADDING); - // Loop through the accounts. - for (uint256 accountIdx = 0; accountIdx < info.accounts.length; ++accountIdx) { - (uint256 supplyValue, uint256 borrowValue) = - _getAccountMarketValues(info, info.accounts[accountIdx]); - // All accounts must currently be solvent. - if (borrowValue != 0 && D18.div(supplyValue, borrowValue) < minCr) { - return 0; - } - // If this is the same account used to in the withdraw/borrow action, - // compute the maker amount at which it will become insolvent. - if (accountIdx != withdraw.accountIdx) { - continue; - } - // Compute the deposit/collateralization rate, which is the rate at - // which (USD) value is added to the account across all markets. - int256 dd = 0; - for (uint256 i = 0; i < info.actions.length - 1; ++i) { - IDydxBridge.BridgeAction memory deposit = info.actions[i]; - assert(deposit.actionType == IDydxBridge.BridgeActionType.Deposit); - if (deposit.accountIdx == accountIdx) { - dd = D18.add( - dd, - _getActionRateValue( - info, - deposit - ) - ); - } - } - // Compute the borrow/withdraw rate, which is the rate at which - // (USD) value is deducted from the account. - int256 db = _getActionRateValue( - info, - withdraw - ); - // If the deposit to withdraw ratio is >= the minimum collateralization - // ratio, then we will never become insolvent at these prices. - if (D18.div(dd, db) >= minCr) { - continue; - } - // If the adjusted deposit rates are equal, the account will remain - // at the same level of collateralization. - if (D18.mul(minCr, db) == dd) { - continue; - } - // The collateralization ratio for this account, parameterized by - // `t` (maker amount), is given by: - // `cr = (supplyValue + t * dd) / (borrowValue + t * db)` - // Solving for `t` gives us: - // `t = (supplyValue - cr * borrowValue) / (cr * db - dd)` - int256 t = D18.div( - D18.sub(supplyValue, D18.mul(minCr, borrowValue)), - D18.sub(D18.mul(minCr, db), dd) - ); - solventMakerAmount = LibSafeMath.min256( - solventMakerAmount, - // `t` is in maker token units, so convert it to maker wei. - _toWei(info.makerTokenAddress, uint256(D18.clip(t))) - ); - } - } - - /// @dev Create a `BalanceCheckInfo` struct. - /// @param order An order with a `DydxBridge` maker asset. - /// @param dydx The address of the Dydx contract. - /// @return info The `BalanceCheckInfo` struct. - function _getBalanceCheckInfo(LibOrder.Order memory order, address dydx) - private - pure - returns (BalanceCheckInfo memory info) - { - bytes memory rawBridgeData; - (, info.makerTokenAddress, info.bridgeAddress, rawBridgeData) = - LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData); - info.dydx = IDydx(dydx); - info.makerAddress = order.makerAddress; - if (order.takerAssetData.length == 36) { - if (order.takerAssetData.readBytes4(0) == IAssetData(0).ERC20Token.selector) { - (, info.takerTokenAddress) = - LibAssetData.decodeERC20AssetData(order.takerAssetData); - } - } - info.orderMakerToTakerRate = D18.div(order.takerAssetAmount, order.makerAssetAmount); - (IDydxBridge.BridgeData memory bridgeData) = - abi.decode(rawBridgeData, (IDydxBridge.BridgeData)); - info.accounts = bridgeData.accountNumbers; - info.actions = bridgeData.actions; - } - - /// @dev Returns the conversion rate for an action. - /// @param action A `BridgeAction`. - function _getActionRate(IDydxBridge.BridgeAction memory action) - private - pure - returns (int256 rate) - { - rate = action.conversionRateDenominator == 0 - ? D18.one() - : D18.div( - action.conversionRateNumerator, - action.conversionRateDenominator - ); - } - - /// @dev Returns the USD value of an action based on its conversion rate - /// and market prices. - /// @param info State from `_getBalanceCheckInfo()`. - /// @param action A `BridgeAction`. - function _getActionRateValue( - BalanceCheckInfo memory info, - IDydxBridge.BridgeAction memory action - ) - private - view - returns (int256 value) - { - address toToken = info.dydx.getMarketTokenAddress(action.marketId); - uint256 fromTokenDecimals = LibERC20Token.decimals(info.makerTokenAddress); - uint256 toTokenDecimals = LibERC20Token.decimals(toToken); - // First express the rate as 18-decimal units. - value = toTokenDecimals > fromTokenDecimals - ? int256( - uint256(_getActionRate(action)) - .safeDiv(10 ** (toTokenDecimals - fromTokenDecimals)) - ) - : int256( - uint256(_getActionRate(action)) - .safeMul(10 ** (fromTokenDecimals - toTokenDecimals)) - ); - // Prices have 18 + (18 - TOKEN_DECIMALS) decimal places because - // consistency is stupid. - uint256 price = info.dydx.getMarketPrice(action.marketId).value; - // Make prices have 18 decimals. - if (toTokenDecimals > 18) { - price = price.safeMul(10 ** (toTokenDecimals - 18)); - } else { - price = price.safeDiv(10 ** (18 - toTokenDecimals)); - } - // The action value is the action rate times the price. - value = D18.mul(price, value); - // Scale by the market premium. - int256 marketPremium = D18.add( - D18.one(), - info.dydx.getMarketMarginPremium(action.marketId).value - ); - if (action.actionType == IDydxBridge.BridgeActionType.Deposit) { - value = D18.div(value, marketPremium); - } else { - value = D18.mul(value, marketPremium); - } - } - - /// @dev Convert a `D18` fraction of 1 token to the equivalent integer wei. - /// @param token Address the of the token. - /// @param units Token units expressed with 18 digit precision. - function _toWei(address token, uint256 units) - private - view - returns (uint256 rate) - { - uint256 decimals = LibERC20Token.decimals(token); - rate = decimals > 18 - ? units.safeMul(10 ** (decimals - 18)) - : units.safeDiv(10 ** (18 - decimals)); - } - - /// @dev Get the global minimum collateralization ratio required for - /// an account to be considered solvent. - /// @param dydx The Dydx interface. - function _getMinimumCollateralizationRatio(IDydx dydx) - private - view - returns (int256 ratio) - { - IDydx.RiskParams memory riskParams = dydx.getRiskParams(); - return D18.add(D18.one(), D18.toSigned(riskParams.marginRatio.value)); - } - - /// @dev Get the total supply and borrow values for an account across all markets. - /// @param info State from `_getBalanceCheckInfo()`. - /// @param account The Dydx account identifier. - function _getAccountMarketValues(BalanceCheckInfo memory info, uint256 account) - private - view - returns (uint256 supplyValue, uint256 borrowValue) - { - (IDydx.Value memory supplyValue_, IDydx.Value memory borrowValue_) = - info.dydx.getAdjustedAccountValues(IDydx.AccountInfo( - info.makerAddress, - account - )); - // Account values have 36 decimal places because dydx likes to make sure - // you're paying attention. - return (supplyValue_.value / 1e18, borrowValue_.value / 1e18); - } - - /// @dev Get the amount of an ERC20 token held by `owner` that can be transferred - /// by `spender`. - /// @param tokenAddress The address of the ERC20 token. - /// @param owner The address of the token holder. - /// @param spender The address of the token spender. - function _getTransferabeTokenAmount( - address tokenAddress, - address owner, - address spender - ) - private - view - returns (uint256 transferableAmount) - { - return LibSafeMath.min256( - LibERC20Token.allowance(tokenAddress, owner, spender), - LibERC20Token.balanceOf(tokenAddress, owner) - ); - } -} diff --git a/contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol b/contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol deleted file mode 100644 index 7dbe548211..0000000000 --- a/contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol +++ /dev/null @@ -1,227 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - - -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -library LibOrderTransferSimulation { - using LibBytes for bytes; - - enum OrderTransferResults { - TakerAssetDataFailed, // Transfer of takerAsset failed - MakerAssetDataFailed, // Transfer of makerAsset failed - TakerFeeAssetDataFailed, // Transfer of takerFeeAsset failed - MakerFeeAssetDataFailed, // Transfer of makerFeeAsset failed - TransfersSuccessful // All transfers in the order were successful - } - - // NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)` - // may cause later. - address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332); - - // keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); - bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; - - /// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer. - /// @param order The order to simulate transfers for. - /// @param takerAddress The address of the taker that will fill the order. - /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. - /// @return The index of the first failed transfer (or 4 if all transfers are successful). - function getSimulatedOrderMakerTransferResults( - address exchange, - LibOrder.Order memory order, - address takerAddress, - uint256 takerAssetFillAmount - ) - public - returns (OrderTransferResults orderTransferResults) - { - LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( - order, - takerAssetFillAmount, - IExchange(exchange).protocolFeeMultiplier(), - tx.gasprice - ); - - bytes[] memory assetData = new bytes[](2); - address[] memory fromAddresses = new address[](2); - address[] memory toAddresses = new address[](2); - uint256[] memory amounts = new uint256[](2); - - // Transfer `makerAsset` from maker to taker - assetData[0] = order.makerAssetData; - fromAddresses[0] = order.makerAddress; - toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; - amounts[0] = fillResults.makerAssetFilledAmount; - - // Transfer `makerFeeAsset` from maker to feeRecipient - assetData[1] = order.makerFeeAssetData; - fromAddresses[1] = order.makerAddress; - toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; - amounts[1] = fillResults.makerFeePaid; - - return _simulateTransferFromCalls( - exchange, - assetData, - fromAddresses, - toAddresses, - amounts - ); - } - - /// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. - /// @param order The order to simulate transfers for. - /// @param takerAddress The address of the taker that will fill the order. - /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. - /// @return The index of the first failed transfer (or 4 if all transfers are successful). - function getSimulatedOrderTransferResults( - address exchange, - LibOrder.Order memory order, - address takerAddress, - uint256 takerAssetFillAmount - ) - public - returns (OrderTransferResults orderTransferResults) - { - LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( - order, - takerAssetFillAmount, - IExchange(exchange).protocolFeeMultiplier(), - tx.gasprice - ); - - // Create input arrays - bytes[] memory assetData = new bytes[](4); - address[] memory fromAddresses = new address[](4); - address[] memory toAddresses = new address[](4); - uint256[] memory amounts = new uint256[](4); - - // Transfer `takerAsset` from taker to maker - assetData[0] = order.takerAssetData; - fromAddresses[0] = takerAddress; - toAddresses[0] = order.makerAddress; - amounts[0] = takerAssetFillAmount; - - // Transfer `makerAsset` from maker to taker - assetData[1] = order.makerAssetData; - fromAddresses[1] = order.makerAddress; - toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; - amounts[1] = fillResults.makerAssetFilledAmount; - - // Transfer `takerFeeAsset` from taker to feeRecipient - assetData[2] = order.takerFeeAssetData; - fromAddresses[2] = takerAddress; - toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; - amounts[2] = fillResults.takerFeePaid; - - // Transfer `makerFeeAsset` from maker to feeRecipient - assetData[3] = order.makerFeeAssetData; - fromAddresses[3] = order.makerAddress; - toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; - amounts[3] = fillResults.makerFeePaid; - - return _simulateTransferFromCalls( - exchange, - assetData, - fromAddresses, - toAddresses, - amounts - ); - } - - /// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. - /// @param orders Array of orders to individually simulate transfers for. - /// @param takerAddresses Array of addresses of takers that will fill each order. - /// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. - /// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. - function getSimulatedOrdersTransferResults( - address exchange, - LibOrder.Order[] memory orders, - address[] memory takerAddresses, - uint256[] memory takerAssetFillAmounts - ) - public - returns (OrderTransferResults[] memory orderTransferResults) - { - uint256 length = orders.length; - orderTransferResults = new OrderTransferResults[](length); - for (uint256 i = 0; i != length; i++) { - orderTransferResults[i] = getSimulatedOrderTransferResults( - exchange, - orders[i], - takerAddresses[i], - takerAssetFillAmounts[i] - ); - } - return orderTransferResults; - } - - /// @dev Makes the simulation call with information about the transfers and processes - /// the returndata. - /// @param assetData The assetdata to use to make transfers. - /// @param fromAddresses The addresses to transfer funds. - /// @param toAddresses The addresses that will receive funds - /// @param amounts The amounts involved in the transfer. - function _simulateTransferFromCalls( - address exchange, - bytes[] memory assetData, - address[] memory fromAddresses, - address[] memory toAddresses, - uint256[] memory amounts - ) - private - returns (OrderTransferResults orderTransferResults) - { - // Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)` - bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector( - IExchange(address(0)).simulateDispatchTransferFromCalls.selector, - assetData, - fromAddresses, - toAddresses, - amounts - ); - - // Perform call and catch revert - (, bytes memory returnData) = address(exchange).call(simulateDispatchTransferFromCallsData); - - bytes4 selector = returnData.readBytes4(0); - if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) { - // Decode AssetProxyDispatchError and return index of failed transfer - (, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder.decodeAssetProxyDispatchError(returnData); - return OrderTransferResults(uint8(uint256(failedTransferIndex))); - } else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) { - // Decode AssetProxyTransferError and return index of failed transfer - (bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder.decodeAssetProxyTransferError(returnData); - return OrderTransferResults(uint8(uint256(failedTransferIndex))); - } else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) { - // All transfers were successful - return OrderTransferResults.TransfersSuccessful; - } else { - revert("UNKNOWN_RETURN_DATA"); - } - } -} diff --git a/contracts/dev-utils/contracts/src/LibTransactionDecoder.sol b/contracts/dev-utils/contracts/src/LibTransactionDecoder.sol deleted file mode 100644 index 34df3cdebc..0000000000 --- a/contracts/dev-utils/contracts/src/LibTransactionDecoder.sol +++ /dev/null @@ -1,188 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -library LibTransactionDecoder { - - using LibBytes for bytes; - - /// @dev Decodes the call data for an Exchange contract method call. - /// @param transactionData ABI-encoded calldata for an Exchange - /// contract method call. - /// @return The name of the function called, and the parameters it was - /// given. For single-order fills and cancels, the arrays will have - /// just one element. - function decodeZeroExTransactionData(bytes memory transactionData) - public - pure - returns( - string memory functionName, - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - { - bytes4 functionSelector = transactionData.readBytes4(0); - - if (functionSelector == IExchange(address(0)).batchCancelOrders.selector) { - functionName = "batchCancelOrders"; - } else if (functionSelector == IExchange(address(0)).batchFillOrders.selector) { - functionName = "batchFillOrders"; - } else if (functionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector) { - functionName = "batchFillOrdersNoThrow"; - } else if (functionSelector == IExchange(address(0)).batchFillOrKillOrders.selector) { - functionName = "batchFillOrKillOrders"; - } else if (functionSelector == IExchange(address(0)).cancelOrder.selector) { - functionName = "cancelOrder"; - } else if (functionSelector == IExchange(address(0)).fillOrder.selector) { - functionName = "fillOrder"; - } else if (functionSelector == IExchange(address(0)).fillOrKillOrder.selector) { - functionName = "fillOrKillOrder"; - } else if (functionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector) { - functionName = "marketBuyOrdersNoThrow"; - } else if (functionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector) { - functionName = "marketSellOrdersNoThrow"; - } else if (functionSelector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector) { - functionName = "marketBuyOrdersFillOrKill"; - } else if (functionSelector == IExchange(address(0)).marketSellOrdersFillOrKill.selector) { - functionName = "marketSellOrdersFillOrKill"; - } else if (functionSelector == IExchange(address(0)).matchOrders.selector) { - functionName = "matchOrders"; - } else if ( - functionSelector == IExchange(address(0)).cancelOrdersUpTo.selector || - functionSelector == IExchange(address(0)).executeTransaction.selector - ) { - revert("UNIMPLEMENTED"); - } else { - revert("UNKNOWN_FUNCTION_SELECTOR"); - } - - if (functionSelector == IExchange(address(0)).batchCancelOrders.selector) { - // solhint-disable-next-line indent - orders = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order[])); - takerAssetFillAmounts = new uint256[](0); - signatures = new bytes[](0); - } else if ( - functionSelector == IExchange(address(0)).batchFillOrKillOrders.selector || - functionSelector == IExchange(address(0)).batchFillOrders.selector || - functionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector - ) { - (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForBatchFill(transactionData); - } else if (functionSelector == IExchange(address(0)).cancelOrder.selector) { - orders = new LibOrder.Order[](1); - orders[0] = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order)); - takerAssetFillAmounts = new uint256[](0); - signatures = new bytes[](0); - } else if ( - functionSelector == IExchange(address(0)).fillOrKillOrder.selector || - functionSelector == IExchange(address(0)).fillOrder.selector - ) { - (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForSingleOrderFill(transactionData); - } else if ( - functionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector || - functionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector || - functionSelector == IExchange(address(0)).marketBuyOrdersFillOrKill.selector || - functionSelector == IExchange(address(0)).marketSellOrdersFillOrKill.selector - ) { - (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForMarketFill(transactionData); - } else if (functionSelector == IExchange(address(0)).matchOrders.selector) { - ( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - bytes memory leftSignature, - bytes memory rightSignature - ) = abi.decode( - transactionData.slice(4, transactionData.length), - (LibOrder.Order, LibOrder.Order, bytes, bytes) - ); - - orders = new LibOrder.Order[](2); - orders[0] = leftOrder; - orders[1] = rightOrder; - - takerAssetFillAmounts = new uint256[](2); - takerAssetFillAmounts[0] = leftOrder.takerAssetAmount; - takerAssetFillAmounts[1] = rightOrder.takerAssetAmount; - - signatures = new bytes[](2); - signatures[0] = leftSignature; - signatures[1] = rightSignature; - } - } - - function _makeReturnValuesForSingleOrderFill(bytes memory transactionData) - private - pure - returns( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - { - orders = new LibOrder.Order[](1); - takerAssetFillAmounts = new uint256[](1); - signatures = new bytes[](1); - // solhint-disable-next-line indent - (orders[0], takerAssetFillAmounts[0], signatures[0]) = abi.decode( - transactionData.slice(4, transactionData.length), - (LibOrder.Order, uint256, bytes) - ); - } - - function _makeReturnValuesForBatchFill(bytes memory transactionData) - private - pure - returns( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - { - // solhint-disable-next-line indent - (orders, takerAssetFillAmounts, signatures) = abi.decode( - transactionData.slice(4, transactionData.length), - // solhint-disable-next-line indent - (LibOrder.Order[], uint256[], bytes[]) - ); - } - - function _makeReturnValuesForMarketFill(bytes memory transactionData) - private - pure - returns( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - { - takerAssetFillAmounts = new uint256[](1); - // solhint-disable-next-line indent - (orders, takerAssetFillAmounts[0], signatures) = abi.decode( - transactionData.slice(4, transactionData.length), - // solhint-disable-next-line indent - (LibOrder.Order[], uint256, bytes[]) - ); - } -} diff --git a/contracts/dev-utils/contracts/src/OrderTransferSimulationUtils.sol b/contracts/dev-utils/contracts/src/OrderTransferSimulationUtils.sol deleted file mode 100644 index 1c22f60a92..0000000000 --- a/contracts/dev-utils/contracts/src/OrderTransferSimulationUtils.sol +++ /dev/null @@ -1,233 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - - -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -contract OrderTransferSimulationUtils { - - using LibBytes for bytes; - - enum OrderTransferResults { - TakerAssetDataFailed, // Transfer of takerAsset failed - MakerAssetDataFailed, // Transfer of makerAsset failed - TakerFeeAssetDataFailed, // Transfer of takerFeeAsset failed - MakerFeeAssetDataFailed, // Transfer of makerFeeAsset failed - TransfersSuccessful // All transfers in the order were successful - } - - // NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)` - // may cause later. - address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332); - - // keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); - bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; - - // solhint-disable var-name-mixedcase - IExchange internal _EXCHANGE; - // solhint-enable var-name-mixedcase - - constructor (address _exchange) - public - { - _EXCHANGE = IExchange(_exchange); - } - - /// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer. - /// @param order The order to simulate transfers for. - /// @param takerAddress The address of the taker that will fill the order. - /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. - /// @return The index of the first failed transfer (or 4 if all transfers are successful). - function getSimulatedOrderMakerTransferResults( - LibOrder.Order memory order, - address takerAddress, - uint256 takerAssetFillAmount - ) - public - returns (OrderTransferResults orderTransferResults) - { - LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( - order, - takerAssetFillAmount, - _EXCHANGE.protocolFeeMultiplier(), - tx.gasprice - ); - - bytes[] memory assetData = new bytes[](2); - address[] memory fromAddresses = new address[](2); - address[] memory toAddresses = new address[](2); - uint256[] memory amounts = new uint256[](2); - - // Transfer `makerAsset` from maker to taker - assetData[0] = order.makerAssetData; - fromAddresses[0] = order.makerAddress; - toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; - amounts[0] = fillResults.makerAssetFilledAmount; - - // Transfer `makerFeeAsset` from maker to feeRecipient - assetData[1] = order.makerFeeAssetData; - fromAddresses[1] = order.makerAddress; - toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; - amounts[1] = fillResults.makerFeePaid; - - return _simulateTransferFromCalls( - assetData, - fromAddresses, - toAddresses, - amounts - ); - } - - /// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. - /// @param order The order to simulate transfers for. - /// @param takerAddress The address of the taker that will fill the order. - /// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. - /// @return The index of the first failed transfer (or 4 if all transfers are successful). - function getSimulatedOrderTransferResults( - LibOrder.Order memory order, - address takerAddress, - uint256 takerAssetFillAmount - ) - public - returns (OrderTransferResults orderTransferResults) - { - LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults( - order, - takerAssetFillAmount, - _EXCHANGE.protocolFeeMultiplier(), - tx.gasprice - ); - - // Create input arrays - bytes[] memory assetData = new bytes[](4); - address[] memory fromAddresses = new address[](4); - address[] memory toAddresses = new address[](4); - uint256[] memory amounts = new uint256[](4); - - // Transfer `takerAsset` from taker to maker - assetData[0] = order.takerAssetData; - fromAddresses[0] = takerAddress; - toAddresses[0] = order.makerAddress; - amounts[0] = takerAssetFillAmount; - - // Transfer `makerAsset` from maker to taker - assetData[1] = order.makerAssetData; - fromAddresses[1] = order.makerAddress; - toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress; - amounts[1] = fillResults.makerAssetFilledAmount; - - // Transfer `takerFeeAsset` from taker to feeRecipient - assetData[2] = order.takerFeeAssetData; - fromAddresses[2] = takerAddress; - toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; - amounts[2] = fillResults.takerFeePaid; - - // Transfer `makerFeeAsset` from maker to feeRecipient - assetData[3] = order.makerFeeAssetData; - fromAddresses[3] = order.makerAddress; - toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress; - amounts[3] = fillResults.makerFeePaid; - - return _simulateTransferFromCalls( - assetData, - fromAddresses, - toAddresses, - amounts - ); - } - - /// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. - /// @param orders Array of orders to individually simulate transfers for. - /// @param takerAddresses Array of addresses of takers that will fill each order. - /// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. - /// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. - function getSimulatedOrdersTransferResults( - LibOrder.Order[] memory orders, - address[] memory takerAddresses, - uint256[] memory takerAssetFillAmounts - ) - public - returns (OrderTransferResults[] memory orderTransferResults) - { - uint256 length = orders.length; - orderTransferResults = new OrderTransferResults[](length); - for (uint256 i = 0; i != length; i++) { - orderTransferResults[i] = getSimulatedOrderTransferResults( - orders[i], - takerAddresses[i], - takerAssetFillAmounts[i] - ); - } - return orderTransferResults; - } - - /// @dev Makes the simulation call with information about the transfers and processes - /// the returndata. - /// @param assetData The assetdata to use to make transfers. - /// @param fromAddresses The addresses to transfer funds. - /// @param toAddresses The addresses that will receive funds - /// @param amounts The amounts involved in the transfer. - function _simulateTransferFromCalls( - bytes[] memory assetData, - address[] memory fromAddresses, - address[] memory toAddresses, - uint256[] memory amounts - ) - internal - returns (OrderTransferResults orderTransferResults) - { - // Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)` - bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector( - IExchange(address(0)).simulateDispatchTransferFromCalls.selector, - assetData, - fromAddresses, - toAddresses, - amounts - ); - - // Perform call and catch revert - (, bytes memory returnData) = address(_EXCHANGE).call(simulateDispatchTransferFromCallsData); - - bytes4 selector = returnData.readBytes4(0); - if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) { - // Decode AssetProxyDispatchError and return index of failed transfer - (, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder - .decodeAssetProxyDispatchError(returnData); - return OrderTransferResults(uint8(uint256(failedTransferIndex))); - } else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) { - // Decode AssetProxyTransferError and return index of failed transfer - (bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder - .decodeAssetProxyTransferError(returnData); - return OrderTransferResults(uint8(uint256(failedTransferIndex))); - } else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) { - // All transfers were successful - return OrderTransferResults.TransfersSuccessful; - } else { - revert("UNKNOWN_RETURN_DATA"); - } - } -} diff --git a/contracts/dev-utils/contracts/src/OrderValidationUtils.sol b/contracts/dev-utils/contracts/src/OrderValidationUtils.sol deleted file mode 100644 index 948e1d8138..0000000000 --- a/contracts/dev-utils/contracts/src/OrderValidationUtils.sol +++ /dev/null @@ -1,279 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./Addresses.sol"; -import "./AssetBalance.sol"; -import "./LibAssetData.sol"; -import "./LibOrderTransferSimulation.sol"; - - -contract OrderValidationUtils is - Addresses, - AssetBalance -{ - using LibBytes for bytes; - using LibSafeMath for uint256; - - /// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable. - /// @param order The order structure. - /// @param signature Signature provided by maker that proves the order's authenticity. - /// `0x01` can always be provided if the signature does not need to be validated. - /// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order), - /// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state), - /// and isValidSignature (validity of the provided signature). - /// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled" - /// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final - /// amount of each asset that can be filled. - function getOrderRelevantState(LibOrder.Order memory order, bytes memory signature) - public - returns ( - LibOrder.OrderInfo memory orderInfo, - uint256 fillableTakerAssetAmount, - bool isValidSignature - ) - { - // Get info specific to order - orderInfo = IExchange(exchangeAddress).getOrderInfo(order); - - // Validate the maker's signature - address makerAddress = order.makerAddress; - isValidSignature = IExchange(exchangeAddress).isValidOrderSignature( - order, - signature - ); - - // Get the transferable amount of the `makerAsset` - uint256 transferableMakerAssetAmount = _getTransferableConvertedMakerAssetAmount( - order - ); - - // Get the amount of `takerAsset` that is transferable to maker given the - // transferability of `makerAsset`, `makerFeeAsset`, - // and the total amounts specified in the order - uint256 transferableTakerAssetAmount; - if (order.makerAssetData.equals(order.makerFeeAssetData)) { - // If `makerAsset` equals `makerFeeAsset`, the % that can be filled is - // transferableMakerAssetAmount / (makerAssetAmount + makerFee) - transferableTakerAssetAmount = LibMath.getPartialAmountFloor( - transferableMakerAssetAmount, - order.makerAssetAmount.safeAdd(order.makerFee), - order.takerAssetAmount - ); - } else { - // If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount) - if (order.makerFee == 0) { - transferableTakerAssetAmount = LibMath.getPartialAmountFloor( - transferableMakerAssetAmount, - order.makerAssetAmount, - order.takerAssetAmount - ); - - // If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of - // (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee) - } else { - // Get the transferable amount of the `makerFeeAsset` - uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount( - makerAddress, - order.makerFeeAssetData - ); - uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor( - transferableMakerAssetAmount, - order.makerAssetAmount, - order.takerAssetAmount - ); - uint256 transferableMakerFeeToTakerAmount = LibMath.getPartialAmountFloor( - transferableMakerFeeAssetAmount, - order.makerFee, - order.takerAssetAmount - ); - transferableTakerAssetAmount = LibSafeMath.min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount); - } - } - - // `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount` - fillableTakerAssetAmount = LibSafeMath.min256( - order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount), - transferableTakerAssetAmount - ); - - // Ensure that all of the asset data is valid. Fee asset data only needs - // to be valid if the fees are nonzero. - if (!_areOrderAssetDatasValid(order)) { - fillableTakerAssetAmount = 0; - } - - // If the order is not fillable, then the fillable taker asset amount is - // zero by definition. - if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) { - fillableTakerAssetAmount = 0; - } - - return (orderInfo, fillableTakerAssetAmount, isValidSignature); - } - - /// @dev Fetches all order-relevant information needed to validate if the supplied orders are fillable. - /// @param orders Array of order structures. - /// @param signatures Array of signatures provided by makers that prove the authenticity of the orders. - /// `0x01` can always be provided if a signature does not need to be validated. - /// @return The ordersInfo (array of the hash, status, and `takerAssetAmount` already filled for each order), - /// fillableTakerAssetAmounts (array of amounts for each order's `takerAssetAmount` that is fillable given all on-chain state), - /// and isValidSignature (array containing the validity of each provided signature). - /// NOTE: If the `takerAssetData` encodes data for multiple assets, each element of `fillableTakerAssetAmounts` - /// will represent a "scaled" amount, meaning it must be multiplied by all the individual asset amounts within - /// the `takerAssetData` to get the final amount of each asset that can be filled. - function getOrderRelevantStates(LibOrder.Order[] memory orders, bytes[] memory signatures) - public - returns ( - LibOrder.OrderInfo[] memory ordersInfo, - uint256[] memory fillableTakerAssetAmounts, - bool[] memory isValidSignature - ) - { - uint256 length = orders.length; - ordersInfo = new LibOrder.OrderInfo[](length); - fillableTakerAssetAmounts = new uint256[](length); - isValidSignature = new bool[](length); - - for (uint256 i = 0; i != length; i++) { - (ordersInfo[i], fillableTakerAssetAmounts[i], isValidSignature[i]) = getOrderRelevantState( - orders[i], - signatures[i] - ); - } - - return (ordersInfo, fillableTakerAssetAmounts, isValidSignature); - } - - /// @dev Gets the amount of an asset transferable by the maker of an order. - /// @param ownerAddress Address of the owner of the asset. - /// @param assetData Description of tokens, per the AssetProxy contract specification. - /// @return The amount of the asset tranferable by the owner. - /// NOTE: If the `assetData` encodes data for multiple assets, the `transferableAssetAmount` - /// will represent the amount of times the entire `assetData` can be transferred. To calculate - /// the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by - /// the individual asset amounts located within the `assetData`. - function getTransferableAssetAmount(address ownerAddress, bytes memory assetData) - public - returns (uint256 transferableAssetAmount) - { - (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance( - ownerAddress, - assetData - ); - transferableAssetAmount = LibSafeMath.min256(balance, allowance); - return transferableAssetAmount; - } - - /// @dev Gets the amount of an asset transferable by the maker of an order. - /// Similar to `getTransferableAssetAmount()`, but can handle maker asset - /// types that depend on taker assets being transferred first (e.g., Dydx bridge). - /// @param order The order. - /// @return transferableAssetAmount Amount of maker asset that can be transferred. - function _getTransferableConvertedMakerAssetAmount( - LibOrder.Order memory order - ) - internal - returns (uint256 transferableAssetAmount) - { - (uint256 balance, uint256 allowance) = _getConvertibleMakerBalanceAndAssetProxyAllowance(order); - transferableAssetAmount = LibSafeMath.min256(balance, allowance); - return LibSafeMath.min256(transferableAssetAmount, order.makerAssetAmount); - } - - /// @dev Checks that the asset data contained in a ZeroEx is valid and returns - /// a boolean that indicates whether or not the asset data was found to be valid. - /// @param order A ZeroEx order to validate. - /// @return The validatity of the asset data. - function _areOrderAssetDatasValid(LibOrder.Order memory order) - internal - pure - returns (bool) - { - return _isAssetDataValid(order.makerAssetData) && - (order.makerFee == 0 || _isAssetDataValid(order.makerFeeAssetData)) && - _isAssetDataValid(order.takerAssetData) && - (order.takerFee == 0 || _isAssetDataValid(order.takerFeeAssetData)); - } - - /// @dev This function handles the edge cases around taker validation. This function - /// currently attempts to find duplicate ERC721 token's in the taker - /// multiAssetData. - /// @param assetData The asset data that should be validated. - /// @return Whether or not the order should be considered valid. - function _isAssetDataValid(bytes memory assetData) - internal - pure - returns (bool) - { - // Asset data must be composed of an asset proxy Id and a bytes segment with - // a length divisible by 32. - if (assetData.length % 32 != 4) { - return false; - } - - // Only process the taker asset data if it is multiAssetData. - bytes4 assetProxyId = assetData.readBytes4(0); - if (assetProxyId != IAssetData(address(0)).MultiAsset.selector) { - return true; - } - - // Get array of values and array of assetDatas - (, , bytes[] memory nestedAssetData) = - LibAssetData.decodeMultiAssetData(assetData); - - uint256 length = nestedAssetData.length; - for (uint256 i = 0; i != length; i++) { - // TODO(jalextowle): Implement similar validation for non-fungible ERC1155 asset data. - bytes4 nestedAssetProxyId = nestedAssetData[i].readBytes4(0); - if (nestedAssetProxyId == IAssetData(address(0)).ERC721Token.selector) { - if (_isAssetDataDuplicated(nestedAssetData, i)) { - return false; - } - } - } - - return true; - } - - /// Determines whether or not asset data is duplicated later in the nested asset data. - /// @param nestedAssetData The asset data to scan for duplication. - /// @param startIdx The index where the scan should begin. - /// @return A boolean reflecting whether or not the starting asset data was duplicated. - function _isAssetDataDuplicated( - bytes[] memory nestedAssetData, - uint256 startIdx - ) - internal - pure - returns (bool) - { - uint256 length = nestedAssetData.length; - for (uint256 i = startIdx + 1; i < length; i++) { - if (nestedAssetData[startIdx].equals(nestedAssetData[i])) { - return true; - } - } - } -} diff --git a/contracts/dev-utils/contracts/test/TestDydx.sol b/contracts/dev-utils/contracts/test/TestDydx.sol deleted file mode 100644 index c2e771ca47..0000000000 --- a/contracts/dev-utils/contracts/test/TestDydx.sol +++ /dev/null @@ -1,181 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; - - -// solhint-disable separate-by-one-line-in-contract -contract TestDydx { - - struct OperatorConfig { - address owner; - address operator; - } - - struct AccountConfig { - address owner; - uint256 accountId; - int256[] balances; - } - - struct MarketInfo { - address token; - uint256 price; - } - - struct TestConfig { - uint256 marginRatio; - OperatorConfig[] operators; - AccountConfig[] accounts; - MarketInfo[] markets; - } - - mapping (bytes32 => bool) private _operators; - mapping (bytes32 => int256) private _balance; - MarketInfo[] private _markets; - uint256 private _marginRatio; - - constructor(TestConfig memory config) public { - _marginRatio = config.marginRatio; - for (uint256 marketId = 0; marketId < config.markets.length; ++marketId) { - _markets.push(config.markets[marketId]); - } - for (uint256 i = 0; i < config.operators.length; ++i) { - OperatorConfig memory op = config.operators[i]; - _operators[_getOperatorHash(op.owner, op.operator)] = true; - } - for (uint256 i = 0; i < config.accounts.length; ++i) { - AccountConfig memory acct = config.accounts[i]; - for (uint256 marketId = 0; marketId < acct.balances.length; ++marketId) { - _balance[_getBalanceHash(acct.owner, acct.accountId, marketId)] = - acct.balances[marketId]; - } - } - } - - function getIsLocalOperator( - address owner, - address operator - ) - external - view - returns (bool isLocalOperator) - { - return _operators[_getOperatorHash(owner, operator)]; - } - - function getMarketTokenAddress( - uint256 marketId - ) - external - view - returns (address tokenAddress) - { - return _markets[marketId].token; - } - - function getRiskParams() - external - view - returns (IDydx.RiskParams memory riskParams) - { - return IDydx.RiskParams({ - marginRatio: IDydx.D256(_marginRatio), - liquidationSpread: IDydx.D256(0), - earningsRate: IDydx.D256(0), - minBorrowedValue: IDydx.Value(0) - }); - } - - function getAdjustedAccountValues( - IDydx.AccountInfo calldata account - ) - external - view - returns (IDydx.Value memory supplyValue, IDydx.Value memory borrowValue) - { - for (uint256 marketId = 0; marketId < _markets.length; ++marketId) { - int256 balance = - _balance[_getBalanceHash(account.owner, account.number, marketId)]; - // Account values have 36 decimal places. - // `getMarketPrice()` returns a unit with - // 18 + (18 - TOKEN_DECIMALS) decimal places so multiplying the price - // with the wei balance will result in a 36 decimal value. - balance = balance * int256(getMarketPrice(marketId).value); - if (balance >= 0) { - supplyValue.value += uint256(balance); - } else { - borrowValue.value += uint256(-balance); - } - } - } - - function getMarketMarginPremium(uint256) - external - view - returns (IDydx.D256 memory premium) - { - // Return 0. - return premium; - } - - function getMarketPrice( - uint256 marketId - ) - public - view - returns (IDydx.Price memory price) - { - MarketInfo memory market = _markets[marketId]; - uint256 decimals = LibERC20Token.decimals(market.token); - price.value = _markets[marketId].price; - // Market prices have 18 + (18 - TOKEN_DECIMALS) - if (decimals > 18) { - price.value /= 10 ** (decimals - 18); - } else { - price.value *= 10 ** (18 - decimals); - } - } - - function _getOperatorHash(address owner, address operator) - private - pure - returns (bytes32 operatorHash) - { - return keccak256(abi.encode( - owner, - operator - )); - } - - function _getBalanceHash(address owner, uint256 accountId, uint256 marketId) - private - pure - returns (bytes32 balanceHash) - { - return keccak256(abi.encode( - owner, - accountId, - marketId - )); - } -} diff --git a/contracts/dev-utils/contracts/test/TestLibDydxBalance.sol b/contracts/dev-utils/contracts/test/TestLibDydxBalance.sol deleted file mode 100644 index 0ab8dc037d..0000000000 --- a/contracts/dev-utils/contracts/test/TestLibDydxBalance.sol +++ /dev/null @@ -1,116 +0,0 @@ -/* - - Copyright 2019 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.5.16; -pragma experimental ABIEncoderV2; - -import "../src/LibDydxBalance.sol"; - - -contract TestLibDydxBalanceToken { - - uint8 public decimals; - mapping (address => uint256) public balanceOf; - mapping (address => mapping (address => uint256)) public allowance; - - constructor(uint8 decimals_) public { - decimals = decimals_; - } - - function setBalance(address owner, uint256 balance) external { - balanceOf[owner] = balance; - } - - function setApproval( - address owner, - address spender, - uint256 allowance_ - ) - external - { - allowance[owner][spender] = allowance_; - } -} - - -contract TestLibDydxBalance { - - mapping (address => TestLibDydxBalanceToken) private tokens; - - function createToken(uint8 decimals) external returns (address) { - TestLibDydxBalanceToken token = new TestLibDydxBalanceToken(decimals); - return address(tokens[address(token)] = token); - } - - function setTokenBalance( - address tokenAddress, - address owner, - uint256 balance - ) - external - { - tokens[tokenAddress].setBalance(owner, balance); - } - - function setTokenApproval( - address tokenAddress, - address owner, - address spender, - uint256 allowance - ) - external - { - tokens[tokenAddress].setApproval(owner, spender, allowance); - } - - function getDydxMakerBalance(LibOrder.Order memory order, address dydx) - public - view - returns (uint256 balance) - { - return LibDydxBalance.getDydxMakerBalance(order, dydx); - } - - function getSolventMakerAmount( - LibDydxBalance.BalanceCheckInfo memory info - ) - public - view - returns (uint256 solventMakerAmount) - { - return LibDydxBalance._getSolventMakerAmount(info); - } - - function getDepositableMakerAmount( - LibDydxBalance.BalanceCheckInfo memory info - ) - public - view - returns (uint256 depositableMakerAmount) - { - return LibDydxBalance._getDepositableMakerAmount(info); - } - - function areActionsWellFormed(LibDydxBalance.BalanceCheckInfo memory info) - public - view - returns (bool areWellFormed) - { - return LibDydxBalance._areActionsWellFormed(info); - } -} diff --git a/contracts/dev-utils/package.json b/contracts/dev-utils/package.json deleted file mode 100644 index cb1fdcd29a..0000000000 --- a/contracts/dev-utils/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@0x/contracts-dev-utils", - "version": "1.3.36", - "engines": { - "node": ">=6.12" - }, - "description": "0x protocol specific utility contracts", - "main": "lib/src/index.js", - "scripts": { - "build": "yarn pre_build && tsc -b", - "test": "yarn assert_deployable && yarn mocha -t 10000 -b ./lib/test/**_test.js", - "assert_deployable": "node -e \"const bytecodeLen = (require('./generated-artifacts/DevUtils.json').compilerOutput.evm.bytecode.object.length-2)/2; assert(bytecodeLen<=0x6000,'DevUtils contract is too big to deploy, per EIP-170. '+bytecodeLen+'>'+0x6000)\"", - "build:ci": "yarn build", - "pre_build": "run-s compile quantify_bytecode contracts:gen generate_contract_wrappers contracts:copy", - "compile": "sol-compiler", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "quantify_bytecode": "echo EVM bytecode object lengths:;for i in ./test/generated-artifacts/*.json; do node -e \"console.log('$i\t' + (require('$i').compilerOutput.evm.bytecode.object.length - 2) / 2)\"; done", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "DevUtils,LibAssetData,LibDydxBalance,LibOrderTransferSimulation,LibTransactionDecoder", - "abis": "./test/generated-artifacts/@(Addresses|AssetBalance|DevUtils|EthBalanceChecker|ExternalFunctions|LibAssetData|LibDydxBalance|LibOrderTransferSimulation|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils|TestDydx|TestLibDydxBalance).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/dev-utils", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/assert": "^3.0.27", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/utils": "^6.4.3", - "ethereum-types": "^3.5.0", - "ethers": "~4.0.4", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@types/node": "12.12.54" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/dev-utils/src/artifacts.ts b/contracts/dev-utils/src/artifacts.ts deleted file mode 100644 index bdc1925bbc..0000000000 --- a/contracts/dev-utils/src/artifacts.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as DevUtils from '../generated-artifacts/DevUtils.json'; -import * as LibAssetData from '../generated-artifacts/LibAssetData.json'; -import * as LibDydxBalance from '../generated-artifacts/LibDydxBalance.json'; -import * as LibOrderTransferSimulation from '../generated-artifacts/LibOrderTransferSimulation.json'; -import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json'; -export const artifacts = { - DevUtils: DevUtils as ContractArtifact, - LibAssetData: LibAssetData as ContractArtifact, - LibDydxBalance: LibDydxBalance as ContractArtifact, - LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact, - LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, -}; diff --git a/contracts/dev-utils/src/index.ts b/contracts/dev-utils/src/index.ts deleted file mode 100644 index 91a089b69a..0000000000 --- a/contracts/dev-utils/src/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -export { artifacts } from './artifacts'; -export { DevUtilsContract } from './wrappers'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/dev-utils/src/wrappers.ts b/contracts/dev-utils/src/wrappers.ts deleted file mode 100644 index e3af16194b..0000000000 --- a/contracts/dev-utils/src/wrappers.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/dev_utils'; -export * from '../generated-wrappers/lib_asset_data'; -export * from '../generated-wrappers/lib_dydx_balance'; -export * from '../generated-wrappers/lib_order_transfer_simulation'; -export * from '../generated-wrappers/lib_transaction_decoder'; diff --git a/contracts/dev-utils/test/artifacts.ts b/contracts/dev-utils/test/artifacts.ts deleted file mode 100644 index e4c1802bc0..0000000000 --- a/contracts/dev-utils/test/artifacts.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Addresses from '../test/generated-artifacts/Addresses.json'; -import * as AssetBalance from '../test/generated-artifacts/AssetBalance.json'; -import * as DevUtils from '../test/generated-artifacts/DevUtils.json'; -import * as EthBalanceChecker from '../test/generated-artifacts/EthBalanceChecker.json'; -import * as ExternalFunctions from '../test/generated-artifacts/ExternalFunctions.json'; -import * as LibAssetData from '../test/generated-artifacts/LibAssetData.json'; -import * as LibDydxBalance from '../test/generated-artifacts/LibDydxBalance.json'; -import * as LibOrderTransferSimulation from '../test/generated-artifacts/LibOrderTransferSimulation.json'; -import * as LibTransactionDecoder from '../test/generated-artifacts/LibTransactionDecoder.json'; -import * as OrderTransferSimulationUtils from '../test/generated-artifacts/OrderTransferSimulationUtils.json'; -import * as OrderValidationUtils from '../test/generated-artifacts/OrderValidationUtils.json'; -import * as TestDydx from '../test/generated-artifacts/TestDydx.json'; -import * as TestLibDydxBalance from '../test/generated-artifacts/TestLibDydxBalance.json'; -export const artifacts = { - Addresses: Addresses as ContractArtifact, - AssetBalance: AssetBalance as ContractArtifact, - DevUtils: DevUtils as ContractArtifact, - EthBalanceChecker: EthBalanceChecker as ContractArtifact, - ExternalFunctions: ExternalFunctions as ContractArtifact, - LibAssetData: LibAssetData as ContractArtifact, - LibDydxBalance: LibDydxBalance as ContractArtifact, - LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact, - LibTransactionDecoder: LibTransactionDecoder as ContractArtifact, - OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact, - OrderValidationUtils: OrderValidationUtils as ContractArtifact, - TestDydx: TestDydx as ContractArtifact, - TestLibDydxBalance: TestLibDydxBalance as ContractArtifact, -}; diff --git a/contracts/dev-utils/test/lib_dydx_balance_test.ts b/contracts/dev-utils/test/lib_dydx_balance_test.ts deleted file mode 100644 index 6d06adfb56..0000000000 --- a/contracts/dev-utils/test/lib_dydx_balance_test.ts +++ /dev/null @@ -1,1170 +0,0 @@ -import { - DydxBridgeAction, - DydxBridgeActionType, - DydxBridgeData, - dydxBridgeDataEncoder, - IAssetDataContract, -} from '@0x/contracts-asset-proxy'; -import { - blockchainTests, - constants, - expect, - getRandomFloat, - getRandomInteger, - Numberish, - randomAddress, -} from '@0x/contracts-test-utils'; -import { Order } from '@0x/types'; -import { BigNumber, fromTokenUnitAmount, toTokenUnitAmount } from '@0x/utils'; - -import { artifacts as devUtilsArtifacts } from './artifacts'; -import { TestDydxContract, TestLibDydxBalanceContract } from './wrappers'; - -blockchainTests('LibDydxBalance', env => { - interface TestDydxConfig { - marginRatio: BigNumber; - operators: Array<{ - owner: string; - operator: string; - }>; - accounts: Array<{ - owner: string; - accountId: BigNumber; - balances: BigNumber[]; - }>; - markets: Array<{ - token: string; - decimals: number; - price: BigNumber; - }>; - } - - const MARGIN_RATIO = 1.5; - const PRICE_DECIMALS = 18; - const MAKER_DECIMALS = 6; - const TAKER_DECIMALS = 18; - const INITIAL_TAKER_TOKEN_BALANCE = fromTokenUnitAmount(1000, TAKER_DECIMALS); - const BRIDGE_ADDRESS = randomAddress(); - const ACCOUNT_OWNER = randomAddress(); - const MAKER_PRICE = 150; - const TAKER_PRICE = 100; - const SOLVENT_ACCOUNT_IDX = 0; - // const MIN_SOLVENT_ACCOUNT_IDX = 1; - const INSOLVENT_ACCOUNT_IDX = 2; - const ZERO_BALANCE_ACCOUNT_IDX = 3; - const DYDX_CONFIG: TestDydxConfig = { - marginRatio: fromTokenUnitAmount(MARGIN_RATIO - 1, PRICE_DECIMALS), - operators: [{ owner: ACCOUNT_OWNER, operator: BRIDGE_ADDRESS }], - accounts: [ - { - owner: ACCOUNT_OWNER, - accountId: getRandomInteger(1, 2 ** 64), - // Account exceeds collateralization. - balances: [fromTokenUnitAmount(10, TAKER_DECIMALS), fromTokenUnitAmount(-1, MAKER_DECIMALS)], - }, - { - owner: ACCOUNT_OWNER, - accountId: getRandomInteger(1, 2 ** 64), - // Account is at minimum collateralization. - balances: [ - fromTokenUnitAmount((MAKER_PRICE / TAKER_PRICE) * MARGIN_RATIO * 5, TAKER_DECIMALS), - fromTokenUnitAmount(-5, MAKER_DECIMALS), - ], - }, - { - owner: ACCOUNT_OWNER, - accountId: getRandomInteger(1, 2 ** 64), - // Account is undercollateralized.. - balances: [fromTokenUnitAmount(1, TAKER_DECIMALS), fromTokenUnitAmount(-2, MAKER_DECIMALS)], - }, - { - owner: ACCOUNT_OWNER, - accountId: getRandomInteger(1, 2 ** 64), - // Account has no balance. - balances: [fromTokenUnitAmount(0, TAKER_DECIMALS), fromTokenUnitAmount(0, MAKER_DECIMALS)], - }, - ], - markets: [ - { - token: constants.NULL_ADDRESS, // TBD - decimals: TAKER_DECIMALS, - price: fromTokenUnitAmount(TAKER_PRICE, PRICE_DECIMALS), - }, - { - token: constants.NULL_ADDRESS, // TBD - decimals: MAKER_DECIMALS, - price: fromTokenUnitAmount(MAKER_PRICE, PRICE_DECIMALS), - }, - ], - }; - - let dydx: TestDydxContract; - let testContract: TestLibDydxBalanceContract; - let assetDataContract: IAssetDataContract; - let takerTokenAddress: string; - let makerTokenAddress: string; - - before(async () => { - assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, env.provider); - - testContract = await TestLibDydxBalanceContract.deployWithLibrariesFrom0xArtifactAsync( - devUtilsArtifacts.TestLibDydxBalance, - devUtilsArtifacts, - env.provider, - env.txDefaults, - {}, - ); - - // Create tokens. - takerTokenAddress = await testContract.createToken(TAKER_DECIMALS).callAsync(); - await testContract.createToken(TAKER_DECIMALS).awaitTransactionSuccessAsync(); - makerTokenAddress = await testContract.createToken(MAKER_DECIMALS).callAsync(); - await testContract.createToken(MAKER_DECIMALS).awaitTransactionSuccessAsync(); - - DYDX_CONFIG.markets[0].token = takerTokenAddress; - DYDX_CONFIG.markets[1].token = makerTokenAddress; - - dydx = await TestDydxContract.deployFrom0xArtifactAsync( - devUtilsArtifacts.TestDydx, - env.provider, - env.txDefaults, - {}, - DYDX_CONFIG, - ); - - // Mint taker tokens. - await testContract - .setTokenBalance(takerTokenAddress, ACCOUNT_OWNER, INITIAL_TAKER_TOKEN_BALANCE) - .awaitTransactionSuccessAsync(); - // Approve the Dydx contract to spend takerToken. - await testContract - .setTokenApproval(takerTokenAddress, ACCOUNT_OWNER, dydx.address, constants.MAX_UINT256) - .awaitTransactionSuccessAsync(); - }); - - interface BalanceCheckInfo { - dydx: string; - bridgeAddress: string; - makerAddress: string; - makerTokenAddress: string; - takerTokenAddress: string; - orderMakerToTakerRate: BigNumber; - accounts: BigNumber[]; - actions: DydxBridgeAction[]; - } - - function createBalanceCheckInfo(fields: Partial = {}): BalanceCheckInfo { - return { - dydx: dydx.address, - bridgeAddress: BRIDGE_ADDRESS, - makerAddress: ACCOUNT_OWNER, - makerTokenAddress: DYDX_CONFIG.markets[1].token, - takerTokenAddress: DYDX_CONFIG.markets[0].token, - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(10, TAKER_DECIMALS).div(fromTokenUnitAmount(5, MAKER_DECIMALS)), - ), - accounts: [DYDX_CONFIG.accounts[SOLVENT_ACCOUNT_IDX].accountId], - actions: [], - ...fields, - }; - } - - function getFilledAccountCollateralizations( - config: TestDydxConfig, - checkInfo: BalanceCheckInfo, - makerAssetFillAmount: BigNumber, - ): BigNumber[] { - const values: BigNumber[][] = checkInfo.accounts.map((accountId, accountIdx) => { - const accountBalances = config.accounts[accountIdx].balances.slice(); - for (const action of checkInfo.actions) { - const actionMarketId = action.marketId.toNumber(); - const actionAccountIdx = action.accountIdx.toNumber(); - if (checkInfo.accounts[actionAccountIdx] !== accountId) { - continue; - } - const rate = action.conversionRateDenominator.eq(0) - ? new BigNumber(1) - : action.conversionRateNumerator.div(action.conversionRateDenominator); - const change = makerAssetFillAmount.times( - action.actionType === DydxBridgeActionType.Deposit ? rate : rate.negated(), - ); - accountBalances[actionMarketId] = change.plus(accountBalances[actionMarketId]); - } - return accountBalances.map((b, marketId) => - toTokenUnitAmount(b, config.markets[marketId].decimals).times( - toTokenUnitAmount(config.markets[marketId].price, PRICE_DECIMALS), - ), - ); - }); - return values - .map(accountValues => { - return [ - // supply - BigNumber.sum(...accountValues.filter(b => b.gte(0))), - // borrow - BigNumber.sum(...accountValues.filter(b => b.lt(0))).abs(), - ]; - }) - .map(([supply, borrow]) => supply.div(borrow)); - } - - function getRandomRate(): BigNumber { - return getRandomFloat(0, 1); - } - - // Computes a deposit rate that is the minimum to keep an account solvent - // perpetually. - function getBalancedDepositRate(withdrawRate: BigNumber, scaling: Numberish = 1): BigNumber { - // Add a small amount to the margin ratio to stay just above insolvency. - return withdrawRate.times((MAKER_PRICE / TAKER_PRICE) * (MARGIN_RATIO + 1.1e-4)).times(scaling); - } - - function takerToMakerAmount(takerAmount: BigNumber): BigNumber { - return takerAmount.times(new BigNumber(10).pow(MAKER_DECIMALS - TAKER_DECIMALS)); - } - - describe('_getSolventMakerAmount()', () => { - it('computes fillable amount for a solvent maker', async () => { - // Deposit collateral at a rate low enough to steadily reduce the - // withdraw account's collateralization ratio. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate, Math.random()); - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // The collateralization ratio after filling `makerAssetFillAmount` - // should be exactly at `MARGIN_RATIO`. - const cr = getFilledAccountCollateralizations(DYDX_CONFIG, checkInfo, makerAssetFillAmount); - expect(cr[0].dp(2)).to.bignumber.eq(MARGIN_RATIO); - }); - - it('computes fillable amount for a solvent maker with zero-sized deposits', async () => { - const withdrawRate = getRandomRate(); - const depositRate = new BigNumber(0); - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // The collateralization ratio after filling `makerAssetFillAmount` - // should be exactly at `MARGIN_RATIO`. - const cr = getFilledAccountCollateralizations(DYDX_CONFIG, checkInfo, makerAssetFillAmount); - expect(cr[0].dp(2)).to.bignumber.eq(MARGIN_RATIO); - }); - - it('computes fillable amount for a solvent maker with no deposits', async () => { - const withdrawRate = getRandomRate(); - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // The collateralization ratio after filling `makerAssetFillAmount` - // should be exactly at `MARGIN_RATIO`. - const cr = getFilledAccountCollateralizations(DYDX_CONFIG, checkInfo, makerAssetFillAmount); - expect(cr[0].dp(2)).to.bignumber.eq(MARGIN_RATIO); - }); - - it('computes fillable amount for a solvent maker with multiple deposits', async () => { - // Deposit collateral at a rate low enough to steadily reduce the - // withdraw account's collateralization ratio. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate, Math.random()); - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate.times(0.75), TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate.times(0.25), TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // The collateralization ratio after filling `makerAssetFillAmount` - // should be exactly at `MARGIN_RATIO`. - const cr = getFilledAccountCollateralizations(DYDX_CONFIG, checkInfo, makerAssetFillAmount); - expect(cr[0].dp(2)).to.bignumber.eq(MARGIN_RATIO); - }); - - it('returns infinite amount for a perpetually solvent maker', async () => { - // Deposit collateral at a rate that keeps the withdraw account's - // collateralization ratio constant. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate); - const checkInfo = createBalanceCheckInfo({ - // Deposit/Withdraw at a rate == marginRatio. - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('returns infinite amount for a perpetually solvent maker with multiple deposits', async () => { - // Deposit collateral at a rate that keeps the withdraw account's - // collateralization ratio constant. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate); - const checkInfo = createBalanceCheckInfo({ - // Deposit/Withdraw at a rate == marginRatio. - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate.times(0.25), TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate.times(0.75), TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('does not count deposits to other accounts', async () => { - // Deposit collateral at a rate that keeps the withdraw account's - // collateralization ratio constant, BUT we split it in two deposits - // and one will go into a different account. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate); - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate.times(0.5), TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Deposit, - // Deposit enough to balance out withdraw, but - // into a different account. - accountIdx: new BigNumber(1), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate.times(0.5), TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - }); - - it('returns zero on an account that is under-collateralized', async () => { - // Even though the deposit rate is enough to meet the minimum collateralization ratio, - // the account is under-collateralized from the start, so cannot be filled. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate); - const checkInfo = createBalanceCheckInfo({ - accounts: [DYDX_CONFIG.accounts[INSOLVENT_ACCOUNT_IDX].accountId], - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(0); - }); - - it( - 'returns zero on an account that has no balance if deposit ' + - 'to withdraw ratio is < the minimum collateralization rate', - async () => { - // If the deposit rate is not enough to meet the minimum collateralization ratio, - // the fillable maker amount is zero because it will become insolvent as soon as - // the withdraw occurs. - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate, 0.99); - const checkInfo = createBalanceCheckInfo({ - accounts: [DYDX_CONFIG.accounts[ZERO_BALANCE_ACCOUNT_IDX].accountId], - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(0); - }, - ); - - it( - 'returns infinite on an account that has no balance if deposit ' + - 'to withdraw ratio is >= the minimum collateralization rate', - async () => { - const withdrawRate = getRandomRate(); - const depositRate = getBalancedDepositRate(withdrawRate); - const checkInfo = createBalanceCheckInfo({ - accounts: [DYDX_CONFIG.accounts[ZERO_BALANCE_ACCOUNT_IDX].accountId], - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: fromTokenUnitAmount(withdrawRate), - conversionRateDenominator: fromTokenUnitAmount(1), - }, - ], - }); - const makerAssetFillAmount = await testContract.getSolventMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(constants.MAX_UINT256); - }, - ); - }); - - blockchainTests.resets('_getDepositableMakerAmount()', () => { - it('returns infinite if no deposit action', async () => { - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(10, TAKER_DECIMALS).div(fromTokenUnitAmount(100, MAKER_DECIMALS)), - ), - actions: [], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('returns infinite if deposit rate is zero', async () => { - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(10, TAKER_DECIMALS).div(fromTokenUnitAmount(100, MAKER_DECIMALS)), - ), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(0, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('returns infinite if taker tokens cover the deposit rate', async () => { - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(10, TAKER_DECIMALS).div(fromTokenUnitAmount(100, MAKER_DECIMALS)), - ), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(Math.random() * 0.1, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(constants.MAX_UINT256); - }); - - it('returns correct amount if taker tokens only partially cover deposit rate', async () => { - // The taker tokens getting exchanged in will only partially cover the deposit. - const exchangeRate = 0.1; - const depositRate = Math.random() + exchangeRate; - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS).div(fromTokenUnitAmount(1, MAKER_DECIMALS)), - ), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // Compute the equivalent taker asset fill amount. - const takerAssetFillAmount = fromTokenUnitAmount( - toTokenUnitAmount(makerAssetFillAmount, MAKER_DECIMALS) - // Reduce the deposit rate by the exchange rate. - .times(depositRate - exchangeRate), - TAKER_DECIMALS, - ); - // Which should equal the entire taker token balance of the account owner. - // We do some rounding to account for integer vs FP vs symbolic precision differences. - expect(toTokenUnitAmount(takerAssetFillAmount, TAKER_DECIMALS).dp(5)).to.bignumber.eq( - toTokenUnitAmount(INITIAL_TAKER_TOKEN_BALANCE, TAKER_DECIMALS).dp(5), - ); - }); - - it('returns correct amount if the taker asset not an ERC20', async () => { - const depositRate = 0.1; - const checkInfo = createBalanceCheckInfo({ - // The `takerTokenAddress` will be zero if the asset is not an ERC20. - takerTokenAddress: constants.NULL_ADDRESS, - orderMakerToTakerRate: fromTokenUnitAmount(fromTokenUnitAmount(0.1, MAKER_DECIMALS)), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // Compute the equivalent taker asset fill amount. - const takerAssetFillAmount = fromTokenUnitAmount( - toTokenUnitAmount(makerAssetFillAmount, MAKER_DECIMALS) - // Reduce the deposit rate by the exchange rate. - .times(depositRate), - TAKER_DECIMALS, - ); - // Which should equal the entire taker token balance of the account owner. - // We do some rounding to account for integer vs FP vs symbolic precision differences. - expect(toTokenUnitAmount(takerAssetFillAmount, TAKER_DECIMALS).dp(6)).to.bignumber.eq( - toTokenUnitAmount(INITIAL_TAKER_TOKEN_BALANCE, TAKER_DECIMALS).dp(6), - ); - }); - - it('returns the correct amount if taker:maker deposit rate is 1:1 and' + 'token != taker token', async () => { - const checkInfo = createBalanceCheckInfo({ - takerTokenAddress: randomAddress(), - // These amounts should be effectively ignored in the final computation - // because the token being deposited is not the taker token. - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(10, TAKER_DECIMALS).div(fromTokenUnitAmount(100, MAKER_DECIMALS)), - ), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(1, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(takerToMakerAmount(INITIAL_TAKER_TOKEN_BALANCE)); - }); - - it('returns the smallest viable maker amount with multiple deposits', async () => { - // The taker tokens getting exchanged in will only partially cover the deposit. - const exchangeRate = 0.1; - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount( - fromTokenUnitAmount(exchangeRate, TAKER_DECIMALS).div(fromTokenUnitAmount(1, MAKER_DECIMALS)), - ), - actions: [ - // Technically, deposits of the same token are not allowed, but the - // check isn't done in this function so we'll do this to simulate - // two deposits to distinct tokens. - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(Math.random() + exchangeRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(Math.random() + exchangeRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.not.bignumber.eq(constants.MAX_UINT256); - // Extract the deposit rates. - const depositRates = checkInfo.actions.map(a => - toTokenUnitAmount(a.conversionRateNumerator, TAKER_DECIMALS).div( - toTokenUnitAmount(a.conversionRateDenominator, MAKER_DECIMALS), - ), - ); - // The largest deposit rate will result in the smallest maker asset fill amount. - const maxDepositRate = BigNumber.max(...depositRates); - // Compute the equivalent taker asset fill amounts. - const takerAssetFillAmount = fromTokenUnitAmount( - toTokenUnitAmount(makerAssetFillAmount, MAKER_DECIMALS) - // Reduce the deposit rate by the exchange rate. - .times(maxDepositRate.minus(exchangeRate)), - TAKER_DECIMALS, - ); - // Which should equal the entire taker token balance of the account owner. - // We do some rounding to account for integer vs FP vs symbolic precision differences. - expect(toTokenUnitAmount(takerAssetFillAmount, TAKER_DECIMALS).dp(5)).to.bignumber.eq( - toTokenUnitAmount(INITIAL_TAKER_TOKEN_BALANCE, TAKER_DECIMALS).dp(5), - ); - }); - - it( - 'returns zero if the maker has no taker tokens and the deposit rate is' + 'greater than the exchange rate', - async () => { - await testContract - .setTokenBalance(takerTokenAddress, ACCOUNT_OWNER, constants.ZERO_AMOUNT) - .awaitTransactionSuccessAsync(); - // The taker tokens getting exchanged in will only partially cover the deposit. - const exchangeRate = 0.1; - const depositRate = Math.random() + exchangeRate; - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount(fromTokenUnitAmount(1 / exchangeRate, MAKER_DECIMALS)), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(0); - }, - ); - - it( - 'returns zero if dydx has no taker token allowance and the deposit rate is' + - 'greater than the exchange rate', - async () => { - await testContract - .setTokenApproval(takerTokenAddress, ACCOUNT_OWNER, dydx.address, constants.ZERO_AMOUNT) - .awaitTransactionSuccessAsync(); - // The taker tokens getting exchanged in will only partially cover the deposit. - const exchangeRate = 0.1; - const depositRate = Math.random() + exchangeRate; - const checkInfo = createBalanceCheckInfo({ - orderMakerToTakerRate: fromTokenUnitAmount(fromTokenUnitAmount(1 / exchangeRate, MAKER_DECIMALS)), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(depositRate, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - ], - }); - const makerAssetFillAmount = await testContract.getDepositableMakerAmount(checkInfo).callAsync(); - expect(makerAssetFillAmount).to.bignumber.eq(0); - }, - ); - }); - - describe('_areActionsWellFormed()', () => { - it('Returns false if no actions', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if there is an account index out of range in deposits', async () => { - const checkInfo = createBalanceCheckInfo({ - accounts: DYDX_CONFIG.accounts.slice(0, 2).map(a => a.accountId), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(2), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if a market is not unique among deposits', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if no withdraw at the end', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if a withdraw comes before a deposit', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if more than one withdraw', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if withdraw is not for maker token', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Returns false if withdraw is for an out of range account', async () => { - const checkInfo = createBalanceCheckInfo({ - accounts: DYDX_CONFIG.accounts.slice(0, 2).map(a => a.accountId), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(2), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.false(); - }); - - it('Can return true if no deposit', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.true(); - }); - - it('Can return true if no deposit', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.true(); - }); - - it('Can return true with multiple deposits', async () => { - const checkInfo = createBalanceCheckInfo({ - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }); - const r = await testContract.areActionsWellFormed(checkInfo).callAsync(); - expect(r).to.be.true(); - }); - }); - - function createERC20AssetData(tokenAddress: string): string { - return assetDataContract.ERC20Token(tokenAddress).getABIEncodedTransactionData(); - } - - function createERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { - return assetDataContract.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData(); - } - - function createBridgeAssetData( - makerTokenAddress_: string, - bridgeAddress: string, - data: Partial = {}, - ): string { - return assetDataContract - .ERC20Bridge( - makerTokenAddress_, - bridgeAddress, - dydxBridgeDataEncoder.encode({ - bridgeData: { - accountNumbers: DYDX_CONFIG.accounts.slice(0, 1).map(a => a.accountId), - actions: [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: fromTokenUnitAmount(1, TAKER_DECIMALS), - conversionRateDenominator: fromTokenUnitAmount(1, MAKER_DECIMALS), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - ...data, - }, - }), - ) - .getABIEncodedTransactionData(); - } - - function createOrder(orderFields: Partial = {}): Order { - return { - chainId: 1, - exchangeAddress: randomAddress(), - salt: getRandomInteger(1, constants.MAX_UINT256), - expirationTimeSeconds: getRandomInteger(1, constants.MAX_UINT256), - feeRecipientAddress: randomAddress(), - makerAddress: ACCOUNT_OWNER, - takerAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - makerFee: getRandomInteger(1, constants.MAX_UINT256), - takerFee: getRandomInteger(1, constants.MAX_UINT256), - makerAssetAmount: fromTokenUnitAmount(100, MAKER_DECIMALS), - takerAssetAmount: fromTokenUnitAmount(10, TAKER_DECIMALS), - makerAssetData: createBridgeAssetData(makerTokenAddress, BRIDGE_ADDRESS), - takerAssetData: createERC20AssetData(takerTokenAddress), - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - ...orderFields, - }; - } - - describe('getDydxMakerBalance()', () => { - it('returns nonzero with valid order', async () => { - const order = createOrder(); - const r = await testContract.getDydxMakerBalance(order, dydx.address).callAsync(); - expect(r).to.not.bignumber.eq(0); - }); - - it('returns nonzero with valid order with an ERC721 taker asset', async () => { - const order = createOrder({ - takerAssetData: createERC721AssetData(randomAddress(), getRandomInteger(1, constants.MAX_UINT256)), - }); - const r = await testContract.getDydxMakerBalance(order, dydx.address).callAsync(); - expect(r).to.not.bignumber.eq(0); - }); - - it('returns 0 if bridge is not a local operator', async () => { - const order = createOrder({ - makerAssetData: createBridgeAssetData(ACCOUNT_OWNER, randomAddress()), - }); - const r = await testContract.getDydxMakerBalance(order, dydx.address).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('returns 0 if bridge data does not have well-formed actions', async () => { - const order = createOrder({ - makerAssetData: createBridgeAssetData(takerTokenAddress, BRIDGE_ADDRESS, { - // Two withdraw actions is invalid. - actions: [ - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(0), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0), - conversionRateDenominator: new BigNumber(0), - }, - ], - }), - }); - const r = await testContract.getDydxMakerBalance(order, dydx.address).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('returns 0 if the maker token withdraw rate is < 1', async () => { - const order = createOrder({ - makerAssetData: createBridgeAssetData(takerTokenAddress, BRIDGE_ADDRESS, { - actions: [ - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: new BigNumber(0), - marketId: new BigNumber(1), - conversionRateNumerator: new BigNumber(0.99e18), - conversionRateDenominator: new BigNumber(1e18), - }, - ], - }), - }); - const r = await testContract.getDydxMakerBalance(order, dydx.address).callAsync(); - expect(r).to.bignumber.eq(0); - }); - }); -}); -// tslint:disable-next-line: max-file-line-count diff --git a/contracts/dev-utils/test/wrappers.ts b/contracts/dev-utils/test/wrappers.ts deleted file mode 100644 index 01f291fa09..0000000000 --- a/contracts/dev-utils/test/wrappers.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/addresses'; -export * from '../test/generated-wrappers/asset_balance'; -export * from '../test/generated-wrappers/dev_utils'; -export * from '../test/generated-wrappers/eth_balance_checker'; -export * from '../test/generated-wrappers/external_functions'; -export * from '../test/generated-wrappers/lib_asset_data'; -export * from '../test/generated-wrappers/lib_dydx_balance'; -export * from '../test/generated-wrappers/lib_order_transfer_simulation'; -export * from '../test/generated-wrappers/lib_transaction_decoder'; -export * from '../test/generated-wrappers/order_transfer_simulation_utils'; -export * from '../test/generated-wrappers/order_validation_utils'; -export * from '../test/generated-wrappers/test_dydx'; -export * from '../test/generated-wrappers/test_lib_dydx_balance'; diff --git a/contracts/dev-utils/truffle-config.js b/contracts/dev-utils/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/dev-utils/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/dev-utils/tsconfig.json b/contracts/dev-utils/tsconfig.json deleted file mode 100644 index eccc9bf633..0000000000 --- a/contracts/dev-utils/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/DevUtils.json", - "generated-artifacts/LibAssetData.json", - "generated-artifacts/LibDydxBalance.json", - "generated-artifacts/LibOrderTransferSimulation.json", - "generated-artifacts/LibTransactionDecoder.json", - "test/generated-artifacts/Addresses.json", - "test/generated-artifacts/AssetBalance.json", - "test/generated-artifacts/DevUtils.json", - "test/generated-artifacts/EthBalanceChecker.json", - "test/generated-artifacts/ExternalFunctions.json", - "test/generated-artifacts/LibAssetData.json", - "test/generated-artifacts/LibDydxBalance.json", - "test/generated-artifacts/LibOrderTransferSimulation.json", - "test/generated-artifacts/LibTransactionDecoder.json", - "test/generated-artifacts/OrderTransferSimulationUtils.json", - "test/generated-artifacts/OrderValidationUtils.json", - "test/generated-artifacts/TestDydx.json", - "test/generated-artifacts/TestLibDydxBalance.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/dev-utils/tslint.json b/contracts/dev-utils/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/dev-utils/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/dev-utils/typedoc-tsconfig.json b/contracts/dev-utils/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/dev-utils/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/erc1155/.npmignore b/contracts/erc1155/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/erc1155/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/erc1155/CHANGELOG.json b/contracts/erc1155/CHANGELOG.json deleted file mode 100644 index fc445f9b2f..0000000000 --- a/contracts/erc1155/CHANGELOG.json +++ /dev/null @@ -1,623 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "2.1.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "2.1.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "2.1.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "2.1.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "2.1.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "2.1.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "2.1.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "2.1.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "2.1.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "2.1.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "2.1.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "2.1.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "2.1.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "2.1.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "2.1.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "2.1.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "2.1.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "2.1.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "2.1.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "2.1.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "2.1.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "2.1.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "2.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "2.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "2.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "2.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "2.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "2.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "2.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "2.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "2.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "2.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "2.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "2.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "2.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "2.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Fix broken tests", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.", - "pr": 1819 - }, - { - "note": "Replaced `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1575296764 - }, - { - "version": "1.2.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "1.2.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "1.2.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - } - ], - "timestamp": 1574030254 - }, - { - "version": "1.2.0-beta.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1573159180 - }, - { - "version": "1.2.0-beta.0", - "changes": [ - { - "note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.", - "pr": 1819 - }, - { - "note": "Replaced `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "1.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "1.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "1.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "1.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.11", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564604963 - }, - { - "timestamp": 1563957393, - "version": "1.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "1.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "1.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "1.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "1.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "1.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1557799313 - }, - { - "timestamp": 1557507213, - "version": "1.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "timestamp": 1553091633, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Created ERC1155 contracts package", - "pr": 1657 - } - ] - } -] diff --git a/contracts/erc1155/CHANGELOG.md b/contracts/erc1155/CHANGELOG.md deleted file mode 100644 index 3ae4dd8e16..0000000000 --- a/contracts/erc1155/CHANGELOG.md +++ /dev/null @@ -1,277 +0,0 @@ - - -CHANGELOG - -## v2.1.37 - _August 16, 2021_ - - * Dependencies updated - -## v2.1.36 - _August 11, 2021_ - - * Dependencies updated - -## v2.1.35 - _August 6, 2021_ - - * Dependencies updated - -## v2.1.34 - _June 22, 2021_ - - * Dependencies updated - -## v2.1.33 - _June 11, 2021_ - - * Dependencies updated - -## v2.1.32 - _June 2, 2021_ - - * Dependencies updated - -## v2.1.31 - _May 25, 2021_ - - * Dependencies updated - -## v2.1.30 - _May 21, 2021_ - - * Dependencies updated - -## v2.1.29 - _May 5, 2021_ - - * Dependencies updated - -## v2.1.28 - _April 28, 2021_ - - * Dependencies updated - -## v2.1.27 - _April 1, 2021_ - - * Dependencies updated - -## v2.1.26 - _March 17, 2021_ - - * Dependencies updated - -## v2.1.25 - _February 24, 2021_ - - * Dependencies updated - -## v2.1.24 - _February 10, 2021_ - - * Dependencies updated - -## v2.1.23 - _January 26, 2021_ - - * Dependencies updated - -## v2.1.22 - _January 13, 2021_ - - * Dependencies updated - -## v2.1.21 - _January 4, 2021_ - - * Dependencies updated - -## v2.1.20 - _December 23, 2020_ - - * Dependencies updated - -## v2.1.19 - _December 17, 2020_ - - * Dependencies updated - -## v2.1.18 - _December 9, 2020_ - - * Dependencies updated - -## v2.1.17 - _December 7, 2020_ - - * Dependencies updated - -## v2.1.16 - _December 3, 2020_ - - * Dependencies updated - -## v2.1.15 - _November 19, 2020_ - - * Dependencies updated - -## v2.1.14 - _November 13, 2020_ - - * Dependencies updated - -## v2.1.13 - _November 3, 2020_ - - * Dependencies updated - -## v2.1.12 - _November 3, 2020_ - - * Dependencies updated - -## v2.1.11 - _November 2, 2020_ - - * Dependencies updated - -## v2.1.10 - _October 28, 2020_ - - * Dependencies updated - -## v2.1.9 - _October 27, 2020_ - - * Dependencies updated - -## v2.1.8 - _October 21, 2020_ - - * Dependencies updated - -## v2.1.7 - _July 15, 2020_ - - * Dependencies updated - -## v2.1.6 - _June 24, 2020_ - - * Dependencies updated - -## v2.1.5 - _March 3, 2020_ - - * Dependencies updated - -## v2.1.4 - _February 27, 2020_ - - * Dependencies updated - -## v2.1.3 - _February 26, 2020_ - - * Dependencies updated - -## v2.1.2 - _February 25, 2020_ - - * Dependencies updated - -## v2.1.1 - _February 15, 2020_ - - * Dependencies updated - -## v2.1.0 - _February 8, 2020_ - - * Fix broken tests (#2462) - -## v2.0.6 - _February 6, 2020_ - - * Dependencies updated - -## v2.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v2.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v2.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v2.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v2.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v2.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819) - * Replaced `SafeMath` with `LibSafeMath` (#2254) - -## v1.2.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v1.2.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v1.2.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - -## v1.2.0-beta.1 - _November 7, 2019_ - - * Dependencies updated - -## v1.2.0-beta.0 - _October 3, 2019_ - - * Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819) - * Replaced `SafeMath` with `LibSafeMath` (#2254) - -## v1.1.15 - _September 17, 2019_ - - * Dependencies updated - -## v1.1.14 - _September 3, 2019_ - - * Dependencies updated - -## v1.1.13 - _August 22, 2019_ - - * Dependencies updated - -## v1.1.12 - _August 8, 2019_ - - * Dependencies updated - -## v1.1.11 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v1.1.10 - _July 24, 2019_ - - * Dependencies updated - -## v1.1.9 - _July 15, 2019_ - - * Dependencies updated - -## v1.1.8 - _July 13, 2019_ - - * Dependencies updated - -## v1.1.7 - _July 13, 2019_ - - * Dependencies updated - -## v1.1.6 - _May 24, 2019_ - - * Dependencies updated - -## v1.1.5 - _May 15, 2019_ - - * Dependencies updated - -## v1.1.4 - _May 14, 2019_ - - * Dependencies updated - -## v1.1.2 - _May 10, 2019_ - - * Dependencies updated - -## v1.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v1.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v1.0.1 - _March 20, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Created ERC1155 contracts package (#1657) diff --git a/contracts/erc1155/DEPLOYS.json b/contracts/erc1155/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/erc1155/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/erc1155/README.md b/contracts/erc1155/README.md deleted file mode 100644 index 7773a26126..0000000000 --- a/contracts/erc1155/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## ERC1155 Tokens - -This package contains implementations of various [ERC1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) tokens. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-erc1155 --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-erc1155 yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-erc1155 yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/erc1155/compiler.json b/contracts/erc1155/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/erc1155/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/erc1155/contracts/src/ERC1155.sol b/contracts/erc1155/contracts/src/ERC1155.sol deleted file mode 100644 index c76fedf007..0000000000 --- a/contracts/erc1155/contracts/src/ERC1155.sol +++ /dev/null @@ -1,248 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/LibAddress.sol"; -import "./interfaces/IERC1155.sol"; -import "./interfaces/IERC1155Receiver.sol"; -import "./MixinNonFungibleToken.sol"; - - -contract ERC1155 is - IERC1155, - MixinNonFungibleToken -{ - using LibAddress for address; - using LibSafeMath for uint256; - - // selectors for receiver callbacks - bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61; - bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81; - - // id => (owner => balance) - mapping (uint256 => mapping(address => uint256)) internal balances; - - // owner => (operator => approved) - mapping (address => mapping(address => bool)) internal operatorApproval; - - /// @notice Transfers value amount of an _id from the _from address to the _to address specified. - /// @dev MUST emit TransferSingle event on success. - /// Caller must be approved to manage the _from account's tokens (see isApprovedForAll). - /// MUST throw if `_to` is the zero address. - /// MUST throw if balance of sender for token `_id` is lower than the `_value` sent. - /// MUST throw on any other error. - /// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). - /// If so, it MUST call `onERC1155Received` on `_to` and revert if the return value - /// is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`. - /// @param from Source address - /// @param to Target address - /// @param id ID of the token type - /// @param value Transfer amount - /// @param data Additional data with no specified format, sent in call to `_to` - function safeTransferFrom( - address from, - address to, - uint256 id, - uint256 value, - bytes calldata data - ) - external - { - // sanity checks - require( - to != address(0x0), - "CANNOT_TRANSFER_TO_ADDRESS_ZERO" - ); - require( - from == msg.sender || operatorApproval[from][msg.sender] == true, - "INSUFFICIENT_ALLOWANCE" - ); - - // perform transfer - if (isNonFungible(id)) { - require( - value == 1, - "AMOUNT_EQUAL_TO_ONE_REQUIRED" - ); - require( - nfOwners[id] == from, - "NFT_NOT_OWNED_BY_FROM_ADDRESS" - ); - nfOwners[id] = to; - // You could keep balance of NF type in base type id like so: - // uint256 baseType = getNonFungibleBaseType(_id); - // balances[baseType][_from] = balances[baseType][_from].safeSub(_value); - // balances[baseType][_to] = balances[baseType][_to].safeAdd(_value); - } else { - balances[id][from] = balances[id][from].safeSub(value); - balances[id][to] = balances[id][to].safeAdd(value); - } - emit TransferSingle(msg.sender, from, to, id, value); - - // if `to` is a contract then trigger its callback - if (to.isContract()) { - bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155Received( - msg.sender, - from, - id, - value, - data - ); - require( - callbackReturnValue == ERC1155_RECEIVED, - "BAD_RECEIVER_RETURN_VALUE" - ); - } - } - - /// @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call). - /// @dev MUST emit TransferBatch event on success. - /// Caller must be approved to manage the _from account's tokens (see isApprovedForAll). - /// MUST throw if `_to` is the zero address. - /// MUST throw if length of `_ids` is not the same as length of `_values`. - /// MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_values` sent. - /// MUST throw on any other error. - /// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). - /// If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return value - /// is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`. - /// @param from Source addresses - /// @param to Target addresses - /// @param ids IDs of each token type - /// @param values Transfer amounts per token type - /// @param data Additional data with no specified format, sent in call to `_to` - function safeBatchTransferFrom( - address from, - address to, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) - external - { - // sanity checks - require( - to != address(0x0), - "CANNOT_TRANSFER_TO_ADDRESS_ZERO" - ); - require( - ids.length == values.length, - "TOKEN_AND_VALUES_LENGTH_MISMATCH" - ); - - // Only supporting a global operator approval allows us to do - // only 1 check and not to touch storage to handle allowances. - require( - from == msg.sender || operatorApproval[from][msg.sender] == true, - "INSUFFICIENT_ALLOWANCE" - ); - - // perform transfers - for (uint256 i = 0; i < ids.length; ++i) { - // Cache value to local variable to reduce read costs. - uint256 id = ids[i]; - uint256 value = values[i]; - - if (isNonFungible(id)) { - require( - value == 1, - "AMOUNT_EQUAL_TO_ONE_REQUIRED" - ); - require( - nfOwners[id] == from, - "NFT_NOT_OWNED_BY_FROM_ADDRESS" - ); - nfOwners[id] = to; - } else { - balances[id][from] = balances[id][from].safeSub(value); - balances[id][to] = balances[id][to].safeAdd(value); - } - } - emit TransferBatch(msg.sender, from, to, ids, values); - - // if `to` is a contract then trigger its callback - if (to.isContract()) { - bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155BatchReceived( - msg.sender, - from, - ids, - values, - data - ); - require( - callbackReturnValue == ERC1155_BATCH_RECEIVED, - "BAD_RECEIVER_RETURN_VALUE" - ); - } - } - - /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. - /// @dev MUST emit the ApprovalForAll event on success. - /// @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 { - operatorApproval[msg.sender][operator] = approved; - emit ApprovalForAll(msg.sender, operator, approved); - } - - /// @notice Queries the approval status of an operator for a given owner. - /// @param owner The owner of the Tokens - /// @param operator Address of authorized operator - /// @return True if the operator is approved, false if not - function isApprovedForAll(address owner, address operator) external view returns (bool) { - return operatorApproval[owner][operator]; - } - - /// @notice Get the balance of an account's Tokens. - /// @param owner The address of the token holder - /// @param id ID of the Token - /// @return The _owner's balance of the Token type requested - function balanceOf(address owner, uint256 id) external view returns (uint256) { - if (isNonFungibleItem(id)) { - return nfOwners[id] == owner ? 1 : 0; - } - return balances[id][owner]; - } - - /// @notice Get the balance of multiple account/token pairs - /// @param owners The addresses of the token holders - /// @param ids ID of the Tokens - /// @return The _owner's balance of the Token types requested - function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory balances_) { - // sanity check - require( - owners.length == ids.length, - "OWNERS_AND_IDS_MUST_HAVE_SAME_LENGTH" - ); - - // get balances - balances_ = new uint256[](owners.length); - for (uint256 i = 0; i < owners.length; ++i) { - uint256 id = ids[i]; - if (isNonFungibleItem(id)) { - balances_[i] = nfOwners[id] == owners[i] ? 1 : 0; - } else { - balances_[i] = balances[id][owners[i]]; - } - } - - return balances_; - } -} diff --git a/contracts/erc1155/contracts/src/ERC1155Mintable.sol b/contracts/erc1155/contracts/src/ERC1155Mintable.sol deleted file mode 100644 index 9db42f8888..0000000000 --- a/contracts/erc1155/contracts/src/ERC1155Mintable.sol +++ /dev/null @@ -1,219 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./ERC1155.sol"; -import "./interfaces/IERC1155Mintable.sol"; - - -/// @dev Mintable form of ERC1155 -/// Shows how easy it is to mint new items -contract ERC1155Mintable is - IERC1155Mintable, - ERC1155 -{ - using LibSafeMath for uint256; - - /// token nonce - uint256 internal nonce; - - /// mapping from token to creator - mapping (uint256 => address) public creators; - - /// mapping from token to max index - mapping (uint256 => uint256) public maxIndex; - - /// asserts token is owned by msg.sender - modifier creatorOnly(uint256 _id) { - require(creators[_id] == msg.sender); - _; - } - - /// @dev creates a new token - /// @param uri URI of token - /// @param isNF is non-fungible token - /// @return type_ of token (a unique identifier) - function create( - string calldata uri, - bool isNF - ) - external - returns (uint256 type_) - { - // Store the type in the upper 128 bits - type_ = (++nonce << 128); - - // Set a flag if this is an NFI. - if (isNF) { - type_ = type_ | TYPE_NF_BIT; - } - - // This will allow restricted access to creators. - creators[type_] = msg.sender; - - // emit a Transfer event with Create semantic to help with discovery. - emit TransferSingle( - msg.sender, - address(0x0), - address(0x0), - type_, - 0 - ); - - if (bytes(uri).length > 0) { - emit URI(uri, type_); - } - } - - /// @dev creates a new token - /// @param type_ of token - /// @param uri URI of token - function createWithType( - uint256 type_, - string calldata uri - ) - external - { - // This will allow restricted access to creators. - creators[type_] = msg.sender; - - // emit a Transfer event with Create semantic to help with discovery. - emit TransferSingle( - msg.sender, - address(0x0), - address(0x0), - type_, - 0 - ); - - if (bytes(uri).length > 0) { - emit URI(uri, type_); - } - } - - /// @dev mints fungible tokens - /// @param id token type - /// @param to beneficiaries of minted tokens - /// @param quantities amounts of minted tokens - function mintFungible( - uint256 id, - address[] calldata to, - uint256[] calldata quantities - ) - external - creatorOnly(id) - { - // sanity checks - require( - isFungible(id), - "TRIED_TO_MINT_FUNGIBLE_FOR_NON_FUNGIBLE_TOKEN" - ); - - // mint tokens - for (uint256 i = 0; i < to.length; ++i) { - // cache to reduce number of loads - address dst = to[i]; - uint256 quantity = quantities[i]; - - // Grant the items to the caller - balances[id][dst] = quantity.safeAdd(balances[id][dst]); - - // Emit the Transfer/Mint event. - // the 0x0 source address implies a mint - // It will also provide the circulating supply info. - emit TransferSingle( - msg.sender, - address(0x0), - dst, - id, - quantity - ); - - // if `to` is a contract then trigger its callback - if (dst.isContract()) { - bytes4 callbackReturnValue = IERC1155Receiver(dst).onERC1155Received( - msg.sender, - msg.sender, - id, - quantity, - "" - ); - require( - callbackReturnValue == ERC1155_RECEIVED, - "BAD_RECEIVER_RETURN_VALUE" - ); - } - } - } - - /// @dev mints a non-fungible token - /// @param type_ token type - /// @param to beneficiaries of minted tokens - function mintNonFungible( - uint256 type_, - address[] calldata to - ) - external - creatorOnly(type_) - { - // No need to check this is a nf type rather than an id since - // creatorOnly() will only let a type pass through. - require( - isNonFungible(type_), - "TRIED_TO_MINT_NON_FUNGIBLE_FOR_FUNGIBLE_TOKEN" - ); - - // Index are 1-based. - uint256 index = maxIndex[type_] + 1; - - for (uint256 i = 0; i < to.length; ++i) { - // cache to reduce number of loads - address dst = to[i]; - uint256 id = type_ | index + i; - - nfOwners[id] = dst; - - // You could use base-type id to store NF type balances if you wish. - // balances[_type][dst] = quantity.safeAdd(balances[_type][dst]); - - emit TransferSingle(msg.sender, address(0x0), dst, id, 1); - - // if `to` is a contract then trigger its callback - if (dst.isContract()) { - bytes4 callbackReturnValue = IERC1155Receiver(dst).onERC1155Received( - msg.sender, - msg.sender, - id, - 1, - "" - ); - require( - callbackReturnValue == ERC1155_RECEIVED, - "BAD_RECEIVER_RETURN_VALUE" - ); - } - } - - // record the `maxIndex` of this nft type - // this allows us to mint more nft's of this type in a subsequent call. - maxIndex[type_] = to.length.safeAdd(maxIndex[type_]); - } -} diff --git a/contracts/erc1155/contracts/src/MixinNonFungibleToken.sol b/contracts/erc1155/contracts/src/MixinNonFungibleToken.sol deleted file mode 100644 index ce43e0f4bc..0000000000 --- a/contracts/erc1155/contracts/src/MixinNonFungibleToken.sol +++ /dev/null @@ -1,73 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -contract MixinNonFungibleToken { - /// Use a split bit implementation. - /// Store the type in the upper 128 bits.. - uint256 constant internal TYPE_MASK = uint256(uint128(~0)) << 128; - - /// ..and the non-fungible index in the lower 128 - uint256 constant internal NF_INDEX_MASK = uint128(~0); - - /// The top bit is a flag to tell if this is a NFI. - uint256 constant internal TYPE_NF_BIT = 1 << 255; - - /// mapping of nft to owner - mapping (uint256 => address) internal nfOwners; - - /// @dev Returns true if token is non-fungible - function isNonFungible(uint256 id) public pure returns(bool) { - return id & TYPE_NF_BIT == TYPE_NF_BIT; - } - - /// @dev Returns true if token is fungible - function isFungible(uint256 id) public pure returns(bool) { - return id & TYPE_NF_BIT == 0; - } - - /// @dev Returns index of non-fungible token - function getNonFungibleIndex(uint256 id) public pure returns(uint256) { - return id & NF_INDEX_MASK; - } - - /// @dev Returns base type of non-fungible token - function getNonFungibleBaseType(uint256 id) public pure returns(uint256) { - return id & TYPE_MASK; - } - - /// @dev Returns true if input is base-type of a non-fungible token - function isNonFungibleBaseType(uint256 id) public pure returns(bool) { - // A base type has the NF bit but does not have an index. - return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK == 0); - } - - /// @dev Returns true if input is a non-fungible token - function isNonFungibleItem(uint256 id) public pure returns(bool) { - // A base type has the NF bit but does has an index. - return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0); - } - - /// @dev returns owner of a non-fungible token - function ownerOf(uint256 id) public view returns (address) { - return nfOwners[id]; - } -} diff --git a/contracts/erc1155/contracts/src/interfaces/IERC1155.sol b/contracts/erc1155/contracts/src/interfaces/IERC1155.sol deleted file mode 100644 index de0720e608..0000000000 --- a/contracts/erc1155/contracts/src/interfaces/IERC1155.sol +++ /dev/null @@ -1,153 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -/// @title ERC-1155 Multi Token Standard -/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md -/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. -interface IERC1155 { - - /// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, - /// including zero value transfers as well as minting or burning. - /// Operator will always be msg.sender. - /// Either event from address `0x0` signifies a minting operation. - /// An event to address `0x0` signifies a burning or melting operation. - /// The total value transferred from address 0x0 minus the total value transferred to 0x0 may - /// be used by clients and exchanges to be added to the "circulating supply" for a given token ID. - /// To define a token ID with no initial balance, the contract SHOULD emit the TransferSingle event - /// from `0x0` to `0x0`, with the token creator as `_operator`. - event TransferSingle( - address indexed operator, - address indexed from, - address indexed to, - uint256 id, - uint256 value - ); - - /// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, - /// including zero value transfers as well as minting or burning. - ///Operator will always be msg.sender. - /// Either event from address `0x0` signifies a minting operation. - /// An event to address `0x0` signifies a burning or melting operation. - /// The total value transferred from address 0x0 minus the total value transferred to 0x0 may - /// be used by clients and exchanges to be added to the "circulating supply" for a given token ID. - /// To define multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event - /// from `0x0` to `0x0`, with the token creator as `_operator`. - event TransferBatch( - address indexed operator, - address indexed from, - address indexed to, - uint256[] ids, - uint256[] values - ); - - /// @dev MUST emit when an approval is updated. - event ApprovalForAll( - address indexed owner, - address indexed operator, - bool approved - ); - - /// @dev MUST emit when the URI is updated for a token ID. - /// URIs are defined in RFC 3986. - /// The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata JSON Schema". - event URI( - string value, - uint256 indexed id - ); - - /// @notice Transfers value amount of an _id from the _from address to the _to address specified. - /// @dev MUST emit TransferSingle event on success. - /// Caller must be approved to manage the _from account's tokens (see isApprovedForAll). - /// MUST throw if `_to` is the zero address. - /// MUST throw if balance of sender for token `_id` is lower than the `_value` sent. - /// MUST throw on any other error. - /// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). - /// If so, it MUST call `onERC1155Received` on `_to` and revert if the return value - /// is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`. - /// @param from Source address - /// @param to Target address - /// @param id ID of the token type - /// @param value Transfer amount - /// @param data Additional data with no specified format, sent in call to `_to` - function safeTransferFrom( - address from, - address to, - uint256 id, - uint256 value, - bytes calldata data - ) - external; - - /// @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call). - /// @dev MUST emit TransferBatch event on success. - /// Caller must be approved to manage the _from account's tokens (see isApprovedForAll). - /// MUST throw if `_to` is the zero address. - /// MUST throw if length of `_ids` is not the same as length of `_values`. - /// MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_values` sent. - /// MUST throw on any other error. - /// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). - /// If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return value - /// is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`. - /// @param from Source addresses - /// @param to Target addresses - /// @param ids IDs of each token type - /// @param values Transfer amounts per token type - /// @param data Additional data with no specified format, sent in call to `_to` - function safeBatchTransferFrom( - address from, - address to, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) - external; - - /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. - /// @dev MUST emit the ApprovalForAll event on success. - /// @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 Queries the approval status of an operator for a given owner. - /// @param owner The owner of the Tokens - /// @param operator Address of authorized operator - /// @return True if the operator is approved, false if not - function isApprovedForAll(address owner, address operator) external view returns (bool); - - /// @notice Get the balance of an account's Tokens. - /// @param owner The address of the token holder - /// @param id ID of the Token - /// @return The _owner's balance of the Token type requested - function balanceOf(address owner, uint256 id) external view returns (uint256); - - /// @notice Get the balance of multiple account/token pairs - /// @param owners The addresses of the token holders - /// @param ids ID of the Tokens - /// @return The _owner's balance of the Token types requested - function balanceOfBatch( - address[] calldata owners, - uint256[] calldata ids - ) - external - view - returns (uint256[] memory balances_); -} diff --git a/contracts/erc1155/contracts/src/interfaces/IERC1155Mintable.sol b/contracts/erc1155/contracts/src/interfaces/IERC1155Mintable.sol deleted file mode 100644 index 036156a4ed..0000000000 --- a/contracts/erc1155/contracts/src/interfaces/IERC1155Mintable.sol +++ /dev/null @@ -1,61 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./IERC1155.sol"; - - -/// @dev Mintable form of ERC1155 -/// Shows how easy it is to mint new items -contract IERC1155Mintable is - IERC1155 -{ - - /// @dev creates a new token - /// @param uri URI of token - /// @param isNF is non-fungible token - /// @return _type of token (a unique identifier) - function create( - string calldata uri, - bool isNF - ) - external - returns (uint256 type_); - - /// @dev mints fungible tokens - /// @param id token type - /// @param to beneficiaries of minted tokens - /// @param quantities amounts of minted tokens - function mintFungible( - uint256 id, - address[] calldata to, - uint256[] calldata quantities - ) - external; - - /// @dev mints a non-fungible token - /// @param type_ token type - /// @param to beneficiaries of minted tokens - function mintNonFungible( - uint256 type_, - address[] calldata to - ) - external; -} diff --git a/contracts/erc1155/contracts/src/interfaces/IERC1155Receiver.sol b/contracts/erc1155/contracts/src/interfaces/IERC1155Receiver.sol deleted file mode 100644 index 6ce95759f9..0000000000 --- a/contracts/erc1155/contracts/src/interfaces/IERC1155Receiver.sol +++ /dev/null @@ -1,68 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -interface IERC1155Receiver { - - /// @notice Handle the receipt of a single ERC1155 token type - /// @dev The smart contract calls this function on the recipient - /// after a `safeTransferFrom`. 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 id An array containing the ids of the token being transferred - /// @param value An array containing the amount of tokens being transferred - /// @param data Additional data with no specified format - /// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` - function onERC1155Received( - address operator, - address from, - uint256 id, - uint256 value, - bytes calldata data - ) - external - returns(bytes4); - - /// @notice Handle the receipt of multiple ERC1155 token types - /// @dev The smart contract calls this function on the recipient - /// after a `safeTransferFrom`. 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 ids An array containing ids of each token being transferred - /// @param values An array containing amounts of each token being transferred - /// @param data Additional data with no specified format - /// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` - function onERC1155BatchReceived( - address operator, - address from, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) - external - returns(bytes4); -} diff --git a/contracts/erc1155/contracts/test/DummyERC1155Receiver.sol b/contracts/erc1155/contracts/test/DummyERC1155Receiver.sol deleted file mode 100644 index 5f402448f9..0000000000 --- a/contracts/erc1155/contracts/test/DummyERC1155Receiver.sol +++ /dev/null @@ -1,126 +0,0 @@ -/* - - Copyright 2019 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.5.5; - -import "../src/interfaces/IERC1155Receiver.sol"; - - -contract DummyERC1155Receiver is - IERC1155Receiver -{ - - bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61; - bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81; - bool internal shouldRejectTransfer; - - event TokenReceived( - address operator, - address from, - uint256 tokenId, - uint256 tokenValue, - bytes data - ); - - event BatchTokenReceived( - address operator, - address from, - uint256[] tokenIds, - uint256[] tokenValues, - bytes data - ); - - constructor () public { - shouldRejectTransfer = false; - } - - /// @notice Handle the receipt of a single ERC1155 token type - /// @dev The smart contract calls this function on the recipient - /// after a `safeTransferFrom`. 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 id An array containing the ids of the token being transferred - /// @param value An array containing the amount of tokens being transferred - /// @param data Additional data with no specified format - /// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` - function onERC1155Received( - address operator, - address from, - uint256 id, - uint256 value, - bytes calldata data - ) - external - returns(bytes4) - { - if (shouldRejectTransfer) { - revert("TRANSFER_REJECTED"); - } - emit TokenReceived( - operator, - from, - id, - value, - data - ); - return ERC1155_RECEIVED; - } - - /// @notice Handle the receipt of multiple ERC1155 token types - /// @dev The smart contract calls this function on the recipient - /// after a `safeTransferFrom`. 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 ids An array containing ids of each token being transferred - /// @param values An array containing amounts of each token being transferred - /// @param data Additional data with no specified format - /// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` - function onERC1155BatchReceived( - address operator, - address from, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) - external - returns (bytes4) - { - if (shouldRejectTransfer) { - revert("TRANSFER_REJECTED"); - } - emit BatchTokenReceived( - operator, - from, - ids, - values, - data - ); - return ERC1155_BATCH_RECEIVED; - } - - // @dev If set to true then all future transfers will be rejected. - function setRejectTransferFlag(bool _shouldRejectTransfer) external { - shouldRejectTransfer = _shouldRejectTransfer; - } -} diff --git a/contracts/erc1155/package.json b/contracts/erc1155/package.json deleted file mode 100644 index d260c3e1e5..0000000000 --- a/contracts/erc1155/package.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "name": "@0x/contracts-erc1155", - "version": "2.1.37", - "engines": { - "node": ">=6.12" - }, - "description": "Token contracts used by 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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "ERC1155,ERC1155Mintable,IERC1155Receiver,DummyERC1155Receiver", - "abis": "./test/generated-artifacts/@(DummyERC1155Receiver|ERC1155|ERC1155Mintable|IERC1155|IERC1155Mintable|IERC1155Receiver|MixinNonFungibleToken).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "ethereum-types": "^3.5.0", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "lodash": "^4.17.11" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/erc1155/src/artifacts.ts b/contracts/erc1155/src/artifacts.ts deleted file mode 100644 index 42606f89ca..0000000000 --- a/contracts/erc1155/src/artifacts.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as DummyERC1155Receiver from '../generated-artifacts/DummyERC1155Receiver.json'; -import * as ERC1155 from '../generated-artifacts/ERC1155.json'; -import * as ERC1155Mintable from '../generated-artifacts/ERC1155Mintable.json'; -import * as IERC1155Receiver from '../generated-artifacts/IERC1155Receiver.json'; -export const artifacts = { - ERC1155: ERC1155 as ContractArtifact, - ERC1155Mintable: ERC1155Mintable as ContractArtifact, - IERC1155Receiver: IERC1155Receiver as ContractArtifact, - DummyERC1155Receiver: DummyERC1155Receiver as ContractArtifact, -}; diff --git a/contracts/erc1155/src/erc1155_wrapper.ts b/contracts/erc1155/src/erc1155_wrapper.ts deleted file mode 100644 index 254e1d1314..0000000000 --- a/contracts/erc1155/src/erc1155_wrapper.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers'; - -export class Erc1155Wrapper { - private readonly _erc1155Contract: ERC1155MintableContract; - private readonly _contractOwner: string; - - constructor(contractInstance: ERC1155MintableContract, contractOwner: string) { - this._erc1155Contract = contractInstance; - this._contractOwner = contractOwner; - } - public getContract(): ERC1155MintableContract { - return this._erc1155Contract; - } - public async getBalancesAsync(owners: string[], tokens: BigNumber[]): Promise { - const balances = await this._erc1155Contract.balanceOfBatch(owners, tokens).callAsync(); - return balances; - } - public async safeTransferFromAsync( - from: string, - to: string, - token: BigNumber, - value: BigNumber, - callbackData?: string, - delegatedSpender?: string, - ): Promise { - const spender = delegatedSpender === undefined ? from : delegatedSpender; - const callbackDataHex = callbackData === undefined ? '0x' : callbackData; - const tx = await this._erc1155Contract - .safeTransferFrom(from, to, token, value, callbackDataHex) - .awaitTransactionSuccessAsync({ - from: spender, - }); - return tx; - } - public async safeBatchTransferFromAsync( - from: string, - to: string, - tokens: BigNumber[], - values: BigNumber[], - callbackData?: string, - delegatedSpender?: string, - ): Promise { - const spender = delegatedSpender === undefined ? from : delegatedSpender; - const callbackDataHex = callbackData === undefined ? '0x' : callbackData; - const tx = await this._erc1155Contract - .safeBatchTransferFrom(from, to, tokens, values, callbackDataHex) - .awaitTransactionSuccessAsync({ from: spender }); - return tx; - } - public async mintFungibleTokensAsync( - beneficiaries: string[], - tokenAmounts: BigNumber | BigNumber[], - ): Promise { - const tokenUri = 'dummyFungibleToken'; - const tokenIsNonFungible = false; - const tx = await this._erc1155Contract.create(tokenUri, tokenIsNonFungible).awaitTransactionSuccessAsync({ - from: this._contractOwner, - }); - // tslint:disable-next-line no-unnecessary-type-assertion - const createFungibleTokenLog = tx.logs[0] as LogWithDecodedArgs; - const tokenId = createFungibleTokenLog.args.id; - await this.mintKnownFungibleTokensAsync(tokenId, beneficiaries, tokenAmounts); - return tokenId; - } - public async mintKnownFungibleTokensAsync( - tokenId: BigNumber, - beneficiaries: string[], - tokenAmounts: BigNumber | BigNumber[], - ): Promise { - const tokenAmountsAsArray = _.isArray(tokenAmounts) ? tokenAmounts : []; - if (!_.isArray(tokenAmounts)) { - _.each(_.range(0, beneficiaries.length), () => { - tokenAmountsAsArray.push(tokenAmounts); - }); - } - await this._erc1155Contract - .mintFungible(tokenId, beneficiaries, tokenAmountsAsArray) - .awaitTransactionSuccessAsync({ from: this._contractOwner }); - } - public async mintNonFungibleTokensAsync(beneficiaries: string[]): Promise<[BigNumber, BigNumber[]]> { - const tokenUri = 'dummyNonFungibleToken'; - const tokenIsNonFungible = true; - const tx = await this._erc1155Contract.create(tokenUri, tokenIsNonFungible).awaitTransactionSuccessAsync({ - from: this._contractOwner, - }); - // tslint:disable-next-line no-unnecessary-type-assertion - const createFungibleTokenLog = tx.logs[0] as LogWithDecodedArgs; - const token = createFungibleTokenLog.args.id; - await this._erc1155Contract.mintNonFungible(token, beneficiaries).awaitTransactionSuccessAsync({ - from: this._contractOwner, - }); - const encodedNftIds: BigNumber[] = []; - const nftIdBegin = 1; - const nftIdEnd = beneficiaries.length + 1; - const nftIdRange = _.range(nftIdBegin, nftIdEnd); - _.each(nftIdRange, (nftId: number) => { - const encodedNftId = token.plus(nftId); - encodedNftIds.push(encodedNftId); - }); - return [token, encodedNftIds]; - } - public async setApprovalForAllAsync( - owner: string, - beneficiary: string, - isApproved: boolean, - ): Promise { - const tx = await this._erc1155Contract.setApprovalForAll(beneficiary, isApproved).awaitTransactionSuccessAsync({ - from: owner, - }); - return tx; - } - public async isApprovedForAllAsync(owner: string, beneficiary: string): Promise { - const isApprovedForAll = await this._erc1155Contract.isApprovedForAll(owner, beneficiary).callAsync(); - return isApprovedForAll; - } - public async assertBalancesAsync( - owners: string[], - tokens: BigNumber[], - expectedBalances: BigNumber[], - ): Promise { - const ownersExtended: string[] = []; - let tokensExtended: BigNumber[] = []; - _.each(owners, (owner: string) => { - tokensExtended = tokensExtended.concat(tokens); - _.each(_.range(0, tokens.length), () => { - ownersExtended.push(owner); - }); - }); - const balances = await this.getBalancesAsync(ownersExtended, tokensExtended); - _.each(balances, (balance: BigNumber, i: number) => { - if (!balance.isEqualTo(expectedBalances[i])) { - throw new Error(`${ownersExtended[i]}${tokensExtended[i]} balance not equal ${expectedBalances[i]}`); - } - }); - } - public async isNonFungibleItemAsync(tokenId: BigNumber): Promise { - return this._erc1155Contract.isNonFungibleItem(tokenId).callAsync(); - } - public async isFungibleItemAsync(tokenId: BigNumber): Promise { - return !(await this.isNonFungibleItemAsync(tokenId)); - } - public async getOwnerOfAsync(tokenId: BigNumber): Promise { - return this._erc1155Contract.ownerOf(tokenId).callAsync(); - } - /** - * @dev Get the balance of an ERC1155 token for a given owner and token ID. - */ - public async getBalanceAsync(ownerAddress: string, tokenId: BigNumber): Promise { - return this._erc1155Contract.balanceOf(ownerAddress, tokenId).callAsync(); - } -} diff --git a/contracts/erc1155/src/index.ts b/contracts/erc1155/src/index.ts deleted file mode 100644 index af331d61b6..0000000000 --- a/contracts/erc1155/src/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -export { - DummyERC1155ReceiverContract, - ERC1155Contract, - ERC1155MintableContract, - IERC1155ReceiverContract, - DummyERC1155ReceiverBatchTokenReceivedEventArgs, - ERC1155TransferSingleEventArgs, - ERC1155TransferBatchEventArgs, - ERC1155Events, -} from './wrappers'; -export { artifacts } from './artifacts'; -export { Erc1155Wrapper } from './erc1155_wrapper'; -export { - TransactionReceiptWithDecodedLogs, - TransactionReceiptStatus, - ContractChains, - CompilerOpts, - StandardContractOutput, - ContractArtifact, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/erc1155/src/wrappers.ts b/contracts/erc1155/src/wrappers.ts deleted file mode 100644 index f48fde01c5..0000000000 --- a/contracts/erc1155/src/wrappers.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/dummy_erc1155_receiver'; -export * from '../generated-wrappers/erc1155'; -export * from '../generated-wrappers/erc1155_mintable'; -export * from '../generated-wrappers/i_erc1155_receiver'; diff --git a/contracts/erc1155/test/artifacts.ts b/contracts/erc1155/test/artifacts.ts deleted file mode 100644 index dd3e54205d..0000000000 --- a/contracts/erc1155/test/artifacts.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as DummyERC1155Receiver from '../test/generated-artifacts/DummyERC1155Receiver.json'; -import * as ERC1155 from '../test/generated-artifacts/ERC1155.json'; -import * as ERC1155Mintable from '../test/generated-artifacts/ERC1155Mintable.json'; -import * as IERC1155 from '../test/generated-artifacts/IERC1155.json'; -import * as IERC1155Mintable from '../test/generated-artifacts/IERC1155Mintable.json'; -import * as IERC1155Receiver from '../test/generated-artifacts/IERC1155Receiver.json'; -import * as MixinNonFungibleToken from '../test/generated-artifacts/MixinNonFungibleToken.json'; -export const artifacts = { - ERC1155: ERC1155 as ContractArtifact, - ERC1155Mintable: ERC1155Mintable as ContractArtifact, - MixinNonFungibleToken: MixinNonFungibleToken as ContractArtifact, - IERC1155: IERC1155 as ContractArtifact, - IERC1155Mintable: IERC1155Mintable as ContractArtifact, - IERC1155Receiver: IERC1155Receiver as ContractArtifact, - DummyERC1155Receiver: DummyERC1155Receiver as ContractArtifact, -}; diff --git a/contracts/erc1155/test/erc1155_token.ts b/contracts/erc1155/test/erc1155_token.ts deleted file mode 100644 index 2236ea8011..0000000000 --- a/contracts/erc1155/test/erc1155_token.ts +++ /dev/null @@ -1,459 +0,0 @@ -import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -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 { Erc1155Wrapper } from '../src/erc1155_wrapper'; -import { ERC1155MintableContract } from '../src/wrappers'; - -import { artifacts } from './artifacts'; -import { DummyERC1155ReceiverBatchTokenReceivedEventArgs, DummyERC1155ReceiverContract } from './wrappers'; -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -// tslint:disable:no-unnecessary-type-assertion -describe('ERC1155Token', () => { - // constant values used in transfer tests - const nftOwnerBalance = new BigNumber(1); - const nftNotOwnerBalance = new BigNumber(0); - const spenderInitialFungibleBalance = new BigNumber(500); - const receiverInitialFungibleBalance = new BigNumber(0); - const fungibleValueToTransfer = spenderInitialFungibleBalance.div(2); - const nonFungibleValueToTransfer = nftOwnerBalance; - const receiverCallbackData = '0x01020304'; - // tokens & addresses - let owner: string; - let spender: string; - let delegatedSpender: string; - let receiver: string; - let erc1155Contract: ERC1155MintableContract; - let erc1155Receiver: DummyERC1155ReceiverContract; - let nonFungibleToken: BigNumber; - let erc1155Wrapper: Erc1155Wrapper; - let fungibleToken: BigNumber; - // tests - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - // deploy erc1155 contract & receiver - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - [owner, spender, delegatedSpender] = accounts; - erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( - artifacts.ERC1155Mintable, - provider, - txDefaults, - artifacts, - ); - erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( - artifacts.DummyERC1155Receiver, - provider, - txDefaults, - artifacts, - ); - receiver = erc1155Receiver.address; - // create wrapper & mint erc1155 tokens - erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, owner); - fungibleToken = await erc1155Wrapper.mintFungibleTokensAsync([spender], spenderInitialFungibleBalance); - let nonFungibleTokens: BigNumber[]; - [, nonFungibleTokens] = await erc1155Wrapper.mintNonFungibleTokensAsync([spender]); - nonFungibleToken = nonFungibleTokens[0]; - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('safeTransferFrom', () => { - it('should transfer fungible token if called by token owner', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = fungibleToken; - const valueToTransfer = fungibleValueToTransfer; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeTransferFromAsync( - spender, - receiver, - fungibleToken, - valueToTransfer, - receiverCallbackData, - ); - // check balances after transfer - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(valueToTransfer), - receiverInitialFungibleBalance.plus(valueToTransfer), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); - }); - it('should transfer non-fungible token if called by token owner', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = nonFungibleToken; - const valueToTransfer = nonFungibleValueToTransfer; - // check balances before transfer - const expectedInitialBalances = [nftOwnerBalance, nftNotOwnerBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeTransferFromAsync( - spender, - receiver, - tokenToTransfer, - valueToTransfer, - receiverCallbackData, - ); - // check balances after transfer - const expectedFinalBalances = [nftNotOwnerBalance, nftOwnerBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); - }); - it('should trigger callback if transferring to a contract', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = fungibleToken; - const valueToTransfer = fungibleValueToTransfer; - // check balances before transfer - const expectedInitialBalances = [ - spenderInitialFungibleBalance, - receiverInitialFungibleBalance, - nftOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - const tx = await erc1155Wrapper.safeTransferFromAsync( - spender, - receiver, - tokenToTransfer, - valueToTransfer, - receiverCallbackData, - ); - expect(tx.logs.length).to.be.equal(2); - const receiverLog = tx.logs[1] as LogWithDecodedArgs; - // check callback logs - const expectedCallbackLog = { - operator: spender, - from: spender, - tokenId: tokenToTransfer, - tokenValue: valueToTransfer, - data: receiverCallbackData, - }; - expect(receiverLog.args.operator).to.be.equal(expectedCallbackLog.operator); - expect(receiverLog.args.from).to.be.equal(expectedCallbackLog.from); - expect(receiverLog.args.tokenId).to.be.bignumber.equal(expectedCallbackLog.tokenId); - expect(receiverLog.args.tokenValue).to.be.bignumber.equal(expectedCallbackLog.tokenValue); - expect(receiverLog.args.data).to.be.deep.equal(expectedCallbackLog.data); - // check balances after transfer - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(valueToTransfer), - receiverInitialFungibleBalance.plus(valueToTransfer), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); - }); - it('should revert if transfer reverts', async () => { - // setup test parameters - const tokenToTransfer = fungibleToken; - const valueToTransfer = spenderInitialFungibleBalance.plus(1); - // create the expected error (a uint256 underflow) - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - spenderInitialFungibleBalance, - valueToTransfer, - ); - // execute transfer - const tx = erc1155Contract - .safeTransferFrom(spender, receiver, tokenToTransfer, valueToTransfer, receiverCallbackData) - .sendTransactionAsync({ from: spender }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if callback reverts', async () => { - // setup test parameters - const tokenToTransfer = fungibleToken; - const valueToTransfer = fungibleValueToTransfer; - // set receiver to reject balances - const shouldRejectTransfer = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).sendTransactionAsync(), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // execute transfer - return expect( - erc1155Contract - .safeTransferFrom(spender, receiver, tokenToTransfer, valueToTransfer, receiverCallbackData) - .awaitTransactionSuccessAsync({ from: spender }), - ).to.revertWith(RevertReason.TransferRejected); - }); - }); - describe('batchSafeTransferFrom', () => { - it('should transfer fungible tokens if called by token owner', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = [fungibleToken]; - const valuesToTransfer = [fungibleValueToTransfer]; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeBatchTransferFromAsync( - spender, - receiver, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // check balances after transfer - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(valuesToTransfer[0]), - receiverInitialFungibleBalance.plus(valuesToTransfer[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should transfer non-fungible token if called by token owner', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = [nonFungibleToken]; - const valuesToTransfer = [nonFungibleValueToTransfer]; - // check balances before transfer - const expectedInitialBalances = [nftOwnerBalance, nftNotOwnerBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeBatchTransferFromAsync( - spender, - receiver, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // check balances after transfer - const expectedFinalBalances = [nftNotOwnerBalance, nftOwnerBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should transfer mix of fungible / non-fungible tokens if called by token owner', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = [fungibleToken, nonFungibleToken]; - const valuesToTransfer = [fungibleValueToTransfer, nonFungibleValueToTransfer]; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - nftOwnerBalance, - // receiver - receiverInitialFungibleBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeBatchTransferFromAsync( - spender, - receiver, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - // check balances after transfer - const expectedFinalBalances = [ - // spender - spenderInitialFungibleBalance.minus(valuesToTransfer[0]), - nftNotOwnerBalance, - // receiver - receiverInitialFungibleBalance.plus(valuesToTransfer[0]), - nftOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should trigger callback if transferring to a contract', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = [fungibleToken, nonFungibleToken]; - const valuesToTransfer = [fungibleValueToTransfer, nonFungibleValueToTransfer]; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - nftOwnerBalance, - // receiver - receiverInitialFungibleBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const tx = await erc1155Wrapper.safeBatchTransferFromAsync( - spender, - receiver, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - expect(tx.logs.length).to.be.equal(2); - const receiverLog = tx.logs[1] as LogWithDecodedArgs; - // check callback logs - const expectedCallbackLog = { - operator: spender, - from: spender, - tokenIds: tokensToTransfer, - tokenValues: valuesToTransfer, - data: receiverCallbackData, - }; - expect(receiverLog.args.operator).to.be.equal(expectedCallbackLog.operator); - expect(receiverLog.args.from).to.be.equal(expectedCallbackLog.from); - expect(receiverLog.args.tokenIds.length).to.be.equal(2); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(expectedCallbackLog.tokenIds[0]); - expect(receiverLog.args.tokenIds[1]).to.be.bignumber.equal(expectedCallbackLog.tokenIds[1]); - expect(receiverLog.args.tokenValues.length).to.be.equal(2); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(expectedCallbackLog.tokenValues[0]); - expect(receiverLog.args.tokenValues[1]).to.be.bignumber.equal(expectedCallbackLog.tokenValues[1]); - expect(receiverLog.args.data).to.be.deep.equal(expectedCallbackLog.data); - // check balances after transfer - const expectedFinalBalances = [ - // spender - spenderInitialFungibleBalance.minus(valuesToTransfer[0]), - nftNotOwnerBalance, - // receiver - receiverInitialFungibleBalance.plus(valuesToTransfer[0]), - nftOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should revert if transfer reverts', async () => { - // setup test parameters - const tokensToTransfer = [fungibleToken]; - const valuesToTransfer = [spenderInitialFungibleBalance.plus(1)]; - // create the expected error (a uint256 underflow) - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - spenderInitialFungibleBalance, - valuesToTransfer[0], - ); - // execute transfer - const tx = erc1155Contract - .safeBatchTransferFrom(spender, receiver, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .sendTransactionAsync({ from: spender }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if callback reverts', async () => { - // setup test parameters - const tokensToTransfer = [fungibleToken]; - const valuesToTransfer = [fungibleValueToTransfer]; - // set receiver to reject balances - const shouldRejectTransfer = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).sendTransactionAsync(), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // execute transfer - return expect( - erc1155Contract - .safeBatchTransferFrom(spender, receiver, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .awaitTransactionSuccessAsync({ from: spender }), - ).to.revertWith(RevertReason.TransferRejected); - }); - }); - describe('setApprovalForAll', () => { - it('should transfer token via safeTransferFrom if called by approved account', async () => { - // set approval - const isApprovedForAll = true; - await erc1155Wrapper.setApprovalForAllAsync(spender, delegatedSpender, isApprovedForAll); - const isApprovedForAllCheck = await erc1155Wrapper.isApprovedForAllAsync(spender, delegatedSpender); - expect(isApprovedForAllCheck).to.be.true(); - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = fungibleToken; - const valueToTransfer = fungibleValueToTransfer; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeTransferFromAsync( - spender, - receiver, - tokenToTransfer, - valueToTransfer, - receiverCallbackData, - delegatedSpender, - ); - // check balances after transfer - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(valueToTransfer), - receiverInitialFungibleBalance.plus(valueToTransfer), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); - }); - it('should revert if trying to transfer tokens via safeTransferFrom by an unapproved account', async () => { - // check approval not set - const isApprovedForAllCheck = await erc1155Wrapper.isApprovedForAllAsync(spender, delegatedSpender); - expect(isApprovedForAllCheck).to.be.false(); - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = fungibleToken; - const valueToTransfer = fungibleValueToTransfer; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - return expect( - erc1155Contract - .safeTransferFrom(spender, receiver, tokenToTransfer, valueToTransfer, receiverCallbackData) - .awaitTransactionSuccessAsync({ from: delegatedSpender }), - ).to.revertWith(RevertReason.InsufficientAllowance); - }); - it('should transfer token via safeBatchTransferFrom if called by approved account', async () => { - // set approval - const isApprovedForAll = true; - await erc1155Wrapper.setApprovalForAllAsync(spender, delegatedSpender, isApprovedForAll); - const isApprovedForAllCheck = await erc1155Wrapper.isApprovedForAllAsync(spender, delegatedSpender); - expect(isApprovedForAllCheck).to.be.true(); - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = [fungibleToken]; - const valuesToTransfer = [fungibleValueToTransfer]; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await erc1155Wrapper.safeBatchTransferFromAsync( - spender, - receiver, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - delegatedSpender, - ); - // check balances after transfer - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(valuesToTransfer[0]), - receiverInitialFungibleBalance.plus(valuesToTransfer[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should revert if trying to transfer tokens via safeBatchTransferFrom by an unapproved account', async () => { - // check approval not set - const isApprovedForAllCheck = await erc1155Wrapper.isApprovedForAllAsync(spender, delegatedSpender); - expect(isApprovedForAllCheck).to.be.false(); - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = [fungibleToken]; - const valuesToTransfer = [fungibleValueToTransfer]; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - return expect( - erc1155Contract - .safeBatchTransferFrom(spender, receiver, tokensToTransfer, valuesToTransfer, receiverCallbackData) - .awaitTransactionSuccessAsync({ from: delegatedSpender }), - ).to.revertWith(RevertReason.InsufficientAllowance); - }); - }); -}); -// tslint:disable:max-file-line-count -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/erc1155/test/global_hooks.ts b/contracts/erc1155/test/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/erc1155/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/erc1155/test/wrappers.ts b/contracts/erc1155/test/wrappers.ts deleted file mode 100644 index 1f7cf349d1..0000000000 --- a/contracts/erc1155/test/wrappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/dummy_erc1155_receiver'; -export * from '../test/generated-wrappers/erc1155'; -export * from '../test/generated-wrappers/erc1155_mintable'; -export * from '../test/generated-wrappers/i_erc1155_mintable'; -export * from '../test/generated-wrappers/i_erc1155_receiver'; -export * from '../test/generated-wrappers/ierc1155'; -export * from '../test/generated-wrappers/mixin_non_fungible_token'; diff --git a/contracts/erc1155/truffle-config.js b/contracts/erc1155/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/erc1155/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/erc1155/tsconfig.json b/contracts/erc1155/tsconfig.json deleted file mode 100644 index 751a5cace3..0000000000 --- a/contracts/erc1155/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/DummyERC1155Receiver.json", - "generated-artifacts/ERC1155.json", - "generated-artifacts/ERC1155Mintable.json", - "generated-artifacts/IERC1155Receiver.json", - "test/generated-artifacts/DummyERC1155Receiver.json", - "test/generated-artifacts/ERC1155.json", - "test/generated-artifacts/ERC1155Mintable.json", - "test/generated-artifacts/IERC1155.json", - "test/generated-artifacts/IERC1155Mintable.json", - "test/generated-artifacts/IERC1155Receiver.json", - "test/generated-artifacts/MixinNonFungibleToken.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/erc1155/tslint.json b/contracts/erc1155/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/erc1155/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/erc1155/typedoc-tsconfig.json b/contracts/erc1155/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/erc1155/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/erc721/.npmignore b/contracts/erc721/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/erc721/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/erc721/.solhintignore b/contracts/erc721/.solhintignore deleted file mode 100644 index 1e33ec53ba..0000000000 --- a/contracts/erc721/.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/contracts/erc721/CHANGELOG.json b/contracts/erc721/CHANGELOG.json deleted file mode 100644 index 45f97e3924..0000000000 --- a/contracts/erc721/CHANGELOG.json +++ /dev/null @@ -1,700 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "3.1.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "3.1.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "3.1.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "3.1.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "3.1.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "3.1.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "3.1.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "3.1.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "3.1.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "3.1.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "3.1.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "3.1.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "3.1.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "3.1.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "3.1.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "3.1.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "3.1.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "3.1.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "3.1.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "3.1.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "3.1.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "3.1.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "3.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "3.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "3.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "3.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "3.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "3.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "3.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "3.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "3.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "3.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "3.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "3.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "3.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Fix broken tests", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "3.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "3.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "3.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Replaced `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1575296764 - }, - { - "version": "2.2.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "2.2.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "2.2.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - } - ], - "timestamp": 1574030254 - }, - { - "version": "2.2.0-beta.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1573159180 - }, - { - "version": "2.2.0-beta.0", - "changes": [ - { - "note": "Dependencies updated" - }, - { - "note": "Replaced `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "2.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "2.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "2.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "2.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.11", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564604963 - }, - { - "timestamp": 1563957393, - "version": "2.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "2.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "2.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "2.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "2.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "2.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1557799313 - }, - { - "timestamp": 1557507213, - "version": "2.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Upgrade contracts to Solidity 0.5.5", - "pr": 1682 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "1.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "1.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549373905, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Move all ERC721 contracts out of contracts-tokens to new package", - "pr": 1539 - } - ] - } -] diff --git a/contracts/erc721/CHANGELOG.md b/contracts/erc721/CHANGELOG.md deleted file mode 100644 index 9e9546f02f..0000000000 --- a/contracts/erc721/CHANGELOG.md +++ /dev/null @@ -1,312 +0,0 @@ - - -CHANGELOG - -## v3.1.37 - _August 16, 2021_ - - * Dependencies updated - -## v3.1.36 - _August 11, 2021_ - - * Dependencies updated - -## v3.1.35 - _August 6, 2021_ - - * Dependencies updated - -## v3.1.34 - _June 22, 2021_ - - * Dependencies updated - -## v3.1.33 - _June 11, 2021_ - - * Dependencies updated - -## v3.1.32 - _June 2, 2021_ - - * Dependencies updated - -## v3.1.31 - _May 25, 2021_ - - * Dependencies updated - -## v3.1.30 - _May 21, 2021_ - - * Dependencies updated - -## v3.1.29 - _May 5, 2021_ - - * Dependencies updated - -## v3.1.28 - _April 28, 2021_ - - * Dependencies updated - -## v3.1.27 - _April 1, 2021_ - - * Dependencies updated - -## v3.1.26 - _March 17, 2021_ - - * Dependencies updated - -## v3.1.25 - _February 24, 2021_ - - * Dependencies updated - -## v3.1.24 - _February 10, 2021_ - - * Dependencies updated - -## v3.1.23 - _January 26, 2021_ - - * Dependencies updated - -## v3.1.22 - _January 13, 2021_ - - * Dependencies updated - -## v3.1.21 - _January 4, 2021_ - - * Dependencies updated - -## v3.1.20 - _December 23, 2020_ - - * Dependencies updated - -## v3.1.19 - _December 17, 2020_ - - * Dependencies updated - -## v3.1.18 - _December 9, 2020_ - - * Dependencies updated - -## v3.1.17 - _December 7, 2020_ - - * Dependencies updated - -## v3.1.16 - _December 3, 2020_ - - * Dependencies updated - -## v3.1.15 - _November 19, 2020_ - - * Dependencies updated - -## v3.1.14 - _November 13, 2020_ - - * Dependencies updated - -## v3.1.13 - _November 3, 2020_ - - * Dependencies updated - -## v3.1.12 - _November 3, 2020_ - - * Dependencies updated - -## v3.1.11 - _November 2, 2020_ - - * Dependencies updated - -## v3.1.10 - _October 28, 2020_ - - * Dependencies updated - -## v3.1.9 - _October 27, 2020_ - - * Dependencies updated - -## v3.1.8 - _October 21, 2020_ - - * Dependencies updated - -## v3.1.7 - _July 15, 2020_ - - * Dependencies updated - -## v3.1.6 - _June 24, 2020_ - - * Dependencies updated - -## v3.1.5 - _March 3, 2020_ - - * Dependencies updated - -## v3.1.4 - _February 27, 2020_ - - * Dependencies updated - -## v3.1.3 - _February 26, 2020_ - - * Dependencies updated - -## v3.1.2 - _February 25, 2020_ - - * Dependencies updated - -## v3.1.1 - _February 15, 2020_ - - * Dependencies updated - -## v3.1.0 - _February 8, 2020_ - - * Fix broken tests (#2462) - -## v3.0.6 - _February 6, 2020_ - - * Dependencies updated - -## v3.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v3.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v3.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v3.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v3.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v3.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Replaced `SafeMath` with `LibSafeMath` (#2254) - -## v2.2.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v2.2.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v2.2.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - -## v2.2.0-beta.1 - _November 7, 2019_ - - * Dependencies updated - -## v2.2.0-beta.0 - _October 3, 2019_ - - * Dependencies updated - * Replaced `SafeMath` with `LibSafeMath` (#2254) - -## v2.1.15 - _September 17, 2019_ - - * Dependencies updated - -## v2.1.14 - _September 3, 2019_ - - * Dependencies updated - -## v2.1.13 - _August 22, 2019_ - - * Dependencies updated - -## v2.1.12 - _August 8, 2019_ - - * Dependencies updated - -## v2.1.11 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v2.1.10 - _July 24, 2019_ - - * Dependencies updated - -## v2.1.9 - _July 15, 2019_ - - * Dependencies updated - -## v2.1.8 - _July 13, 2019_ - - * Dependencies updated - -## v2.1.7 - _July 13, 2019_ - - * Dependencies updated - -## v2.1.6 - _May 24, 2019_ - - * Dependencies updated - -## v2.1.5 - _May 15, 2019_ - - * Dependencies updated - -## v2.1.4 - _May 14, 2019_ - - * Dependencies updated - -## v2.1.2 - _May 10, 2019_ - - * Dependencies updated - -## v2.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v2.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v2.0.0 - _March 20, 2019_ - - * Upgrade contracts to Solidity 0.5.5 (#1682) - -## v1.0.9 - _March 1, 2019_ - - * Dependencies updated - -## v1.0.8 - _February 27, 2019_ - - * Dependencies updated - -## v1.0.7 - _February 26, 2019_ - - * Dependencies updated - -## v1.0.6 - _February 25, 2019_ - - * Dependencies updated - -## v1.0.5 - _February 9, 2019_ - - * Dependencies updated - -## v1.0.4 - _February 7, 2019_ - - * Dependencies updated - -## v1.0.3 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v1.0.2 - _February 6, 2019_ - - * Dependencies updated - -## v1.0.1 - _February 5, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Move all ERC721 contracts out of contracts-tokens to new package (#1539) diff --git a/contracts/erc721/DEPLOYS.json b/contracts/erc721/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/erc721/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/erc721/README.md b/contracts/erc721/README.md deleted file mode 100644 index 2639246180..0000000000 --- a/contracts/erc721/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## ERC721 Tokens - -This package contains implementations of various [ERC721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md) tokens. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-erc721 --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-erc721 yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-erc721 yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/erc721/compiler.json b/contracts/erc721/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/erc721/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/erc721/contracts/src/ERC721Token.sol b/contracts/erc721/contracts/src/ERC721Token.sol deleted file mode 100644 index 810016d195..0000000000 --- a/contracts/erc721/contracts/src/ERC721Token.sol +++ /dev/null @@ -1,278 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "./interfaces/IERC721Token.sol"; -import "./interfaces/IERC721Receiver.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; - - -contract ERC721Token is - IERC721Token -{ - using LibSafeMath for uint256; - - // 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 calldata _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] = balances[_from].safeSub(1); - balances[_to] = balances[_to].safeAdd(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/contracts/erc721/contracts/src/MintableERC721Token.sol b/contracts/erc721/contracts/src/MintableERC721Token.sol deleted file mode 100644 index 667b5994a9..0000000000 --- a/contracts/erc721/contracts/src/MintableERC721Token.sol +++ /dev/null @@ -1,85 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./ERC721Token.sol"; - - -contract MintableERC721Token is - ERC721Token -{ - using LibSafeMath for uint256; - - /// @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] = balances[_to].safeAdd(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] = balances[_owner].safeSub(1); - - emit Transfer( - _owner, - address(0), - _tokenId - ); - } -} diff --git a/contracts/erc721/contracts/src/interfaces/IERC721Receiver.sol b/contracts/erc721/contracts/src/interfaces/IERC721Receiver.sol deleted file mode 100644 index b22883db77..0000000000 --- a/contracts/erc721/contracts/src/interfaces/IERC721Receiver.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -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 calldata _data - ) - external - returns (bytes4); -} diff --git a/contracts/erc721/contracts/src/interfaces/IERC721Token.sol b/contracts/erc721/contracts/src/interfaces/IERC721Token.sol deleted file mode 100644 index c3830a6bdd..0000000000 --- a/contracts/erc721/contracts/src/interfaces/IERC721Token.sol +++ /dev/null @@ -1,158 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -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 calldata _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/contracts/erc721/contracts/test/DummyERC721Receiver.sol b/contracts/erc721/contracts/test/DummyERC721Receiver.sol deleted file mode 100644 index a1bdf4f344..0000000000 --- a/contracts/erc721/contracts/test/DummyERC721Receiver.sol +++ /dev/null @@ -1,67 +0,0 @@ -/* - - Copyright 2019 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.5.5; - -import "../src/interfaces/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 calldata _data - ) - external - returns (bytes4) - { - emit TokenReceived( - _operator, - _from, - _tokenId, - _data - ); - return ERC721_RECEIVED; - } -} diff --git a/contracts/erc721/contracts/test/DummyERC721Token.sol b/contracts/erc721/contracts/test/DummyERC721Token.sol deleted file mode 100644 index f1cfd8e2cc..0000000000 --- a/contracts/erc721/contracts/test/DummyERC721Token.sol +++ /dev/null @@ -1,63 +0,0 @@ -/* - - Copyright 2019 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.5.5; - -import "../src/MintableERC721Token.sol"; -import "@0x/contracts-utils/contracts/src/Ownable.sol"; - - -// solhint-disable no-empty-blocks -contract DummyERC721Token is - Ownable, - MintableERC721Token -{ - string public name; - string public symbol; - - constructor ( - string memory _name, - string memory _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/contracts/erc721/contracts/test/InvalidERC721Receiver.sol b/contracts/erc721/contracts/test/InvalidERC721Receiver.sol deleted file mode 100644 index ed5ff0650a..0000000000 --- a/contracts/erc721/contracts/test/InvalidERC721Receiver.sol +++ /dev/null @@ -1,66 +0,0 @@ -/* - - Copyright 2019 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.5.5; - -import "../src/interfaces/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 calldata _data - ) - external - returns (bytes4) - { - emit TokenReceived( - _operator, - _from, - _tokenId, - _data - ); - return INVALID_ERC721_RECEIVED; - } -} diff --git a/contracts/erc721/package.json b/contracts/erc721/package.json deleted file mode 100644 index cf022ef9a9..0000000000 --- a/contracts/erc721/package.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "name": "@0x/contracts-erc721", - "version": "3.1.37", - "engines": { - "node": ">=6.12" - }, - "description": "Token contracts used by 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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "DummyERC721Token,ERC721Token,IERC721Receiver,DummyERC721Receiver", - "abis": "./test/generated-artifacts/@(DummyERC721Receiver|DummyERC721Token|ERC721Token|IERC721Receiver|IERC721Token|InvalidERC721Receiver|MintableERC721Token).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "ethereum-types": "^3.5.0", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/erc721/src/artifacts.ts b/contracts/erc721/src/artifacts.ts deleted file mode 100644 index 6a7cf0034c..0000000000 --- a/contracts/erc721/src/artifacts.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as DummyERC721Receiver from '../generated-artifacts/DummyERC721Receiver.json'; -import * as DummyERC721Token from '../generated-artifacts/DummyERC721Token.json'; -import * as ERC721Token from '../generated-artifacts/ERC721Token.json'; -import * as IERC721Receiver from '../generated-artifacts/IERC721Receiver.json'; -export const artifacts = { - DummyERC721Token: DummyERC721Token as ContractArtifact, - ERC721Token: ERC721Token as ContractArtifact, - IERC721Receiver: IERC721Receiver as ContractArtifact, - DummyERC721Receiver: DummyERC721Receiver as ContractArtifact, -}; diff --git a/contracts/erc721/src/index.ts b/contracts/erc721/src/index.ts deleted file mode 100644 index 39b775943f..0000000000 --- a/contracts/erc721/src/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -export { - DummyERC721ReceiverContract, - DummyERC721TokenContract, - ERC721TokenContract, - ERC721TokenEvents, - ERC721TokenTransferEventArgs, - IERC721ReceiverContract, -} from './wrappers'; -export { artifacts } from './artifacts'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/erc721/src/wrappers.ts b/contracts/erc721/src/wrappers.ts deleted file mode 100644 index 0f0bd5c866..0000000000 --- a/contracts/erc721/src/wrappers.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/dummy_erc721_receiver'; -export * from '../generated-wrappers/dummy_erc721_token'; -export * from '../generated-wrappers/erc721_token'; -export * from '../generated-wrappers/i_erc721_receiver'; diff --git a/contracts/erc721/test/artifacts.ts b/contracts/erc721/test/artifacts.ts deleted file mode 100644 index 327aa03b77..0000000000 --- a/contracts/erc721/test/artifacts.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as DummyERC721Receiver from '../test/generated-artifacts/DummyERC721Receiver.json'; -import * as DummyERC721Token from '../test/generated-artifacts/DummyERC721Token.json'; -import * as ERC721Token from '../test/generated-artifacts/ERC721Token.json'; -import * as IERC721Receiver from '../test/generated-artifacts/IERC721Receiver.json'; -import * as IERC721Token from '../test/generated-artifacts/IERC721Token.json'; -import * as InvalidERC721Receiver from '../test/generated-artifacts/InvalidERC721Receiver.json'; -import * as MintableERC721Token from '../test/generated-artifacts/MintableERC721Token.json'; -export const artifacts = { - ERC721Token: ERC721Token as ContractArtifact, - MintableERC721Token: MintableERC721Token as ContractArtifact, - IERC721Receiver: IERC721Receiver as ContractArtifact, - IERC721Token: IERC721Token as ContractArtifact, - DummyERC721Receiver: DummyERC721Receiver as ContractArtifact, - DummyERC721Token: DummyERC721Token as ContractArtifact, - InvalidERC721Receiver: InvalidERC721Receiver as ContractArtifact, -}; diff --git a/contracts/erc721/test/erc721_token.ts b/contracts/erc721/test/erc721_token.ts deleted file mode 100644 index 58d3668ee9..0000000000 --- a/contracts/erc721/test/erc721_token.ts +++ /dev/null @@ -1,282 +0,0 @@ -import { - chaiSetup, - constants, - expectTransactionFailedWithoutReasonAsync, - LogDecoder, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -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, - DummyERC721TokenContract, - DummyERC721TokenTransferEventArgs, - InvalidERC721ReceiverContract, -} from './wrappers'; - -import { artifacts } from './artifacts'; - -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, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync( - artifacts.DummyERC721Receiver, - provider, - txDefaults, - artifacts, - ); - logDecoder = new LogDecoder(web3Wrapper, artifacts); - await web3Wrapper.awaitTransactionSuccessAsync( - await token.mint(owner, tokenId).sendTransactionAsync({ 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); - return expect(token.transferFrom(from, to, unownedTokenId).awaitTransactionSuccessAsync()).to.revertWith( - RevertReason.Erc721ZeroOwner, - ); - }); - it('should revert if transferring to a null address', async () => { - const from = owner; - const to = constants.NULL_ADDRESS; - return expect(token.transferFrom(from, to, tokenId).awaitTransactionSuccessAsync()).to.revertWith( - RevertReason.Erc721ZeroToAddress, - ); - }); - it('should revert if the from address does not own the token', async () => { - const from = spender; - const to = erc721Receiver.address; - return expect(token.transferFrom(from, to, tokenId).awaitTransactionSuccessAsync()).to.revertWith( - 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; - return expect( - token.transferFrom(from, to, tokenId).awaitTransactionSuccessAsync({ from: spender }), - ).to.revertWith(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(from, to, tokenId).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - 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(spender, isApproved).sendTransactionAsync(), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - - const from = owner; - const to = erc721Receiver.address; - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await token.transferFrom(from, to, tokenId).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - 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(spender, tokenId).sendTransactionAsync(), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - - const from = owner; - const to = erc721Receiver.address; - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await token.transferFrom(from, to, tokenId).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - - const approvedAddress = await token.getApproved(tokenId).callAsync(); - expect(approvedAddress).to.be.equal(constants.NULL_ADDRESS); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - 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(from, to, tokenId).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - 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, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - const from = owner; - const to = contract.address; - await expectTransactionFailedWithoutReasonAsync( - token.safeTransferFrom1(from, to, tokenId).sendTransactionAsync(), - ); - }); - it('should revert if onERC721Received does not return the correct value', async () => { - const invalidErc721Receiver = await InvalidERC721ReceiverContract.deployFrom0xArtifactAsync( - artifacts.InvalidERC721Receiver, - provider, - txDefaults, - artifacts, - ); - const from = owner; - const to = invalidErc721Receiver.address; - return expect(token.safeTransferFrom1(from, to, tokenId).sendTransactionAsync()).to.revertWith( - 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(from, to, tokenId).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - const transferLog = txReceipt.logs[0] as LogWithDecodedArgs; - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; - 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(from, to, tokenId, data).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - 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, - artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - const from = owner; - const to = contract.address; - await expectTransactionFailedWithoutReasonAsync( - token.safeTransferFrom2(from, to, tokenId, data).sendTransactionAsync(), - ); - }); - it('should revert if onERC721Received does not return the correct value', async () => { - const invalidErc721Receiver = await InvalidERC721ReceiverContract.deployFrom0xArtifactAsync( - artifacts.InvalidERC721Receiver, - provider, - txDefaults, - artifacts, - ); - const from = owner; - const to = invalidErc721Receiver.address; - return expect(token.safeTransferFrom2(from, to, tokenId, data).sendTransactionAsync()).to.revertWith( - 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(from, to, tokenId, data).sendTransactionAsync(), - ); - const newOwner = await token.ownerOf(tokenId).callAsync(); - expect(newOwner).to.be.equal(to); - const transferLog = txReceipt.logs[0] as LogWithDecodedArgs; - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; - 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/contracts/erc721/test/global_hooks.ts b/contracts/erc721/test/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/erc721/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/erc721/test/wrappers.ts b/contracts/erc721/test/wrappers.ts deleted file mode 100644 index bcf38a7079..0000000000 --- a/contracts/erc721/test/wrappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/dummy_erc721_receiver'; -export * from '../test/generated-wrappers/dummy_erc721_token'; -export * from '../test/generated-wrappers/erc721_token'; -export * from '../test/generated-wrappers/i_erc721_receiver'; -export * from '../test/generated-wrappers/i_erc721_token'; -export * from '../test/generated-wrappers/invalid_erc721_receiver'; -export * from '../test/generated-wrappers/mintable_erc721_token'; diff --git a/contracts/erc721/truffle-config.js b/contracts/erc721/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/erc721/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/erc721/tsconfig.json b/contracts/erc721/tsconfig.json deleted file mode 100644 index 279937a8d0..0000000000 --- a/contracts/erc721/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/DummyERC721Receiver.json", - "generated-artifacts/DummyERC721Token.json", - "generated-artifacts/ERC721Token.json", - "generated-artifacts/IERC721Receiver.json", - "test/generated-artifacts/DummyERC721Receiver.json", - "test/generated-artifacts/DummyERC721Token.json", - "test/generated-artifacts/ERC721Token.json", - "test/generated-artifacts/IERC721Receiver.json", - "test/generated-artifacts/IERC721Token.json", - "test/generated-artifacts/InvalidERC721Receiver.json", - "test/generated-artifacts/MintableERC721Token.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/erc721/tslint.json b/contracts/erc721/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/erc721/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/erc721/typedoc-tsconfig.json b/contracts/erc721/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/erc721/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/exchange-forwarder/.npmignore b/contracts/exchange-forwarder/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/exchange-forwarder/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/exchange-forwarder/CHANGELOG.json b/contracts/exchange-forwarder/CHANGELOG.json deleted file mode 100644 index 6ec96f57fc..0000000000 --- a/contracts/exchange-forwarder/CHANGELOG.json +++ /dev/null @@ -1,721 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "4.2.38", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "4.2.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "4.2.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "4.2.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "4.2.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "4.2.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "4.2.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "4.2.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "4.2.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "4.2.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "4.2.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "4.2.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "4.2.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "4.2.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "4.2.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "4.2.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "4.2.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "4.2.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "4.2.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "4.2.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "4.2.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "4.2.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "4.2.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "4.2.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "4.2.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "4.2.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "4.2.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "4.2.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "4.2.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "4.2.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "4.2.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "4.2.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "4.2.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "4.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "4.2.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "4.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "4.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "4.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.2.0", - "changes": [ - { - "note": "Export `EvmBytecodeOutputLinkReferences` type.", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "version": "4.1.0", - "changes": [ - { - "note": "Refactor, moved LibAssetDataTransfer and MixinWeth(Utils) to extensions", - "pr": 2455 - } - ], - "timestamp": 1580988106 - }, - { - "timestamp": 1580811564, - "version": "4.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "4.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "4.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "4.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "4.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Added buy support for ERC20Bridge", - "pr": 2356 - }, - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export ForwarderRevertErrors", - "pr": 2321 - }, - { - "note": "Use `LibERC20Token` in `MixinAssets`", - "pr": 2309 - } - ], - "timestamp": 1575296764 - }, - { - "version": "3.1.0-beta.4", - "changes": [ - { - "note": "Added buy support for ERC20Bridge", - "pr": 2356 - } - ], - "timestamp": 1575290197 - }, - { - "version": "3.1.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "3.1.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export ForwarderRevertErrors", - "pr": 2321 - } - ], - "timestamp": 1574030254 - }, - { - "version": "3.1.0-beta.1", - "changes": [ - { - "note": "Use `LibERC20Token` in `MixinAssets`", - "pr": 2309 - } - ], - "timestamp": 1573159180 - }, - { - "version": "3.1.0-beta.0", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "3.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "3.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "3.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "3.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.8", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564607468 - }, - { - "timestamp": 1563957393, - "version": "3.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "3.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "3.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "3.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557799313, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Update contracts to solidity ^0.5.5 and unpin dependencies", - "pr": 1796 - } - ], - "timestamp": 1557507213 - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Do not reexport external dependencies", - "pr": 1682 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "1.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "1.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549373905, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Move Forwarder contract out of contracts-extensions into new package", - "pr": 1539 - } - ] - } -] diff --git a/contracts/exchange-forwarder/CHANGELOG.md b/contracts/exchange-forwarder/CHANGELOG.md deleted file mode 100644 index 1644984f61..0000000000 --- a/contracts/exchange-forwarder/CHANGELOG.md +++ /dev/null @@ -1,318 +0,0 @@ - - -CHANGELOG - -## v4.2.38 - _August 16, 2021_ - - * Dependencies updated - -## v4.2.37 - _August 11, 2021_ - - * Dependencies updated - -## v4.2.36 - _August 6, 2021_ - - * Dependencies updated - -## v4.2.35 - _June 22, 2021_ - - * Dependencies updated - -## v4.2.34 - _June 11, 2021_ - - * Dependencies updated - -## v4.2.33 - _June 2, 2021_ - - * Dependencies updated - -## v4.2.32 - _May 25, 2021_ - - * Dependencies updated - -## v4.2.31 - _May 21, 2021_ - - * Dependencies updated - -## v4.2.30 - _May 5, 2021_ - - * Dependencies updated - -## v4.2.29 - _April 28, 2021_ - - * Dependencies updated - -## v4.2.28 - _April 1, 2021_ - - * Dependencies updated - -## v4.2.27 - _March 17, 2021_ - - * Dependencies updated - -## v4.2.26 - _February 24, 2021_ - - * Dependencies updated - -## v4.2.25 - _February 10, 2021_ - - * Dependencies updated - -## v4.2.24 - _January 26, 2021_ - - * Dependencies updated - -## v4.2.23 - _January 13, 2021_ - - * Dependencies updated - -## v4.2.22 - _January 4, 2021_ - - * Dependencies updated - -## v4.2.21 - _December 23, 2020_ - - * Dependencies updated - -## v4.2.20 - _December 17, 2020_ - - * Dependencies updated - -## v4.2.19 - _December 16, 2020_ - - * Dependencies updated - -## v4.2.18 - _December 9, 2020_ - - * Dependencies updated - -## v4.2.17 - _December 7, 2020_ - - * Dependencies updated - -## v4.2.16 - _December 3, 2020_ - - * Dependencies updated - -## v4.2.15 - _November 19, 2020_ - - * Dependencies updated - -## v4.2.14 - _November 13, 2020_ - - * Dependencies updated - -## v4.2.13 - _November 3, 2020_ - - * Dependencies updated - -## v4.2.12 - _November 3, 2020_ - - * Dependencies updated - -## v4.2.11 - _November 2, 2020_ - - * Dependencies updated - -## v4.2.10 - _October 28, 2020_ - - * Dependencies updated - -## v4.2.9 - _October 27, 2020_ - - * Dependencies updated - -## v4.2.8 - _October 21, 2020_ - - * Dependencies updated - -## v4.2.7 - _July 15, 2020_ - - * Dependencies updated - -## v4.2.6 - _June 24, 2020_ - - * Dependencies updated - -## v4.2.5 - _March 3, 2020_ - - * Dependencies updated - -## v4.2.4 - _February 27, 2020_ - - * Dependencies updated - -## v4.2.3 - _February 26, 2020_ - - * Dependencies updated - -## v4.2.2 - _February 25, 2020_ - - * Dependencies updated - -## v4.2.1 - _February 15, 2020_ - - * Dependencies updated - -## v4.2.0 - _February 8, 2020_ - - * Export `EvmBytecodeOutputLinkReferences` type. (#2462) - -## v4.1.0 - _February 6, 2020_ - - * Refactor, moved LibAssetDataTransfer and MixinWeth(Utils) to extensions (#2455) - -## v4.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v4.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v4.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v4.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v4.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v4.0.0 - _December 2, 2019_ - - * Added buy support for ERC20Bridge (#2356) - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export ForwarderRevertErrors (#2321) - * Use `LibERC20Token` in `MixinAssets` (#2309) - -## v3.1.0-beta.4 - _December 2, 2019_ - - * Added buy support for ERC20Bridge (#2356) - -## v3.1.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v3.1.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export ForwarderRevertErrors (#2321) - -## v3.1.0-beta.1 - _November 7, 2019_ - - * Use `LibERC20Token` in `MixinAssets` (#2309) - -## v3.1.0-beta.0 - _October 3, 2019_ - - * Dependencies updated - -## v3.0.12 - _September 17, 2019_ - - * Dependencies updated - -## v3.0.11 - _September 3, 2019_ - - * Dependencies updated - -## v3.0.10 - _August 22, 2019_ - - * Dependencies updated - -## v3.0.9 - _August 8, 2019_ - - * Dependencies updated - -## v3.0.8 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v3.0.7 - _July 24, 2019_ - - * Dependencies updated - -## v3.0.6 - _July 15, 2019_ - - * Dependencies updated - -## v3.0.5 - _July 13, 2019_ - - * Dependencies updated - -## v3.0.4 - _July 13, 2019_ - - * Dependencies updated - -## v3.0.3 - _May 24, 2019_ - - * Dependencies updated - -## v3.0.2 - _May 15, 2019_ - - * Dependencies updated - -## v3.0.1 - _May 14, 2019_ - - * Dependencies updated - -## v3.0.0 - _May 10, 2019_ - - * Update contracts to solidity ^0.5.5 and unpin dependencies (#1796) - -## v2.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v2.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v2.0.0 - _March 20, 2019_ - - * Do not reexport external dependencies (#1682) - -## v1.0.9 - _March 1, 2019_ - - * Dependencies updated - -## v1.0.8 - _February 27, 2019_ - - * Dependencies updated - -## v1.0.7 - _February 26, 2019_ - - * Dependencies updated - -## v1.0.6 - _February 25, 2019_ - - * Dependencies updated - -## v1.0.5 - _February 9, 2019_ - - * Dependencies updated - -## v1.0.4 - _February 7, 2019_ - - * Dependencies updated - -## v1.0.3 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v1.0.2 - _February 6, 2019_ - - * Dependencies updated - -## v1.0.1 - _February 5, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Move Forwarder contract out of contracts-extensions into new package (#1539) diff --git a/contracts/exchange-forwarder/DEPLOYS.json b/contracts/exchange-forwarder/DEPLOYS.json deleted file mode 100644 index 86bd264c45..0000000000 --- a/contracts/exchange-forwarder/DEPLOYS.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "name": "Forwarder", - "version": "1.1.0", - "changes": [ - { - "note": "Round up when calculating remaining amounts in marketBuy functions", - "pr": 1162, - "networks": { - "1": "0x5468a1dc173652ee28d249c271fa9933144746b1", - "3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e", - "4": "0xd2dbf3250a764eaaa94fa0c84ed87c0edc8ed04e", - "42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6" - } - } - ] - }, - { - "name": "Forwarder", - "version": "1.0.0", - "changes": [ - { - "note": "protocol v2 deploy", - "networks": { - "1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6", - "3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3", - "42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8" - } - } - ] - } -] diff --git a/contracts/exchange-forwarder/README.md b/contracts/exchange-forwarder/README.md deleted file mode 100644 index d55437f380..0000000000 --- a/contracts/exchange-forwarder/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## Exchange Forwarder - -This package contains the implementation of the [`Forwarder`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract. This contract is intended to improve the UX of interacting with the 0x [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract by abstracting user approvals, converting ETH to WETH, and paying fees. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-exchange-forwarder --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-exchange-forwarder yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-exchange-forwarder yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/exchange-forwarder/compiler.json b/contracts/exchange-forwarder/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/exchange-forwarder/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/exchange-forwarder/contracts/src/Forwarder.sol b/contracts/exchange-forwarder/contracts/src/Forwarder.sol deleted file mode 100644 index fbf3754d91..0000000000 --- a/contracts/exchange-forwarder/contracts/src/Forwarder.sol +++ /dev/null @@ -1,275 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; -import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/Ownable.sol"; -import "./libs/LibForwarderRichErrors.sol"; -import "./MixinExchangeWrapper.sol"; -import "./MixinReceiver.sol"; -import "./interfaces/IForwarder.sol"; - - -contract Forwarder is - IForwarder, - Ownable, - MixinWethUtils, - MixinExchangeWrapper, - MixinReceiver -{ - using LibBytes for bytes; - using LibAssetDataTransfer for bytes; - using LibSafeMath for uint256; - - constructor ( - address _exchange, - address _exchangeV2, - address _weth - ) - public - Ownable() - MixinWethUtils( - _exchange, - _weth - ) - MixinExchangeWrapper( - _exchange, - _exchangeV2 - ) - {} // solhint-disable-line no-empty-blocks - - /// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets - /// that were accidentally sent to this contract. - /// @param assetData Byte array encoded for the respective asset proxy. - /// @param amount Amount of the asset to withdraw. - function withdrawAsset( - bytes calldata assetData, - uint256 amount - ) - external - onlyOwner - { - assetData.transferOut(amount); - } - - /// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf. - /// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the - /// Forwarder contract to the fee recipient. - /// This method needs to be called before forwarding orders of a maker asset that hasn't - /// previously been approved. - /// @param assetData Byte array encoded for the respective asset proxy. - function approveMakerAssetProxy(bytes calldata assetData) - external - { - bytes4 proxyId = assetData.readBytes4(0); - bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector; - - // For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid. - if (proxyId == erc20ProxyId) { - address proxyAddress = EXCHANGE.getAssetProxy(erc20ProxyId); - if (proxyAddress == address(0)) { - LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError()); - } - address token = assetData.readAddress(16); - LibERC20Token.approve(token, proxyAddress, MAX_UINT256); - } - } - - /// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent - /// as possible, accounting for order and forwarder fees. - /// @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 ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return wethSpentAmount Amount of WETH spent on the given set of orders. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. - function marketSellOrdersWithEth( - LibOrder.Order[] memory orders, - bytes[] memory signatures, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) - { - // Pay ETH affiliate fees to all feeRecipient addresses - uint256 wethRemaining = _transferEthFeesAndWrapRemaining( - ethFeeAmounts, - feeRecipients - ); - // Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender, - // and pays WETH order fees. - ( - wethSpentAmount, - makerAssetAcquiredAmount - ) = _marketSellNoThrow( - orders, - wethRemaining, - signatures - ); - - // Ensure that no extra WETH owned by this contract has been spent. - if (wethSpentAmount > wethRemaining) { - LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError( - wethSpentAmount, - msg.value - )); - } - - // Calculate amount of WETH that hasn't been spent. - wethRemaining = wethRemaining.safeSub(wethSpentAmount); - - // Refund remaining ETH to msg.sender. - _unwrapAndTransferEth(wethRemaining); - } - - /// @dev Purchases as much of orders' makerAssets as possible by selling the specified amount of ETH - /// accounting for order and forwarder fees. This functions throws if ethSellAmount was not reached. - /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset. - /// @param ethSellAmount Desired amount of ETH to sell. - /// @param signatures Proofs that orders have been created by makers. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return wethSpentAmount Amount of WETH spent on the given set of orders. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. - function marketSellAmountWithEth( - LibOrder.Order[] memory orders, - uint256 ethSellAmount, - bytes[] memory signatures, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) - { - if (ethSellAmount > msg.value) { - LibRichErrors.rrevert(LibForwarderRichErrors.CompleteSellFailedError( - ethSellAmount, - msg.value - )); - } - // Pay ETH affiliate fees to all feeRecipient addresses - uint256 wethRemaining = _transferEthFeesAndWrapRemaining( - ethFeeAmounts, - feeRecipients - ); - // Need enough remaining to ensure we can sell ethSellAmount - if (wethRemaining < ethSellAmount) { - LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError( - wethRemaining, - ethSellAmount - )); - } - // Spends up to ethSellAmount to fill orders, transfers purchased assets to msg.sender, - // and pays WETH order fees. - ( - wethSpentAmount, - makerAssetAcquiredAmount - ) = _marketSellExactAmountNoThrow( - orders, - ethSellAmount, - signatures - ); - // Ensure we sold the specified amount (note: wethSpentAmount includes fees) - if (wethSpentAmount < ethSellAmount) { - LibRichErrors.rrevert(LibForwarderRichErrors.CompleteSellFailedError( - ethSellAmount, - wethSpentAmount - )); - } - - // Calculate amount of WETH that hasn't been spent. - wethRemaining = wethRemaining.safeSub(wethSpentAmount); - - // Refund remaining ETH to msg.sender. - _unwrapAndTransferEth(wethRemaining); - } - - /// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction. - /// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can - /// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees). - /// Any ETH not spent will be refunded to sender. - /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset. - /// @param makerAssetBuyAmount Desired amount of makerAsset to purchase. - /// @param signatures Proofs that orders have been created by makers. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return wethSpentAmount Amount of WETH spent on the given set of orders. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. - function marketBuyOrdersWithEth( - LibOrder.Order[] memory orders, - uint256 makerAssetBuyAmount, - bytes[] memory signatures, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) - { - // Pay ETH affiliate fees to all feeRecipient addresses - uint256 wethRemaining = _transferEthFeesAndWrapRemaining( - ethFeeAmounts, - feeRecipients - ); - - // Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender. - ( - wethSpentAmount, - makerAssetAcquiredAmount - ) = _marketBuyFillOrKill( - orders, - makerAssetBuyAmount, - signatures - ); - - // Ensure that no extra WETH owned by this contract has been spent. - if (wethSpentAmount > wethRemaining) { - LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError( - wethSpentAmount, - msg.value - )); - } - - // Calculate amount of WETH that hasn't been spent. - wethRemaining = wethRemaining.safeSub(wethSpentAmount); - - // Refund remaining ETH to msg.sender. - _unwrapAndTransferEth(wethRemaining); - } -} diff --git a/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol b/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol deleted file mode 100644 index c255f624d4..0000000000 --- a/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol +++ /dev/null @@ -1,581 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./libs/LibForwarderRichErrors.sol"; -import "./interfaces/IExchangeV2.sol"; - - -contract MixinExchangeWrapper { - - // The v2 order id is the first 4 bytes of the ExchangeV2 order schema hash. - // bytes4(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", - // ")" - // ))); - bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8; - bytes4 constant internal ERC20_BRIDGE_PROXY_ID = 0xdc1600f3; - - // solhint-disable var-name-mixedcase - IExchange internal EXCHANGE; - IExchangeV2 internal EXCHANGE_V2; - // solhint-enable var-name-mixedcase - - using LibBytes for bytes; - using LibAssetDataTransfer for bytes; - using LibSafeMath for uint256; - - constructor ( - address _exchange, - address _exchangeV2 - ) - public - { - EXCHANGE = IExchange(_exchange); - EXCHANGE_V2 = IExchangeV2(_exchangeV2); - } - - struct SellFillResults { - uint256 wethSpentAmount; - uint256 makerAssetAcquiredAmount; - uint256 protocolFeePaid; - } - - /// @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) - { - if (_isV2Order(order)) { - return _fillV2OrderNoThrow( - order, - takerAssetFillAmount, - signature - ); - } - - return _fillV3OrderNoThrow( - order, - takerAssetFillAmount, - signature - ); - } - - /// @dev Executes a single call of fillOrder according to the wethSellAmount and - /// the amount already sold. - /// @param order A single order specification. - /// @param signature Signature for the given order. - /// @param remainingTakerAssetFillAmount Remaining amount of WETH to sell. - /// @return wethSpentAmount Amount of WETH spent on the given order. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given order. - function _marketSellSingleOrder( - LibOrder.Order memory order, - bytes memory signature, - uint256 remainingTakerAssetFillAmount - ) - internal - returns (SellFillResults memory sellFillResults) - { - // If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance. - bytes4 makerAssetProxyId = order.makerAssetData.readBytes4(0); - address tokenAddress; - uint256 balanceBefore; - if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { - tokenAddress = order.makerAssetData.readAddress(16); - balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this)); - } - // No taker fee or percentage fee - if ( - order.takerFee == 0 || - _areUnderlyingAssetsEqual(order.takerFeeAssetData, order.makerAssetData) - ) { - // Attempt to sell the remaining amount of WETH - LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( - order, - remainingTakerAssetFillAmount, - signature - ); - - sellFillResults.wethSpentAmount = singleFillResults.takerAssetFilledAmount; - sellFillResults.protocolFeePaid = singleFillResults.protocolFeePaid; - - // Subtract fee from makerAssetFilledAmount for the net amount acquired. - sellFillResults.makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount - .safeSub(singleFillResults.takerFeePaid); - - // WETH fee - } else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.takerAssetData)) { - - // We will first sell WETH as the takerAsset, then use it to pay the takerFee. - // This ensures that we reserve enough to pay the taker and protocol fees. - uint256 takerAssetFillAmount = LibMath.getPartialAmountCeil( - order.takerAssetAmount, - order.takerAssetAmount.safeAdd(order.takerFee), - remainingTakerAssetFillAmount - ); - - LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( - order, - takerAssetFillAmount, - signature - ); - - // WETH is also spent on the taker fee, so we add it here. - sellFillResults.wethSpentAmount = singleFillResults.takerAssetFilledAmount - .safeAdd(singleFillResults.takerFeePaid); - sellFillResults.makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount; - sellFillResults.protocolFeePaid = singleFillResults.protocolFeePaid; - - // Unsupported fee - } else { - LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData)); - } - - // Account for the ERC20Bridge transfering more of the maker asset than expected. - if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { - uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this)); - sellFillResults.makerAssetAcquiredAmount = LibSafeMath.max256( - balanceAfter.safeSub(balanceBefore), - sellFillResults.makerAssetAcquiredAmount - ); - } - - order.makerAssetData.transferOut(sellFillResults.makerAssetAcquiredAmount); - return sellFillResults; - } - - /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker. - /// @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 totalWethSpentAmount Total amount of WETH spent on the given orders. - /// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders. - function _marketSellNoThrow( - LibOrder.Order[] memory orders, - uint256 wethSellAmount, - bytes[] memory signatures - ) - internal - returns ( - uint256 totalWethSpentAmount, - uint256 totalMakerAssetAcquiredAmount - ) - { - uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier()); - - for (uint256 i = 0; i != orders.length; i++) { - // Preemptively skip to avoid division by zero in _marketSellSingleOrder - if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) { - continue; - } - - // The remaining amount of WETH to sell - uint256 remainingTakerAssetFillAmount = wethSellAmount - .safeSub(totalWethSpentAmount); - uint256 currentProtocolFee = _isV2Order(orders[i]) ? 0 : protocolFee; - if (remainingTakerAssetFillAmount > currentProtocolFee) { - // Do not count the protocol fee as part of the fill amount. - remainingTakerAssetFillAmount = remainingTakerAssetFillAmount.safeSub(currentProtocolFee); - } else { - // Stop if we don't have at least enough ETH to pay another protocol fee. - break; - } - - SellFillResults memory sellFillResults = _marketSellSingleOrder( - orders[i], - signatures[i], - remainingTakerAssetFillAmount - ); - - totalWethSpentAmount = totalWethSpentAmount - .safeAdd(sellFillResults.wethSpentAmount) - .safeAdd(sellFillResults.protocolFeePaid); - totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount - .safeAdd(sellFillResults.makerAssetAcquiredAmount); - - // Stop execution if the entire amount of WETH has been sold - if (totalWethSpentAmount >= wethSellAmount) { - break; - } - } - } - - /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH (exclusive of protocol fee) - /// has been sold by taker. - /// @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 totalWethSpentAmount Total amount of WETH spent on the given orders. - /// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders. - function _marketSellExactAmountNoThrow( - LibOrder.Order[] memory orders, - uint256 wethSellAmount, - bytes[] memory signatures - ) - internal - returns ( - uint256 totalWethSpentAmount, - uint256 totalMakerAssetAcquiredAmount - ) - { - uint256 totalProtocolFeePaid; - - for (uint256 i = 0; i != orders.length; i++) { - // Preemptively skip to avoid division by zero in _marketSellSingleOrder - if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) { - continue; - } - - // The remaining amount of WETH to sell - uint256 remainingTakerAssetFillAmount = wethSellAmount - .safeSub(totalWethSpentAmount); - - SellFillResults memory sellFillResults = _marketSellSingleOrder( - orders[i], - signatures[i], - remainingTakerAssetFillAmount - ); - - totalWethSpentAmount = totalWethSpentAmount - .safeAdd(sellFillResults.wethSpentAmount); - totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount - .safeAdd(sellFillResults.makerAssetAcquiredAmount); - totalProtocolFeePaid = totalProtocolFeePaid.safeAdd(sellFillResults.protocolFeePaid); - - // Stop execution if the entire amount of WETH has been sold - if (totalWethSpentAmount >= wethSellAmount) { - break; - } - } - totalWethSpentAmount = totalWethSpentAmount.safeAdd(totalProtocolFeePaid); - } - - /// @dev Executes a single call of fillOrder according to the makerAssetBuyAmount and - /// the amount already bought. - /// @param order A single order specification. - /// @param signature Signature for the given order. - /// @param remainingMakerAssetFillAmount Remaining amount of maker asset to buy. - /// @return wethSpentAmount Amount of WETH spent on the given order. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given order. - function _marketBuySingleOrder( - LibOrder.Order memory order, - bytes memory signature, - uint256 remainingMakerAssetFillAmount - ) - internal - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) - { - // No taker fee or WETH fee - if ( - order.takerFee == 0 || - _areUnderlyingAssetsEqual(order.takerFeeAssetData, order.takerAssetData) - ) { - // Calculate the remaining amount of takerAsset to sell - uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil( - order.takerAssetAmount, - order.makerAssetAmount, - remainingMakerAssetFillAmount - ); - - // Attempt to sell the remaining amount of takerAsset - LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( - order, - remainingTakerAssetFillAmount, - signature - ); - - // WETH is also spent on the protocol and taker fees, so we add it here. - wethSpentAmount = singleFillResults.takerAssetFilledAmount - .safeAdd(singleFillResults.takerFeePaid) - .safeAdd(singleFillResults.protocolFeePaid); - - makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount; - - // Percentage fee - } else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.makerAssetData)) { - // Calculate the remaining amount of takerAsset to sell - uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil( - order.takerAssetAmount, - order.makerAssetAmount.safeSub(order.takerFee), - remainingMakerAssetFillAmount - ); - - // Attempt to sell the remaining amount of takerAsset - LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( - order, - remainingTakerAssetFillAmount, - signature - ); - - wethSpentAmount = singleFillResults.takerAssetFilledAmount - .safeAdd(singleFillResults.protocolFeePaid); - - // Subtract fee from makerAssetFilledAmount for the net amount acquired. - makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount - .safeSub(singleFillResults.takerFeePaid); - - // Unsupported fee - } else { - LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData)); - } - - return (wethSpentAmount, makerAssetAcquiredAmount); - } - - /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is acquired. - /// Note that the Forwarder may fill more than the makerAssetBuyAmount so that, after percentage fees - /// are paid, the net amount acquired after fees is equal to makerAssetBuyAmount (modulo rounding). - /// The asset being sold by taker must always be WETH. - /// @param orders Array of order specifications. - /// @param makerAssetBuyAmount Desired amount of makerAsset to fill. - /// @param signatures Proofs that orders have been signed by makers. - /// @return totalWethSpentAmount Total amount of WETH spent on the given orders. - /// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders. - function _marketBuyFillOrKill( - LibOrder.Order[] memory orders, - uint256 makerAssetBuyAmount, - bytes[] memory signatures - ) - internal - returns ( - uint256 totalWethSpentAmount, - uint256 totalMakerAssetAcquiredAmount - ) - { - uint256 ordersLength = orders.length; - for (uint256 i = 0; i != ordersLength; i++) { - // Preemptively skip to avoid division by zero in _marketBuySingleOrder - if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) { - continue; - } - - uint256 remainingMakerAssetFillAmount = makerAssetBuyAmount - .safeSub(totalMakerAssetAcquiredAmount); - - // If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance. - bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0); - address tokenAddress; - uint256 balanceBefore; - if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { - tokenAddress = orders[i].makerAssetData.readAddress(16); - balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this)); - } - - ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) = _marketBuySingleOrder( - orders[i], - signatures[i], - remainingMakerAssetFillAmount - ); - - // Account for the ERC20Bridge transfering more of the maker asset than expected. - if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { - uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this)); - makerAssetAcquiredAmount = LibSafeMath.max256( - balanceAfter.safeSub(balanceBefore), - makerAssetAcquiredAmount - ); - } - - orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount); - - totalWethSpentAmount = totalWethSpentAmount - .safeAdd(wethSpentAmount); - totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount - .safeAdd(makerAssetAcquiredAmount); - - // Stop execution if the entire amount of makerAsset has been bought - if (totalMakerAssetAcquiredAmount >= makerAssetBuyAmount) { - break; - } - } - - if (totalMakerAssetAcquiredAmount < makerAssetBuyAmount) { - LibRichErrors.rrevert(LibForwarderRichErrors.CompleteBuyFailedError( - makerAssetBuyAmount, - totalMakerAssetAcquiredAmount - )); - } - } - - /// @dev Fills the input ExchangeV2 order. The `makerFeeAssetData` must be - // equal to EXCHANGE_V2_ORDER_ID (0x770501f8). - /// 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 _fillV2OrderNoThrow( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - // Strip v3 specific fields from order - IExchangeV2.Order memory v2Order = IExchangeV2.Order({ - makerAddress: order.makerAddress, - takerAddress: order.takerAddress, - feeRecipientAddress: order.feeRecipientAddress, - senderAddress: order.senderAddress, - makerAssetAmount: order.makerAssetAmount, - takerAssetAmount: order.takerAssetAmount, - // NOTE: We assume fees are 0 for all v2 orders. Orders with non-zero fees will fail to be filled. - makerFee: 0, - takerFee: 0, - expirationTimeSeconds: order.expirationTimeSeconds, - salt: order.salt, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData - }); - - // ABI encode calldata for `fillOrder` - bytes memory fillOrderCalldata = abi.encodeWithSelector( - IExchangeV2(address(0)).fillOrder.selector, - v2Order, - takerAssetFillAmount, - signature - ); - - address exchange = address(EXCHANGE_V2); - (bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata); - if (didSucceed) { - assert(returnData.length == 128); - // NOTE: makerFeePaid, takerFeePaid, and protocolFeePaid will always be 0 for v2 orders - (fillResults.makerAssetFilledAmount, fillResults.takerAssetFilledAmount) = abi.decode(returnData, (uint256, uint256)); - } - - // fillResults values will be 0 by default if call was unsuccessful - return fillResults; - } - - /// @dev Fills the input ExchangeV3 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 _fillV3OrderNoThrow( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - // ABI encode calldata for `fillOrder` - bytes memory fillOrderCalldata = abi.encodeWithSelector( - IExchange(address(0)).fillOrder.selector, - order, - takerAssetFillAmount, - signature - ); - - address exchange = address(EXCHANGE); - (bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata); - if (didSucceed) { - assert(returnData.length == 160); - fillResults = abi.decode(returnData, (LibFillResults.FillResults)); - } - - // fillResults values will be 0 by default if call was unsuccessful - return fillResults; - } - - /// @dev Checks whether one asset is effectively equal to another asset. - /// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if - /// one is the ERC20Bridge equivalent of the other. - /// @param assetData1 Byte array encoded for the takerFee asset proxy. - /// @param assetData2 Byte array encoded for the maker asset proxy. - /// @return areEqual Whether or not the underlying assets are equal. - function _areUnderlyingAssetsEqual( - bytes memory assetData1, - bytes memory assetData2 - ) - internal - pure - returns (bool) - { - bytes4 assetProxyId1 = assetData1.readBytes4(0); - bytes4 assetProxyId2 = assetData2.readBytes4(0); - bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector; - bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector; - - if ( - (assetProxyId1 == erc20ProxyId || assetProxyId1 == erc20BridgeProxyId) && - (assetProxyId2 == erc20ProxyId || assetProxyId2 == erc20BridgeProxyId) - ) { - // Compare the underlying token addresses. - address token1 = assetData1.readAddress(16); - address token2 = assetData2.readAddress(16); - return (token1 == token2); - } else { - return assetData1.equals(assetData2); - } - } - - /// @dev Checks whether an order is a v2 order. - /// @param order Order struct containing order specifications. - /// @return True if the order's `makerFeeAssetData` is set to the v2 order id. - function _isV2Order(LibOrder.Order memory order) - internal - pure - returns (bool) - { - return order.makerFeeAssetData.length > 3 && order.makerFeeAssetData.readBytes4(0) == EXCHANGE_V2_ORDER_ID; - } -} diff --git a/contracts/exchange-forwarder/contracts/src/MixinReceiver.sol b/contracts/exchange-forwarder/contracts/src/MixinReceiver.sol deleted file mode 100644 index 3ca5c1c407..0000000000 --- a/contracts/exchange-forwarder/contracts/src/MixinReceiver.sol +++ /dev/null @@ -1,76 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract MixinReceiver { - - bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61; - bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81; - - /// @notice Handle the receipt of a single ERC1155 token type - /// @dev The smart contract calls this function on the recipient - /// after a `safeTransferFrom`. 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 id An array containing the ids of the token being transferred - /// @param value An array containing the amount of tokens being transferred - /// @param data Additional data with no specified format - /// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` - function onERC1155Received( - address operator, - address from, - uint256 id, - uint256 value, - bytes calldata data - ) - external - returns (bytes4) - { - return ERC1155_RECEIVED; - } - - /// @notice Handle the receipt of multiple ERC1155 token types - /// @dev The smart contract calls this function on the recipient - /// after a `safeTransferFrom`. 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 ids An array containing ids of each token being transferred - /// @param values An array containing amounts of each token being transferred - /// @param data Additional data with no specified format - /// @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` - function onERC1155BatchReceived( - address operator, - address from, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) - external - returns (bytes4) - { - return ERC1155_BATCH_RECEIVED; - } -} \ No newline at end of file diff --git a/contracts/exchange-forwarder/contracts/src/interfaces/IExchangeV2.sol b/contracts/exchange-forwarder/contracts/src/interfaces/IExchangeV2.sol deleted file mode 100644 index 732e953f83..0000000000 --- a/contracts/exchange-forwarder/contracts/src/interfaces/IExchangeV2.sol +++ /dev/null @@ -1,75 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -contract IExchangeV2 { - - // 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 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 OrderInfo { - uint8 orderStatus; // Status that describes order's validity and fillability. - bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash). - uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled. - } - - /// @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 - returns (FillResults memory fillResults); - - /// @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 - returns (OrderInfo memory orderInfo); -} diff --git a/contracts/exchange-forwarder/contracts/src/interfaces/IForwarder.sol b/contracts/exchange-forwarder/contracts/src/interfaces/IForwarder.sol deleted file mode 100644 index b288ddeec8..0000000000 --- a/contracts/exchange-forwarder/contracts/src/interfaces/IForwarder.sol +++ /dev/null @@ -1,95 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; - - -contract IForwarder { - - /// @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 calldata assetData, - uint256 amount - ) - external; - - /// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf. - /// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the - /// Forwarder contract to the fee recipient. - /// This method needs to be called before forwarding orders of a maker asset that hasn't - /// previously been approved. - /// @param assetData Byte array encoded for the respective asset proxy. - function approveMakerAssetProxy( - bytes calldata assetData - ) - external; - - /// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent - /// as possible, accounting for order and forwarder fees. - /// @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 ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return wethSpentAmount Amount of WETH spent on the given set of orders. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. - function marketSellOrdersWithEth( - LibOrder.Order[] memory orders, - bytes[] memory signatures, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ); - - /// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction. - /// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can - /// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees). - /// Any ETH not spent will be refunded to sender. - /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset. - /// @param makerAssetBuyAmount Desired amount of makerAsset to purchase. - /// @param signatures Proofs that orders have been created by makers. - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return wethSpentAmount Amount of WETH spent on the given set of orders. - /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. - function marketBuyOrdersWithEth( - LibOrder.Order[] memory orders, - uint256 makerAssetBuyAmount, - bytes[] memory signatures, - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - public - payable - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ); -} diff --git a/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol b/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol deleted file mode 100644 index 44047e040b..0000000000 --- a/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol +++ /dev/null @@ -1,110 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -library LibForwarderRichErrors { - - // bytes4(keccak256("UnregisteredAssetProxyError()")) - bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR = - 0xf3b96b8d; - - // bytes4(keccak256("CompleteBuyFailedError(uint256,uint256)")) - bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR = - 0x91353a0c; - - // bytes4(keccak256("CompleteSellFailedError(uint256,uint256)")) - bytes4 internal constant COMPLETE_SELL_FAILED_ERROR_SELECTOR = - 0x450a0219; - - // bytes4(keccak256("UnsupportedFeeError(bytes)")) - bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR = - 0x31360af1; - - // bytes4(keccak256("OverspentWethError(uint256,uint256)")) - bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR = - 0xcdcbed5d; - - // solhint-disable func-name-mixedcase - function UnregisteredAssetProxyError() - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR); - } - - function CompleteBuyFailedError( - uint256 expectedAssetBuyAmount, - uint256 actualAssetBuyAmount - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - COMPLETE_BUY_FAILED_ERROR_SELECTOR, - expectedAssetBuyAmount, - actualAssetBuyAmount - ); - } - - function CompleteSellFailedError( - uint256 expectedAssetSellAmount, - uint256 actualAssetSellAmount - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - COMPLETE_SELL_FAILED_ERROR_SELECTOR, - expectedAssetSellAmount, - actualAssetSellAmount - ); - } - - function UnsupportedFeeError( - bytes memory takerFeeAssetData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - UNSUPPORTED_FEE_ERROR_SELECTOR, - takerFeeAssetData - ); - } - - function OverspentWethError( - uint256 wethSpent, - uint256 msgValue - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - OVERSPENT_WETH_ERROR_SELECTOR, - wethSpent, - msgValue - ); - } -} diff --git a/contracts/exchange-forwarder/contracts/test/TestForwarder.sol b/contracts/exchange-forwarder/contracts/test/TestForwarder.sol deleted file mode 100644 index 6447bce93e..0000000000 --- a/contracts/exchange-forwarder/contracts/test/TestForwarder.sol +++ /dev/null @@ -1,63 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol"; -import "../src/MixinExchangeWrapper.sol"; -import "../src/MixinReceiver.sol"; - - -contract TestForwarder is - MixinExchangeWrapper, - MixinReceiver -{ - using LibAssetDataTransfer for bytes; - - // solhint-disable no-empty-blocks - constructor () - public - MixinExchangeWrapper( - address(0), - address(0) - ) - {} - - function areUnderlyingAssetsEqual( - bytes memory assetData1, - bytes memory assetData2 - ) - public - returns (bool) - { - return _areUnderlyingAssetsEqual( - assetData1, - assetData2 - ); - } - - function transferOut( - bytes memory assetData, - uint256 amount - ) - public - { - assetData.transferOut(amount); - } -} diff --git a/contracts/exchange-forwarder/package.json b/contracts/exchange-forwarder/package.json deleted file mode 100644 index 35ff2e2763..0000000000 --- a/contracts/exchange-forwarder/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "@0x/contracts-exchange-forwarder", - "version": "4.2.38", - "engines": { - "node": ">=6.12" - }, - "description": "Smart contract extensions of 0x protocol", - "main": "lib/src/index.js", - "directories": { - "test": "test" - }, - "scripts": { - "build": "yarn pre_build && tsc -b", - "build:ts": "tsc -b", - "build:ci": "yarn build", - "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "Forwarder,IExchangeV2", - "abis": "./test/generated-artifacts/@(Forwarder|IExchangeV2|IForwarder|LibForwarderRichErrors|MixinExchangeWrapper|MixinReceiver|TestForwarder).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-dev-utils": "^1.3.36", - "@0x/contracts-erc1155": "^2.1.37", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-erc721": "^3.1.37", - "@0x/contracts-exchange": "^3.2.38", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/order-utils": "^10.4.28", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/typescript-typings": "^5.2.0", - "ethereum-types": "^3.5.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/exchange-forwarder/src/artifacts.ts b/contracts/exchange-forwarder/src/artifacts.ts deleted file mode 100644 index bdb4b1b56b..0000000000 --- a/contracts/exchange-forwarder/src/artifacts.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Forwarder from '../generated-artifacts/Forwarder.json'; -import * as IExchangeV2 from '../generated-artifacts/IExchangeV2.json'; -export const artifacts = { Forwarder: Forwarder as ContractArtifact, IExchangeV2: IExchangeV2 as ContractArtifact }; diff --git a/contracts/exchange-forwarder/src/index.ts b/contracts/exchange-forwarder/src/index.ts deleted file mode 100644 index fa0aeffec4..0000000000 --- a/contracts/exchange-forwarder/src/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -export { artifacts } from './artifacts'; -export { ForwarderContract, IExchangeV2Contract } from './wrappers'; -export { ExchangeForwarderRevertErrors } from '@0x/utils'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/exchange-forwarder/src/wrappers.ts b/contracts/exchange-forwarder/src/wrappers.ts deleted file mode 100644 index 46d3326781..0000000000 --- a/contracts/exchange-forwarder/src/wrappers.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/forwarder'; -export * from '../generated-wrappers/i_exchange_v2'; diff --git a/contracts/exchange-forwarder/test/artifacts.ts b/contracts/exchange-forwarder/test/artifacts.ts deleted file mode 100644 index c4b14eccd3..0000000000 --- a/contracts/exchange-forwarder/test/artifacts.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Forwarder from '../test/generated-artifacts/Forwarder.json'; -import * as IExchangeV2 from '../test/generated-artifacts/IExchangeV2.json'; -import * as IForwarder from '../test/generated-artifacts/IForwarder.json'; -import * as LibForwarderRichErrors from '../test/generated-artifacts/LibForwarderRichErrors.json'; -import * as MixinExchangeWrapper from '../test/generated-artifacts/MixinExchangeWrapper.json'; -import * as MixinReceiver from '../test/generated-artifacts/MixinReceiver.json'; -import * as TestForwarder from '../test/generated-artifacts/TestForwarder.json'; -export const artifacts = { - Forwarder: Forwarder as ContractArtifact, - MixinExchangeWrapper: MixinExchangeWrapper as ContractArtifact, - MixinReceiver: MixinReceiver as ContractArtifact, - IExchangeV2: IExchangeV2 as ContractArtifact, - IForwarder: IForwarder as ContractArtifact, - LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact, - TestForwarder: TestForwarder as ContractArtifact, -}; diff --git a/contracts/exchange-forwarder/test/asset_test.ts b/contracts/exchange-forwarder/test/asset_test.ts deleted file mode 100644 index 0ee8cca8c4..0000000000 --- a/contracts/exchange-forwarder/test/asset_test.ts +++ /dev/null @@ -1,374 +0,0 @@ -import { IAssetDataContract } from '@0x/contracts-asset-proxy'; -import { - artifacts as ERC1155Artifacts, - ERC1155Events, - ERC1155MintableContract, - ERC1155TransferBatchEventArgs, - Erc1155Wrapper, -} from '@0x/contracts-erc1155'; -import { - artifacts as ERC20Artifacts, - DummyERC20TokenContract, - ERC20TokenEvents, - ERC20TokenTransferEventArgs, -} from '@0x/contracts-erc20'; -import { - artifacts as ERC721Artifacts, - DummyERC721TokenContract, - ERC721TokenEvents, - ERC721TokenTransferEventArgs, -} from '@0x/contracts-erc721'; -import { - blockchainTests, - constants, - expect, - getRandomInteger, - randomAddress, - verifyEventsFromLogs, -} from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils, LibAssetDataTransferRevertErrors } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; - -import { artifacts } from './artifacts'; -import { TestForwarderContract } from './wrappers'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Supported asset type unit tests', env => { - let forwarder: TestForwarderContract; - let assetDataEncoder: IAssetDataContract; - let bridgeAddress: string; - let bridgeData: string; - let receiver: string; - - let erc20Token: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let erc1155Token: ERC1155MintableContract; - let erc1155Wrapper: Erc1155Wrapper; - let nftId: BigNumber; - - let erc20AssetData: string; - let erc721AssetData: string; - let erc20BridgeAssetData: string; - let staticCallAssetData: string; - let multiAssetData: string; - - before(async () => { - [receiver] = await env.getAccountAddressesAsync(); - assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider); - - forwarder = await TestForwarderContract.deployFrom0xArtifactAsync( - artifacts.TestForwarder, - env.provider, - env.txDefaults, - { ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts, ...ERC1155Artifacts }, - ); - - erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - ERC20Artifacts.DummyERC20Token, - env.provider, - env.txDefaults, - ERC20Artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - erc20AssetData = assetDataEncoder.ERC20Token(erc20Token.address).getABIEncodedTransactionData(); - - erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync( - ERC721Artifacts.DummyERC721Token, - env.provider, - env.txDefaults, - ERC721Artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ); - nftId = getRandomInteger(0, constants.MAX_UINT256); - erc721AssetData = assetDataEncoder.ERC721Token(erc721Token.address, nftId).getABIEncodedTransactionData(); - - erc1155Token = await ERC1155MintableContract.deployFrom0xArtifactAsync( - ERC1155Artifacts.ERC1155Mintable, - env.provider, - env.txDefaults, - ERC1155Artifacts, - ); - erc1155Wrapper = new Erc1155Wrapper(erc1155Token, receiver); - - bridgeAddress = randomAddress(); - bridgeData = hexUtils.random(); - erc20BridgeAssetData = assetDataEncoder - .ERC20Bridge(erc20Token.address, bridgeAddress, bridgeData) - .getABIEncodedTransactionData(); - - staticCallAssetData = assetDataEncoder - .StaticCall(randomAddress(), hexUtils.random(), constants.KECCAK256_NULL) - .getABIEncodedTransactionData(); - - multiAssetData = assetDataEncoder - .MultiAsset([new BigNumber(1)], [erc20AssetData]) - .getABIEncodedTransactionData(); - }); - - describe('_areUnderlyingAssetsEqual', () => { - it('returns true if assetData1 == assetData2 are ERC20', async () => { - const result = await forwarder.areUnderlyingAssetsEqual(erc20AssetData, erc20AssetData).callAsync(); - expect(result).to.be.true(); - }); - it('returns true if assetData1 == assetData2 are ERC20Bridge', async () => { - const result = await forwarder - .areUnderlyingAssetsEqual(erc20BridgeAssetData, erc20BridgeAssetData) - .callAsync(); - expect(result).to.be.true(); - }); - it('returns true if assetData2 is the ERC20Bridge equivalent of assetData1', async () => { - const result = await forwarder.areUnderlyingAssetsEqual(erc20AssetData, erc20BridgeAssetData).callAsync(); - expect(result).to.be.true(); - }); - it('returns false if assetData1 != assetData2 are ERC20', async () => { - const differentERC20AssetData = assetDataEncoder.ERC20Token(randomAddress()).getABIEncodedTransactionData(); - const result = await forwarder - .areUnderlyingAssetsEqual(erc20AssetData, differentERC20AssetData) - .callAsync(); - expect(result).to.be.false(); - }); - it('returns false if assetData1 is ERC20 and assetData2 is ERC721', async () => { - const result = await forwarder.areUnderlyingAssetsEqual(erc20AssetData, erc721AssetData).callAsync(); - expect(result).to.be.false(); - }); - it('returns false if assetData2 is ERC20Bridge, but for a different token than assetData1', async () => { - const mismatchedErc20BridgeAssetData = assetDataEncoder - .ERC20Bridge(randomAddress(), bridgeAddress, bridgeData) - .getABIEncodedTransactionData(); - const result = await forwarder - .areUnderlyingAssetsEqual(erc20AssetData, mismatchedErc20BridgeAssetData) - .callAsync(); - expect(result).to.be.false(); - }); - it('returns true if assetData1 == assetData2 are ERC721', async () => { - const result = await forwarder.areUnderlyingAssetsEqual(erc721AssetData, erc721AssetData).callAsync(); - expect(result).to.be.true(); - }); - it('returns false if assetData1 != assetData2 are ERC721', async () => { - const differentErc721AssetData = assetDataEncoder - .ERC721Token(randomAddress(), getRandomInteger(0, constants.MAX_UINT256)) - .getABIEncodedTransactionData(); - const result = await forwarder - .areUnderlyingAssetsEqual(erc721AssetData, differentErc721AssetData) - .callAsync(); - expect(result).to.be.false(); - }); - it('returns true if assetData1 == assetData2 are StaticCall', async () => { - const result = await forwarder - .areUnderlyingAssetsEqual(staticCallAssetData, staticCallAssetData) - .callAsync(); - expect(result).to.be.true(); - }); - it('returns false if assetData1 != assetData2 are StaticCall', async () => { - const differentStaticCallAssetData = assetDataEncoder - .StaticCall(randomAddress(), hexUtils.random(), constants.KECCAK256_NULL) - .getABIEncodedTransactionData(); - const result = await forwarder - .areUnderlyingAssetsEqual(staticCallAssetData, differentStaticCallAssetData) - .callAsync(); - expect(result).to.be.false(); - }); - it('returns false if assetData1 is ERC20 and assetData2 is MultiAsset', async () => { - const result = await forwarder.areUnderlyingAssetsEqual(erc20AssetData, multiAssetData).callAsync(); - expect(result).to.be.false(); - }); - it('returns true if assetData1 == assetData2 are MultiAsset (single nested asset)', async () => { - const result = await forwarder.areUnderlyingAssetsEqual(multiAssetData, multiAssetData).callAsync(); - expect(result).to.be.true(); - }); - it('returns true if assetData1 == assetData2 are MultiAsset (multiple nested assets)', async () => { - const assetData = assetDataEncoder - .MultiAsset( - [getRandomInteger(0, constants.MAX_UINT256), new BigNumber(1)], - [erc20AssetData, erc721AssetData], - ) - .getABIEncodedTransactionData(); - const result = await forwarder.areUnderlyingAssetsEqual(assetData, assetData).callAsync(); - expect(result).to.be.true(); - }); - it('returns false if assetData1 != assetData2 are MultiAsset', async () => { - const differentMultiAssetData = assetDataEncoder - .MultiAsset([getRandomInteger(0, constants.MAX_UINT256)], [erc721AssetData]) - .getABIEncodedTransactionData(); - const result = await forwarder - .areUnderlyingAssetsEqual(multiAssetData, differentMultiAssetData) - .callAsync(); - expect(result).to.be.false(); - }); - }); - - describe('transferOut', () => { - const TRANSFER_AMOUNT = new BigNumber(1); - before(async () => { - await erc20Token - .setBalance(forwarder.address, constants.INITIAL_ERC20_BALANCE) - .awaitTransactionSuccessAsync(); - await erc721Token.mint(forwarder.address, nftId).awaitTransactionSuccessAsync(); - }); - - it('transfers an ERC20 token given ERC20 assetData', async () => { - const txReceipt = await forwarder - .transferOut(erc20AssetData, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - verifyEventsFromLogs( - txReceipt.logs, - [{ _from: forwarder.address, _to: receiver, _value: TRANSFER_AMOUNT }], - ERC20TokenEvents.Transfer, - ); - }); - it('transfers an ERC721 token given ERC721 assetData and amount == 1', async () => { - const txReceipt = await forwarder - .transferOut(erc721AssetData, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - verifyEventsFromLogs( - txReceipt.logs, - [{ _from: forwarder.address, _to: receiver, _tokenId: nftId }], - ERC721TokenEvents.Transfer, - ); - }); - it('reverts if attempting to transfer an ERC721 token with amount != 1', async () => { - const invalidAmount = new BigNumber(2); - const tx = forwarder - .transferOut(erc721AssetData, invalidAmount) - .awaitTransactionSuccessAsync({ from: receiver }); - const expectedError = new LibAssetDataTransferRevertErrors.Erc721AmountMustEqualOneError(invalidAmount); - return expect(tx).to.revertWith(expectedError); - }); - it('transfers a single ERC1155 token', async () => { - const values = [new BigNumber(1)]; - const amount = new BigNumber(1); - const ids = [await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], values)]; - const assetData = assetDataEncoder - .ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES) - .getABIEncodedTransactionData(); - const txReceipt = await forwarder - .transferOut(assetData, amount) - .awaitTransactionSuccessAsync({ from: receiver }); - verifyEventsFromLogs( - txReceipt.logs, - [{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values }], - ERC1155Events.TransferBatch, - ); - }); - it('transfers multiple ids of an ERC1155 token', async () => { - const amount = new BigNumber(1); - const ids = [ - await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]), - await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]), - ]; - const values = [amount, amount]; - const assetData = assetDataEncoder - .ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES) - .getABIEncodedTransactionData(); - const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync(); - verifyEventsFromLogs( - txReceipt.logs, - [{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values }], - ERC1155Events.TransferBatch, - ); - }); - it('scales up values when transfering ERC1155 tokens', async () => { - const amount = new BigNumber(2); - const values = [new BigNumber(1), new BigNumber(2)]; - const scaledValues = values.map(value => value.times(amount)); - const ids = [ - await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [scaledValues[0]]), - await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [scaledValues[1]]), - ]; - const assetData = assetDataEncoder - .ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES) - .getABIEncodedTransactionData(); - const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync(); - verifyEventsFromLogs( - txReceipt.logs, - [{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values: scaledValues }], - ERC1155Events.TransferBatch, - ); - }); - it('transfers a single ERC20 token wrapped as MultiAsset', async () => { - const nestedAmount = new BigNumber(1337); - const erc20MultiAssetData = assetDataEncoder - .MultiAsset([nestedAmount], [erc20AssetData]) - .getABIEncodedTransactionData(); - const multiAssetAmount = new BigNumber(2); - const txReceipt = await forwarder - .transferOut(erc20MultiAssetData, multiAssetAmount) - .awaitTransactionSuccessAsync({ from: receiver }); - verifyEventsFromLogs( - txReceipt.logs, - [{ _from: forwarder.address, _to: receiver, _value: multiAssetAmount.times(nestedAmount) }], - ERC20TokenEvents.Transfer, - ); - }); - it('transfers ERC20, ERC721, and StaticCall assets wrapped as MultiAsset', async () => { - const nestedAmounts = [new BigNumber(1337), TRANSFER_AMOUNT, TRANSFER_AMOUNT]; - const assortedMultiAssetData = assetDataEncoder - .MultiAsset(nestedAmounts, [erc20AssetData, erc721AssetData, staticCallAssetData]) - .getABIEncodedTransactionData(); - const txReceipt = await forwarder - .transferOut(assortedMultiAssetData, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - expect(txReceipt.logs.length).to.equal(2); - // tslint:disable:no-unnecessary-type-assertion - const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs).args; - const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs).args; - // tslint:enable:no-unnecessary-type-assertion - expect(erc20TransferEvent).to.deep.equal({ - _from: forwarder.address, - _to: receiver, - _value: nestedAmounts[0], - }); - expect(erc721TransferEvent).to.deep.equal({ _from: forwarder.address, _to: receiver, _tokenId: nftId }); - }); - it('performs nested MultiAsset transfers', async () => { - const nestedAmounts = [TRANSFER_AMOUNT, TRANSFER_AMOUNT, TRANSFER_AMOUNT]; - const assortedMultiAssetData = assetDataEncoder - .MultiAsset(nestedAmounts, [multiAssetData, erc721AssetData, staticCallAssetData]) - .getABIEncodedTransactionData(); - const txReceipt = await forwarder - .transferOut(assortedMultiAssetData, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - expect(txReceipt.logs.length).to.equal(2); - // tslint:disable:no-unnecessary-type-assertion - const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs).args; - const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs).args; - // tslint:enable:no-unnecessary-type-assertion - expect(erc20TransferEvent).to.deep.equal({ - _from: forwarder.address, - _to: receiver, - _value: TRANSFER_AMOUNT, - }); - expect(erc721TransferEvent).to.deep.equal({ _from: forwarder.address, _to: receiver, _tokenId: nftId }); - }); - it('transfers an ERC20 token given ERC20Bridge assetData', async () => { - const txReceipt = await forwarder - .transferOut(erc20BridgeAssetData, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - verifyEventsFromLogs( - txReceipt.logs, - [{ _from: forwarder.address, _to: receiver, _value: TRANSFER_AMOUNT }], - ERC20TokenEvents.Transfer, - ); - }); - it('noops (emits no events) for StaticCall assetData', async () => { - const txReceipt = await forwarder - .transferOut(staticCallAssetData, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - expect(txReceipt.logs.length).to.equal(0); - }); - it('reverts if assetData is unsupported', async () => { - const randomBytes = hexUtils.random(); - const tx = forwarder - .transferOut(randomBytes, TRANSFER_AMOUNT) - .awaitTransactionSuccessAsync({ from: receiver }); - const expectedError = new LibAssetDataTransferRevertErrors.UnsupportedAssetProxyError( - hexUtils.slice(randomBytes, 0, 4), - ); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); diff --git a/contracts/exchange-forwarder/test/wrappers.ts b/contracts/exchange-forwarder/test/wrappers.ts deleted file mode 100644 index 4d0e984bd3..0000000000 --- a/contracts/exchange-forwarder/test/wrappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/forwarder'; -export * from '../test/generated-wrappers/i_exchange_v2'; -export * from '../test/generated-wrappers/i_forwarder'; -export * from '../test/generated-wrappers/lib_forwarder_rich_errors'; -export * from '../test/generated-wrappers/mixin_exchange_wrapper'; -export * from '../test/generated-wrappers/mixin_receiver'; -export * from '../test/generated-wrappers/test_forwarder'; diff --git a/contracts/exchange-forwarder/truffle-config.js b/contracts/exchange-forwarder/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/exchange-forwarder/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/exchange-forwarder/tsconfig.json b/contracts/exchange-forwarder/tsconfig.json deleted file mode 100644 index 8c17b92d88..0000000000 --- a/contracts/exchange-forwarder/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/Forwarder.json", - "generated-artifacts/IExchangeV2.json", - "test/generated-artifacts/Forwarder.json", - "test/generated-artifacts/IExchangeV2.json", - "test/generated-artifacts/IForwarder.json", - "test/generated-artifacts/LibForwarderRichErrors.json", - "test/generated-artifacts/MixinExchangeWrapper.json", - "test/generated-artifacts/MixinReceiver.json", - "test/generated-artifacts/TestForwarder.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/exchange-forwarder/tslint.json b/contracts/exchange-forwarder/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/exchange-forwarder/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/exchange-forwarder/typedoc-tsconfig.json b/contracts/exchange-forwarder/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/exchange-forwarder/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/exchange-libs/.npmignore b/contracts/exchange-libs/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/exchange-libs/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/exchange-libs/CHANGELOG.json b/contracts/exchange-libs/CHANGELOG.json deleted file mode 100644 index 52cb9b223e..0000000000 --- a/contracts/exchange-libs/CHANGELOG.json +++ /dev/null @@ -1,925 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "4.3.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "4.3.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "4.3.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "4.3.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "4.3.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "4.3.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "4.3.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "4.3.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "4.3.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "4.3.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "4.3.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "4.3.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "4.3.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "4.3.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "4.3.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "4.3.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "4.3.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "4.3.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "4.3.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "4.3.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "4.3.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "4.3.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "4.3.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "4.3.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "4.3.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "4.3.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "4.3.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "4.3.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "4.3.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "4.3.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "4.3.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "4.3.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "4.3.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "4.3.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "4.3.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "4.3.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "4.3.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.3.0", - "changes": [ - { - "note": "Export `EvmBytecodeOutputLinkReferences` type.", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "version": "4.2.0", - "changes": [ - { - "note": "Moved LibAssetDataTransfer here from forwarder", - "pr": 2455 - } - ], - "timestamp": 1580988106 - }, - { - "timestamp": 1580811564, - "version": "4.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.1.0", - "changes": [ - { - "note": "Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`.", - "pr": 2437 - } - ], - "timestamp": 1579682890 - }, - { - "timestamp": 1578272714, - "version": "4.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "4.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "4.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export LibMathRevertErrors", - "pr": 2321 - }, - { - "note": "Break up `LibEIP712` into reusable components", - "pr": 1742 - }, - { - "note": "Add `chainId` to EIP712 domain schema", - "pr": 1742 - }, - { - "note": "Rename `verifyingContract` to `verifyingContractAddress` in domain schema", - "pr": 1742 - }, - { - "note": "Add LibZeroExTransaction contract", - "pr": 1753 - }, - { - "note": "Add verifyingContractIfExists arg to LibEIP712ExchangeDomain constructor", - "pr": 1753 - }, - { - "note": "Remove LibEIP712ExchangeDomainConstants and LibEIP712 contracts", - "pr": 1753 - }, - { - "note": "Add `LibExchangeRichErrorDecoder` contract.", - "pr": 1790 - }, - { - "note": "Break out types/interaces from `MExchangeRichErrors` into `MExchangeRichErrorTypes`.", - "pr": 1790 - }, - { - "note": "Reorder some revert error parameters for consistency", - "pr": 1790 - }, - { - "note": "Add new `Order` fields for arbitrary fee tokens (ZEIP-28).", - "pr": 1819 - }, - { - "note": "Remove `LibAbiEncoder` and `LibConstants`.", - "pr": 1819 - }, - { - "note": "Add `generate-exchange-selectors` package script.", - "pr": 1819 - }, - { - "note": "Add `expirationTimeSeconds` to `ZeroExTransaction` struct", - "pr": 1823 - }, - { - "note": "Add reference functions for `LibMath` and `LibFillResults`", - "pr": 2031 - }, - { - "note": "Move in revamped `LibMath` tests from the `contracts-exchange` package.", - "pr": 2031 - }, - { - "note": "Move in revamped `LibFillResults` tests from the `contracts-exchange` package.", - "pr": 2031 - }, - { - "note": "Remove unecessary zero-denominator checks in `LibMath`.", - "pr": 2031 - }, - { - "note": "Fix coverage hooks.", - "pr": 2031 - }, - { - "note": "Regenerate selectors.", - "pr": 2042 - }, - { - "note": "Convert `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries", - "pr": 2055 - }, - { - "note": "Remove `LibExchangeSelectors`", - "pr": 2055 - }, - { - "note": "Add `LibExchangeRichErrors`", - "pr": 2055 - }, - { - "note": "Add `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults`", - "pr": 2055 - }, - { - "note": "Remove `_hashEIP712ExchangeMessage` from `LibEIP712ExchangeDomain`", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.", - "pr": 2075 - }, - { - "note": "Move `IWallet.sol` from `asset-proxy` and `exchange` packages to here.", - "pr": 2233 - } - ], - "timestamp": 1575296764 - }, - { - "version": "3.1.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "3.1.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "3.1.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export LibMathRevertErrors", - "pr": 2321 - } - ], - "timestamp": 1574030254 - }, - { - "version": "3.1.0-beta.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1573159180 - }, - { - "version": "3.1.0-beta.0", - "changes": [ - { - "note": "Break up `LibEIP712` into reusable components", - "pr": 1742 - }, - { - "note": "Add `chainId` to EIP712 domain schema", - "pr": 1742 - }, - { - "note": "Rename `verifyingContract` to `verifyingContractAddress` in domain schema", - "pr": 1742 - }, - { - "note": "Add LibZeroExTransaction contract", - "pr": 1753 - }, - { - "note": "Add verifyingContractIfExists arg to LibEIP712ExchangeDomain constructor", - "pr": 1753 - }, - { - "note": "Remove LibEIP712ExchangeDomainConstants and LibEIP712 contracts", - "pr": 1753 - }, - { - "note": "Add `LibExchangeRichErrorDecoder` contract.", - "pr": 1790 - }, - { - "note": "Break out types/interaces from `MExchangeRichErrors` into `MExchangeRichErrorTypes`.", - "pr": 1790 - }, - { - "note": "Reorder some revert error parameters for consistency", - "pr": 1790 - }, - { - "note": "Add new `Order` fields for arbitrary fee tokens (ZEIP-28).", - "pr": 1819 - }, - { - "note": "Remove `LibAbiEncoder` and `LibConstants`.", - "pr": 1819 - }, - { - "note": "Add `generate-exchange-selectors` package script.", - "pr": 1819 - }, - { - "note": "Add `expirationTimeSeconds` to `ZeroExTransaction` struct", - "pr": 1823 - }, - { - "note": "Add reference functions for `LibMath` and `LibFillResults`", - "pr": 2031 - }, - { - "note": "Move in revamped `LibMath` tests from the `contracts-exchange` package.", - "pr": 2031 - }, - { - "note": "Move in revamped `LibFillResults` tests from the `contracts-exchange` package.", - "pr": 2031 - }, - { - "note": "Remove unecessary zero-denominator checks in `LibMath`.", - "pr": 2031 - }, - { - "note": "Fix coverage hooks.", - "pr": 2031 - }, - { - "note": "Regenerate selectors.", - "pr": 2042 - }, - { - "note": "Convert `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries", - "pr": 2055 - }, - { - "note": "Remove `LibExchangeSelectors`", - "pr": 2055 - }, - { - "note": "Add `LibExchangeRichErrors`", - "pr": 2055 - }, - { - "note": "Add `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults`", - "pr": 2055 - }, - { - "note": "Remove `_hashEIP712ExchangeMessage` from `LibEIP712ExchangeDomain`", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.", - "pr": 2075 - }, - { - "note": "Move `IWallet.sol` from `asset-proxy` and `exchange` packages to here.", - "pr": 2233 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "3.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "3.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "3.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "3.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.4", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564604963 - }, - { - "timestamp": 1563957393, - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Move `LibTransactionDecoder` to contracts/dev-utils package", - "pr": 1848 - } - ], - "timestamp": 1563006338 - }, - { - "timestamp": 1558712885, - "version": "2.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "2.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1557799313 - }, - { - "timestamp": 1557507213, - "version": "2.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Upgrade contracts to Solidity 0.5.5", - "pr": 1682 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "1.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "1.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "1.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Upgrade contracts to Solidity 0.5.3", - "pr": 1604 - }, - { - "note": "Make constants internal", - "pr": 1604 - } - ], - "timestamp": 1551130135 - }, - { - "timestamp": 1549733923, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549373905, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Rename contracts-libs to contracts-exchange-libs", - "pr": 1539 - }, - { - "note": "Move LibAddressArray contract to contracts-utils", - "pr": 1539 - } - ] - } -] diff --git a/contracts/exchange-libs/CHANGELOG.md b/contracts/exchange-libs/CHANGELOG.md deleted file mode 100644 index cdc4c608eb..0000000000 --- a/contracts/exchange-libs/CHANGELOG.md +++ /dev/null @@ -1,367 +0,0 @@ - - -CHANGELOG - -## v4.3.37 - _August 16, 2021_ - - * Dependencies updated - -## v4.3.36 - _August 11, 2021_ - - * Dependencies updated - -## v4.3.35 - _August 6, 2021_ - - * Dependencies updated - -## v4.3.34 - _June 22, 2021_ - - * Dependencies updated - -## v4.3.33 - _June 11, 2021_ - - * Dependencies updated - -## v4.3.32 - _June 2, 2021_ - - * Dependencies updated - -## v4.3.31 - _May 25, 2021_ - - * Dependencies updated - -## v4.3.30 - _May 21, 2021_ - - * Dependencies updated - -## v4.3.29 - _May 5, 2021_ - - * Dependencies updated - -## v4.3.28 - _April 28, 2021_ - - * Dependencies updated - -## v4.3.27 - _April 1, 2021_ - - * Dependencies updated - -## v4.3.26 - _March 17, 2021_ - - * Dependencies updated - -## v4.3.25 - _February 24, 2021_ - - * Dependencies updated - -## v4.3.24 - _February 10, 2021_ - - * Dependencies updated - -## v4.3.23 - _January 26, 2021_ - - * Dependencies updated - -## v4.3.22 - _January 13, 2021_ - - * Dependencies updated - -## v4.3.21 - _January 4, 2021_ - - * Dependencies updated - -## v4.3.20 - _December 23, 2020_ - - * Dependencies updated - -## v4.3.19 - _December 17, 2020_ - - * Dependencies updated - -## v4.3.18 - _December 9, 2020_ - - * Dependencies updated - -## v4.3.17 - _December 7, 2020_ - - * Dependencies updated - -## v4.3.16 - _December 3, 2020_ - - * Dependencies updated - -## v4.3.15 - _November 19, 2020_ - - * Dependencies updated - -## v4.3.14 - _November 13, 2020_ - - * Dependencies updated - -## v4.3.13 - _November 3, 2020_ - - * Dependencies updated - -## v4.3.12 - _November 3, 2020_ - - * Dependencies updated - -## v4.3.11 - _November 2, 2020_ - - * Dependencies updated - -## v4.3.10 - _October 28, 2020_ - - * Dependencies updated - -## v4.3.9 - _October 27, 2020_ - - * Dependencies updated - -## v4.3.8 - _October 21, 2020_ - - * Dependencies updated - -## v4.3.7 - _July 15, 2020_ - - * Dependencies updated - -## v4.3.6 - _June 24, 2020_ - - * Dependencies updated - -## v4.3.5 - _March 3, 2020_ - - * Dependencies updated - -## v4.3.4 - _February 27, 2020_ - - * Dependencies updated - -## v4.3.3 - _February 26, 2020_ - - * Dependencies updated - -## v4.3.2 - _February 25, 2020_ - - * Dependencies updated - -## v4.3.1 - _February 15, 2020_ - - * Dependencies updated - -## v4.3.0 - _February 8, 2020_ - - * Export `EvmBytecodeOutputLinkReferences` type. (#2462) - -## v4.2.0 - _February 6, 2020_ - - * Moved LibAssetDataTransfer here from forwarder (#2455) - -## v4.1.1 - _February 4, 2020_ - - * Dependencies updated - -## v4.1.0 - _January 22, 2020_ - - * Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437) - -## v4.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v4.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v4.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v4.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export LibMathRevertErrors (#2321) - * Break up `LibEIP712` into reusable components (#1742) - * Add `chainId` to EIP712 domain schema (#1742) - * Rename `verifyingContract` to `verifyingContractAddress` in domain schema (#1742) - * Add LibZeroExTransaction contract (#1753) - * Add verifyingContractIfExists arg to LibEIP712ExchangeDomain constructor (#1753) - * Remove LibEIP712ExchangeDomainConstants and LibEIP712 contracts (#1753) - * Add `LibExchangeRichErrorDecoder` contract. (#1790) - * Break out types/interaces from `MExchangeRichErrors` into `MExchangeRichErrorTypes`. (#1790) - * Reorder some revert error parameters for consistency (#1790) - * Add new `Order` fields for arbitrary fee tokens (ZEIP-28). (#1819) - * Remove `LibAbiEncoder` and `LibConstants`. (#1819) - * Add `generate-exchange-selectors` package script. (#1819) - * Add `expirationTimeSeconds` to `ZeroExTransaction` struct (#1823) - * Add reference functions for `LibMath` and `LibFillResults` (#2031) - * Move in revamped `LibMath` tests from the `contracts-exchange` package. (#2031) - * Move in revamped `LibFillResults` tests from the `contracts-exchange` package. (#2031) - * Remove unecessary zero-denominator checks in `LibMath`. (#2031) - * Fix coverage hooks. (#2031) - * Regenerate selectors. (#2042) - * Convert `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries (#2055) - * Remove `LibExchangeSelectors` (#2055) - * Add `LibExchangeRichErrors` (#2055) - * Add `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` (#2055) - * Remove `_hashEIP712ExchangeMessage` from `LibEIP712ExchangeDomain` (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields. (#2075) - * Move `IWallet.sol` from `asset-proxy` and `exchange` packages to here. (#2233) - -## v3.1.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v3.1.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v3.1.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export LibMathRevertErrors (#2321) - -## v3.1.0-beta.1 - _November 7, 2019_ - - * Dependencies updated - -## v3.1.0-beta.0 - _October 3, 2019_ - - * Break up `LibEIP712` into reusable components (#1742) - * Add `chainId` to EIP712 domain schema (#1742) - * Rename `verifyingContract` to `verifyingContractAddress` in domain schema (#1742) - * Add LibZeroExTransaction contract (#1753) - * Add verifyingContractIfExists arg to LibEIP712ExchangeDomain constructor (#1753) - * Remove LibEIP712ExchangeDomainConstants and LibEIP712 contracts (#1753) - * Add `LibExchangeRichErrorDecoder` contract. (#1790) - * Break out types/interaces from `MExchangeRichErrors` into `MExchangeRichErrorTypes`. (#1790) - * Reorder some revert error parameters for consistency (#1790) - * Add new `Order` fields for arbitrary fee tokens (ZEIP-28). (#1819) - * Remove `LibAbiEncoder` and `LibConstants`. (#1819) - * Add `generate-exchange-selectors` package script. (#1819) - * Add `expirationTimeSeconds` to `ZeroExTransaction` struct (#1823) - * Add reference functions for `LibMath` and `LibFillResults` (#2031) - * Move in revamped `LibMath` tests from the `contracts-exchange` package. (#2031) - * Move in revamped `LibFillResults` tests from the `contracts-exchange` package. (#2031) - * Remove unecessary zero-denominator checks in `LibMath`. (#2031) - * Fix coverage hooks. (#2031) - * Regenerate selectors. (#2042) - * Convert `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries (#2055) - * Remove `LibExchangeSelectors` (#2055) - * Add `LibExchangeRichErrors` (#2055) - * Add `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` (#2055) - * Remove `_hashEIP712ExchangeMessage` from `LibEIP712ExchangeDomain` (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields. (#2075) - * Move `IWallet.sol` from `asset-proxy` and `exchange` packages to here. (#2233) - -## v3.0.8 - _September 17, 2019_ - - * Dependencies updated - -## v3.0.7 - _September 3, 2019_ - - * Dependencies updated - -## v3.0.6 - _August 22, 2019_ - - * Dependencies updated - -## v3.0.5 - _August 8, 2019_ - - * Dependencies updated - -## v3.0.4 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v3.0.3 - _July 24, 2019_ - - * Dependencies updated - -## v3.0.2 - _July 15, 2019_ - - * Dependencies updated - -## v3.0.1 - _July 13, 2019_ - - * Dependencies updated - -## v3.0.0 - _July 13, 2019_ - - * Move `LibTransactionDecoder` to contracts/dev-utils package (#1848) - -## v2.1.6 - _May 24, 2019_ - - * Dependencies updated - -## v2.1.5 - _May 15, 2019_ - - * Dependencies updated - -## v2.1.4 - _May 14, 2019_ - - * Dependencies updated - -## v2.1.2 - _May 10, 2019_ - - * Dependencies updated - -## v2.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v2.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v2.0.0 - _March 20, 2019_ - - * Upgrade contracts to Solidity 0.5.5 (#1682) - -## v1.1.3 - _March 1, 2019_ - - * Dependencies updated - -## v1.1.2 - _February 27, 2019_ - - * Dependencies updated - -## v1.1.1 - _February 26, 2019_ - - * Dependencies updated - -## v1.1.0 - _February 25, 2019_ - - * Upgrade contracts to Solidity 0.5.3 (#1604) - * Make constants internal (#1604) - -## v1.0.5 - _February 9, 2019_ - - * Dependencies updated - -## v1.0.4 - _February 7, 2019_ - - * Dependencies updated - -## v1.0.3 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v1.0.2 - _February 6, 2019_ - - * Dependencies updated - -## v1.0.1 - _February 5, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Rename contracts-libs to contracts-exchange-libs (#1539) - * Move LibAddressArray contract to contracts-utils (#1539) diff --git a/contracts/exchange-libs/README.md b/contracts/exchange-libs/README.md deleted file mode 100644 index 85039470fb..0000000000 --- a/contracts/exchange-libs/README.md +++ /dev/null @@ -1,69 +0,0 @@ -## Exchange Libraries - -This package contains the implementations of various libraries and utilities used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract. These libraries may be useful when creating external contracts that interact with the `Exchange` contract. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-exchange-libs --save -``` - -## 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=@0x/contracts-exchange-libs yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-exchange-libs yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/exchange-libs/compiler.json b/contracts/exchange-libs/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/exchange-libs/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/exchange-libs/contracts/src/IWallet.sol b/contracts/exchange-libs/contracts/src/IWallet.sol deleted file mode 100644 index 2bb323e578..0000000000 --- a/contracts/exchange-libs/contracts/src/IWallet.sol +++ /dev/null @@ -1,38 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -contract IWallet { - - bytes4 internal constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; - - /// @dev Validates a hash with the `Wallet` signature type. - /// @param hash Message hash that is signed. - /// @param signature Proof of signing. - /// @return magicValue `bytes4(0xb0671381)` if the signature check succeeds. - function isValidSignature( - bytes32 hash, - bytes calldata signature - ) - external - view - returns (bytes4 magicValue); -} diff --git a/contracts/exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol b/contracts/exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol deleted file mode 100644 index 8e9628afdf..0000000000 --- a/contracts/exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol +++ /dev/null @@ -1,54 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; - - -contract LibEIP712ExchangeDomain { - - // EIP712 Exchange Domain Name value - string constant internal _EIP712_EXCHANGE_DOMAIN_NAME = "0x Protocol"; - - // EIP712 Exchange Domain Version value - string constant internal _EIP712_EXCHANGE_DOMAIN_VERSION = "3.0.0"; - - // solhint-disable var-name-mixedcase - /// @dev Hash of the EIP712 Domain Separator data - /// @return 0 Domain hash. - bytes32 public EIP712_EXCHANGE_DOMAIN_HASH; - // solhint-enable var-name-mixedcase - - /// @param chainId Chain ID of the network this contract is deployed on. - /// @param verifyingContractAddressIfExists Address of the verifying contract (null if the address of this contract) - constructor ( - uint256 chainId, - address verifyingContractAddressIfExists - ) - public - { - address verifyingContractAddress = verifyingContractAddressIfExists == address(0) ? address(this) : verifyingContractAddressIfExists; - EIP712_EXCHANGE_DOMAIN_HASH = LibEIP712.hashEIP712Domain( - _EIP712_EXCHANGE_DOMAIN_NAME, - _EIP712_EXCHANGE_DOMAIN_VERSION, - chainId, - verifyingContractAddress - ); - } -} diff --git a/contracts/exchange-libs/contracts/src/LibExchangeRichErrors.sol b/contracts/exchange-libs/contracts/src/LibExchangeRichErrors.sol deleted file mode 100644 index 234c2eaf0a..0000000000 --- a/contracts/exchange-libs/contracts/src/LibExchangeRichErrors.sol +++ /dev/null @@ -1,614 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "./LibOrder.sol"; - - -library LibExchangeRichErrors { - - enum AssetProxyDispatchErrorCodes { - INVALID_ASSET_DATA_LENGTH, - UNKNOWN_ASSET_PROXY - } - - enum BatchMatchOrdersErrorCodes { - ZERO_LEFT_ORDERS, - ZERO_RIGHT_ORDERS, - INVALID_LENGTH_LEFT_SIGNATURES, - INVALID_LENGTH_RIGHT_SIGNATURES - } - - enum ExchangeContextErrorCodes { - INVALID_MAKER, - INVALID_TAKER, - INVALID_SENDER - } - - enum FillErrorCodes { - INVALID_TAKER_AMOUNT, - TAKER_OVERPAY, - OVERFILL, - INVALID_FILL_PRICE - } - - enum SignatureErrorCodes { - BAD_ORDER_SIGNATURE, - BAD_TRANSACTION_SIGNATURE, - INVALID_LENGTH, - UNSUPPORTED, - ILLEGAL, - INAPPROPRIATE_SIGNATURE_TYPE, - INVALID_SIGNER - } - - enum TransactionErrorCodes { - ALREADY_EXECUTED, - EXPIRED - } - - enum IncompleteFillErrorCode { - INCOMPLETE_MARKET_BUY_ORDERS, - INCOMPLETE_MARKET_SELL_ORDERS, - INCOMPLETE_FILL_ORDER - } - - // bytes4(keccak256("SignatureError(uint8,bytes32,address,bytes)")) - bytes4 internal constant SIGNATURE_ERROR_SELECTOR = - 0x7e5a2318; - - // bytes4(keccak256("SignatureValidatorNotApprovedError(address,address)")) - bytes4 internal constant SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR = - 0xa15c0d06; - - // bytes4(keccak256("EIP1271SignatureError(address,bytes,bytes,bytes)")) - bytes4 internal constant EIP1271_SIGNATURE_ERROR_SELECTOR = - 0x5bd0428d; - - // bytes4(keccak256("SignatureWalletError(bytes32,address,bytes,bytes)")) - bytes4 internal constant SIGNATURE_WALLET_ERROR_SELECTOR = - 0x1b8388f7; - - // bytes4(keccak256("OrderStatusError(bytes32,uint8)")) - bytes4 internal constant ORDER_STATUS_ERROR_SELECTOR = - 0xfdb6ca8d; - - // bytes4(keccak256("ExchangeInvalidContextError(uint8,bytes32,address)")) - bytes4 internal constant EXCHANGE_INVALID_CONTEXT_ERROR_SELECTOR = - 0xe53c76c8; - - // bytes4(keccak256("FillError(uint8,bytes32)")) - bytes4 internal constant FILL_ERROR_SELECTOR = - 0xe94a7ed0; - - // bytes4(keccak256("OrderEpochError(address,address,uint256)")) - bytes4 internal constant ORDER_EPOCH_ERROR_SELECTOR = - 0x4ad31275; - - // bytes4(keccak256("AssetProxyExistsError(bytes4,address)")) - bytes4 internal constant ASSET_PROXY_EXISTS_ERROR_SELECTOR = - 0x11c7b720; - - // bytes4(keccak256("AssetProxyDispatchError(uint8,bytes32,bytes)")) - bytes4 internal constant ASSET_PROXY_DISPATCH_ERROR_SELECTOR = - 0x488219a6; - - // bytes4(keccak256("AssetProxyTransferError(bytes32,bytes,bytes)")) - bytes4 internal constant ASSET_PROXY_TRANSFER_ERROR_SELECTOR = - 0x4678472b; - - // bytes4(keccak256("NegativeSpreadError(bytes32,bytes32)")) - bytes4 internal constant NEGATIVE_SPREAD_ERROR_SELECTOR = - 0xb6555d6f; - - // bytes4(keccak256("TransactionError(uint8,bytes32)")) - bytes4 internal constant TRANSACTION_ERROR_SELECTOR = - 0xf5985184; - - // bytes4(keccak256("TransactionExecutionError(bytes32,bytes)")) - bytes4 internal constant TRANSACTION_EXECUTION_ERROR_SELECTOR = - 0x20d11f61; - - // bytes4(keccak256("TransactionGasPriceError(bytes32,uint256,uint256)")) - bytes4 internal constant TRANSACTION_GAS_PRICE_ERROR_SELECTOR = - 0xa26dac09; - - // bytes4(keccak256("TransactionInvalidContextError(bytes32,address)")) - bytes4 internal constant TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR = - 0xdec4aedf; - - // bytes4(keccak256("IncompleteFillError(uint8,uint256,uint256)")) - bytes4 internal constant INCOMPLETE_FILL_ERROR_SELECTOR = - 0x18e4b141; - - // bytes4(keccak256("BatchMatchOrdersError(uint8)")) - bytes4 internal constant BATCH_MATCH_ORDERS_ERROR_SELECTOR = - 0xd4092f4f; - - // bytes4(keccak256("PayProtocolFeeError(bytes32,uint256,address,address,bytes)")) - bytes4 internal constant PAY_PROTOCOL_FEE_ERROR_SELECTOR = - 0x87cb1e75; - - // solhint-disable func-name-mixedcase - function SignatureErrorSelector() - internal - pure - returns (bytes4) - { - return SIGNATURE_ERROR_SELECTOR; - } - - function SignatureValidatorNotApprovedErrorSelector() - internal - pure - returns (bytes4) - { - return SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR; - } - - function EIP1271SignatureErrorSelector() - internal - pure - returns (bytes4) - { - return EIP1271_SIGNATURE_ERROR_SELECTOR; - } - - function SignatureWalletErrorSelector() - internal - pure - returns (bytes4) - { - return SIGNATURE_WALLET_ERROR_SELECTOR; - } - - function OrderStatusErrorSelector() - internal - pure - returns (bytes4) - { - return ORDER_STATUS_ERROR_SELECTOR; - } - - function ExchangeInvalidContextErrorSelector() - internal - pure - returns (bytes4) - { - return EXCHANGE_INVALID_CONTEXT_ERROR_SELECTOR; - } - - function FillErrorSelector() - internal - pure - returns (bytes4) - { - return FILL_ERROR_SELECTOR; - } - - function OrderEpochErrorSelector() - internal - pure - returns (bytes4) - { - return ORDER_EPOCH_ERROR_SELECTOR; - } - - function AssetProxyExistsErrorSelector() - internal - pure - returns (bytes4) - { - return ASSET_PROXY_EXISTS_ERROR_SELECTOR; - } - - function AssetProxyDispatchErrorSelector() - internal - pure - returns (bytes4) - { - return ASSET_PROXY_DISPATCH_ERROR_SELECTOR; - } - - function AssetProxyTransferErrorSelector() - internal - pure - returns (bytes4) - { - return ASSET_PROXY_TRANSFER_ERROR_SELECTOR; - } - - function NegativeSpreadErrorSelector() - internal - pure - returns (bytes4) - { - return NEGATIVE_SPREAD_ERROR_SELECTOR; - } - - function TransactionErrorSelector() - internal - pure - returns (bytes4) - { - return TRANSACTION_ERROR_SELECTOR; - } - - function TransactionExecutionErrorSelector() - internal - pure - returns (bytes4) - { - return TRANSACTION_EXECUTION_ERROR_SELECTOR; - } - - function IncompleteFillErrorSelector() - internal - pure - returns (bytes4) - { - return INCOMPLETE_FILL_ERROR_SELECTOR; - } - - function BatchMatchOrdersErrorSelector() - internal - pure - returns (bytes4) - { - return BATCH_MATCH_ORDERS_ERROR_SELECTOR; - } - - function TransactionGasPriceErrorSelector() - internal - pure - returns (bytes4) - { - return TRANSACTION_GAS_PRICE_ERROR_SELECTOR; - } - - function TransactionInvalidContextErrorSelector() - internal - pure - returns (bytes4) - { - return TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR; - } - - function PayProtocolFeeErrorSelector() - internal - pure - returns (bytes4) - { - return PAY_PROTOCOL_FEE_ERROR_SELECTOR; - } - - function BatchMatchOrdersError( - BatchMatchOrdersErrorCodes errorCode - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - BATCH_MATCH_ORDERS_ERROR_SELECTOR, - errorCode - ); - } - - function SignatureError( - SignatureErrorCodes errorCode, - bytes32 hash, - address signerAddress, - bytes memory signature - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - SIGNATURE_ERROR_SELECTOR, - errorCode, - hash, - signerAddress, - signature - ); - } - - function SignatureValidatorNotApprovedError( - address signerAddress, - address validatorAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR, - signerAddress, - validatorAddress - ); - } - - function EIP1271SignatureError( - address verifyingContractAddress, - bytes memory data, - bytes memory signature, - bytes memory errorData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - EIP1271_SIGNATURE_ERROR_SELECTOR, - verifyingContractAddress, - data, - signature, - errorData - ); - } - - function SignatureWalletError( - bytes32 hash, - address walletAddress, - bytes memory signature, - bytes memory errorData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - SIGNATURE_WALLET_ERROR_SELECTOR, - hash, - walletAddress, - signature, - errorData - ); - } - - function OrderStatusError( - bytes32 orderHash, - LibOrder.OrderStatus orderStatus - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ORDER_STATUS_ERROR_SELECTOR, - orderHash, - orderStatus - ); - } - - function ExchangeInvalidContextError( - ExchangeContextErrorCodes errorCode, - bytes32 orderHash, - address contextAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - EXCHANGE_INVALID_CONTEXT_ERROR_SELECTOR, - errorCode, - orderHash, - contextAddress - ); - } - - function FillError( - FillErrorCodes errorCode, - bytes32 orderHash - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - FILL_ERROR_SELECTOR, - errorCode, - orderHash - ); - } - - function OrderEpochError( - address makerAddress, - address orderSenderAddress, - uint256 currentEpoch - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ORDER_EPOCH_ERROR_SELECTOR, - makerAddress, - orderSenderAddress, - currentEpoch - ); - } - - function AssetProxyExistsError( - bytes4 assetProxyId, - address assetProxyAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ASSET_PROXY_EXISTS_ERROR_SELECTOR, - assetProxyId, - assetProxyAddress - ); - } - - function AssetProxyDispatchError( - AssetProxyDispatchErrorCodes errorCode, - bytes32 orderHash, - bytes memory assetData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ASSET_PROXY_DISPATCH_ERROR_SELECTOR, - errorCode, - orderHash, - assetData - ); - } - - function AssetProxyTransferError( - bytes32 orderHash, - bytes memory assetData, - bytes memory errorData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ASSET_PROXY_TRANSFER_ERROR_SELECTOR, - orderHash, - assetData, - errorData - ); - } - - function NegativeSpreadError( - bytes32 leftOrderHash, - bytes32 rightOrderHash - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - NEGATIVE_SPREAD_ERROR_SELECTOR, - leftOrderHash, - rightOrderHash - ); - } - - function TransactionError( - TransactionErrorCodes errorCode, - bytes32 transactionHash - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - TRANSACTION_ERROR_SELECTOR, - errorCode, - transactionHash - ); - } - - function TransactionExecutionError( - bytes32 transactionHash, - bytes memory errorData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - TRANSACTION_EXECUTION_ERROR_SELECTOR, - transactionHash, - errorData - ); - } - - function TransactionGasPriceError( - bytes32 transactionHash, - uint256 actualGasPrice, - uint256 requiredGasPrice - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - TRANSACTION_GAS_PRICE_ERROR_SELECTOR, - transactionHash, - actualGasPrice, - requiredGasPrice - ); - } - - function TransactionInvalidContextError( - bytes32 transactionHash, - address currentContextAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR, - transactionHash, - currentContextAddress - ); - } - - function IncompleteFillError( - IncompleteFillErrorCode errorCode, - uint256 expectedAssetFillAmount, - uint256 actualAssetFillAmount - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INCOMPLETE_FILL_ERROR_SELECTOR, - errorCode, - expectedAssetFillAmount, - actualAssetFillAmount - ); - } - - function PayProtocolFeeError( - bytes32 orderHash, - uint256 protocolFee, - address makerAddress, - address takerAddress, - bytes memory errorData - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - PAY_PROTOCOL_FEE_ERROR_SELECTOR, - orderHash, - protocolFee, - makerAddress, - takerAddress, - errorData - ); - } -} diff --git a/contracts/exchange-libs/contracts/src/LibFillResults.sol b/contracts/exchange-libs/contracts/src/LibFillResults.sol deleted file mode 100644 index 9f151dd521..0000000000 --- a/contracts/exchange-libs/contracts/src/LibFillResults.sol +++ /dev/null @@ -1,426 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./LibMath.sol"; -import "./LibOrder.sol"; - - -library LibFillResults { - - using LibSafeMath for uint256; - - struct BatchMatchedFillResults { - FillResults[] left; // Fill results for left orders - FillResults[] right; // Fill results for right orders - uint256 profitInLeftMakerAsset; // Profit taken from left makers - uint256 profitInRightMakerAsset; // Profit taken from right makers - } - - struct FillResults { - uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled. - uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled. - uint256 makerFeePaid; // Total amount of fees paid by maker(s) to feeRecipient(s). - uint256 takerFeePaid; // Total amount of fees paid by taker to feeRecipients(s). - uint256 protocolFeePaid; // Total amount of fees paid by taker to the staking contract. - } - - struct MatchedFillResults { - FillResults left; // Amounts filled and fees paid of left order. - FillResults right; // Amounts filled and fees paid of right order. - uint256 profitInLeftMakerAsset; // Profit taken from the left maker - uint256 profitInRightMakerAsset; // Profit taken from the right 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. - /// @param protocolFeeMultiplier The current protocol fee of the exchange contract. - /// @param gasPrice The gasprice of the transaction. This is provided so that the function call can continue - /// to be pure rather than view. - /// @return fillResults Amounts filled and fees paid by maker and taker. - function calculateFillResults( - LibOrder.Order memory order, - uint256 takerAssetFilledAmount, - uint256 protocolFeeMultiplier, - uint256 gasPrice - ) - internal - pure - returns (FillResults memory fillResults) - { - // Compute proportional transfer amounts - fillResults.takerAssetFilledAmount = takerAssetFilledAmount; - fillResults.makerAssetFilledAmount = LibMath.safeGetPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount - ); - fillResults.makerFeePaid = LibMath.safeGetPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerFee - ); - fillResults.takerFeePaid = LibMath.safeGetPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.takerFee - ); - - // Compute the protocol fee that should be paid for a single fill. - fillResults.protocolFeePaid = gasPrice.safeMul(protocolFeeMultiplier); - - return fillResults; - } - - /// @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 protocolFeeMultiplier The current protocol fee of the exchange contract. - /// @param gasPrice The gasprice of the transaction. This is provided so that the function call can continue - /// to be pure rather than view. - /// @param shouldMaximallyFillOrders A value that indicates whether or not this calculation should use - /// the maximal fill order matching strategy. - /// @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, - uint256 protocolFeeMultiplier, - uint256 gasPrice, - bool shouldMaximallyFillOrders - ) - internal - pure - returns (MatchedFillResults memory matchedFillResults) - { - // Derive maker asset amounts for left & right orders, given store taker assert amounts - uint256 leftTakerAssetAmountRemaining = leftOrder.takerAssetAmount.safeSub(leftOrderTakerAssetFilledAmount); - uint256 leftMakerAssetAmountRemaining = LibMath.safeGetPartialAmountFloor( - leftOrder.makerAssetAmount, - leftOrder.takerAssetAmount, - leftTakerAssetAmountRemaining - ); - uint256 rightTakerAssetAmountRemaining = rightOrder.takerAssetAmount.safeSub(rightOrderTakerAssetFilledAmount); - uint256 rightMakerAssetAmountRemaining = LibMath.safeGetPartialAmountFloor( - rightOrder.makerAssetAmount, - rightOrder.takerAssetAmount, - rightTakerAssetAmountRemaining - ); - - // Maximally fill the orders and pay out profits to the matcher in one or both of the maker assets. - if (shouldMaximallyFillOrders) { - matchedFillResults = _calculateMatchedFillResultsWithMaximalFill( - leftOrder, - rightOrder, - leftMakerAssetAmountRemaining, - leftTakerAssetAmountRemaining, - rightMakerAssetAmountRemaining, - rightTakerAssetAmountRemaining - ); - } else { - matchedFillResults = _calculateMatchedFillResults( - leftOrder, - rightOrder, - leftMakerAssetAmountRemaining, - leftTakerAssetAmountRemaining, - rightMakerAssetAmountRemaining, - rightTakerAssetAmountRemaining - ); - } - - // Compute fees for left order - matchedFillResults.left.makerFeePaid = LibMath.safeGetPartialAmountFloor( - matchedFillResults.left.makerAssetFilledAmount, - leftOrder.makerAssetAmount, - leftOrder.makerFee - ); - matchedFillResults.left.takerFeePaid = LibMath.safeGetPartialAmountFloor( - matchedFillResults.left.takerAssetFilledAmount, - leftOrder.takerAssetAmount, - leftOrder.takerFee - ); - - // Compute fees for right order - matchedFillResults.right.makerFeePaid = LibMath.safeGetPartialAmountFloor( - matchedFillResults.right.makerAssetFilledAmount, - rightOrder.makerAssetAmount, - rightOrder.makerFee - ); - matchedFillResults.right.takerFeePaid = LibMath.safeGetPartialAmountFloor( - matchedFillResults.right.takerAssetFilledAmount, - rightOrder.takerAssetAmount, - rightOrder.takerFee - ); - - // Compute the protocol fee that should be paid for a single fill. In this - // case this should be made the protocol fee for both the left and right orders. - uint256 protocolFee = gasPrice.safeMul(protocolFeeMultiplier); - matchedFillResults.left.protocolFeePaid = protocolFee; - matchedFillResults.right.protocolFeePaid = protocolFee; - - // Return fill results - return matchedFillResults; - } - - /// @dev Adds properties of both FillResults instances. - /// @param fillResults1 The first FillResults. - /// @param fillResults2 The second FillResults. - /// @return The sum of both fill results. - function addFillResults( - FillResults memory fillResults1, - FillResults memory fillResults2 - ) - internal - pure - returns (FillResults memory totalFillResults) - { - totalFillResults.makerAssetFilledAmount = fillResults1.makerAssetFilledAmount.safeAdd(fillResults2.makerAssetFilledAmount); - totalFillResults.takerAssetFilledAmount = fillResults1.takerAssetFilledAmount.safeAdd(fillResults2.takerAssetFilledAmount); - totalFillResults.makerFeePaid = fillResults1.makerFeePaid.safeAdd(fillResults2.makerFeePaid); - totalFillResults.takerFeePaid = fillResults1.takerFeePaid.safeAdd(fillResults2.takerFeePaid); - totalFillResults.protocolFeePaid = fillResults1.protocolFeePaid.safeAdd(fillResults2.protocolFeePaid); - - return totalFillResults; - } - - /// @dev Calculates part of the matched fill results for a given situation using the fill strategy that only - /// awards profit denominated in the left maker asset. - /// @param leftOrder The left order in the order matching situation. - /// @param rightOrder The right order in the order matching situation. - /// @param leftMakerAssetAmountRemaining The amount of the left order maker asset that can still be filled. - /// @param leftTakerAssetAmountRemaining The amount of the left order taker asset that can still be filled. - /// @param rightMakerAssetAmountRemaining The amount of the right order maker asset that can still be filled. - /// @param rightTakerAssetAmountRemaining The amount of the right order taker asset that can still be filled. - /// @return MatchFillResults struct that does not include fees paid. - function _calculateMatchedFillResults( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - uint256 leftMakerAssetAmountRemaining, - uint256 leftTakerAssetAmountRemaining, - uint256 rightMakerAssetAmountRemaining, - uint256 rightTakerAssetAmountRemaining - ) - private - pure - returns (MatchedFillResults memory matchedFillResults) - { - // 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. - // Case 3. - // If the left maker can buy exactly as much as the right maker can sell, then both orders are fully filled. - if (leftTakerAssetAmountRemaining > rightMakerAssetAmountRemaining) { - // Case 1: Right order is fully filled - matchedFillResults = _calculateCompleteRightFill( - leftOrder, - rightMakerAssetAmountRemaining, - rightTakerAssetAmountRemaining - ); - } else if (leftTakerAssetAmountRemaining < rightMakerAssetAmountRemaining) { - // Case 2: Left order is fully filled - matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; - matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; - matchedFillResults.right.makerAssetFilledAmount = leftTakerAssetAmountRemaining; - // 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 = LibMath.safeGetPartialAmountCeil( - rightOrder.takerAssetAmount, - rightOrder.makerAssetAmount, - leftTakerAssetAmountRemaining // matchedFillResults.right.makerAssetFilledAmount - ); - } else { - // leftTakerAssetAmountRemaining == rightMakerAssetAmountRemaining - // Case 3: Both orders are fully filled. Technically, this could be captured by the above cases, but - // this calculation will be more precise since it does not include rounding. - matchedFillResults = _calculateCompleteFillBoth( - leftMakerAssetAmountRemaining, - leftTakerAssetAmountRemaining, - rightMakerAssetAmountRemaining, - rightTakerAssetAmountRemaining - ); - } - - // Calculate amount given to taker - matchedFillResults.profitInLeftMakerAsset = matchedFillResults.left.makerAssetFilledAmount.safeSub( - matchedFillResults.right.takerAssetFilledAmount - ); - - return matchedFillResults; - } - - /// @dev Calculates part of the matched fill results for a given situation using the maximal fill order matching - /// strategy. - /// @param leftOrder The left order in the order matching situation. - /// @param rightOrder The right order in the order matching situation. - /// @param leftMakerAssetAmountRemaining The amount of the left order maker asset that can still be filled. - /// @param leftTakerAssetAmountRemaining The amount of the left order taker asset that can still be filled. - /// @param rightMakerAssetAmountRemaining The amount of the right order maker asset that can still be filled. - /// @param rightTakerAssetAmountRemaining The amount of the right order taker asset that can still be filled. - /// @return MatchFillResults struct that does not include fees paid. - function _calculateMatchedFillResultsWithMaximalFill( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - uint256 leftMakerAssetAmountRemaining, - uint256 leftTakerAssetAmountRemaining, - uint256 rightMakerAssetAmountRemaining, - uint256 rightTakerAssetAmountRemaining - ) - private - pure - returns (MatchedFillResults memory matchedFillResults) - { - // If a maker asset is greater than the opposite taker asset, than there will be a spread denominated in that maker asset. - bool doesLeftMakerAssetProfitExist = leftMakerAssetAmountRemaining > rightTakerAssetAmountRemaining; - bool doesRightMakerAssetProfitExist = rightMakerAssetAmountRemaining > leftTakerAssetAmountRemaining; - - // Calculate the maximum fill results for the maker and taker assets. At least one of the orders will be fully filled. - // - // The maximum that the left maker can possibly buy is the amount that the right order can sell. - // The maximum that the right maker can possibly buy is the amount that the left order can sell. - // - // If the left order is fully filled, profit will be paid out in the left maker asset. If the right order is fully filled, - // the profit will be out in the right maker asset. - // - // There are three cases to consider: - // Case 1. - // If the left maker can buy more than the right maker can sell, then only the right order is fully filled. - // Case 2. - // If the right maker can buy more than the left maker can sell, then only the right order is fully filled. - // Case 3. - // If the right maker can sell the max of what the left maker can buy and the left maker can sell the max of - // what the right maker can buy, then both orders are fully filled. - if (leftTakerAssetAmountRemaining > rightMakerAssetAmountRemaining) { - // Case 1: Right order is fully filled with the profit paid in the left makerAsset - matchedFillResults = _calculateCompleteRightFill( - leftOrder, - rightMakerAssetAmountRemaining, - rightTakerAssetAmountRemaining - ); - } else if (rightTakerAssetAmountRemaining > leftMakerAssetAmountRemaining) { - // Case 2: Left order is fully filled with the profit paid in the right makerAsset. - matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; - matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; - // Round down to ensure the right maker's exchange rate does not exceed the price specified by the order. - // We favor the right maker when the exchange rate must be rounded and the profit is being paid in the - // right maker asset. - matchedFillResults.right.makerAssetFilledAmount = LibMath.safeGetPartialAmountFloor( - rightOrder.makerAssetAmount, - rightOrder.takerAssetAmount, - leftMakerAssetAmountRemaining - ); - matchedFillResults.right.takerAssetFilledAmount = leftMakerAssetAmountRemaining; - } else { - // Case 3: The right and left orders are fully filled - matchedFillResults = _calculateCompleteFillBoth( - leftMakerAssetAmountRemaining, - leftTakerAssetAmountRemaining, - rightMakerAssetAmountRemaining, - rightTakerAssetAmountRemaining - ); - } - - // Calculate amount given to taker in the left order's maker asset if the left spread will be part of the profit. - if (doesLeftMakerAssetProfitExist) { - matchedFillResults.profitInLeftMakerAsset = matchedFillResults.left.makerAssetFilledAmount.safeSub( - matchedFillResults.right.takerAssetFilledAmount - ); - } - - // Calculate amount given to taker in the right order's maker asset if the right spread will be part of the profit. - if (doesRightMakerAssetProfitExist) { - matchedFillResults.profitInRightMakerAsset = matchedFillResults.right.makerAssetFilledAmount.safeSub( - matchedFillResults.left.takerAssetFilledAmount - ); - } - - return matchedFillResults; - } - - /// @dev Calculates the fill results for the maker and taker in the order matching and writes the results - /// to the fillResults that are being collected on the order. Both orders will be fully filled in this - /// case. - /// @param leftMakerAssetAmountRemaining The amount of the left maker asset that is remaining to be filled. - /// @param leftTakerAssetAmountRemaining The amount of the left taker asset that is remaining to be filled. - /// @param rightMakerAssetAmountRemaining The amount of the right maker asset that is remaining to be filled. - /// @param rightTakerAssetAmountRemaining The amount of the right taker asset that is remaining to be filled. - /// @return MatchFillResults struct that does not include fees paid or spreads taken. - function _calculateCompleteFillBoth( - uint256 leftMakerAssetAmountRemaining, - uint256 leftTakerAssetAmountRemaining, - uint256 rightMakerAssetAmountRemaining, - uint256 rightTakerAssetAmountRemaining - ) - private - pure - returns (MatchedFillResults memory matchedFillResults) - { - // Calculate the fully filled results for both orders. - matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; - matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; - matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; - matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; - - return matchedFillResults; - } - - /// @dev Calculates the fill results for the maker and taker in the order matching and writes the results - /// to the fillResults that are being collected on the order. - /// @param leftOrder The left order that is being maximally filled. All of the information about fill amounts - /// can be derived from this order and the right asset remaining fields. - /// @param rightMakerAssetAmountRemaining The amount of the right maker asset that is remaining to be filled. - /// @param rightTakerAssetAmountRemaining The amount of the right taker asset that is remaining to be filled. - /// @return MatchFillResults struct that does not include fees paid or spreads taken. - function _calculateCompleteRightFill( - LibOrder.Order memory leftOrder, - uint256 rightMakerAssetAmountRemaining, - uint256 rightTakerAssetAmountRemaining - ) - private - pure - returns (MatchedFillResults memory matchedFillResults) - { - matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; - matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; - matchedFillResults.left.takerAssetFilledAmount = rightMakerAssetAmountRemaining; - // Round down to ensure the left maker's exchange rate does not exceed the price specified by the order. - // We favor the left maker when the exchange rate must be rounded and the profit is being paid in the - // left maker asset. - matchedFillResults.left.makerAssetFilledAmount = LibMath.safeGetPartialAmountFloor( - leftOrder.makerAssetAmount, - leftOrder.takerAssetAmount, - rightMakerAssetAmountRemaining - ); - - return matchedFillResults; - } -} diff --git a/contracts/exchange-libs/contracts/src/LibOrder.sol b/contracts/exchange-libs/contracts/src/LibOrder.sol deleted file mode 100644 index d17a41d5b6..0000000000 --- a/contracts/exchange-libs/contracts/src/LibOrder.sol +++ /dev/null @@ -1,174 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; - - -library LibOrder { - - using LibOrder for Order; - - // Hash for the EIP712 Order Schema: - // 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,", - // "bytes makerFeeAssetData,", - // "bytes takerFeeAssetData", - // ")" - // )) - bytes32 constant internal _EIP712_ORDER_SCHEMA_HASH = - 0xf80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534; - - // A valid order remains fillable until it is expired, fully filled, or cancelled. - // An order's status 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 - /// @dev Canonical order structure. - 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; // Fee paid to feeRecipient by maker when order is filled. - uint256 takerFee; // Fee paid to feeRecipient by taker when order is filled. - 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 leading bytes4 references the id of the asset proxy. - bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The leading bytes4 references the id of the asset proxy. - bytes makerFeeAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerFeeAsset. The leading bytes4 references the id of the asset proxy. - bytes takerFeeAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerFeeAsset. The leading bytes4 references the id of the asset proxy. - } - // solhint-enable max-line-length - - /// @dev Order information returned by `getOrderInfo()`. - struct OrderInfo { - OrderStatus orderStatus; // Status that describes order's validity and fillability. - bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash). - uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled. - } - - /// @dev Calculates the EIP712 typed data hash of an order with a given domain separator. - /// @param order The order structure. - /// @return EIP712 typed data hash of the order. - function getTypedDataHash(Order memory order, bytes32 eip712ExchangeDomainHash) - internal - pure - returns (bytes32 orderHash) - { - orderHash = LibEIP712.hashEIP712Message( - eip712ExchangeDomainHash, - order.getStructHash() - ); - return orderHash; - } - - /// @dev Calculates EIP712 hash of the order struct. - /// @param order The order structure. - /// @return EIP712 hash of the order struct. - function getStructHash(Order memory order) - internal - pure - returns (bytes32 result) - { - bytes32 schemaHash = _EIP712_ORDER_SCHEMA_HASH; - bytes memory makerAssetData = order.makerAssetData; - bytes memory takerAssetData = order.takerAssetData; - bytes memory makerFeeAssetData = order.makerFeeAssetData; - bytes memory takerFeeAssetData = order.takerFeeAssetData; - - // Assembly for more efficiently computing: - // keccak256(abi.encodePacked( - // EIP712_ORDER_SCHEMA_HASH, - // uint256(order.makerAddress), - // uint256(order.takerAddress), - // uint256(order.feeRecipientAddress), - // uint256(order.senderAddress), - // order.makerAssetAmount, - // order.takerAssetAmount, - // order.makerFee, - // order.takerFee, - // order.expirationTimeSeconds, - // order.salt, - // keccak256(order.makerAssetData), - // keccak256(order.takerAssetData), - // keccak256(order.makerFeeAssetData), - // keccak256(order.takerFeeAssetData) - // )); - - assembly { - // Assert order offset (this is an internal error that should never be triggered) - if lt(order, 32) { - invalid() - } - - // 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) - let pos4 := add(order, 384) - let pos5 := add(order, 416) - - // Backup - let temp1 := mload(pos1) - let temp2 := mload(pos2) - let temp3 := mload(pos3) - let temp4 := mload(pos4) - let temp5 := mload(pos5) - - // Hash in place - mstore(pos1, schemaHash) - mstore(pos2, keccak256(add(makerAssetData, 32), mload(makerAssetData))) // store hash of makerAssetData - mstore(pos3, keccak256(add(takerAssetData, 32), mload(takerAssetData))) // store hash of takerAssetData - mstore(pos4, keccak256(add(makerFeeAssetData, 32), mload(makerFeeAssetData))) // store hash of makerFeeAssetData - mstore(pos5, keccak256(add(takerFeeAssetData, 32), mload(takerFeeAssetData))) // store hash of takerFeeAssetData - result := keccak256(pos1, 480) - - // Restore - mstore(pos1, temp1) - mstore(pos2, temp2) - mstore(pos3, temp3) - mstore(pos4, temp4) - mstore(pos5, temp5) - } - return result; - } -} diff --git a/contracts/exchange-libs/contracts/src/LibZeroExTransaction.sol b/contracts/exchange-libs/contracts/src/LibZeroExTransaction.sol deleted file mode 100644 index 6694d78d3b..0000000000 --- a/contracts/exchange-libs/contracts/src/LibZeroExTransaction.sol +++ /dev/null @@ -1,109 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; - - -library LibZeroExTransaction { - - using LibZeroExTransaction for ZeroExTransaction; - - // Hash for the EIP712 0x transaction schema - // keccak256(abi.encodePacked( - // "ZeroExTransaction(", - // "uint256 salt,", - // "uint256 expirationTimeSeconds,", - // "uint256 gasPrice,", - // "address signerAddress,", - // "bytes data", - // ")" - // )); - bytes32 constant internal _EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0xec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc71541508; - - struct ZeroExTransaction { - uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash. - uint256 expirationTimeSeconds; // Timestamp in seconds at which transaction expires. - uint256 gasPrice; // gasPrice that transaction is required to be executed with. - address signerAddress; // Address of transaction signer. - bytes data; // AbiV2 encoded calldata. - } - - /// @dev Calculates the EIP712 typed data hash of a transaction with a given domain separator. - /// @param transaction 0x transaction structure. - /// @return EIP712 typed data hash of the transaction. - function getTypedDataHash(ZeroExTransaction memory transaction, bytes32 eip712ExchangeDomainHash) - internal - pure - returns (bytes32 transactionHash) - { - // Hash the transaction with the domain separator of the Exchange contract. - transactionHash = LibEIP712.hashEIP712Message( - eip712ExchangeDomainHash, - transaction.getStructHash() - ); - return transactionHash; - } - - /// @dev Calculates EIP712 hash of the 0x transaction struct. - /// @param transaction 0x transaction structure. - /// @return EIP712 hash of the transaction struct. - function getStructHash(ZeroExTransaction memory transaction) - internal - pure - returns (bytes32 result) - { - bytes32 schemaHash = _EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH; - bytes memory data = transaction.data; - uint256 salt = transaction.salt; - uint256 expirationTimeSeconds = transaction.expirationTimeSeconds; - uint256 gasPrice = transaction.gasPrice; - address signerAddress = transaction.signerAddress; - - // Assembly for more efficiently computing: - // result = keccak256(abi.encodePacked( - // schemaHash, - // salt, - // expirationTimeSeconds, - // gasPrice, - // uint256(signerAddress), - // keccak256(data) - // )); - - assembly { - // Compute hash of data - let dataHash := keccak256(add(data, 32), mload(data)) - - // Load free memory pointer - let memPtr := mload(64) - - mstore(memPtr, schemaHash) // hash of schema - mstore(add(memPtr, 32), salt) // salt - mstore(add(memPtr, 64), expirationTimeSeconds) // expirationTimeSeconds - mstore(add(memPtr, 96), gasPrice) // gasPrice - mstore(add(memPtr, 128), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress - mstore(add(memPtr, 160), dataHash) // hash of data - - // Compute hash - result := keccak256(memPtr, 192) - } - return result; - } -} diff --git a/contracts/exchange-libs/contracts/test/TestLibEIP712ExchangeDomain.sol b/contracts/exchange-libs/contracts/test/TestLibEIP712ExchangeDomain.sol deleted file mode 100644 index 7476c8e4c8..0000000000 --- a/contracts/exchange-libs/contracts/test/TestLibEIP712ExchangeDomain.sol +++ /dev/null @@ -1,36 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/LibEIP712ExchangeDomain.sol"; - - -contract TestLibEIP712ExchangeDomain is - LibEIP712ExchangeDomain -{ - - constructor( - uint256 chainId, - address verifyingContractAddressIfExists - ) - public - LibEIP712ExchangeDomain(chainId, verifyingContractAddressIfExists) - {} -} diff --git a/contracts/exchange-libs/contracts/test/TestLibFillResults.sol b/contracts/exchange-libs/contracts/test/TestLibFillResults.sol deleted file mode 100644 index bca710057d..0000000000 --- a/contracts/exchange-libs/contracts/test/TestLibFillResults.sol +++ /dev/null @@ -1,85 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/LibOrder.sol"; -import "../src/LibFillResults.sol"; - - -contract TestLibFillResults { - - using LibFillResults for *; - - function calculateFillResults( - LibOrder.Order memory order, - uint256 takerAssetFilledAmount, - uint256 protocolFeeMultiplier, - uint256 gasPrice - ) - public - pure - returns (LibFillResults.FillResults memory fillResults) - { - fillResults = LibFillResults.calculateFillResults( - order, - takerAssetFilledAmount, - protocolFeeMultiplier, - gasPrice - ); - return fillResults; - } - - function calculateMatchedFillResults( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - uint256 leftOrderTakerAssetFilledAmount, - uint256 rightOrderTakerAssetFilledAmount, - uint256 protocolFeeMultiplier, - uint256 gasPrice, - bool shouldMaximallyFillOrders - ) - public - pure - returns (LibFillResults.MatchedFillResults memory matchedFillResults) - { - matchedFillResults = LibFillResults.calculateMatchedFillResults( - leftOrder, - rightOrder, - leftOrderTakerAssetFilledAmount, - rightOrderTakerAssetFilledAmount, - protocolFeeMultiplier, - gasPrice, - shouldMaximallyFillOrders - ); - return matchedFillResults; - } - - function addFillResults( - LibFillResults.FillResults memory fillResults1, - LibFillResults.FillResults memory fillResults2 - ) - public - pure - returns (LibFillResults.FillResults memory totalFillResults) - { - totalFillResults = LibFillResults.addFillResults(fillResults1, fillResults2); - return totalFillResults; - } -} diff --git a/contracts/exchange-libs/contracts/test/TestLibOrder.sol b/contracts/exchange-libs/contracts/test/TestLibOrder.sol deleted file mode 100644 index 11543790b5..0000000000 --- a/contracts/exchange-libs/contracts/test/TestLibOrder.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/LibOrder.sol"; - - -contract TestLibOrder { - - function getTypedDataHash(LibOrder.Order memory order, bytes32 eip712ExchangeDomainHash) - public - pure - returns (bytes32 orderHash) - { - orderHash = LibOrder.getTypedDataHash(order, eip712ExchangeDomainHash); - return orderHash; - } - - function getStructHash(LibOrder.Order memory order) - public - pure - returns (bytes32 result) - { - result = LibOrder.getStructHash(order); - return result; - } -} diff --git a/contracts/exchange-libs/contracts/test/TestLibZeroExTransaction.sol b/contracts/exchange-libs/contracts/test/TestLibZeroExTransaction.sol deleted file mode 100644 index ab69f971e1..0000000000 --- a/contracts/exchange-libs/contracts/test/TestLibZeroExTransaction.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/LibZeroExTransaction.sol"; - - -contract TestLibZeroExTransaction { - - function getTypedDataHash(LibZeroExTransaction.ZeroExTransaction memory transaction, bytes32 eip712ExchangeDomainHash) - public - pure - returns (bytes32 transactionHash) - { - transactionHash = LibZeroExTransaction.getTypedDataHash(transaction, eip712ExchangeDomainHash); - return transactionHash; - } - - function getStructHash(LibZeroExTransaction.ZeroExTransaction memory transaction) - public - pure - returns (bytes32 result) - { - result = LibZeroExTransaction.getStructHash(transaction); - return result; - } -} \ No newline at end of file diff --git a/contracts/exchange-libs/package.json b/contracts/exchange-libs/package.json deleted file mode 100644 index 2dfd41610f..0000000000 --- a/contracts/exchange-libs/package.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "name": "@0x/contracts-exchange-libs", - "version": "4.3.37", - "engines": { - "node": ">=6.12" - }, - "description": "Smart contract libs 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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "IWallet,LibEIP712ExchangeDomain,LibExchangeRichErrors,LibMath,LibMathRichErrors,LibOrder,LibZeroExTransaction", - "abis": "./test/generated-artifacts/@(IWallet|LibEIP712ExchangeDomain|LibExchangeRichErrors|LibFillResults|LibMath|LibMathRichErrors|LibOrder|LibZeroExTransaction|TestLibEIP712ExchangeDomain|TestLibFillResults|TestLibMath|TestLibOrder|TestLibZeroExTransaction).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/libs", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-gen": "^2.0.38", - "@0x/dev-utils": "^4.2.7", - "@0x/sol-compiler": "^4.7.3", - "@0x/subproviders": "^6.5.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "ethereumjs-util": "^7.0.10", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/order-utils": "^10.4.28", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "ethereum-types": "^3.5.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/exchange-libs/src/artifacts.ts b/contracts/exchange-libs/src/artifacts.ts deleted file mode 100644 index e511f8c4ac..0000000000 --- a/contracts/exchange-libs/src/artifacts.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as IWallet from '../generated-artifacts/IWallet.json'; -import * as LibEIP712ExchangeDomain from '../generated-artifacts/LibEIP712ExchangeDomain.json'; -import * as LibExchangeRichErrors from '../generated-artifacts/LibExchangeRichErrors.json'; -import * as LibMath from '../generated-artifacts/LibMath.json'; -import * as LibMathRichErrors from '../generated-artifacts/LibMathRichErrors.json'; -import * as LibOrder from '../generated-artifacts/LibOrder.json'; -import * as LibZeroExTransaction from '../generated-artifacts/LibZeroExTransaction.json'; -export const artifacts = { - IWallet: IWallet as ContractArtifact, - LibEIP712ExchangeDomain: LibEIP712ExchangeDomain as ContractArtifact, - LibExchangeRichErrors: LibExchangeRichErrors as ContractArtifact, - LibMath: LibMath as ContractArtifact, - LibMathRichErrors: LibMathRichErrors as ContractArtifact, - LibOrder: LibOrder as ContractArtifact, - LibZeroExTransaction: LibZeroExTransaction as ContractArtifact, -}; diff --git a/contracts/exchange-libs/src/index.ts b/contracts/exchange-libs/src/index.ts deleted file mode 100644 index 4fc478ee80..0000000000 --- a/contracts/exchange-libs/src/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -export { artifacts } from './artifacts'; -export { - IWalletContract, - LibEIP712ExchangeDomainContract, - LibExchangeRichErrorsContract, - LibMathContract, - LibMathRichErrorsContract, - LibOrderContract, - LibZeroExTransactionContract, -} from './wrappers'; -export { LibMathRevertErrors } from '@0x/utils'; - -import * as ReferenceFunctionsToExport from './reference_functions'; -export import ReferenceFunctions = ReferenceFunctionsToExport; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/exchange-libs/src/reference_functions.ts b/contracts/exchange-libs/src/reference_functions.ts deleted file mode 100644 index 2966545e68..0000000000 --- a/contracts/exchange-libs/src/reference_functions.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { orderHashUtils } from '@0x/contracts-test-utils'; -import { ReferenceFunctions } from '@0x/contracts-utils'; -import { FillResults, MatchedFillResults, Order } from '@0x/types'; -import { BigNumber, ExchangeRevertErrors, LibMathRevertErrors } from '@0x/utils'; - -const { safeAdd, safeSub, safeMul, safeDiv } = ReferenceFunctions; - -/** - * Checks if rounding error >= 0.1% when rounding down. - */ -export function isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { - if (denominator.eq(0)) { - throw new LibMathRevertErrors.DivisionByZeroError(); - } - if (numerator.eq(0) || target.eq(0)) { - return false; - } - const remainder = numerator.times(target).mod(denominator); - // Need to do this separately because solidity evaluates RHS of the comparison expression first. - const rhs = safeMul(numerator, target); - const lhs = safeMul(remainder, new BigNumber(1000)); - return lhs.gte(rhs); -} - -/** - * Checks if rounding error >= 0.1% when rounding up. - */ -export function isRoundingErrorCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { - if (denominator.eq(0)) { - throw new LibMathRevertErrors.DivisionByZeroError(); - } - if (numerator.eq(0) || target.eq(0)) { - return false; - } - let remainder = numerator.times(target).mod(denominator); - remainder = safeSub(denominator, remainder).mod(denominator); - // Need to do this separately because solidity evaluates RHS of the comparison expression first. - const rhs = safeMul(numerator, target); - const lhs = safeMul(remainder, new BigNumber(1000)); - return lhs.gte(rhs); -} - -/** - * Calculates partial value given a numerator and denominator rounded down. - * Reverts if rounding error is >= 0.1% - */ -export function safeGetPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - if (isRoundingErrorFloor(numerator, denominator, target)) { - throw new LibMathRevertErrors.RoundingError(numerator, denominator, target); - } - return safeDiv(safeMul(numerator, target), denominator); -} - -/** - * Calculates partial value given a numerator and denominator rounded down. - * Reverts if rounding error is >= 0.1% - */ -export function safeGetPartialAmountCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - if (isRoundingErrorCeil(numerator, denominator, target)) { - throw new LibMathRevertErrors.RoundingError(numerator, denominator, target); - } - return safeDiv(safeAdd(safeMul(numerator, target), safeSub(denominator, new BigNumber(1))), denominator); -} - -/** - * Calculates partial value given a numerator and denominator rounded down. - */ -export function getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - return safeDiv(safeMul(numerator, target), denominator); -} - -/** - * Calculates partial value given a numerator and denominator rounded down. - */ -export function getPartialAmountCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - const sub = safeSub(denominator, new BigNumber(1)); // This is computed first to simulate Solidity's order of operations - return safeDiv(safeAdd(safeMul(numerator, target), sub), denominator); -} - -/** - * Adds properties of two `FillResults`. - */ -export function addFillResults(a: FillResults, b: FillResults): FillResults { - return { - makerAssetFilledAmount: safeAdd(a.makerAssetFilledAmount, b.makerAssetFilledAmount), - takerAssetFilledAmount: safeAdd(a.takerAssetFilledAmount, b.takerAssetFilledAmount), - makerFeePaid: safeAdd(a.makerFeePaid, b.makerFeePaid), - takerFeePaid: safeAdd(a.takerFeePaid, b.takerFeePaid), - protocolFeePaid: safeAdd(a.protocolFeePaid, b.protocolFeePaid), - }; -} - -/** - * Calculates amounts filled and fees paid by maker and taker. - */ -export function calculateFillResults( - order: Order, - takerAssetFilledAmount: BigNumber, - protocolFeeMultiplier: BigNumber, - gasPrice: BigNumber, -): FillResults { - const makerAssetFilledAmount = safeGetPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const makerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.makerFee); - const takerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.takerFee); - return { - makerAssetFilledAmount, - takerAssetFilledAmount, - makerFeePaid, - takerFeePaid, - protocolFeePaid: safeMul(protocolFeeMultiplier, gasPrice), - }; -} - -/** - * Calculates amounts filled and fees paid by maker and taker. - */ -export function calculateMatchResults( - leftOrder: Order, - rightOrder: Order, - protocolFeeMultiplier: BigNumber, - gasPrice: BigNumber, - withMaximalFill: boolean = false, -): MatchedFillResults { - // Initialize empty fill results. - const leftFillResults: FillResults = { - makerAssetFilledAmount: new BigNumber(0), - takerAssetFilledAmount: new BigNumber(0), - makerFeePaid: new BigNumber(0), - takerFeePaid: new BigNumber(0), - protocolFeePaid: new BigNumber(0), - }; - const rightFillResults: FillResults = { - makerAssetFilledAmount: new BigNumber(0), - takerAssetFilledAmount: new BigNumber(0), - makerFeePaid: new BigNumber(0), - takerFeePaid: new BigNumber(0), - protocolFeePaid: new BigNumber(0), - }; - let profitInLeftMakerAsset = new BigNumber(0); - let profitInRightMakerAsset = new BigNumber(0); - - // Assert matchable - if ( - leftOrder.makerAssetAmount - .times(rightOrder.makerAssetAmount) - .lt(leftOrder.takerAssetAmount.times(rightOrder.takerAssetAmount)) - ) { - throw new ExchangeRevertErrors.NegativeSpreadError( - orderHashUtils.getOrderHashHex(leftOrder), - orderHashUtils.getOrderHashHex(rightOrder), - ); - } - - // Asset Transfer Amounts - if (leftOrder.takerAssetAmount.gt(rightOrder.makerAssetAmount)) { - leftFillResults.makerAssetFilledAmount = safeGetPartialAmountFloor( - leftOrder.makerAssetAmount, - leftOrder.takerAssetAmount, - rightOrder.makerAssetAmount, - ); - leftFillResults.takerAssetFilledAmount = rightOrder.makerAssetAmount; - rightFillResults.makerAssetFilledAmount = rightOrder.makerAssetAmount; - rightFillResults.takerAssetFilledAmount = rightOrder.takerAssetAmount; - } else if (withMaximalFill && leftOrder.makerAssetAmount.lt(rightOrder.takerAssetAmount)) { - leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount; - leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount; - rightFillResults.makerAssetFilledAmount = safeGetPartialAmountFloor( - rightOrder.makerAssetAmount, - rightOrder.takerAssetAmount, - leftOrder.makerAssetAmount, - ); - rightFillResults.takerAssetFilledAmount = leftOrder.makerAssetAmount; - } else if (!withMaximalFill && leftOrder.takerAssetAmount.lt(rightOrder.makerAssetAmount)) { - leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount; - leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount; - rightFillResults.makerAssetFilledAmount = leftOrder.takerAssetAmount; - rightFillResults.takerAssetFilledAmount = safeGetPartialAmountCeil( - rightOrder.takerAssetAmount, - rightOrder.makerAssetAmount, - leftOrder.takerAssetAmount, - ); - } else { - leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount; - leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount; - rightFillResults.makerAssetFilledAmount = rightOrder.makerAssetAmount; - rightFillResults.takerAssetFilledAmount = rightOrder.takerAssetAmount; - } - - // Profit - profitInLeftMakerAsset = leftFillResults.makerAssetFilledAmount.minus(rightFillResults.makerAssetFilledAmount); - profitInRightMakerAsset = rightFillResults.makerAssetFilledAmount.minus(leftFillResults.makerAssetFilledAmount); - - // Fees - leftFillResults.makerFeePaid = safeGetPartialAmountFloor( - leftFillResults.makerAssetFilledAmount, - leftOrder.makerAssetAmount, - leftOrder.makerFee, - ); - leftFillResults.takerFeePaid = safeGetPartialAmountFloor( - leftFillResults.takerAssetFilledAmount, - leftOrder.takerAssetAmount, - leftOrder.takerFee, - ); - rightFillResults.makerFeePaid = safeGetPartialAmountFloor( - rightFillResults.makerAssetFilledAmount, - rightOrder.makerAssetAmount, - rightOrder.makerFee, - ); - rightFillResults.takerFeePaid = safeGetPartialAmountFloor( - rightFillResults.takerAssetFilledAmount, - rightOrder.takerAssetAmount, - rightOrder.takerFee, - ); - - // Protocol Fee - leftFillResults.protocolFeePaid = safeMul(protocolFeeMultiplier, gasPrice); - rightFillResults.protocolFeePaid = safeMul(protocolFeeMultiplier, gasPrice); - - return { - left: leftFillResults, - right: rightFillResults, - profitInLeftMakerAsset, - profitInRightMakerAsset, - }; -} - -export const LibFractions = { - add: (n1: BigNumber, d1: BigNumber, n2: BigNumber, d2: BigNumber): [BigNumber, BigNumber] => { - if (n1.isZero()) { - return [n2, d2]; - } - if (n2.isZero()) { - return [n1, d1]; - } - const numerator = safeAdd(safeMul(n1, d2), safeMul(n2, d1)); - const denominator = safeMul(d1, d2); - return [numerator, denominator]; - }, - normalize: ( - numerator: BigNumber, - denominator: BigNumber, - maxValue: BigNumber = new BigNumber(2).exponentiatedBy(127), - ): [BigNumber, BigNumber] => { - if (numerator.isGreaterThan(maxValue) || denominator.isGreaterThan(maxValue)) { - let rescaleBase = numerator.isGreaterThanOrEqualTo(denominator) ? numerator : denominator; - rescaleBase = safeDiv(rescaleBase, maxValue); - return [safeDiv(numerator, rescaleBase), safeDiv(denominator, rescaleBase)]; - } else { - return [numerator, denominator]; - } - }, -}; diff --git a/contracts/exchange-libs/src/wrappers.ts b/contracts/exchange-libs/src/wrappers.ts deleted file mode 100644 index 03a7601de2..0000000000 --- a/contracts/exchange-libs/src/wrappers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/i_wallet'; -export * from '../generated-wrappers/lib_e_i_p712_exchange_domain'; -export * from '../generated-wrappers/lib_exchange_rich_errors'; -export * from '../generated-wrappers/lib_math'; -export * from '../generated-wrappers/lib_math_rich_errors'; -export * from '../generated-wrappers/lib_order'; -export * from '../generated-wrappers/lib_zero_ex_transaction'; diff --git a/contracts/exchange-libs/test/artifacts.ts b/contracts/exchange-libs/test/artifacts.ts deleted file mode 100644 index 01c47756ec..0000000000 --- a/contracts/exchange-libs/test/artifacts.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as IWallet from '../test/generated-artifacts/IWallet.json'; -import * as LibEIP712ExchangeDomain from '../test/generated-artifacts/LibEIP712ExchangeDomain.json'; -import * as LibExchangeRichErrors from '../test/generated-artifacts/LibExchangeRichErrors.json'; -import * as LibFillResults from '../test/generated-artifacts/LibFillResults.json'; -import * as LibMath from '../test/generated-artifacts/LibMath.json'; -import * as LibMathRichErrors from '../test/generated-artifacts/LibMathRichErrors.json'; -import * as LibOrder from '../test/generated-artifacts/LibOrder.json'; -import * as LibZeroExTransaction from '../test/generated-artifacts/LibZeroExTransaction.json'; -import * as TestLibEIP712ExchangeDomain from '../test/generated-artifacts/TestLibEIP712ExchangeDomain.json'; -import * as TestLibFillResults from '../test/generated-artifacts/TestLibFillResults.json'; -import * as TestLibMath from '../test/generated-artifacts/TestLibMath.json'; -import * as TestLibOrder from '../test/generated-artifacts/TestLibOrder.json'; -import * as TestLibZeroExTransaction from '../test/generated-artifacts/TestLibZeroExTransaction.json'; -export const artifacts = { - IWallet: IWallet as ContractArtifact, - LibEIP712ExchangeDomain: LibEIP712ExchangeDomain as ContractArtifact, - LibExchangeRichErrors: LibExchangeRichErrors as ContractArtifact, - LibFillResults: LibFillResults as ContractArtifact, - LibMath: LibMath as ContractArtifact, - LibMathRichErrors: LibMathRichErrors as ContractArtifact, - LibOrder: LibOrder as ContractArtifact, - LibZeroExTransaction: LibZeroExTransaction as ContractArtifact, - TestLibEIP712ExchangeDomain: TestLibEIP712ExchangeDomain as ContractArtifact, - TestLibFillResults: TestLibFillResults as ContractArtifact, - TestLibMath: TestLibMath as ContractArtifact, - TestLibOrder: TestLibOrder as ContractArtifact, - TestLibZeroExTransaction: TestLibZeroExTransaction as ContractArtifact, -}; diff --git a/contracts/exchange-libs/test/global_hooks.ts b/contracts/exchange-libs/test/global_hooks.ts deleted file mode 100644 index 91d8693e15..0000000000 --- a/contracts/exchange-libs/test/global_hooks.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { env, EnvVars } from '@0x/dev-utils'; -import { prependSubprovider } from '@0x/subproviders'; -import { providerUtils } from '@0x/utils'; - -const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); -const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); - -if (env.parseBoolean(EnvVars.SolidityCoverage)) { - prependSubprovider(provider, coverageSubprovider); - provider.stop(); -} -if (env.parseBoolean(EnvVars.SolidityProfiler)) { - prependSubprovider(provider, profilerSubprovider); - provider.stop(); -} - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -after('generate coverage report', async () => { - if (env.parseBoolean(EnvVars.SolidityCoverage)) { - await coverageSubprovider.writeCoverageAsync(); - } - if (env.parseBoolean(EnvVars.SolidityProfiler)) { - await profilerSubprovider.writeProfilerOutputAsync(); - } - provider.stop(); -}); diff --git a/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts b/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts deleted file mode 100644 index ddee5eaf1c..0000000000 --- a/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; -import { BigNumber, signTypedDataUtils } from '@0x/utils'; -import * as ethUtil from 'ethereumjs-util'; - -import { TestLibEIP712ExchangeDomainContract } from './wrappers'; - -import { artifacts } from './artifacts'; - -blockchainTests('LibEIP712ExchangeDomain', env => { - describe('constructor', () => { - it('should calculate the correct domain hash when verifyingContractAddressIfExists is set to null', async () => { - const chainId = 1; - const libEIP712ExchangeDomainContract = await TestLibEIP712ExchangeDomainContract.deployFrom0xArtifactAsync( - artifacts.TestLibEIP712ExchangeDomain, - env.provider, - env.txDefaults, - {}, - new BigNumber(chainId), - constants.NULL_ADDRESS, - ); - const domain = { - verifyingContract: libEIP712ExchangeDomainContract.address, - chainId, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - }; - const expectedDomainHash = ethUtil.bufferToHex(signTypedDataUtils.generateDomainHash(domain)); - const actualDomainHash = await libEIP712ExchangeDomainContract.EIP712_EXCHANGE_DOMAIN_HASH().callAsync(); - expect(actualDomainHash).to.be.equal(expectedDomainHash); - }); - it('should calculate the correct domain hash when verifyingContractAddressIfExists is set to a non-null address', async () => { - const chainId = 1; - const verifyingContract = randomAddress(); - const libEIP712ExchangeDomainContract = await TestLibEIP712ExchangeDomainContract.deployFrom0xArtifactAsync( - artifacts.TestLibEIP712ExchangeDomain, - env.provider, - env.txDefaults, - {}, - new BigNumber(chainId), - verifyingContract, - ); - const domain = { - verifyingContract, - chainId, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - }; - const expectedDomainHash = ethUtil.bufferToHex(signTypedDataUtils.generateDomainHash(domain)); - const actualDomainHash = await libEIP712ExchangeDomainContract.EIP712_EXCHANGE_DOMAIN_HASH().callAsync(); - expect(actualDomainHash).to.be.equal(expectedDomainHash); - }); - }); -}); diff --git a/contracts/exchange-libs/test/lib_fill_results.ts b/contracts/exchange-libs/test/lib_fill_results.ts deleted file mode 100644 index a47240e8f3..0000000000 --- a/contracts/exchange-libs/test/lib_fill_results.ts +++ /dev/null @@ -1,1930 +0,0 @@ -import { - blockchainTests, - constants, - describe, - expect, - testCombinatoriallyWithReferenceFunc, - uint256Values, -} from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { FillResults, MatchedFillResults, Order } from '@0x/types'; -import { BigNumber, hexUtils, LibMathRevertErrors } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; - -import { addFillResults, calculateFillResults, getPartialAmountFloor } from '../src/reference_functions'; - -import { artifacts } from './artifacts'; -import { TestLibFillResultsContract } from './wrappers'; - -blockchainTests('LibFillResults', env => { - interface PartialMatchedFillResults { - left: Partial; - right: Partial; - profitInLeftMakerAsset?: BigNumber; - profitInRightMakerAsset?: BigNumber; - } - - const { ONE_ETHER, MAX_UINT256 } = constants; - const EMPTY_ORDER: Order = { - senderAddress: constants.NULL_ADDRESS, - makerAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerAssetAmount: constants.ZERO_AMOUNT, - takerAssetAmount: constants.ZERO_AMOUNT, - makerAssetData: constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - salt: constants.ZERO_AMOUNT, - feeRecipientAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: constants.ZERO_AMOUNT, - chainId: 1, - exchangeAddress: constants.NULL_ADDRESS, - }; - - const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH); - const randomAssetData = () => hexUtils.random(36); - const randomUint256 = () => new BigNumber(hexUtils.random(constants.WORD_LENGTH)); - - let libsContract: TestLibFillResultsContract; - let makerAddressLeft: string; - let makerAddressRight: string; - - before(async () => { - const accounts = await env.getAccountAddressesAsync(); - makerAddressLeft = accounts[0]; - makerAddressRight = accounts[1]; - - libsContract = await TestLibFillResultsContract.deployFrom0xArtifactAsync( - artifacts.TestLibFillResults, - env.provider, - env.txDefaults, - {}, - ); - }); - - describe('calculateFillResults', () => { - describe.optional('combinatorial tests', () => { - function makeOrder( - makerAssetAmount: BigNumber, - takerAssetAmount: BigNumber, - makerFee: BigNumber, - takerFee: BigNumber, - ): Order { - return { - ...EMPTY_ORDER, - makerAssetAmount, - takerAssetAmount, - makerFee, - takerFee, - }; - } - - async function referenceCalculateFillResultsAsync( - orderTakerAssetAmount: BigNumber, - takerAssetFilledAmount: BigNumber, - otherAmount: BigNumber, - ): Promise { - // 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. - return calculateFillResults( - makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount), - takerAssetFilledAmount, - takerAssetFilledAmount, // Using this so that the gas price is distinct from protocolFeeMultiplier - otherAmount, - ); - } - - async function testCalculateFillResultsAsync( - orderTakerAssetAmount: BigNumber, - takerAssetFilledAmount: BigNumber, - otherAmount: BigNumber, - ): Promise { - const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount); - return libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - takerAssetFilledAmount, // Using this so that the gas price is distinct from protocolFeeMultiplier - otherAmount, - ) - .callAsync(); - } - - testCombinatoriallyWithReferenceFunc( - 'calculateFillResults', - referenceCalculateFillResultsAsync, - testCalculateFillResultsAsync, - [uint256Values, uint256Values, uint256Values], - ); - }); - - describe('explicit tests', () => { - const MAX_UINT256_ROOT = constants.MAX_UINT256_ROOT; - const DEFAULT_GAS_PRICE = new BigNumber(200000); - const DEFAULT_PROTOCOL_FEE_MULTIPLIER = new BigNumber(150000); - - function makeOrder(details?: Partial): Order { - return _.assign({}, EMPTY_ORDER, details); - } - - it('matches the output of the reference function', async () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(2), - makerFee: ONE_ETHER.times(0.0023), - takerFee: ONE_ETHER.times(0.0025), - }); - const takerAssetFilledAmount = ONE_ETHER.dividedToIntegerBy(3); - const expected = calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ); - const actual = await libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(); - expect(actual).to.deep.eq(expected); - }); - - it('reverts if computing `fillResults.makerAssetFilledAmount` overflows', async () => { - // All values need to be large to ensure we don't trigger a RoundingError. - const order = makeOrder({ - makerAssetAmount: MAX_UINT256_ROOT.times(2), - takerAssetAmount: MAX_UINT256_ROOT, - }); - const takerAssetFilledAmount = MAX_UINT256_ROOT; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - takerAssetFilledAmount, - order.makerAssetAmount, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if computing `fillResults.makerFeePaid` overflows', async () => { - // All values need to be large to ensure we don't trigger a RoundingError. - const order = makeOrder({ - makerAssetAmount: MAX_UINT256_ROOT, - takerAssetAmount: MAX_UINT256_ROOT, - makerFee: MAX_UINT256_ROOT.times(11), - }); - const takerAssetFilledAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10); - const makerAssetFilledAmount = getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - makerAssetFilledAmount, - order.makerFee, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if computing `fillResults.takerFeePaid` overflows', async () => { - // All values need to be large to ensure we don't trigger a RoundingError. - const order = makeOrder({ - makerAssetAmount: MAX_UINT256_ROOT, - takerAssetAmount: MAX_UINT256_ROOT, - takerFee: MAX_UINT256_ROOT.times(11), - }); - const takerAssetFilledAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - takerAssetFilledAmount, - order.takerFee, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if `order.takerAssetAmount` is 0', async () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: constants.ZERO_AMOUNT, - }); - const takerAssetFilledAmount = ONE_ETHER; - const expectedError = new LibMathRevertErrors.DivisionByZeroError(); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', async () => { - const order = makeOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: ONE_ETHER, - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const expectedError = new LibMathRevertErrors.RoundingError( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if there is a rounding error computing `makerFeePaid`', async () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER, - makerFee: new BigNumber(100), - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const makerAssetFilledAmount = getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new LibMathRevertErrors.RoundingError( - makerAssetFilledAmount, - order.makerAssetAmount, - order.makerFee, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if there is a rounding error computing `takerFeePaid`', async () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER, - takerFee: new BigNumber(100), - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const makerAssetFilledAmount = getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new LibMathRevertErrors.RoundingError( - makerAssetFilledAmount, - order.makerAssetAmount, - order.takerFee, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if computing `fillResults.protocolFeePaid` overflows', async () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(2), - makerFee: ONE_ETHER.times(0.0023), - takerFee: ONE_ETHER.times(0.0025), - }); - const takerAssetFilledAmount = ONE_ETHER.dividedToIntegerBy(3); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - DEFAULT_GAS_PRICE, - MAX_UINT256, - ); - return expect( - libsContract - .calculateFillResults(order, takerAssetFilledAmount, MAX_UINT256, DEFAULT_GAS_PRICE) - .callAsync(), - ).to.revertWith(expectedError); - }); - - it('reverts if there is a rounding error computing `makerFeePaid`', async () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER, - makerFee: new BigNumber(100), - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const makerAssetFilledAmount = getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new LibMathRevertErrors.RoundingError( - makerAssetFilledAmount, - order.makerAssetAmount, - order.makerFee, - ); - return expect( - libsContract - .calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ) - .callAsync(), - ).to.revertWith(expectedError); - }); - }); - }); - - describe('addFillResults', () => { - describe('explicit tests', () => { - const DEFAULT_FILL_RESULTS = [ - { - makerAssetFilledAmount: ONE_ETHER, - takerAssetFilledAmount: ONE_ETHER.times(2), - makerFeePaid: ONE_ETHER.times(0.001), - takerFeePaid: ONE_ETHER.times(0.002), - protocolFeePaid: ONE_ETHER.times(0.003), - }, - { - makerAssetFilledAmount: ONE_ETHER.times(0.01), - takerAssetFilledAmount: ONE_ETHER.times(2).times(0.01), - makerFeePaid: ONE_ETHER.times(0.001).times(0.01), - takerFeePaid: ONE_ETHER.times(0.002).times(0.01), - protocolFeePaid: ONE_ETHER.times(0.003).times(0.01), - }, - ]; - - it('matches the output of the reference function', async () => { - const [a, b] = DEFAULT_FILL_RESULTS; - const expected = addFillResults(a, b); - const actual = await libsContract.addFillResults(a, b).callAsync(); - expect(actual).to.deep.equal(expected); - }); - - it('reverts if computing `makerAssetFilledAmount` overflows', async () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.makerAssetFilledAmount = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.makerAssetFilledAmount, - b.makerAssetFilledAmount, - ); - return expect(libsContract.addFillResults(a, b).callAsync()).to.revertWith(expectedError); - }); - - it('reverts if computing `takerAssetFilledAmount` overflows', async () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.takerAssetFilledAmount = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.takerAssetFilledAmount, - b.takerAssetFilledAmount, - ); - return expect(libsContract.addFillResults(a, b).callAsync()).to.revertWith(expectedError); - }); - - it('reverts if computing `makerFeePaid` overflows', async () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.makerFeePaid = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.makerFeePaid, - b.makerFeePaid, - ); - return expect(libsContract.addFillResults(a, b).callAsync()).to.revertWith(expectedError); - }); - - it('reverts if computing `takerFeePaid` overflows', async () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.takerFeePaid = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.takerFeePaid, - b.takerFeePaid, - ); - return expect(libsContract.addFillResults(a, b).callAsync()).to.revertWith(expectedError); - }); - - it('reverts if computing `protocolFeePaid` overflows', async () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.protocolFeePaid = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.protocolFeePaid, - b.protocolFeePaid, - ); - return expect(libsContract.addFillResults(a, b).callAsync()).to.revertWith(expectedError); - }); - }); - }); - - const EMPTY_FILL_RESULTS: FillResults = { - makerAssetFilledAmount: constants.ZERO_AMOUNT, - takerAssetFilledAmount: constants.ZERO_AMOUNT, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: constants.ZERO_AMOUNT, - }; - - const EMPTY_MATCHED_FILL_RESULTS: MatchedFillResults = { - left: EMPTY_FILL_RESULTS, - right: EMPTY_FILL_RESULTS, - profitInLeftMakerAsset: constants.ZERO_AMOUNT, - profitInRightMakerAsset: constants.ZERO_AMOUNT, - }; - - const COMMON_MATCHED_FILL_RESULTS = { - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 4), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 4), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 18), - profitInRightMakerAsset: constants.ZERO_AMOUNT, - }; - - function createMatchedFillResults(partialMatchedFillResults: PartialMatchedFillResults): MatchedFillResults { - const matchedFillResults = EMPTY_MATCHED_FILL_RESULTS; - matchedFillResults.left = _.assign({}, EMPTY_FILL_RESULTS, partialMatchedFillResults.left); - matchedFillResults.right = _.assign({}, EMPTY_FILL_RESULTS, partialMatchedFillResults.right); - matchedFillResults.profitInLeftMakerAsset = - partialMatchedFillResults.profitInLeftMakerAsset || constants.ZERO_AMOUNT; - matchedFillResults.profitInRightMakerAsset = - partialMatchedFillResults.profitInRightMakerAsset || constants.ZERO_AMOUNT; - return matchedFillResults; - } - - blockchainTests('calculateMatchedFillResults', async () => { - /** - * Asserts that the results of calling `calculateMatchedFillResults()` is consistent with the results that are expected. - */ - async function assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults: MatchedFillResults, - leftOrder: Order, - rightOrder: Order, - leftOrderTakerAssetFilledAmount: BigNumber, - rightOrderTakerAssetFilledAmount: BigNumber, - protocolFeeMultiplier: BigNumber, - gasPrice: BigNumber, - from?: string, - ): Promise { - const actualMatchedFillResults = await libsContract - .calculateMatchedFillResults( - leftOrder, - rightOrder, - leftOrderTakerAssetFilledAmount, - rightOrderTakerAssetFilledAmount, - protocolFeeMultiplier, - gasPrice, - false, - ) - .callAsync({ from }); - expect(actualMatchedFillResults).to.be.deep.eq(expectedMatchedFillResults); - } - - const ORDER_DEFAULTS = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress: randomAddress(), - takerAddress: randomAddress(), - senderAddress: randomAddress(), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: randomUint256(), - salt: randomUint256(), - exchangeAddress: constants.NULL_ADDRESS, - chainId: 1337, // The chain id for the isolated exchange - }; - - function makeOrder(details?: Partial): Order { - return _.assign({}, ORDER_DEFAULTS, details); - } - - before(async () => { - ORDER_DEFAULTS.exchangeAddress = libsContract.address; - }); - - it('should correctly calculate the results when only the right order is fully filled', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(98, 0), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(75, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(75, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(75, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should correctly calculate the results when only the left order is fully filled', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(15, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(90, 0), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(97, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(14, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(15, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.7835051546391752'), 16), // 92.85% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('92.8571428571428571'), 16), // 92.85% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(2, 0), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should give right maker a better price when rounding', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(83, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(49, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5060240963855421'), 16), // 26.506% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('26.5306122448979591'), 16), // 26.531% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 0), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should give left maker a better sell price when rounding', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(12, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(97, 0), - makerAddress: makerAddressLeft, - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(11, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(10, 0), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should give right maker and right taker a favorable fee price when rounding', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(83, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(49, 0), - makerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - takerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(2650, 0), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(2653, 0), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 0), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should give left maker and left taker a favorable fee price when rounding', async () => { - // Create orders to match - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(12, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(97, 0), - makerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - takerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(11, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(9166, 0), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(9175, 0), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(10, 0), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(1000, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1005, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(2126, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1063, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1000, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1005, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1005, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(503, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.2718720602069614'), 16), // 47.27% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('47.3189087488240827'), 16), // 47.31% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(497, 0), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when orders completely fill each other', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 18), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when left order is completely filled and right order is partially filled', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(20, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(4, 18), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(50, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(50, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 18), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(10, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(10, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 18), - }); - await assertCalculateMatchedFillResultsAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { - const feeRecipientAddress = randomAddress(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - feeRecipientAddress, - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if taker == leftMaker', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - leftOrder.makerAddress, - ); - }); - - it('should transfer the correct amounts if taker == leftMaker', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - rightOrder.makerAddress, - ); - }); - - it('should transfer the correct amounts if taker == leftFeeRecipient', async () => { - const feeRecipientAddressLeft = randomAddress(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress: feeRecipientAddressLeft, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - feeRecipientAddressLeft, - ); - }); - - it('should transfer the correct amounts if taker == rightFeeRecipient', async () => { - const feeRecipientAddressRight = randomAddress(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - feeRecipientAddress: feeRecipientAddressRight, - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - feeRecipientAddressRight, - ); - }); - - it('should transfer the correct amounts if leftMaker == leftFeeRecipient && rightMaker == rightFeeRecipient', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress: makerAddressLeft, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - feeRecipientAddress: makerAddressRight, - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if leftMaker == leftFeeRecipient && leftMakerFeeAsset == leftTakerAsset', async () => { - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeeAssetData: rightOrder.makerAssetData, - feeRecipientAddress: makerAddressLeft, - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if rightMaker == rightFeeRecipient && rightMakerFeeAsset == rightTakerAsset', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeeAssetData: leftOrder.makerAssetData, - feeRecipientAddress: makerAddressRight, - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if rightMaker == rightFeeRecipient && rightTakerAsset == rightMakerFeeAsset && leftMaker == leftFeeRecipient && leftTakerAsset == leftMakerFeeAsset', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress: makerAddressLeft, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeeAssetData: leftOrder.makerAssetData, - feeRecipientAddress: makerAddressRight, - }); - await assertCalculateMatchedFillResultsAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - }); - - blockchainTests('calculateMatchedFillResultsWithMaximalFill', async () => { - /** - * Asserts that the results of calling `calculateMatchedFillResults()` is consistent with the results that are expected. - */ - async function assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults: MatchedFillResults, - leftOrder: Order, - rightOrder: Order, - leftOrderTakerAssetFilledAmount: BigNumber, - rightOrderTakerAssetFilledAmount: BigNumber, - protocolFeeMultiplier: BigNumber, - gasPrice: BigNumber, - from?: string, - ): Promise { - const actualMatchedFillResults = await libsContract - .calculateMatchedFillResults( - leftOrder, - rightOrder, - leftOrderTakerAssetFilledAmount, - rightOrderTakerAssetFilledAmount, - protocolFeeMultiplier, - gasPrice, - true, - ) - .callAsync({ from }); - expect(actualMatchedFillResults).to.be.deep.eq(expectedMatchedFillResults); - } - - const ORDER_DEFAULTS = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress: randomAddress(), - takerAddress: randomAddress(), - senderAddress: randomAddress(), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: randomUint256(), - salt: randomUint256(), - exchangeAddress: constants.NULL_ADDRESS, - chainId: 1337, // The chain id for the isolated exchange - }; - - function makeOrder(details?: Partial): Order { - return _.assign({}, ORDER_DEFAULTS, details); - } - - before(async () => { - ORDER_DEFAULTS.exchangeAddress = libsContract.address; - }); - - it('should transfer correct amounts when right order is fully filled', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(98, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(75, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(75, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(75, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(13, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - new BigNumber(150000), - new BigNumber(100000), - ); - }); - - it('Should transfer correct amounts when left order is fully filled', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(15, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(90, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(196, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(28, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(15, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(105, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(15, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('53.5714285714285714'), 16), // 53.57% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('53.5714285714285714'), 16), // 53.57% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: constants.ZERO_AMOUNT, - profitInRightMakerAsset: Web3Wrapper.toBaseUnitAmount(15, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - new BigNumber(150000), - new BigNumber(100000), - ); - }); - - it('Should transfer correct amounts when left order is fully filled', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(87, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(48, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(29, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('33.3333333333333333'), 16), // 33.33% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('33.3333333333333333'), 16), // 33.33% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: constants.ZERO_AMOUNT, - profitInRightMakerAsset: Web3Wrapper.toBaseUnitAmount(7, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should fully fill both orders and pay out profit in both maker assets', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(7, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(4, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(8, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(6, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(7, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(4, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(8, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(6, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(1, 0), - profitInRightMakerAsset: Web3Wrapper.toBaseUnitAmount(4, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should give left maker a better sell price when rounding', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(12, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(97, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(11, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(10, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should give right maker and right taker a favorable fee price when rounding', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(87, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(48, 0), - makerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - takerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(22, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(29, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(16, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(3333, 0), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(3333, 0), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInRightMakerAsset: Web3Wrapper.toBaseUnitAmount(7, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should give left maker and left taker a favorable fee price when rounding', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(12, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(97, 0), - makerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - takerFee: Web3Wrapper.toBaseUnitAmount(10000, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(11, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(9166, 0), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(9175, 0), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(89, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInLeftMakerAsset: Web3Wrapper.toBaseUnitAmount(10, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - const expectedMatchedFillResults = { - ...COMMON_MATCHED_FILL_RESULTS, - left: { - ...COMMON_MATCHED_FILL_RESULTS.left, - makerFeePaid: Web3Wrapper.toBaseUnitAmount(10, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(10, 16), - }, - }; - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - const rightOrder2 = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - }); - const expectedMatchedFillResults2 = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(45, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(45, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults2, - leftOrder, - rightOrder2, - Web3Wrapper.toBaseUnitAmount(10, 18), - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => { - const leftOrder = makeOrder({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(1000, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1005, 0), - }); - const rightOrder = makeOrder({ - makerAddress: makerAddressRight, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(2126, 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1063, 0), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1000, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1005, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(2000, 0), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(1000, 0), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('94.0733772342427093'), 16), // 94.07% - takerFeePaid: Web3Wrapper.toBaseUnitAmount(new BigNumber('94.0733772342427093'), 16), // 94.07% - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInRightMakerAsset: Web3Wrapper.toBaseUnitAmount(995, 0), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const expectedMatchedFillResults = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(100, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(10, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(10, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - profitInRightMakerAsset: Web3Wrapper.toBaseUnitAmount(3, 18), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - // 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 leftOrder2 = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - }); - const expectedMatchedFillResults2 = createMatchedFillResults({ - left: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(45, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - right: { - makerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(45, 18), - takerAssetFilledAmount: Web3Wrapper.toBaseUnitAmount(90, 18), - makerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - takerFeePaid: Web3Wrapper.toBaseUnitAmount(90, 16), - protocolFeePaid: Web3Wrapper.toBaseUnitAmount(15, 9), - }, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - expectedMatchedFillResults2, - leftOrder2, - rightOrder, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(10, 18), - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 5), - ); - }); - - it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { - const feeRecipientAddress = randomAddress(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - feeRecipientAddress, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if taker == leftMaker', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - leftOrder.makerAddress, - ); - }); - - it('should transfer the correct amounts if taker == rightMaker', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - rightOrder.makerAddress, - ); - }); - - it('should transfer the correct amounts if taker == leftFeeRecipient', async () => { - const feeRecipientAddress = randomAddress(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - feeRecipientAddress, - ); - }); - - it('should transfer the correct amounts if taker == rightFeeRecipient', async () => { - const feeRecipientAddress = randomAddress(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - feeRecipientAddress, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - feeRecipientAddress, - ); - }); - - it('should transfer the correct amounts if leftMaker == leftFeeRecipient && rightMaker == rightFeeRecipient', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - feeRecipientAddress: makerAddressLeft, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - feeRecipientAddress: makerAddressRight, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if leftMaker == leftFeeRecipient && leftMakerFeeAsset == leftTakerAsset', async () => { - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - }); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeeAssetData: rightOrder.makerAssetData, - feeRecipientAddress: makerAddressLeft, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if rightMaker == rightFeeRecipient && rightMakerFeeAsset == rightTakerAsset', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeeAssetData: leftOrder.makerAssetData, - feeRecipientAddress: makerAddressRight, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - - it('should transfer the correct amounts if rightMaker == rightFeeRecipient && rightTakerAsset == rightMakerFeeAsset && leftMaker == leftFeeRecipient && leftTakerAsset == leftMakerFeeAsset', async () => { - const makerFeeAssetData = randomAssetData(); - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(5, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - makerFeeAssetData, - feeRecipientAddress: makerAddressLeft, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(2, 18), - makerFeeAssetData: leftOrder.makerAssetData, - feeRecipientAddress: makerAddressRight, - }); - await assertCalculateMatchedFillResultsWithMaximalFillAsync( - COMMON_MATCHED_FILL_RESULTS, - leftOrder, - rightOrder, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - Web3Wrapper.toBaseUnitAmount(15, 4), - Web3Wrapper.toBaseUnitAmount(1, 0), - ); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/exchange-libs/test/lib_order.ts b/contracts/exchange-libs/test/lib_order.ts deleted file mode 100644 index 7b8a9ea340..0000000000 --- a/contracts/exchange-libs/test/lib_order.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { blockchainTests, constants, describe, expect, orderHashUtils } from '@0x/contracts-test-utils'; -import { eip712Utils } from '@0x/order-utils'; -import { Order } from '@0x/types'; -import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { TestLibOrderContract } from './wrappers'; - -import { artifacts } from './artifacts'; - -blockchainTests('LibOrder', env => { - let libOrderContract: TestLibOrderContract; - - const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH); - const randomHash = () => hexUtils.random(constants.WORD_LENGTH); - const randomUint256 = () => new BigNumber(randomHash()); - const randomAssetData = () => hexUtils.random(36); - - const EMPTY_ORDER: Order = { - exchangeAddress: constants.NULL_ADDRESS, - chainId: 0, - senderAddress: constants.NULL_ADDRESS, - makerAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerAssetAmount: constants.ZERO_AMOUNT, - takerAssetAmount: constants.ZERO_AMOUNT, - makerAssetData: constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - salt: constants.ZERO_AMOUNT, - feeRecipientAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: constants.ZERO_AMOUNT, - }; - - before(async () => { - libOrderContract = await TestLibOrderContract.deployFrom0xArtifactAsync( - artifacts.TestLibOrder, - env.provider, - env.txDefaults, - {}, - ); - }); - - /** - * Tests the `getTypedDataHash()` function against a reference hash. - */ - async function testGetTypedDataHashAsync(order: Order): Promise { - const expectedHash = orderHashUtils.getOrderHashHex(order); - const domainHash = ethUtil.bufferToHex( - signTypedDataUtils.generateDomainHash({ - chainId: order.chainId, - verifyingContract: order.exchangeAddress, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - }), - ); - const actualHash = await libOrderContract.getTypedDataHash(order, domainHash).callAsync(); - expect(actualHash).to.be.eq(expectedHash); - } - - describe('getTypedDataHash', () => { - it('should correctly hash an empty order', async () => { - await testGetTypedDataHashAsync({ - ...EMPTY_ORDER, - exchangeAddress: libOrderContract.address, - }); - }); - - it('should correctly hash a non-empty order', async () => { - await testGetTypedDataHashAsync({ - exchangeAddress: libOrderContract.address, - chainId: 1337, - senderAddress: randomAddress(), - makerAddress: randomAddress(), - takerAddress: randomAddress(), - makerFee: randomUint256(), - takerFee: randomUint256(), - makerAssetAmount: randomUint256(), - takerAssetAmount: randomUint256(), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - salt: randomUint256(), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: randomUint256(), - }); - }); - - it('orderHash should differ if the domain hash is different', async () => { - const domainHash1 = ethUtil.bufferToHex( - signTypedDataUtils.generateDomainHash({ - chainId: EMPTY_ORDER.chainId, - verifyingContract: EMPTY_ORDER.exchangeAddress, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - }), - ); - const domainHash2 = ethUtil.bufferToHex( - signTypedDataUtils.generateDomainHash({ - verifyingContract: EMPTY_ORDER.exchangeAddress, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - chainId: 1337, - }), - ); - const orderHashHex1 = await libOrderContract.getTypedDataHash(EMPTY_ORDER, domainHash1).callAsync(); - const orderHashHex2 = await libOrderContract.getTypedDataHash(EMPTY_ORDER, domainHash2).callAsync(); - expect(orderHashHex1).to.be.not.equal(orderHashHex2); - }); - }); - - /** - * Tests the `getStructHash()` function against a reference hash. - */ - async function testGetStructHashAsync(order: Order): Promise { - const typedData = eip712Utils.createOrderTypedData(order); - const expectedHash = ethUtil.bufferToHex(signTypedDataUtils.generateTypedDataHashWithoutDomain(typedData)); - const actualHash = await libOrderContract.getStructHash(order).callAsync(); - expect(actualHash).to.be.eq(expectedHash); - } - - describe('getStructHash', () => { - it('should correctly hash an empty order', async () => { - await testGetStructHashAsync(EMPTY_ORDER); - }); - - it('should correctly hash a non-empty order', async () => { - await testGetStructHashAsync({ - // The domain is not used in this test, so it's okay if it is left empty. - exchangeAddress: constants.NULL_ADDRESS, - chainId: 0, - senderAddress: randomAddress(), - makerAddress: randomAddress(), - takerAddress: randomAddress(), - makerFee: randomUint256(), - takerFee: randomUint256(), - makerAssetAmount: randomUint256(), - takerAssetAmount: randomUint256(), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - salt: randomUint256(), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: randomUint256(), - }); - }); - }); -}); diff --git a/contracts/exchange-libs/test/lib_zero_ex_transaction.ts b/contracts/exchange-libs/test/lib_zero_ex_transaction.ts deleted file mode 100644 index c13e94dcef..0000000000 --- a/contracts/exchange-libs/test/lib_zero_ex_transaction.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { blockchainTests, constants, describe, expect, transactionHashUtils } from '@0x/contracts-test-utils'; -import { eip712Utils } from '@0x/order-utils'; -import { ZeroExTransaction } from '@0x/types'; -import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { TestLibZeroExTransactionContract } from './wrappers'; - -import { artifacts } from './artifacts'; - -blockchainTests('LibZeroExTransaction', env => { - let libZeroExTransactionContract: TestLibZeroExTransactionContract; - - const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH); - const randomHash = () => hexUtils.random(constants.WORD_LENGTH); - const randomUint256 = () => new BigNumber(randomHash()); - const randomAssetData = () => hexUtils.random(36); - - const EMPTY_TRANSACTION: ZeroExTransaction = { - salt: constants.ZERO_AMOUNT, - expirationTimeSeconds: constants.ZERO_AMOUNT, - gasPrice: constants.ZERO_AMOUNT, - signerAddress: constants.NULL_ADDRESS, - data: constants.NULL_BYTES, - domain: { - verifyingContract: constants.NULL_ADDRESS, - chainId: 0, - }, - }; - - before(async () => { - libZeroExTransactionContract = await TestLibZeroExTransactionContract.deployFrom0xArtifactAsync( - artifacts.TestLibZeroExTransaction, - env.provider, - env.txDefaults, - {}, - ); - }); - - /** - * Tests the `getTypedDataHash()` function against a reference hash. - */ - async function testGetTypedDataHashAsync(transaction: ZeroExTransaction): Promise { - const expectedHash = transactionHashUtils.getTransactionHashHex(transaction); - const domainHash = ethUtil.bufferToHex( - signTypedDataUtils.generateDomainHash({ - ...transaction.domain, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - }), - ); - const actualHash = await libZeroExTransactionContract.getTypedDataHash(transaction, domainHash).callAsync(); - expect(actualHash).to.be.eq(expectedHash); - } - - describe('getTypedDataHash', () => { - it('should correctly hash an empty transaction', async () => { - await testGetTypedDataHashAsync({ - ...EMPTY_TRANSACTION, - domain: { - ...EMPTY_TRANSACTION.domain, - verifyingContract: libZeroExTransactionContract.address, - }, - }); - }); - - it('should correctly hash a non-empty transaction', async () => { - await testGetTypedDataHashAsync({ - salt: randomUint256(), - expirationTimeSeconds: randomUint256(), - gasPrice: randomUint256(), - signerAddress: randomAddress(), - data: randomAssetData(), - domain: { - ...EMPTY_TRANSACTION.domain, - verifyingContract: libZeroExTransactionContract.address, - }, - }); - }); - it('transactionHash should differ if the domain hash is different', async () => { - const domainHash1 = ethUtil.bufferToHex( - signTypedDataUtils.generateDomainHash({ - ...EMPTY_TRANSACTION.domain, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - }), - ); - const domainHash2 = ethUtil.bufferToHex( - signTypedDataUtils.generateDomainHash({ - ...EMPTY_TRANSACTION.domain, - name: constants.EIP712_DOMAIN_NAME, - version: constants.EIP712_DOMAIN_VERSION, - chainId: 1337, - }), - ); - const transactionHashHex1 = await libZeroExTransactionContract - .getTypedDataHash(EMPTY_TRANSACTION, domainHash1) - .callAsync(); - const transactionHashHex2 = await libZeroExTransactionContract - .getTypedDataHash(EMPTY_TRANSACTION, domainHash2) - .callAsync(); - expect(transactionHashHex1).to.be.not.equal(transactionHashHex2); - }); - }); - - /** - * Tests the `getStructHash()` function against a reference hash. - */ - async function testGetStructHashAsync(transaction: ZeroExTransaction): Promise { - const typedData = eip712Utils.createZeroExTransactionTypedData(transaction); - const expectedHash = ethUtil.bufferToHex(signTypedDataUtils.generateTypedDataHashWithoutDomain(typedData)); - const actualHash = await libZeroExTransactionContract.getStructHash(transaction).callAsync(); - expect(actualHash).to.be.eq(expectedHash); - } - - describe('getStructHash', () => { - it('should correctly hash an empty transaction', async () => { - await testGetStructHashAsync(EMPTY_TRANSACTION); - }); - - it('should correctly hash a non-empty transaction', async () => { - await testGetStructHashAsync({ - salt: randomUint256(), - expirationTimeSeconds: randomUint256(), - gasPrice: randomUint256(), - signerAddress: randomAddress(), - data: randomAssetData(), - // The domain is not used in this test, so it's okay if it is left empty. - domain: { - verifyingContract: constants.NULL_ADDRESS, - chainId: 0, - }, - }); - }); - }); -}); diff --git a/contracts/exchange-libs/test/reference_functions.ts b/contracts/exchange-libs/test/reference_functions.ts deleted file mode 100644 index 08fdf9b7ac..0000000000 --- a/contracts/exchange-libs/test/reference_functions.ts +++ /dev/null @@ -1,328 +0,0 @@ -import { constants, describe, expect } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { BigNumber, LibMathRevertErrors } from '@0x/utils'; -import * as _ from 'lodash'; - -import { - addFillResults, - getPartialAmountCeil, - getPartialAmountFloor, - isRoundingErrorCeil, - isRoundingErrorFloor, - safeGetPartialAmountCeil, - safeGetPartialAmountFloor, -} from '../src/reference_functions'; - -describe('Reference Functions', () => { - const { ONE_ETHER, MAX_UINT256, MAX_UINT256_ROOT, ZERO_AMOUNT } = constants; - describe('LibFillResults', () => { - describe('addFillResults', () => { - const DEFAULT_FILL_RESULTS = [ - { - makerAssetFilledAmount: ONE_ETHER, - takerAssetFilledAmount: ONE_ETHER.times(2), - makerFeePaid: ONE_ETHER.times(0.001), - takerFeePaid: ONE_ETHER.times(0.002), - protocolFeePaid: ONE_ETHER.times(0.003), - }, - { - makerAssetFilledAmount: ONE_ETHER.times(0.01), - takerAssetFilledAmount: ONE_ETHER.times(2).times(0.01), - makerFeePaid: ONE_ETHER.times(0.001).times(0.01), - takerFeePaid: ONE_ETHER.times(0.002).times(0.01), - protocolFeePaid: ONE_ETHER.times(0.003).times(0.01), - }, - ]; - - it('reverts if computing `makerAssetFilledAmount` overflows', () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.makerAssetFilledAmount = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.makerAssetFilledAmount, - b.makerAssetFilledAmount, - ); - expect(() => addFillResults(a, b)).to.throw(expectedError.message); - }); - - it('reverts if computing `takerAssetFilledAmount` overflows', () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.takerAssetFilledAmount = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.takerAssetFilledAmount, - b.takerAssetFilledAmount, - ); - expect(() => addFillResults(a, b)).to.throw(expectedError.message); - }); - - it('reverts if computing `makerFeePaid` overflows', () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.makerFeePaid = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.makerFeePaid, - b.makerFeePaid, - ); - expect(() => addFillResults(a, b)).to.throw(expectedError.message); - }); - - it('reverts if computing `takerFeePaid` overflows', () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.takerFeePaid = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.takerFeePaid, - b.takerFeePaid, - ); - expect(() => addFillResults(a, b)).to.throw(expectedError.message); - }); - - it('reverts if computing `protocolFeePaid` overflows', () => { - const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS); - b.protocolFeePaid = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a.protocolFeePaid, - b.protocolFeePaid, - ); - expect(() => addFillResults(a, b)).to.throw(expectedError.message); - }); - }); - }); - - describe('LibMath', () => { - describe('getPartialAmountFloor', () => { - describe('explicit tests', () => { - it('reverts if `denominator` is zero', () => { - const numerator = ONE_ETHER; - const denominator = ZERO_AMOUNT; - const target = ONE_ETHER.times(0.01); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.DivisionByZero, - numerator.times(target), - denominator, - ); - return expect(() => getPartialAmountFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `numerator * target` overflows', () => { - const numerator = MAX_UINT256; - const denominator = ONE_ETHER.dividedToIntegerBy(2); - const target = MAX_UINT256_ROOT.times(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - numerator, - target, - ); - return expect(() => getPartialAmountFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - }); - }); - - describe('getPartialAmountCeil', () => { - describe('explicit tests', () => { - it('reverts if `denominator` is zero', () => { - const numerator = ONE_ETHER; - const denominator = ZERO_AMOUNT; - const target = ONE_ETHER.times(0.01); - // This will actually manifest as a subtraction underflow. - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - denominator, - new BigNumber(1), - ); - return expect(() => getPartialAmountCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `numerator * target` overflows', () => { - const numerator = MAX_UINT256; - const denominator = ONE_ETHER.dividedToIntegerBy(2); - const target = MAX_UINT256_ROOT.times(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - numerator, - target, - ); - return expect(() => getPartialAmountCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - }); - }); - - describe('safeGetPartialAmountFloor', () => { - describe('explicit tests', () => { - it('reverts for a rounding error', () => { - const numerator = new BigNumber(1e3); - const denominator = new BigNumber(1e4); - const target = new BigNumber(333); - const expectedError = new LibMathRevertErrors.RoundingError(numerator, denominator, target); - return expect(() => safeGetPartialAmountFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `denominator` is zero', () => { - const numerator = ONE_ETHER; - const denominator = ZERO_AMOUNT; - const target = ONE_ETHER.times(0.01); - const expectedError = new LibMathRevertErrors.DivisionByZeroError(); - return expect(() => safeGetPartialAmountFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `numerator * target` overflows', () => { - const numerator = MAX_UINT256; - const denominator = ONE_ETHER.dividedToIntegerBy(2); - const target = MAX_UINT256_ROOT.times(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - numerator, - target, - ); - return expect(() => safeGetPartialAmountFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - }); - }); - - describe('safeGetPartialAmountCeil', () => { - describe('explicit tests', () => { - it('reverts for a rounding error', () => { - const numerator = new BigNumber(1e3); - const denominator = new BigNumber(1e4); - const target = new BigNumber(333); - const expectedError = new LibMathRevertErrors.RoundingError(numerator, denominator, target); - return expect(() => safeGetPartialAmountCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `denominator` is zero', () => { - const numerator = ONE_ETHER; - const denominator = ZERO_AMOUNT; - const target = ONE_ETHER.times(0.01); - const expectedError = new LibMathRevertErrors.DivisionByZeroError(); - return expect(() => safeGetPartialAmountCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `numerator * target` overflows', () => { - const numerator = MAX_UINT256; - const denominator = ONE_ETHER.dividedToIntegerBy(2); - const target = MAX_UINT256_ROOT.times(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - numerator, - target, - ); - return expect(() => safeGetPartialAmountCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - }); - }); - - describe('isRoundingErrorFloor', () => { - describe('explicit tests', () => { - it('returns true when `numerator * target / denominator` produces an error >= 0.1%', async () => { - const numerator = new BigNumber(100); - const denominator = new BigNumber(102); - const target = new BigNumber(52); - // tslint:disable-next-line: boolean-naming - const actual = isRoundingErrorFloor(numerator, denominator, target); - expect(actual).to.eq(true); - }); - - it('returns false when `numerator * target / denominator` produces an error < 0.1%', async () => { - const numerator = new BigNumber(100); - const denominator = new BigNumber(101); - const target = new BigNumber(92); - // tslint:disable-next-line: boolean-naming - const actual = isRoundingErrorFloor(numerator, denominator, target); - expect(actual).to.eq(false); - }); - - it('reverts if `denominator` is zero', () => { - const numerator = ONE_ETHER; - const denominator = ZERO_AMOUNT; - const target = ONE_ETHER.times(0.01); - const expectedError = new LibMathRevertErrors.DivisionByZeroError(); - return expect(() => isRoundingErrorFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `numerator * target` overflows', () => { - const numerator = MAX_UINT256; - const denominator = ONE_ETHER.dividedToIntegerBy(2); - const target = MAX_UINT256_ROOT.times(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - numerator, - target, - ); - return expect(() => isRoundingErrorFloor(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - }); - }); - - describe('isRoundingErrorCeil', () => { - describe('explicit tests', () => { - it('returns true when `numerator * target / (denominator - 1)` produces an error >= 0.1%', async () => { - const numerator = new BigNumber(100); - const denominator = new BigNumber(101); - const target = new BigNumber(92); - // tslint:disable-next-line: boolean-naming - const actual = isRoundingErrorCeil(numerator, denominator, target); - expect(actual).to.eq(true); - }); - - it('returns false when `numerator * target / (denominator - 1)` produces an error < 0.1%', async () => { - const numerator = new BigNumber(100); - const denominator = new BigNumber(102); - const target = new BigNumber(52); - // tslint:disable-next-line: boolean-naming - const actual = isRoundingErrorCeil(numerator, denominator, target); - expect(actual).to.eq(false); - }); - - it('reverts if `denominator` is zero', () => { - const numerator = ONE_ETHER; - const denominator = ZERO_AMOUNT; - const target = ONE_ETHER.times(0.01); - const expectedError = new LibMathRevertErrors.DivisionByZeroError(); - return expect(() => isRoundingErrorCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - - it('reverts if `numerator * target` overflows', () => { - const numerator = MAX_UINT256; - const denominator = ONE_ETHER.dividedToIntegerBy(2); - const target = MAX_UINT256_ROOT.times(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - numerator, - target, - ); - return expect(() => isRoundingErrorCeil(numerator, denominator, target)).to.throw( - expectedError.message, - ); - }); - }); - }); - }); -}); diff --git a/contracts/exchange-libs/test/utils/index.ts b/contracts/exchange-libs/test/utils/index.ts deleted file mode 100644 index 5388544a28..0000000000 --- a/contracts/exchange-libs/test/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { SchemaDefinition, SchemaParameterDefinition, stringifySchema } from './schema'; diff --git a/contracts/exchange-libs/test/utils/schema.ts b/contracts/exchange-libs/test/utils/schema.ts deleted file mode 100644 index 04d4160887..0000000000 --- a/contracts/exchange-libs/test/utils/schema.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as _ from 'lodash'; - -export interface SchemaParameterDefinition { - name: string; - type: string; -} - -export interface SchemaDefinition { - name: string; - parameters: SchemaParameterDefinition[]; -} - -/** - * Convert a schema definition into a function string. - * @param The schema definition. - * @return The function string of the schema definition.. - */ -export function stringifySchema(schema: SchemaDefinition): string { - const parameters = []; - for (const parameter of schema.parameters) { - parameters.push(`${parameter.type} ${parameter.name}`); - } - return `${schema.name}(${parameters.join(',')})`; -} diff --git a/contracts/exchange-libs/test/wrappers.ts b/contracts/exchange-libs/test/wrappers.ts deleted file mode 100644 index c0205dc234..0000000000 --- a/contracts/exchange-libs/test/wrappers.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/i_wallet'; -export * from '../test/generated-wrappers/lib_e_i_p712_exchange_domain'; -export * from '../test/generated-wrappers/lib_exchange_rich_errors'; -export * from '../test/generated-wrappers/lib_fill_results'; -export * from '../test/generated-wrappers/lib_math'; -export * from '../test/generated-wrappers/lib_math_rich_errors'; -export * from '../test/generated-wrappers/lib_order'; -export * from '../test/generated-wrappers/lib_zero_ex_transaction'; -export * from '../test/generated-wrappers/test_lib_e_i_p712_exchange_domain'; -export * from '../test/generated-wrappers/test_lib_fill_results'; -export * from '../test/generated-wrappers/test_lib_math'; -export * from '../test/generated-wrappers/test_lib_order'; -export * from '../test/generated-wrappers/test_lib_zero_ex_transaction'; diff --git a/contracts/exchange-libs/truffle-config.js b/contracts/exchange-libs/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/exchange-libs/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/exchange-libs/tsconfig.json b/contracts/exchange-libs/tsconfig.json deleted file mode 100644 index 26f76e6e57..0000000000 --- a/contracts/exchange-libs/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./scripts/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/IWallet.json", - "generated-artifacts/LibEIP712ExchangeDomain.json", - "generated-artifacts/LibExchangeRichErrors.json", - "generated-artifacts/LibMath.json", - "generated-artifacts/LibMathRichErrors.json", - "generated-artifacts/LibOrder.json", - "generated-artifacts/LibZeroExTransaction.json", - "test/generated-artifacts/IWallet.json", - "test/generated-artifacts/LibEIP712ExchangeDomain.json", - "test/generated-artifacts/LibExchangeRichErrors.json", - "test/generated-artifacts/LibFillResults.json", - "test/generated-artifacts/LibMath.json", - "test/generated-artifacts/LibMathRichErrors.json", - "test/generated-artifacts/LibOrder.json", - "test/generated-artifacts/LibZeroExTransaction.json", - "test/generated-artifacts/TestLibEIP712ExchangeDomain.json", - "test/generated-artifacts/TestLibFillResults.json", - "test/generated-artifacts/TestLibMath.json", - "test/generated-artifacts/TestLibOrder.json", - "test/generated-artifacts/TestLibZeroExTransaction.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/exchange-libs/tslint.json b/contracts/exchange-libs/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/exchange-libs/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/exchange/.npmignore b/contracts/exchange/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/exchange/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/exchange/CHANGELOG.json b/contracts/exchange/CHANGELOG.json deleted file mode 100644 index 4bd0f44e44..0000000000 --- a/contracts/exchange/CHANGELOG.json +++ /dev/null @@ -1,1136 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "3.2.38", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "3.2.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "3.2.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "3.2.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "3.2.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "3.2.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "3.2.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "3.2.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "3.2.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "3.2.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "3.2.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "3.2.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "3.2.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "3.2.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "3.2.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "3.2.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "3.2.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "3.2.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "3.2.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "3.2.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "3.2.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "3.2.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "3.2.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "3.2.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "3.2.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "3.2.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "3.2.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "3.2.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "3.2.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "3.2.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "3.2.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "3.2.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "3.2.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "3.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "3.2.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "3.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "3.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "3.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.2.0", - "changes": [ - { - "note": "Flip `LibExchangeRichErrorDecoder` to an actual library.", - "pr": 2462 - }, - { - "note": "Remove dependency on `DevUtils` for asset data encoding/decoding", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Uses updated event decoding to properly decodes arrays and objects.", - "pr": 2443 - } - ], - "timestamp": 1579682890 - }, - { - "timestamp": 1578272714, - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export ExchangeRevertErrors", - "pr": 2321 - }, - { - "note": "Round up in `marketBuyOrdersNoThrow()` so `marketBuyOrdersFillOrKill()` doesn't throw up.", - "pr": 2338 - }, - { - "note": "LocalBalanceStore.create and constructor now require an instance of DevUtilsContract", - "pr": 2304 - }, - { - "note": "In LocalBalanceStore, `transferAsset` is now `transferAssetAsync`", - "pr": 2304 - }, - { - "note": "Test utility classes AssetWrapper, MatchOrderTester, and OrderFactoryFromScenario constructors now require an instance of DevUtilsContract", - "pr": 2304 - }, - { - "note": "In OrderFactoryFromScenario, `generateOrder` is now `generateOrderAsync`", - "pr": 2304 - }, - { - "note": "Use new/cheaper reentrancy guard/mutex", - "pr": 1699 - }, - { - "note": "Update domain separator", - "pr": 1742 - }, - { - "note": "Refactor `executeTransaction` to take `ZeroExTransaction` struct as input", - "pr": 1753 - }, - { - "note": "Refactor example contracts that use `executeTransaction`", - "pr": 1753 - }, - { - "note": "Upgrade all string reverts to rich reverts", - "pr": 1761 - }, - { - "note": "Add support for `SignatureType.OrderValidator` for orders", - "pr": 1774 - }, - { - "note": "Add support for `SignatureType.WalletOrderValidator` for orders", - "pr": 1774 - }, - { - "note": "Add a `bytes` return value to `executeTransaction`, which is equal to the encoded return data of the underlying Exchange function call", - "pr": 1793 - }, - { - "note": "Implement `batchExecuteTransactions`", - "pr": 1793 - }, - { - "note": "Refactor preSign to be compatible with `executeTransaction`", - "pr": 1793 - }, - { - "note": "Remove ZRX fees in lieu of arbitrary maker and taker fee tokens.", - "pr": 1819 - }, - { - "note": "Incorporate Multi-asset and ERC1155 tests into `fillOrder` and `matchOrders` tests", - "pr": 1819 - }, - { - "note": "Swap fill order from maker -> taker to taker -> maker", - "pr": 1819 - }, - { - "note": "Avoid redundant transfer in `fillOrder()` and `matchOrders()` when maker/taker is the same as feeRecipient and assets are the same", - "pr": 1819 - }, - { - "note": "Implement `cancelOrderNoThrow` and `batchCancelOrdersNoThrow` functions", - "pr": 1827 - }, - { - "note": "`executeTransaction` will now revert if the input transaction is expired", - "pr": 1832 - }, - { - "note": "Log an `TransactionExecuted` event when an `executeTransaction` call is successful", - "pr": 1832 - }, - { - "note": "Return a FillResults array for batch fill variants", - "pr": 1834 - }, - { - "note": "Add `MixinTransferSimulator` contract for simulating multiple transfers on-chain", - "pr": 1868 - }, - { - "note": "Add `EIP1271Wallet` signature type", - "pr": 1885 - }, - { - "note": "Remove `WalletOrderValidator` and `OrderValidator` signature types", - "pr": 1885 - }, - { - "note": "Make the regular `Validator` signature type have EIP1271 behavior", - "pr": 1885 - }, - { - "note": "Always check signature types that are validated via contract (not just on first fill).", - "pr": 1885 - }, - { - "note": "Remove unecessary rich revert error types.", - "pr": 1885 - }, - { - "note": "Add `IEIP1271Wallet` interface", - "pr": 1885 - }, - { - "note": "Add `validatorAddress` field to `SignatureValidatorError` rich reverts", - "pr": 1885 - }, - { - "note": "Make `calculateMatchedFillResults` public", - "pr": 1885 - }, - { - "note": "Updated RichErrors to the library pattern", - "pr": 1913 - }, - { - "note": "Rewrote _dispatchTransferFrom in Solidity", - "pr": 2020 - }, - { - "note": "Add `TestIsolatedExchange` contract and `IsolatedExchangeWrapper` test class", - "pr": 2031 - }, - { - "note": "Add `ReferenceFunctions` as package export.", - "pr": 2031 - }, - { - "note": "Remove `TestExchangeMath.sol`. Exchange math functions are now tested in the `exchange-libs` package and reference implementations are available there as well.", - "pr": 2031 - }, - { - "note": "Remove functions from `TestExchangeInternals.sol` that are no longer tested in this package.", - "pr": 2031 - }, - { - "note": "Remove `_assertValidFill()`", - "pr": 2031 - }, - { - "note": "Add `wrapper_unit_tests` tests and `TestWrapperFunctions` contract", - "pr": 2042 - }, - { - "note": "Disallow `signerAddress == 0` in signature validation functions.", - "pr": 2042 - }, - { - "note": "Update `Wallet` signature type behavior to be in line with v2.1.", - "pr": 2042 - }, - { - "note": "Add (semi) automated reentrancy tests and remove manual ones", - "pr": 2042 - }, - { - "note": "Refactor to use new `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries", - "pr": 2055 - }, - { - "note": "Remove `LibExchangeRichErrors` and `IExchangeRichErrors`", - "pr": 2055 - }, - { - "note": "Use built in selectors instead of `LibExchangeSelectors` constants", - "pr": 2055 - }, - { - "note": "Move `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` in `exchange-libs` package", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Rename `marketSellOrders` and `marketBuyOrders` back to `marketSellOrdersNoThrow` and `marketBuyOrdersNoThrow`.", - "pr": 2075 - }, - { - "note": "Introduce new `marketSellOrdersFillOrKill` and `marketBuyOrdersFillOrKill` functions.", - "pr": 2075 - }, - { - "note": "Use `abi.decode()` in `LibExchangeRichErrorDecoder` over `LibBytes`.", - "pr": 2075 - }, - { - "note": "Overridden functions in `ReentrancyTester` now return sane values.", - "pr": 2075 - } - ], - "timestamp": 1575296764 - }, - { - "version": "2.2.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "2.2.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "2.2.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduced new export ExchangeRevertErrors", - "pr": 2321 - }, - { - "note": "Round up in `marketBuyOrdersNoThrow()` so `marketBuyOrdersFillOrKill()` doesn't throw up.", - "pr": 2338 - } - ], - "timestamp": 1574030254 - }, - { - "version": "2.2.0-beta.1", - "changes": [ - { - "note": "LocalBalanceStore.create and constructor now require an instance of DevUtilsContract", - "pr": 2304 - }, - { - "note": "In LocalBalanceStore, `transferAsset` is now `transferAssetAsync`", - "pr": 2304 - }, - { - "note": "Test utility classes AssetWrapper, MatchOrderTester, and OrderFactoryFromScenario constructors now require an instance of DevUtilsContract", - "pr": 2304 - }, - { - "note": "In OrderFactoryFromScenario, `generateOrder` is now `generateOrderAsync`", - "pr": 2304 - } - ], - "timestamp": 1573159180 - }, - { - "version": "2.2.0-beta.0", - "changes": [ - { - "note": "Use new/cheaper reentrancy guard/mutex", - "pr": 1699 - }, - { - "note": "Update domain separator", - "pr": 1742 - }, - { - "note": "Refactor `executeTransaction` to take `ZeroExTransaction` struct as input", - "pr": 1753 - }, - { - "note": "Refactor example contracts that use `executeTransaction`", - "pr": 1753 - }, - { - "note": "Upgrade all string reverts to rich reverts", - "pr": 1761 - }, - { - "note": "Add support for `SignatureType.OrderValidator` for orders", - "pr": 1774 - }, - { - "note": "Add support for `SignatureType.WalletOrderValidator` for orders", - "pr": 1774 - }, - { - "note": "Add a `bytes` return value to `executeTransaction`, which is equal to the encoded return data of the underlying Exchange function call", - "pr": 1793 - }, - { - "note": "Implement `batchExecuteTransactions`", - "pr": 1793 - }, - { - "note": "Refactor preSign to be compatible with `executeTransaction`", - "pr": 1793 - }, - { - "note": "Remove ZRX fees in lieu of arbitrary maker and taker fee tokens.", - "pr": 1819 - }, - { - "note": "Incorporate Multi-asset and ERC1155 tests into `fillOrder` and `matchOrders` tests", - "pr": 1819 - }, - { - "note": "Swap fill order from maker -> taker to taker -> maker", - "pr": 1819 - }, - { - "note": "Avoid redundant transfer in `fillOrder()` and `matchOrders()` when maker/taker is the same as feeRecipient and assets are the same", - "pr": 1819 - }, - { - "note": "Implement `cancelOrderNoThrow` and `batchCancelOrdersNoThrow` functions", - "pr": 1827 - }, - { - "note": "`executeTransaction` will now revert if the input transaction is expired", - "pr": 1832 - }, - { - "note": "Log an `TransactionExecuted` event when an `executeTransaction` call is successful", - "pr": 1832 - }, - { - "note": "Return a FillResults array for batch fill variants", - "pr": 1834 - }, - { - "note": "Add `MixinTransferSimulator` contract for simulating multiple transfers on-chain", - "pr": 1868 - }, - { - "note": "Add `EIP1271Wallet` signature type", - "pr": 1885 - }, - { - "note": "Remove `WalletOrderValidator` and `OrderValidator` signature types", - "pr": 1885 - }, - { - "note": "Make the regular `Validator` signature type have EIP1271 behavior", - "pr": 1885 - }, - { - "note": "Always check signature types that are validated via contract (not just on first fill).", - "pr": 1885 - }, - { - "note": "Remove unecessary rich revert error types.", - "pr": 1885 - }, - { - "note": "Add `IEIP1271Wallet` interface", - "pr": 1885 - }, - { - "note": "Add `validatorAddress` field to `SignatureValidatorError` rich reverts", - "pr": 1885 - }, - { - "note": "Make `calculateMatchedFillResults` public", - "pr": 1885 - }, - { - "note": "Updated RichErrors to the library pattern", - "pr": 1913 - }, - { - "note": "Rewrote _dispatchTransferFrom in Solidity", - "pr": 2020 - }, - { - "note": "Add `TestIsolatedExchange` contract and `IsolatedExchangeWrapper` test class", - "pr": 2031 - }, - { - "note": "Add `ReferenceFunctions` as package export.", - "pr": 2031 - }, - { - "note": "Remove `TestExchangeMath.sol`. Exchange math functions are now tested in the `exchange-libs` package and reference implementations are available there as well.", - "pr": 2031 - }, - { - "note": "Remove functions from `TestExchangeInternals.sol` that are no longer tested in this package.", - "pr": 2031 - }, - { - "note": "Remove `_assertValidFill()`", - "pr": 2031 - }, - { - "note": "Add `wrapper_unit_tests` tests and `TestWrapperFunctions` contract", - "pr": 2042 - }, - { - "note": "Disallow `signerAddress == 0` in signature validation functions.", - "pr": 2042 - }, - { - "note": "Update `Wallet` signature type behavior to be in line with v2.1.", - "pr": 2042 - }, - { - "note": "Add (semi) automated reentrancy tests and remove manual ones", - "pr": 2042 - }, - { - "note": "Refactor to use new `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries", - "pr": 2055 - }, - { - "note": "Remove `LibExchangeRichErrors` and `IExchangeRichErrors`", - "pr": 2055 - }, - { - "note": "Use built in selectors instead of `LibExchangeSelectors` constants", - "pr": 2055 - }, - { - "note": "Move `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` in `exchange-libs` package", - "pr": 2055 - }, - { - "note": "Compile and export all contracts, artifacts, and wrappers by default", - "pr": 2055 - }, - { - "note": "Rename `marketSellOrders` and `marketBuyOrders` back to `marketSellOrdersNoThrow` and `marketBuyOrdersNoThrow`.", - "pr": 2075 - }, - { - "note": "Introduce new `marketSellOrdersFillOrKill` and `marketBuyOrdersFillOrKill` functions.", - "pr": 2075 - }, - { - "note": "Use `abi.decode()` in `LibExchangeRichErrorDecoder` over `LibBytes`.", - "pr": 2075 - }, - { - "note": "Overridden functions in `ReentrancyTester` now return sane values.", - "pr": 2075 - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "2.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "2.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "2.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "2.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.10", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564607468 - }, - { - "timestamp": 1563957393, - "version": "2.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "2.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "2.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "2.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "2.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "2.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557799313, - "version": "2.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557507213, - "version": "2.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Do not reexport external dependencies", - "pr": 1682 - }, - { - "note": "Upgrade contracts to Solidity 0.5.5", - "pr": 1682 - }, - { - "note": "Integration testing for ERC1155Proxy", - "pr": 1673 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "1.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "1.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549373905, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Move Exchange contract out of contracts-protocol to new package", - "pr": 1539 - }, - { - "note": "Move example contracts out of contracts-examples to new package", - "pr": 1539 - } - ] - } -] diff --git a/contracts/exchange/CHANGELOG.md b/contracts/exchange/CHANGELOG.md deleted file mode 100644 index f284ee2d81..0000000000 --- a/contracts/exchange/CHANGELOG.md +++ /dev/null @@ -1,422 +0,0 @@ - - -CHANGELOG - -## v3.2.38 - _August 16, 2021_ - - * Dependencies updated - -## v3.2.37 - _August 11, 2021_ - - * Dependencies updated - -## v3.2.36 - _August 6, 2021_ - - * Dependencies updated - -## v3.2.35 - _June 22, 2021_ - - * Dependencies updated - -## v3.2.34 - _June 11, 2021_ - - * Dependencies updated - -## v3.2.33 - _June 2, 2021_ - - * Dependencies updated - -## v3.2.32 - _May 25, 2021_ - - * Dependencies updated - -## v3.2.31 - _May 21, 2021_ - - * Dependencies updated - -## v3.2.30 - _May 5, 2021_ - - * Dependencies updated - -## v3.2.29 - _April 28, 2021_ - - * Dependencies updated - -## v3.2.28 - _April 1, 2021_ - - * Dependencies updated - -## v3.2.27 - _March 17, 2021_ - - * Dependencies updated - -## v3.2.26 - _February 24, 2021_ - - * Dependencies updated - -## v3.2.25 - _February 10, 2021_ - - * Dependencies updated - -## v3.2.24 - _January 26, 2021_ - - * Dependencies updated - -## v3.2.23 - _January 13, 2021_ - - * Dependencies updated - -## v3.2.22 - _January 4, 2021_ - - * Dependencies updated - -## v3.2.21 - _December 23, 2020_ - - * Dependencies updated - -## v3.2.20 - _December 17, 2020_ - - * Dependencies updated - -## v3.2.19 - _December 16, 2020_ - - * Dependencies updated - -## v3.2.18 - _December 9, 2020_ - - * Dependencies updated - -## v3.2.17 - _December 7, 2020_ - - * Dependencies updated - -## v3.2.16 - _December 3, 2020_ - - * Dependencies updated - -## v3.2.15 - _November 19, 2020_ - - * Dependencies updated - -## v3.2.14 - _November 13, 2020_ - - * Dependencies updated - -## v3.2.13 - _November 3, 2020_ - - * Dependencies updated - -## v3.2.12 - _November 3, 2020_ - - * Dependencies updated - -## v3.2.11 - _November 2, 2020_ - - * Dependencies updated - -## v3.2.10 - _October 28, 2020_ - - * Dependencies updated - -## v3.2.9 - _October 27, 2020_ - - * Dependencies updated - -## v3.2.8 - _October 21, 2020_ - - * Dependencies updated - -## v3.2.7 - _July 15, 2020_ - - * Dependencies updated - -## v3.2.6 - _June 24, 2020_ - - * Dependencies updated - -## v3.2.5 - _March 3, 2020_ - - * Dependencies updated - -## v3.2.4 - _February 27, 2020_ - - * Dependencies updated - -## v3.2.3 - _February 26, 2020_ - - * Dependencies updated - -## v3.2.2 - _February 25, 2020_ - - * Dependencies updated - -## v3.2.1 - _February 15, 2020_ - - * Dependencies updated - -## v3.2.0 - _February 8, 2020_ - - * Flip `LibExchangeRichErrorDecoder` to an actual library. (#2462) - * Remove dependency on `DevUtils` for asset data encoding/decoding (#2462) - -## v3.1.2 - _February 6, 2020_ - - * Dependencies updated - -## v3.1.1 - _February 4, 2020_ - - * Dependencies updated - -## v3.1.0 - _January 22, 2020_ - - * Uses updated event decoding to properly decodes arrays and objects. (#2443) - -## v3.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v3.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v3.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v3.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export ExchangeRevertErrors (#2321) - * Round up in `marketBuyOrdersNoThrow()` so `marketBuyOrdersFillOrKill()` doesn't throw up. (#2338) - * LocalBalanceStore.create and constructor now require an instance of DevUtilsContract (#2304) - * In LocalBalanceStore, `transferAsset` is now `transferAssetAsync` (#2304) - * Test utility classes AssetWrapper, MatchOrderTester, and OrderFactoryFromScenario constructors now require an instance of DevUtilsContract (#2304) - * In OrderFactoryFromScenario, `generateOrder` is now `generateOrderAsync` (#2304) - * Use new/cheaper reentrancy guard/mutex (#1699) - * Update domain separator (#1742) - * Refactor `executeTransaction` to take `ZeroExTransaction` struct as input (#1753) - * Refactor example contracts that use `executeTransaction` (#1753) - * Upgrade all string reverts to rich reverts (#1761) - * Add support for `SignatureType.OrderValidator` for orders (#1774) - * Add support for `SignatureType.WalletOrderValidator` for orders (#1774) - * Add a `bytes` return value to `executeTransaction`, which is equal to the encoded return data of the underlying Exchange function call (#1793) - * Implement `batchExecuteTransactions` (#1793) - * Refactor preSign to be compatible with `executeTransaction` (#1793) - * Remove ZRX fees in lieu of arbitrary maker and taker fee tokens. (#1819) - * Incorporate Multi-asset and ERC1155 tests into `fillOrder` and `matchOrders` tests (#1819) - * Swap fill order from maker -> taker to taker -> maker (#1819) - * Avoid redundant transfer in `fillOrder()` and `matchOrders()` when maker/taker is the same as feeRecipient and assets are the same (#1819) - * Implement `cancelOrderNoThrow` and `batchCancelOrdersNoThrow` functions (#1827) - * `executeTransaction` will now revert if the input transaction is expired (#1832) - * Log an `TransactionExecuted` event when an `executeTransaction` call is successful (#1832) - * Return a FillResults array for batch fill variants (#1834) - * Add `MixinTransferSimulator` contract for simulating multiple transfers on-chain (#1868) - * Add `EIP1271Wallet` signature type (#1885) - * Remove `WalletOrderValidator` and `OrderValidator` signature types (#1885) - * Make the regular `Validator` signature type have EIP1271 behavior (#1885) - * Always check signature types that are validated via contract (not just on first fill). (#1885) - * Remove unecessary rich revert error types. (#1885) - * Add `IEIP1271Wallet` interface (#1885) - * Add `validatorAddress` field to `SignatureValidatorError` rich reverts (#1885) - * Make `calculateMatchedFillResults` public (#1885) - * Updated RichErrors to the library pattern (#1913) - * Rewrote _dispatchTransferFrom in Solidity (#2020) - * Add `TestIsolatedExchange` contract and `IsolatedExchangeWrapper` test class (#2031) - * Add `ReferenceFunctions` as package export. (#2031) - * Remove `TestExchangeMath.sol`. Exchange math functions are now tested in the `exchange-libs` package and reference implementations are available there as well. (#2031) - * Remove functions from `TestExchangeInternals.sol` that are no longer tested in this package. (#2031) - * Remove `_assertValidFill()` (#2031) - * Add `wrapper_unit_tests` tests and `TestWrapperFunctions` contract (#2042) - * Disallow `signerAddress == 0` in signature validation functions. (#2042) - * Update `Wallet` signature type behavior to be in line with v2.1. (#2042) - * Add (semi) automated reentrancy tests and remove manual ones (#2042) - * Refactor to use new `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries (#2055) - * Remove `LibExchangeRichErrors` and `IExchangeRichErrors` (#2055) - * Use built in selectors instead of `LibExchangeSelectors` constants (#2055) - * Move `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` in `exchange-libs` package (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Rename `marketSellOrders` and `marketBuyOrders` back to `marketSellOrdersNoThrow` and `marketBuyOrdersNoThrow`. (#2075) - * Introduce new `marketSellOrdersFillOrKill` and `marketBuyOrdersFillOrKill` functions. (#2075) - * Use `abi.decode()` in `LibExchangeRichErrorDecoder` over `LibBytes`. (#2075) - * Overridden functions in `ReentrancyTester` now return sane values. (#2075) - -## v2.2.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v2.2.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v2.2.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduced new export ExchangeRevertErrors (#2321) - * Round up in `marketBuyOrdersNoThrow()` so `marketBuyOrdersFillOrKill()` doesn't throw up. (#2338) - -## v2.2.0-beta.1 - _November 7, 2019_ - - * LocalBalanceStore.create and constructor now require an instance of DevUtilsContract (#2304) - * In LocalBalanceStore, `transferAsset` is now `transferAssetAsync` (#2304) - * Test utility classes AssetWrapper, MatchOrderTester, and OrderFactoryFromScenario constructors now require an instance of DevUtilsContract (#2304) - * In OrderFactoryFromScenario, `generateOrder` is now `generateOrderAsync` (#2304) - -## v2.2.0-beta.0 - _October 3, 2019_ - - * Use new/cheaper reentrancy guard/mutex (#1699) - * Update domain separator (#1742) - * Refactor `executeTransaction` to take `ZeroExTransaction` struct as input (#1753) - * Refactor example contracts that use `executeTransaction` (#1753) - * Upgrade all string reverts to rich reverts (#1761) - * Add support for `SignatureType.OrderValidator` for orders (#1774) - * Add support for `SignatureType.WalletOrderValidator` for orders (#1774) - * Add a `bytes` return value to `executeTransaction`, which is equal to the encoded return data of the underlying Exchange function call (#1793) - * Implement `batchExecuteTransactions` (#1793) - * Refactor preSign to be compatible with `executeTransaction` (#1793) - * Remove ZRX fees in lieu of arbitrary maker and taker fee tokens. (#1819) - * Incorporate Multi-asset and ERC1155 tests into `fillOrder` and `matchOrders` tests (#1819) - * Swap fill order from maker -> taker to taker -> maker (#1819) - * Avoid redundant transfer in `fillOrder()` and `matchOrders()` when maker/taker is the same as feeRecipient and assets are the same (#1819) - * Implement `cancelOrderNoThrow` and `batchCancelOrdersNoThrow` functions (#1827) - * `executeTransaction` will now revert if the input transaction is expired (#1832) - * Log an `TransactionExecuted` event when an `executeTransaction` call is successful (#1832) - * Return a FillResults array for batch fill variants (#1834) - * Add `MixinTransferSimulator` contract for simulating multiple transfers on-chain (#1868) - * Add `EIP1271Wallet` signature type (#1885) - * Remove `WalletOrderValidator` and `OrderValidator` signature types (#1885) - * Make the regular `Validator` signature type have EIP1271 behavior (#1885) - * Always check signature types that are validated via contract (not just on first fill). (#1885) - * Remove unecessary rich revert error types. (#1885) - * Add `IEIP1271Wallet` interface (#1885) - * Add `validatorAddress` field to `SignatureValidatorError` rich reverts (#1885) - * Make `calculateMatchedFillResults` public (#1885) - * Updated RichErrors to the library pattern (#1913) - * Rewrote _dispatchTransferFrom in Solidity (#2020) - * Add `TestIsolatedExchange` contract and `IsolatedExchangeWrapper` test class (#2031) - * Add `ReferenceFunctions` as package export. (#2031) - * Remove `TestExchangeMath.sol`. Exchange math functions are now tested in the `exchange-libs` package and reference implementations are available there as well. (#2031) - * Remove functions from `TestExchangeInternals.sol` that are no longer tested in this package. (#2031) - * Remove `_assertValidFill()` (#2031) - * Add `wrapper_unit_tests` tests and `TestWrapperFunctions` contract (#2042) - * Disallow `signerAddress == 0` in signature validation functions. (#2042) - * Update `Wallet` signature type behavior to be in line with v2.1. (#2042) - * Add (semi) automated reentrancy tests and remove manual ones (#2042) - * Refactor to use new `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries (#2055) - * Remove `LibExchangeRichErrors` and `IExchangeRichErrors` (#2055) - * Use built in selectors instead of `LibExchangeSelectors` constants (#2055) - * Move `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` in `exchange-libs` package (#2055) - * Compile and export all contracts, artifacts, and wrappers by default (#2055) - * Rename `marketSellOrders` and `marketBuyOrders` back to `marketSellOrdersNoThrow` and `marketBuyOrdersNoThrow`. (#2075) - * Introduce new `marketSellOrdersFillOrKill` and `marketBuyOrdersFillOrKill` functions. (#2075) - * Use `abi.decode()` in `LibExchangeRichErrorDecoder` over `LibBytes`. (#2075) - * Overridden functions in `ReentrancyTester` now return sane values. (#2075) - -## v2.1.14 - _September 17, 2019_ - - * Dependencies updated - -## v2.1.13 - _September 3, 2019_ - - * Dependencies updated - -## v2.1.12 - _August 22, 2019_ - - * Dependencies updated - -## v2.1.11 - _August 8, 2019_ - - * Dependencies updated - -## v2.1.10 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v2.1.9 - _July 24, 2019_ - - * Dependencies updated - -## v2.1.8 - _July 15, 2019_ - - * Dependencies updated - -## v2.1.7 - _July 13, 2019_ - - * Dependencies updated - -## v2.1.6 - _July 13, 2019_ - - * Dependencies updated - -## v2.1.5 - _May 24, 2019_ - - * Dependencies updated - -## v2.1.4 - _May 15, 2019_ - - * Dependencies updated - -## v2.1.3 - _May 14, 2019_ - - * Dependencies updated - -## v2.1.2 - _May 10, 2019_ - - * Dependencies updated - -## v2.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v2.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v2.0.0 - _March 20, 2019_ - - * Do not reexport external dependencies (#1682) - * Upgrade contracts to Solidity 0.5.5 (#1682) - * Integration testing for ERC1155Proxy (#1673) - -## v1.0.9 - _March 1, 2019_ - - * Dependencies updated - -## v1.0.8 - _February 27, 2019_ - - * Dependencies updated - -## v1.0.7 - _February 26, 2019_ - - * Dependencies updated - -## v1.0.6 - _February 25, 2019_ - - * Dependencies updated - -## v1.0.5 - _February 9, 2019_ - - * Dependencies updated - -## v1.0.4 - _February 7, 2019_ - - * Dependencies updated - -## v1.0.3 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v1.0.2 - _February 6, 2019_ - - * Dependencies updated - -## v1.0.1 - _February 5, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Move Exchange contract out of contracts-protocol to new package (#1539) - * Move example contracts out of contracts-examples to new package (#1539) diff --git a/contracts/exchange/DEPLOYS.json b/contracts/exchange/DEPLOYS.json deleted file mode 100644 index 1e110d4f78..0000000000 --- a/contracts/exchange/DEPLOYS.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "name": "Exchange", - "version": "2.0.0", - "changes": [ - { - "note": "protocol v2 deploy", - "networks": { - "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", - "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf", - "4": "0x22ebc052f43a88efa06379426120718170f2204e", - "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2" - } - } - ] - } -] diff --git a/contracts/exchange/README.md b/contracts/exchange/README.md deleted file mode 100644 index 70d8d97616..0000000000 --- a/contracts/exchange/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## Exchange - -This package contains the implementation of the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange). This contract is responsible for settling trades and is typically the entry point for all transactions that interact with the 0x protocol. Lightweight examples of how external contracts can interact with the `Exchange` contract can be found in the [examples](./contracts/examples) directory. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-exchange --save -``` - -## Bug bounty - -A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-exchange yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-exchange yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/exchange/compiler.json b/contracts/exchange/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/exchange/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/exchange/contracts/src/Exchange.sol b/contracts/exchange/contracts/src/Exchange.sol deleted file mode 100644 index 8f5b8f0f89..0000000000 --- a/contracts/exchange/contracts/src/Exchange.sol +++ /dev/null @@ -1,45 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "./MixinMatchOrders.sol"; -import "./MixinWrapperFunctions.sol"; -import "./MixinTransferSimulator.sol"; - - -// solhint-disable no-empty-blocks -// MixinAssetProxyDispatcher, MixinExchangeCore, MixinSignatureValidator, -// and MixinTransactions are all inherited via the other Mixins that are -// used. -/// @dev The 0x Exchange contract. -contract Exchange is - LibEIP712ExchangeDomain, - MixinMatchOrders, - MixinWrapperFunctions, - MixinTransferSimulator -{ - /// @dev Mixins are instantiated in the order they are inherited - /// @param chainId Chain ID of the network this contract is deployed on. - constructor (uint256 chainId) - public - LibEIP712ExchangeDomain(chainId, address(0)) - {} -} diff --git a/contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol b/contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol deleted file mode 100644 index 2e93d5ef84..0000000000 --- a/contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol +++ /dev/null @@ -1,136 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/Ownable.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "./interfaces/IAssetProxy.sol"; -import "./interfaces/IAssetProxyDispatcher.sol"; - - -contract MixinAssetProxyDispatcher is - Ownable, - IAssetProxyDispatcher -{ - using LibBytes for bytes; - - // Mapping from Asset Proxy Id's to their respective Asset Proxy - mapping (bytes4 => address) internal _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 - { - // Ensure that no asset proxy exists with current id. - bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId(); - address currentAssetProxy = _assetProxies[assetProxyId]; - if (currentAssetProxy != address(0)) { - LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyExistsError( - assetProxyId, - currentAssetProxy - )); - } - - // Add asset proxy and log registration. - _assetProxies[assetProxyId] = assetProxy; - emit AssetProxyRegistered( - assetProxyId, - assetProxy - ); - } - - /// @dev Gets an asset proxy. - /// @param assetProxyId Id of the asset proxy. - /// @return assetProxy The asset proxy address registered to assetProxyId. Returns 0x0 if no proxy is registered. - function getAssetProxy(bytes4 assetProxyId) - external - view - returns (address assetProxy) - { - return _assetProxies[assetProxyId]; - } - - /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws. - /// @param orderHash Hash of the order associated with this transfer. - /// @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( - bytes32 orderHash, - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - // Do nothing if no amount should be transferred. - if (amount > 0) { - - // Ensure assetData is padded to 32 bytes (excluding the id) and is at least 4 bytes long - if (assetData.length % 32 != 4) { - LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyDispatchError( - LibExchangeRichErrors.AssetProxyDispatchErrorCodes.INVALID_ASSET_DATA_LENGTH, - orderHash, - assetData - )); - } - - // Lookup assetProxy. - bytes4 assetProxyId = assetData.readBytes4(0); - address assetProxy = _assetProxies[assetProxyId]; - - // Ensure that assetProxy exists - if (assetProxy == address(0)) { - LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyDispatchError( - LibExchangeRichErrors.AssetProxyDispatchErrorCodes.UNKNOWN_ASSET_PROXY, - orderHash, - assetData - )); - } - - // Construct the calldata for the transferFrom call. - bytes memory proxyCalldata = abi.encodeWithSelector( - IAssetProxy(address(0)).transferFrom.selector, - assetData, - from, - to, - amount - ); - - // Call the asset proxy's transferFrom function with the constructed calldata. - (bool didSucceed, bytes memory returnData) = assetProxy.call(proxyCalldata); - - // If the transaction did not succeed, revert with the returned data. - if (!didSucceed) { - LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyTransferError( - orderHash, - assetData, - returnData - )); - } - } - } -} diff --git a/contracts/exchange/contracts/src/MixinExchangeCore.sol b/contracts/exchange/contracts/src/MixinExchangeCore.sol deleted file mode 100644 index c5c1285e24..0000000000 --- a/contracts/exchange/contracts/src/MixinExchangeCore.sol +++ /dev/null @@ -1,499 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/Refundable.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "./interfaces/IExchangeCore.sol"; -import "./MixinAssetProxyDispatcher.sol"; -import "./MixinProtocolFees.sol"; -import "./MixinSignatureValidator.sol"; - - -contract MixinExchangeCore is - IExchangeCore, - Refundable, - LibEIP712ExchangeDomain, - MixinAssetProxyDispatcher, - MixinProtocolFees, - MixinSignatureValidator -{ - using LibOrder for LibOrder.Order; - using LibSafeMath for uint256; - using LibBytes for bytes; - - /// @dev Mapping of orderHash => amount of takerAsset already bought by maker - /// @param 0 Order hash. - /// @return 0 The amount of taker asset filled. - mapping (bytes32 => uint256) public filled; - - /// @dev Mapping of orderHash => cancelled - /// @param 0 Order hash. - /// @return 0 Whether the order was cancelled. - mapping (bytes32 => bool) public cancelled; - - /// @dev 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 - /// @param 0 Address of the order's maker. - /// @param 1 Address of the order's sender. - /// @return 0 Minimum valid order epoch. - 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 - payable - refundFinalBalanceNoReentry - { - 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 orderSenderAddress = 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][orderSenderAddress]; - - // Ensure orderEpoch is monotonically increasing - if (newOrderEpoch <= oldOrderEpoch) { - LibRichErrors.rrevert(LibExchangeRichErrors.OrderEpochError( - makerAddress, - orderSenderAddress, - oldOrderEpoch - )); - } - - // Update orderEpoch - orderEpoch[makerAddress][orderSenderAddress] = newOrderEpoch; - emit CancelUpTo( - makerAddress, - orderSenderAddress, - 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 fillResults Amounts filled and fees paid by maker and taker. - function fillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.FillResults memory fillResults) - { - fillResults = _fillOrder( - order, - takerAssetFillAmount, - signature - ); - return 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 - payable - refundFinalBalanceNoReentry - { - _cancelOrder(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(LibOrder.Order memory order) - public - view - returns (LibOrder.OrderInfo memory orderInfo) - { - // Compute the order hash and fetch the amount of takerAsset that has already been filled - (orderInfo.orderHash, orderInfo.orderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(order); - - // 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 = LibOrder.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 = LibOrder.OrderStatus.INVALID_TAKER_ASSET_AMOUNT; - return orderInfo; - } - - // Validate order availability - if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) { - orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED; - return orderInfo; - } - - // Validate order expiration - // solhint-disable-next-line not-rely-on-time - if (block.timestamp >= order.expirationTimeSeconds) { - orderInfo.orderStatus = LibOrder.OrderStatus.EXPIRED; - return orderInfo; - } - - // Check if order has been cancelled - if (cancelled[orderInfo.orderHash]) { - orderInfo.orderStatus = LibOrder.OrderStatus.CANCELLED; - return orderInfo; - } - if (orderEpoch[order.makerAddress][order.senderAddress] > order.salt) { - orderInfo.orderStatus = LibOrder.OrderStatus.CANCELLED; - return orderInfo; - } - - // All other statuses are ruled out: order is Fillable - orderInfo.orderStatus = LibOrder.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 fillResults Amounts filled and fees paid by maker and taker. - function _fillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - // Fetch order info - LibOrder.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 = order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount); - uint256 takerAssetFilledAmount = LibSafeMath.min256(takerAssetFillAmount, remainingTakerAssetAmount); - - // Compute proportional fill amounts - fillResults = LibFillResults.calculateFillResults( - order, - takerAssetFilledAmount, - protocolFeeMultiplier, - tx.gasprice - ); - - bytes32 orderHash = orderInfo.orderHash; - - // Update exchange internal state - _updateFilledState( - order, - takerAddress, - orderHash, - orderInfo.orderTakerAssetFilledAmount, - fillResults - ); - - // Settle order - _settleOrder( - orderHash, - 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 _cancelOrder(LibOrder.Order memory order) - internal - { - // Fetch current order status - LibOrder.OrderInfo memory orderInfo = getOrderInfo(order); - - // Validate context - _assertValidCancel(order, orderInfo); - - // Noop if order is already unfillable - if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) { - return; - } - - // 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( - LibOrder.Order memory order, - address takerAddress, - bytes32 orderHash, - uint256 orderTakerAssetFilledAmount, - LibFillResults.FillResults memory fillResults - ) - internal - { - // Update state - filled[orderHash] = orderTakerAssetFilledAmount.safeAdd(fillResults.takerAssetFilledAmount); - - emit Fill( - order.makerAddress, - order.feeRecipientAddress, - order.makerAssetData, - order.takerAssetData, - order.makerFeeAssetData, - order.takerFeeAssetData, - orderHash, - takerAddress, - msg.sender, - fillResults.makerAssetFilledAmount, - fillResults.takerAssetFilledAmount, - fillResults.makerFeePaid, - fillResults.takerFeePaid, - fillResults.protocolFeePaid - ); - } - - /// @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 - { - // Perform cancel - cancelled[orderHash] = true; - - // Log cancel - emit Cancel( - order.makerAddress, - order.feeRecipientAddress, - order.makerAssetData, - order.takerAssetData, - msg.sender, - orderHash - ); - } - - /// @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 - { - // An order can only be filled if its status is FILLABLE. - if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) { - LibRichErrors.rrevert(LibExchangeRichErrors.OrderStatusError( - orderInfo.orderHash, - LibOrder.OrderStatus(orderInfo.orderStatus) - )); - } - - // Validate sender is allowed to fill this order - if (order.senderAddress != address(0)) { - if (order.senderAddress != msg.sender) { - LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( - LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_SENDER, - orderInfo.orderHash, - msg.sender - )); - } - } - - // Validate taker is allowed to fill this order - if (order.takerAddress != address(0)) { - if (order.takerAddress != takerAddress) { - LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( - LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_TAKER, - orderInfo.orderHash, - takerAddress - )); - } - } - - // Validate signature - if (!_isValidOrderWithHashSignature( - order, - orderInfo.orderHash, - signature - ) - ) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.BAD_ORDER_SIGNATURE, - orderInfo.orderHash, - order.makerAddress, - signature - )); - } - } - - /// @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 - { - // Validate sender is allowed to cancel this order - if (order.senderAddress != address(0)) { - if (order.senderAddress != msg.sender) { - LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( - LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_SENDER, - orderInfo.orderHash, - msg.sender - )); - } - } - - // Validate transaction signed by maker - address makerAddress = _getCurrentContextAddress(); - if (order.makerAddress != makerAddress) { - LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( - LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_MAKER, - orderInfo.orderHash, - makerAddress - )); - } - } - - /// @dev Settles an order by transferring assets between counterparties. - /// @param orderHash The order hash. - /// @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( - bytes32 orderHash, - LibOrder.Order memory order, - address takerAddress, - LibFillResults.FillResults memory fillResults - ) - internal - { - // Transfer taker -> maker - _dispatchTransferFrom( - orderHash, - order.takerAssetData, - takerAddress, - order.makerAddress, - fillResults.takerAssetFilledAmount - ); - - // Transfer maker -> taker - _dispatchTransferFrom( - orderHash, - order.makerAssetData, - order.makerAddress, - takerAddress, - fillResults.makerAssetFilledAmount - ); - - // Transfer taker fee -> feeRecipient - _dispatchTransferFrom( - orderHash, - order.takerFeeAssetData, - takerAddress, - order.feeRecipientAddress, - fillResults.takerFeePaid - ); - - // Transfer maker fee -> feeRecipient - _dispatchTransferFrom( - orderHash, - order.makerFeeAssetData, - order.makerAddress, - order.feeRecipientAddress, - fillResults.makerFeePaid - ); - - // Pay protocol fee - bool didPayProtocolFee = _paySingleProtocolFee( - orderHash, - fillResults.protocolFeePaid, - order.makerAddress, - takerAddress - ); - - // Protocol fees are not paid if the protocolFeeCollector contract is not set - if (!didPayProtocolFee) { - fillResults.protocolFeePaid = 0; - } - } - - /// @dev Gets the order's hash and amount of takerAsset that has already been filled. - /// @param order Order struct containing order specifications. - /// @return The typed data hash and amount filled of the order. - function _getOrderHashAndFilledAmount(LibOrder.Order memory order) - internal - view - returns (bytes32 orderHash, uint256 orderTakerAssetFilledAmount) - { - orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); - orderTakerAssetFilledAmount = filled[orderHash]; - return (orderHash, orderTakerAssetFilledAmount); - } -} diff --git a/contracts/exchange/contracts/src/MixinMatchOrders.sol b/contracts/exchange/contracts/src/MixinMatchOrders.sol deleted file mode 100644 index 3b5b251b04..0000000000 --- a/contracts/exchange/contracts/src/MixinMatchOrders.sol +++ /dev/null @@ -1,543 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "./interfaces/IMatchOrders.sol"; -import "./MixinExchangeCore.sol"; - - -contract MixinMatchOrders is - MixinExchangeCore, - IMatchOrders -{ - using LibBytes for bytes; - using LibSafeMath for uint256; - using LibOrder for LibOrder.Order; - - /// @dev Match complementary orders that have a profitable spread. - /// Each order is filled at their respective price point, and - /// the matcher receives a profit denominated in the left maker asset. - /// @param leftOrders Set of orders with the same maker / taker asset. - /// @param rightOrders Set of orders to match against `leftOrders` - /// @param leftSignatures Proof that left orders were created by the left makers. - /// @param rightSignatures Proof that right orders were created by the right makers. - /// @return batchMatchedFillResults Amounts filled and profit generated. - function batchMatchOrders( - LibOrder.Order[] memory leftOrders, - LibOrder.Order[] memory rightOrders, - bytes[] memory leftSignatures, - bytes[] memory rightSignatures - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) - { - return _batchMatchOrders( - leftOrders, - rightOrders, - leftSignatures, - rightSignatures, - false - ); - } - - /// @dev Match complementary orders that have a profitable spread. - /// Each order is maximally filled at their respective price point, and - /// the matcher receives a profit denominated in either the left maker asset, - /// right maker asset, or a combination of both. - /// @param leftOrders Set of orders with the same maker / taker asset. - /// @param rightOrders Set of orders to match against `leftOrders` - /// @param leftSignatures Proof that left orders were created by the left makers. - /// @param rightSignatures Proof that right orders were created by the right makers. - /// @return batchMatchedFillResults Amounts filled and profit generated. - function batchMatchOrdersWithMaximalFill( - LibOrder.Order[] memory leftOrders, - LibOrder.Order[] memory rightOrders, - bytes[] memory leftSignatures, - bytes[] memory rightSignatures - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) - { - return _batchMatchOrders( - leftOrders, - rightOrders, - leftSignatures, - rightSignatures, - true - ); - } - - /// @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 - payable - refundFinalBalanceNoReentry - returns (LibFillResults.MatchedFillResults memory matchedFillResults) - { - return _matchOrders( - leftOrder, - rightOrder, - leftSignature, - rightSignature, - false - ); - } - - /// @dev Match two complementary orders that have a profitable spread. - /// Each order is maximally filled at their respective price point, and - /// the matcher receives a profit denominated in either the left maker asset, - /// right maker asset, or a combination of both. - /// @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 by maker and taker of matched orders. - function matchOrdersWithMaximalFill( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - bytes memory leftSignature, - bytes memory rightSignature - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.MatchedFillResults memory matchedFillResults) - { - return _matchOrders( - leftOrder, - rightOrder, - leftSignature, - rightSignature, - true - ); - } - - /// @dev Validates context for matchOrders. Succeeds or throws. - /// @param leftOrder First order to match. - /// @param rightOrder Second order to match. - /// @param leftOrderHash First matched order hash. - /// @param rightOrderHash Second matched order hash. - function _assertValidMatch( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - bytes32 leftOrderHash, - bytes32 rightOrderHash - ) - 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: - // / >= / - // AND - // / >= / - // These equations can be combined to get the following: - if (leftOrder.makerAssetAmount.safeMul(rightOrder.makerAssetAmount) < - leftOrder.takerAssetAmount.safeMul(rightOrder.takerAssetAmount)) { - LibRichErrors.rrevert(LibExchangeRichErrors.NegativeSpreadError( - leftOrderHash, - rightOrderHash - )); - } - } - - /// @dev Match complementary orders that have a profitable spread. - /// Each order is filled at their respective price point, and - /// the matcher receives a profit denominated in the left maker asset. - /// This is the reentrant version of `batchMatchOrders` and `batchMatchOrdersWithMaximalFill`. - /// @param leftOrders Set of orders with the same maker / taker asset. - /// @param rightOrders Set of orders to match against `leftOrders` - /// @param leftSignatures Proof that left orders were created by the left makers. - /// @param rightSignatures Proof that right orders were created by the right makers. - /// @param shouldMaximallyFillOrders A value that indicates whether or not the order matching - /// should be done with maximal fill. - /// @return batchMatchedFillResults Amounts filled and profit generated. - function _batchMatchOrders( - LibOrder.Order[] memory leftOrders, - LibOrder.Order[] memory rightOrders, - bytes[] memory leftSignatures, - bytes[] memory rightSignatures, - bool shouldMaximallyFillOrders - ) - internal - returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) - { - // Ensure that the left and right orders have nonzero lengths. - if (leftOrders.length == 0) { - LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( - LibExchangeRichErrors.BatchMatchOrdersErrorCodes.ZERO_LEFT_ORDERS - )); - } - if (rightOrders.length == 0) { - LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( - LibExchangeRichErrors.BatchMatchOrdersErrorCodes.ZERO_RIGHT_ORDERS - )); - } - - // Ensure that the left and right arrays are compatible. - if (leftOrders.length != leftSignatures.length) { - LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( - LibExchangeRichErrors.BatchMatchOrdersErrorCodes.INVALID_LENGTH_LEFT_SIGNATURES - )); - } - if (rightOrders.length != rightSignatures.length) { - LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( - LibExchangeRichErrors.BatchMatchOrdersErrorCodes.INVALID_LENGTH_RIGHT_SIGNATURES - )); - } - - batchMatchedFillResults.left = new LibFillResults.FillResults[](leftOrders.length); - batchMatchedFillResults.right = new LibFillResults.FillResults[](rightOrders.length); - - // Set up initial indices. - uint256 leftIdx = 0; - uint256 rightIdx = 0; - - // Keep local variables for orders, order filled amounts, and signatures for efficiency. - LibOrder.Order memory leftOrder = leftOrders[0]; - LibOrder.Order memory rightOrder = rightOrders[0]; - (, uint256 leftOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(leftOrder); - (, uint256 rightOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(rightOrder); - LibFillResults.FillResults memory leftFillResults; - LibFillResults.FillResults memory rightFillResults; - - // Loop infinitely (until broken inside of the loop), but keep a counter of how - // many orders have been matched. - for (;;) { - // Match the two orders that are pointed to by the left and right indices - LibFillResults.MatchedFillResults memory matchResults = _matchOrders( - leftOrder, - rightOrder, - leftSignatures[leftIdx], - rightSignatures[rightIdx], - shouldMaximallyFillOrders - ); - - // Update the order filled amounts with the updated takerAssetFilledAmount - leftOrderTakerAssetFilledAmount = leftOrderTakerAssetFilledAmount.safeAdd(matchResults.left.takerAssetFilledAmount); - rightOrderTakerAssetFilledAmount = rightOrderTakerAssetFilledAmount.safeAdd(matchResults.right.takerAssetFilledAmount); - - // Aggregate the new fill results with the previous fill results for the current orders. - leftFillResults = LibFillResults.addFillResults( - leftFillResults, - matchResults.left - ); - rightFillResults = LibFillResults.addFillResults( - rightFillResults, - matchResults.right - ); - - // Update the profit in the left and right maker assets using the profits from - // the match. - batchMatchedFillResults.profitInLeftMakerAsset = batchMatchedFillResults.profitInLeftMakerAsset.safeAdd( - matchResults.profitInLeftMakerAsset - ); - batchMatchedFillResults.profitInRightMakerAsset = batchMatchedFillResults.profitInRightMakerAsset.safeAdd( - matchResults.profitInRightMakerAsset - ); - - // If the leftOrder is filled, update the leftIdx, leftOrder, and leftSignature, - // or break out of the loop if there are no more leftOrders to match. - if (leftOrderTakerAssetFilledAmount >= leftOrder.takerAssetAmount) { - // Update the batched fill results once the leftIdx is updated. - batchMatchedFillResults.left[leftIdx++] = leftFillResults; - // Clear the intermediate fill results value. - leftFillResults = LibFillResults.FillResults(0, 0, 0, 0, 0); - - // If all of the left orders have been filled, break out of the loop. - // Otherwise, update the current right order. - if (leftIdx == leftOrders.length) { - // Update the right batched fill results - batchMatchedFillResults.right[rightIdx] = rightFillResults; - break; - } else { - leftOrder = leftOrders[leftIdx]; - (, leftOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(leftOrder); - } - } - - // If the rightOrder is filled, update the rightIdx, rightOrder, and rightSignature, - // or break out of the loop if there are no more rightOrders to match. - if (rightOrderTakerAssetFilledAmount >= rightOrder.takerAssetAmount) { - // Update the batched fill results once the rightIdx is updated. - batchMatchedFillResults.right[rightIdx++] = rightFillResults; - // Clear the intermediate fill results value. - rightFillResults = LibFillResults.FillResults(0, 0, 0, 0, 0); - - // If all of the right orders have been filled, break out of the loop. - // Otherwise, update the current right order. - if (rightIdx == rightOrders.length) { - // Update the left batched fill results - batchMatchedFillResults.left[leftIdx] = leftFillResults; - break; - } else { - rightOrder = rightOrders[rightIdx]; - (, rightOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(rightOrder); - } - } - } - - // Return the fill results from the batch match - return batchMatchedFillResults; - } - - /// @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). This - /// function is needed to allow for reentrant order matching (used by `batchMatchOrders` and - /// `batchMatchOrdersWithMaximalFill`). - /// @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. - /// @param shouldMaximallyFillOrders Indicates whether or not the maximal fill matching strategy should be used - /// @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, - bool shouldMaximallyFillOrders - ) - internal - returns (LibFillResults.MatchedFillResults memory matchedFillResults) - { - // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData - // by pointing these values to the same location in memory. This is cheaper than checking equality. - // 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, - leftOrderInfo.orderHash, - rightOrderInfo.orderHash - ); - - // Compute proportional fill amounts - matchedFillResults = LibFillResults.calculateMatchedFillResults( - leftOrder, - rightOrder, - leftOrderInfo.orderTakerAssetFilledAmount, - rightOrderInfo.orderTakerAssetFilledAmount, - protocolFeeMultiplier, - tx.gasprice, - shouldMaximallyFillOrders - ); - - // 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( - leftOrderInfo.orderHash, - rightOrderInfo.orderHash, - leftOrder, - rightOrder, - takerAddress, - matchedFillResults - ); - - return matchedFillResults; - } - - /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient. - /// @param leftOrderHash First matched order hash. - /// @param rightOrderHash Second matched order hash. - /// @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( - bytes32 leftOrderHash, - bytes32 rightOrderHash, - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - address takerAddress, - LibFillResults.MatchedFillResults memory matchedFillResults - ) - internal - { - address leftMakerAddress = leftOrder.makerAddress; - address rightMakerAddress = rightOrder.makerAddress; - address leftFeeRecipientAddress = leftOrder.feeRecipientAddress; - address rightFeeRecipientAddress = rightOrder.feeRecipientAddress; - - // Right maker asset -> left maker - _dispatchTransferFrom( - rightOrderHash, - rightOrder.makerAssetData, - rightMakerAddress, - leftMakerAddress, - matchedFillResults.left.takerAssetFilledAmount - ); - - // Left maker asset -> right maker - _dispatchTransferFrom( - leftOrderHash, - leftOrder.makerAssetData, - leftMakerAddress, - rightMakerAddress, - matchedFillResults.right.takerAssetFilledAmount - ); - - // Right maker fee -> right fee recipient - _dispatchTransferFrom( - rightOrderHash, - rightOrder.makerFeeAssetData, - rightMakerAddress, - rightFeeRecipientAddress, - matchedFillResults.right.makerFeePaid - ); - - // Left maker fee -> left fee recipient - _dispatchTransferFrom( - leftOrderHash, - leftOrder.makerFeeAssetData, - leftMakerAddress, - leftFeeRecipientAddress, - matchedFillResults.left.makerFeePaid - ); - - // Settle taker profits. - _dispatchTransferFrom( - leftOrderHash, - leftOrder.makerAssetData, - leftMakerAddress, - takerAddress, - matchedFillResults.profitInLeftMakerAsset - ); - _dispatchTransferFrom( - rightOrderHash, - rightOrder.makerAssetData, - rightMakerAddress, - takerAddress, - matchedFillResults.profitInRightMakerAsset - ); - - // Pay protocol fees for each maker - bool didPayProtocolFees = _payTwoProtocolFees( - leftOrderHash, - rightOrderHash, - matchedFillResults.left.protocolFeePaid, - leftMakerAddress, - rightMakerAddress, - takerAddress - ); - - // Protocol fees are not paid if the protocolFeeCollector contract is not set - if (!didPayProtocolFees) { - matchedFillResults.left.protocolFeePaid = 0; - matchedFillResults.right.protocolFeePaid = 0; - } - - // Settle taker fees. - if ( - leftFeeRecipientAddress == rightFeeRecipientAddress && - leftOrder.takerFeeAssetData.equals(rightOrder.takerFeeAssetData) - ) { - // Fee recipients and taker fee assets are identical, so we can - // transfer them in one go. - _dispatchTransferFrom( - leftOrderHash, - leftOrder.takerFeeAssetData, - takerAddress, - leftFeeRecipientAddress, - matchedFillResults.left.takerFeePaid.safeAdd(matchedFillResults.right.takerFeePaid) - ); - } else { - // Right taker fee -> right fee recipient - _dispatchTransferFrom( - rightOrderHash, - rightOrder.takerFeeAssetData, - takerAddress, - rightFeeRecipientAddress, - matchedFillResults.right.takerFeePaid - ); - - // Left taker fee -> left fee recipient - _dispatchTransferFrom( - leftOrderHash, - leftOrder.takerFeeAssetData, - takerAddress, - leftFeeRecipientAddress, - matchedFillResults.left.takerFeePaid - ); - } - } -} diff --git a/contracts/exchange/contracts/src/MixinProtocolFees.sol b/contracts/exchange/contracts/src/MixinProtocolFees.sol deleted file mode 100644 index cb96b3f1c3..0000000000 --- a/contracts/exchange/contracts/src/MixinProtocolFees.sol +++ /dev/null @@ -1,197 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/Ownable.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "@0x/contracts-staking/contracts/src/interfaces/IStaking.sol"; -import "./interfaces/IProtocolFees.sol"; - - -contract MixinProtocolFees is - IProtocolFees, - Ownable -{ - /// @dev The protocol fee multiplier -- the owner can update this field. - /// @return 0 Gas multplier. - uint256 public protocolFeeMultiplier; - - /// @dev The address of the registered protocolFeeCollector contract -- the owner can update this field. - /// @return 0 Contract to forward protocol fees to. - address public protocolFeeCollector; - - /// @dev Allows the owner to update the protocol fee multiplier. - /// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier. - function setProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier) - external - onlyOwner - { - emit ProtocolFeeMultiplier(protocolFeeMultiplier, updatedProtocolFeeMultiplier); - protocolFeeMultiplier = updatedProtocolFeeMultiplier; - } - - /// @dev Allows the owner to update the protocolFeeCollector address. - /// @param updatedProtocolFeeCollector The updated protocolFeeCollector contract address. - function setProtocolFeeCollectorAddress(address updatedProtocolFeeCollector) - external - onlyOwner - { - _setProtocolFeeCollectorAddress(updatedProtocolFeeCollector); - } - - /// @dev Sets the protocolFeeCollector contract address to 0. - /// Only callable by owner. - function detachProtocolFeeCollector() - external - onlyOwner - { - _setProtocolFeeCollectorAddress(address(0)); - } - - /// @dev Sets the protocolFeeCollector address and emits an event. - /// @param updatedProtocolFeeCollector The updated protocolFeeCollector contract address. - function _setProtocolFeeCollectorAddress(address updatedProtocolFeeCollector) - internal - { - emit ProtocolFeeCollectorAddress(protocolFeeCollector, updatedProtocolFeeCollector); - protocolFeeCollector = updatedProtocolFeeCollector; - } - - /// @dev Pays a protocol fee for a single fill. - /// @param orderHash Hash of the order being filled. - /// @param protocolFee Value of the fee being paid (equal to protocolFeeMultiplier * tx.gasPrice). - /// @param makerAddress Address of maker of order being filled. - /// @param takerAddress Address filling order. - function _paySingleProtocolFee( - bytes32 orderHash, - uint256 protocolFee, - address makerAddress, - address takerAddress - ) - internal - returns (bool) - { - address feeCollector = protocolFeeCollector; - if (feeCollector != address(0)) { - _payProtocolFeeToFeeCollector( - orderHash, - feeCollector, - address(this).balance, - protocolFee, - makerAddress, - takerAddress - ); - return true; - } else { - return false; - } - } - - /// @dev Pays a protocol fee for two orders (used when settling functions in MixinMatchOrders) - /// @param orderHash1 Hash of the first order being filled. - /// @param orderHash2 Hash of the second order being filled. - /// @param protocolFee Value of the fee being paid (equal to protocolFeeMultiplier * tx.gasPrice). - /// @param makerAddress1 Address of maker of first order being filled. - /// @param makerAddress2 Address of maker of second order being filled. - /// @param takerAddress Address filling orders. - function _payTwoProtocolFees( - bytes32 orderHash1, - bytes32 orderHash2, - uint256 protocolFee, - address makerAddress1, - address makerAddress2, - address takerAddress - ) - internal - returns (bool) - { - address feeCollector = protocolFeeCollector; - if (feeCollector != address(0)) { - // Since the `BALANCE` opcode costs 400 gas, we choose to calculate this value by hand rather than calling it twice. - uint256 exchangeBalance = address(this).balance; - - // Pay protocol fee and attribute to first maker - uint256 valuePaid = _payProtocolFeeToFeeCollector( - orderHash1, - feeCollector, - exchangeBalance, - protocolFee, - makerAddress1, - takerAddress - ); - - // Pay protocol fee and attribute to second maker - _payProtocolFeeToFeeCollector( - orderHash2, - feeCollector, - exchangeBalance - valuePaid, - protocolFee, - makerAddress2, - takerAddress - ); - return true; - } else { - return false; - } - } - - /// @dev Pays a single protocol fee. - /// @param orderHash Hash of the order being filled. - /// @param feeCollector Address of protocolFeeCollector contract. - /// @param exchangeBalance Assumed ETH balance of Exchange contract (in wei). - /// @param protocolFee Value of the fee being paid (equal to protocolFeeMultiplier * tx.gasPrice). - /// @param makerAddress Address of maker of order being filled. - /// @param takerAddress Address filling order. - function _payProtocolFeeToFeeCollector( - bytes32 orderHash, - address feeCollector, - uint256 exchangeBalance, - uint256 protocolFee, - address makerAddress, - address takerAddress - ) - internal - returns (uint256 valuePaid) - { - // Do not send a value with the call if the exchange has an insufficient balance - // The protocolFeeCollector contract will fallback to charging WETH - if (exchangeBalance >= protocolFee) { - valuePaid = protocolFee; - } - bytes memory payProtocolFeeData = abi.encodeWithSelector( - IStaking(address(0)).payProtocolFee.selector, - makerAddress, - takerAddress, - protocolFee - ); - // solhint-disable-next-line avoid-call-value - (bool didSucceed, bytes memory returnData) = feeCollector.call.value(valuePaid)(payProtocolFeeData); - if (!didSucceed) { - LibRichErrors.rrevert(LibExchangeRichErrors.PayProtocolFeeError( - orderHash, - protocolFee, - makerAddress, - takerAddress, - returnData - )); - } - return valuePaid; - } -} diff --git a/contracts/exchange/contracts/src/MixinSignatureValidator.sol b/contracts/exchange/contracts/src/MixinSignatureValidator.sol deleted file mode 100644 index e9b1557c86..0000000000 --- a/contracts/exchange/contracts/src/MixinSignatureValidator.sol +++ /dev/null @@ -1,625 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "./interfaces/IWallet.sol"; -import "./interfaces/IEIP1271Wallet.sol"; -import "./interfaces/ISignatureValidator.sol"; -import "./interfaces/IEIP1271Data.sol"; -import "./MixinTransactions.sol"; - - -contract MixinSignatureValidator is - LibEIP712ExchangeDomain, - LibEIP1271, - ISignatureValidator, - MixinTransactions -{ - using LibBytes for bytes; - using LibOrder for LibOrder.Order; - using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction; - - // Magic bytes to be returned by `Wallet` signature type validators. - // bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)")) - bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; - - /// @dev Mapping of hash => signer => signed - /// @param 0 Order hash. - /// @param 1 Signer address. - /// @return 0 Whether the hash is presigned. - mapping (bytes32 => mapping (address => bool)) public preSigned; - - /// @dev Mapping of signer => validator => approved - /// @param 0 Signer address. - /// @param 1 Signature validator address. - /// @return 0 Whether the validator is allowed to validate on behalf of the signer. - mapping (address => mapping (address => bool)) public allowedValidators; - - /// @dev Approves a hash on-chain. - /// After presigning a hash, the preSign signature type will become valid for that hash and signer. - /// @param hash Any 32-byte hash. - function preSign(bytes32 hash) - external - payable - refundFinalBalanceNoReentry - { - address signerAddress = _getCurrentContextAddress(); - preSigned[hash][signerAddress] = true; - } - - /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf - /// using the `Validator` signature type. - /// @param validatorAddress Address of Validator contract. - /// @param approval Approval or disapproval of Validator contract. - function setSignatureValidatorApproval( - address validatorAddress, - bool approval - ) - external - payable - refundFinalBalanceNoReentry - { - 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 isValid `true` if the signature is valid for the given hash and signer. - function isValidHashSignature( - bytes32 hash, - address signerAddress, - bytes memory signature - ) - public - view - returns (bool isValid) - { - SignatureType signatureType = _readValidSignatureType( - hash, - signerAddress, - signature - ); - // Only hash-compatible signature types can be handled by this - // function. - if ( - signatureType == SignatureType.Validator || - signatureType == SignatureType.EIP1271Wallet - ) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INAPPROPRIATE_SIGNATURE_TYPE, - hash, - signerAddress, - signature - )); - } - isValid = _validateHashSignatureTypes( - signatureType, - hash, - signerAddress, - signature - ); - return isValid; - } - - /// @dev Verifies that a signature for an order is valid. - /// @param order The order. - /// @param signature Proof that the order has been signed by signer. - /// @return isValid `true` if the signature is valid for the given order and signer. - function isValidOrderSignature( - LibOrder.Order memory order, - bytes memory signature - ) - public - view - returns (bool isValid) - { - bytes32 orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); - isValid = _isValidOrderWithHashSignature( - order, - orderHash, - signature - ); - return isValid; - } - - /// @dev Verifies that a signature for a transaction is valid. - /// @param transaction The transaction. - /// @param signature Proof that the order has been signed by signer. - /// @return isValid `true` if the signature is valid for the given transaction and signer. - function isValidTransactionSignature( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature - ) - public - view - returns (bool isValid) - { - bytes32 transactionHash = transaction.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); - isValid = _isValidTransactionWithHashSignature( - transaction, - transactionHash, - signature - ); - return isValid; - } - - /// @dev Verifies that an order, with provided order hash, has been signed - /// by the given signer. - /// @param order The order. - /// @param orderHash The hash of the order. - /// @param signature Proof that the hash has been signed by signer. - /// @return isValid True if the signature is valid for the given order and signer. - function _isValidOrderWithHashSignature( - LibOrder.Order memory order, - bytes32 orderHash, - bytes memory signature - ) - internal - view - returns (bool isValid) - { - address signerAddress = order.makerAddress; - SignatureType signatureType = _readValidSignatureType( - orderHash, - signerAddress, - signature - ); - if (signatureType == SignatureType.Validator) { - // The entire order is verified by a validator contract. - isValid = _validateBytesWithValidator( - _encodeEIP1271OrderWithHash(order, orderHash), - orderHash, - signerAddress, - signature - ); - } else if (signatureType == SignatureType.EIP1271Wallet) { - // The entire order is verified by a wallet contract. - isValid = _validateBytesWithWallet( - _encodeEIP1271OrderWithHash(order, orderHash), - signerAddress, - signature - ); - } else { - // Otherwise, it's one of the hash-only signature types. - isValid = _validateHashSignatureTypes( - signatureType, - orderHash, - signerAddress, - signature - ); - } - return isValid; - } - - /// @dev Verifies that a transaction, with provided order hash, has been signed - /// by the given signer. - /// @param transaction The transaction. - /// @param transactionHash The hash of the transaction. - /// @param signature Proof that the hash has been signed by signer. - /// @return isValid True if the signature is valid for the given transaction and signer. - function _isValidTransactionWithHashSignature( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes32 transactionHash, - bytes memory signature - ) - internal - view - returns (bool isValid) - { - address signerAddress = transaction.signerAddress; - SignatureType signatureType = _readValidSignatureType( - transactionHash, - signerAddress, - signature - ); - if (signatureType == SignatureType.Validator) { - // The entire transaction is verified by a validator contract. - isValid = _validateBytesWithValidator( - _encodeEIP1271TransactionWithHash(transaction, transactionHash), - transactionHash, - signerAddress, - signature - ); - } else if (signatureType == SignatureType.EIP1271Wallet) { - // The entire transaction is verified by a wallet contract. - isValid = _validateBytesWithWallet( - _encodeEIP1271TransactionWithHash(transaction, transactionHash), - signerAddress, - signature - ); - } else { - // Otherwise, it's one of the hash-only signature types. - isValid = _validateHashSignatureTypes( - signatureType, - transactionHash, - signerAddress, - signature - ); - } - return isValid; - } - - /// Validates a hash-only signature type - /// (anything but `Validator` and `EIP1271Wallet`). - function _validateHashSignatureTypes( - SignatureType signatureType, - bytes32 hash, - address signerAddress, - bytes memory signature - ) - private - view - returns (bool isValid) - { - // 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. - if (signatureType == SignatureType.Invalid) { - if (signature.length != 1) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signerAddress, - signature - )); - } - isValid = false; - - // Signature using EIP712 - } else if (signatureType == SignatureType.EIP712) { - if (signature.length != 66) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signerAddress, - signature - )); - } - uint8 v = uint8(signature[0]); - bytes32 r = signature.readBytes32(1); - bytes32 s = signature.readBytes32(33); - address recovered = ecrecover( - hash, - v, - r, - s - ); - isValid = signerAddress == recovered; - - // Signed using web3.eth_sign - } else if (signatureType == SignatureType.EthSign) { - if (signature.length != 66) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signerAddress, - signature - )); - } - uint8 v = uint8(signature[0]); - bytes32 r = signature.readBytes32(1); - bytes32 s = signature.readBytes32(33); - address recovered = ecrecover( - keccak256(abi.encodePacked( - "\x19Ethereum Signed Message:\n32", - hash - )), - v, - r, - s - ); - isValid = signerAddress == recovered; - - // Signature verified by wallet contract. - } else if (signatureType == SignatureType.Wallet) { - isValid = _validateHashWithWallet( - hash, - signerAddress, - signature - ); - - // Otherwise, signatureType == SignatureType.PreSigned - } else { - assert(signatureType == SignatureType.PreSigned); - // Signer signed hash previously using the preSign function. - isValid = preSigned[hash][signerAddress]; - } - return isValid; - } - - /// @dev Reads the `SignatureType` from a signature with minimal validation. - function _readSignatureType( - bytes32 hash, - address signerAddress, - bytes memory signature - ) - private - pure - returns (SignatureType) - { - if (signature.length == 0) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signerAddress, - signature - )); - } - return SignatureType(uint8(signature[signature.length - 1])); - } - - /// @dev Reads the `SignatureType` from the end of a signature and validates it. - function _readValidSignatureType( - bytes32 hash, - address signerAddress, - bytes memory signature - ) - private - pure - returns (SignatureType signatureType) - { - // Read the signatureType from the signature - signatureType = _readSignatureType( - hash, - signerAddress, - signature - ); - - // Disallow address zero because ecrecover() returns zero on failure. - if (signerAddress == address(0)) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INVALID_SIGNER, - hash, - signerAddress, - signature - )); - } - - // Ensure signature is supported - if (uint8(signatureType) >= uint8(SignatureType.NSignatureTypes)) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.UNSUPPORTED, - hash, - signerAddress, - signature - )); - } - - // 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) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.ILLEGAL, - hash, - signerAddress, - signature - )); - } - - return signatureType; - } - - /// @dev ABI encodes an order and hash with a selector to be passed into - /// an EIP1271 compliant `isValidSignature` function. - function _encodeEIP1271OrderWithHash( - LibOrder.Order memory order, - bytes32 orderHash - ) - private - pure - returns (bytes memory encoded) - { - return abi.encodeWithSelector( - IEIP1271Data(address(0)).OrderWithHash.selector, - order, - orderHash - ); - } - - /// @dev ABI encodes a transaction and hash with a selector to be passed into - /// an EIP1271 compliant `isValidSignature` function. - function _encodeEIP1271TransactionWithHash( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes32 transactionHash - ) - private - pure - returns (bytes memory encoded) - { - return abi.encodeWithSelector( - IEIP1271Data(address(0)).ZeroExTransactionWithHash.selector, - transaction, - transactionHash - ); - } - - /// @dev Verifies a hash and 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 signature is validated by the Wallet. - function _validateHashWithWallet( - bytes32 hash, - address walletAddress, - bytes memory signature - ) - private - view - returns (bool) - { - // Backup length of signature - uint256 signatureLength = signature.length; - // Temporarily remove signatureType byte from end of signature - signature.writeLength(signatureLength - 1); - // Encode the call data. - bytes memory callData = abi.encodeWithSelector( - IWallet(address(0)).isValidSignature.selector, - hash, - signature - ); - // Restore the original signature length - signature.writeLength(signatureLength); - // Static call the verification function. - (bool didSucceed, bytes memory returnData) = walletAddress.staticcall(callData); - // Return the validity of the signature if the call was successful - if (didSucceed && returnData.length == 32) { - return returnData.readBytes4(0) == LEGACY_WALLET_MAGIC_VALUE; - } - // Revert if the call was unsuccessful - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureWalletError( - hash, - walletAddress, - signature, - returnData - )); - } - - /// @dev Verifies arbitrary data and a signature via an EIP1271 Wallet - /// contract, where the wallet address is also the signer address. - /// @param data Arbitrary signed data. - /// @param walletAddress Contract that will verify the data and signature. - /// @param signature Proof that the data has been signed by signer. - /// @return isValid True if the signature is validated by the Wallet. - function _validateBytesWithWallet( - bytes memory data, - address walletAddress, - bytes memory signature - ) - private - view - returns (bool isValid) - { - isValid = _staticCallEIP1271WalletWithReducedSignatureLength( - walletAddress, - data, - signature, - 1 // The last byte of the signature (signatureType) is removed before making the staticcall - ); - return isValid; - } - - /// @dev Verifies arbitrary data and a signature via an EIP1271 contract - /// whose address is encoded in the signature. - /// @param data Arbitrary signed data. - /// @param hash The hash associated with the data. - /// @param signerAddress Address that should have signed the given hash. - /// @param signature Proof that the data has been signed by signer. - /// @return isValid True if the signature is validated by the validator contract. - function _validateBytesWithValidator( - bytes memory data, - bytes32 hash, - address signerAddress, - bytes memory signature - ) - private - view - returns (bool isValid) - { - uint256 signatureLength = signature.length; - if (signatureLength < 21) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, - hash, - signerAddress, - signature - )); - } - // The validator address is appended to the signature before the signatureType. - // Read the validator address from the signature. - address validatorAddress = signature.readAddress(signatureLength - 21); - // Ensure signer has approved validator. - if (!allowedValidators[signerAddress][validatorAddress]) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureValidatorNotApprovedError( - signerAddress, - validatorAddress - )); - } - isValid = _staticCallEIP1271WalletWithReducedSignatureLength( - validatorAddress, - data, - signature, - 21 // The last 21 bytes of the signature (validatorAddress + signatureType) are removed before making the staticcall - ); - return isValid; - } - - /// @dev Performs a staticcall to an EIP1271 compiant `isValidSignature` function and validates the output. - /// @param verifyingContractAddress Address of EIP1271Wallet or Validator contract. - /// @param data Arbitrary signed data. - /// @param signature Proof that the hash has been signed by signer. Bytes will be temporarily be popped - /// off of the signature before calling `isValidSignature`. - /// @param ignoredSignatureBytesLen The amount of bytes that will be temporarily popped off the the signature. - /// @return The validity of the signature. - function _staticCallEIP1271WalletWithReducedSignatureLength( - address verifyingContractAddress, - bytes memory data, - bytes memory signature, - uint256 ignoredSignatureBytesLen - ) - private - view - returns (bool) - { - // Backup length of the signature - uint256 signatureLength = signature.length; - // Temporarily remove bytes from signature end - signature.writeLength(signatureLength - ignoredSignatureBytesLen); - bytes memory callData = abi.encodeWithSelector( - IEIP1271Wallet(address(0)).isValidSignature.selector, - data, - signature - ); - // Restore original signature length - signature.writeLength(signatureLength); - // Static call the verification function - (bool didSucceed, bytes memory returnData) = verifyingContractAddress.staticcall(callData); - // Return the validity of the signature if the call was successful - if (didSucceed && returnData.length == 32) { - return returnData.readBytes4(0) == EIP1271_MAGIC_VALUE; - } - // Revert if the call was unsuccessful - LibRichErrors.rrevert(LibExchangeRichErrors.EIP1271SignatureError( - verifyingContractAddress, - data, - signature, - returnData - )); - } -} diff --git a/contracts/exchange/contracts/src/MixinTransactions.sol b/contracts/exchange/contracts/src/MixinTransactions.sol deleted file mode 100644 index 8c20f8216f..0000000000 --- a/contracts/exchange/contracts/src/MixinTransactions.sol +++ /dev/null @@ -1,221 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/Refundable.sol"; -import "./interfaces/ITransactions.sol"; -import "./interfaces/ISignatureValidator.sol"; - - -contract MixinTransactions is - Refundable, - LibEIP712ExchangeDomain, - ISignatureValidator, - ITransactions -{ - using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction; - - /// @dev Mapping of transaction hash => executed - /// This prevents transactions from being executed more than once. - /// @param 0 The transaction hash. - /// @return 0 Whether the transation was executed. - mapping (bytes32 => bool) public transactionsExecuted; - - /// @dev Address of current transaction signer. - /// @return 0 The address associated with the the current transaction. - address public currentContextAddress; - - /// @dev Executes an Exchange method call in the context of signer. - /// @param transaction 0x transaction structure. - /// @param signature Proof that transaction has been signed by signer. - /// @return ABI encoded return data of the underlying Exchange function call. - function executeTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature - ) - public - payable - disableRefundUntilEnd - returns (bytes memory) - { - return _executeTransaction(transaction, signature); - } - - /// @dev Executes a batch of Exchange method calls in the context of signer(s). - /// @param transactions Array of 0x transaction structures. - /// @param signatures Array of proofs that transactions have been signed by signer(s). - /// @return returnData Array containing ABI encoded return data for each of the underlying Exchange function calls. - function batchExecuteTransactions( - LibZeroExTransaction.ZeroExTransaction[] memory transactions, - bytes[] memory signatures - ) - public - payable - disableRefundUntilEnd - returns (bytes[] memory returnData) - { - uint256 length = transactions.length; - returnData = new bytes[](length); - for (uint256 i = 0; i != length; i++) { - returnData[i] = _executeTransaction(transactions[i], signatures[i]); - } - return returnData; - } - - /// @dev Executes an Exchange method call in the context of signer. - /// @param transaction 0x transaction structure. - /// @param signature Proof that transaction has been signed by signer. - /// @return ABI encoded return data of the underlying Exchange function call. - function _executeTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature - ) - internal - returns (bytes memory) - { - bytes32 transactionHash = transaction.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); - - _assertExecutableTransaction( - transaction, - signature, - transactionHash - ); - - // Set the current transaction signer - address signerAddress = transaction.signerAddress; - _setCurrentContextAddressIfRequired(signerAddress, signerAddress); - - // Execute transaction - transactionsExecuted[transactionHash] = true; - (bool didSucceed, bytes memory returnData) = address(this).delegatecall(transaction.data); - if (!didSucceed) { - LibRichErrors.rrevert(LibExchangeRichErrors.TransactionExecutionError( - transactionHash, - returnData - )); - } - - // Reset current transaction signer if it was previously updated - _setCurrentContextAddressIfRequired(signerAddress, address(0)); - - emit TransactionExecution(transactionHash); - - return returnData; - } - - /// @dev Validates context for executeTransaction. Succeeds or throws. - /// @param transaction 0x transaction structure. - /// @param signature Proof that transaction has been signed by signer. - /// @param transactionHash EIP712 typed data hash of 0x transaction. - function _assertExecutableTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature, - bytes32 transactionHash - ) - internal - view - { - // Check transaction is not expired - // solhint-disable-next-line not-rely-on-time - if (block.timestamp >= transaction.expirationTimeSeconds) { - LibRichErrors.rrevert(LibExchangeRichErrors.TransactionError( - LibExchangeRichErrors.TransactionErrorCodes.EXPIRED, - transactionHash - )); - } - - // Validate that transaction is executed with the correct gasPrice - uint256 requiredGasPrice = transaction.gasPrice; - if (tx.gasprice != requiredGasPrice) { - LibRichErrors.rrevert(LibExchangeRichErrors.TransactionGasPriceError( - transactionHash, - tx.gasprice, - requiredGasPrice - )); - } - - // Prevent `executeTransaction` from being called when context is already set - address currentContextAddress_ = currentContextAddress; - if (currentContextAddress_ != address(0)) { - LibRichErrors.rrevert(LibExchangeRichErrors.TransactionInvalidContextError( - transactionHash, - currentContextAddress_ - )); - } - - // Validate transaction has not been executed - if (transactionsExecuted[transactionHash]) { - LibRichErrors.rrevert(LibExchangeRichErrors.TransactionError( - LibExchangeRichErrors.TransactionErrorCodes.ALREADY_EXECUTED, - transactionHash - )); - } - - // Validate signature - // Transaction always valid if signer is sender of transaction - address signerAddress = transaction.signerAddress; - if (signerAddress != msg.sender && !_isValidTransactionWithHashSignature( - transaction, - transactionHash, - signature - ) - ) { - LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( - LibExchangeRichErrors.SignatureErrorCodes.BAD_TRANSACTION_SIGNATURE, - transactionHash, - signerAddress, - signature - )); - } - } - - /// @dev Sets the currentContextAddress if the current context is not msg.sender. - /// @param signerAddress Address of the transaction signer. - /// @param contextAddress The current context address. - function _setCurrentContextAddressIfRequired( - address signerAddress, - address contextAddress - ) - internal - { - if (signerAddress != msg.sender) { - currentContextAddress = contextAddress; - } - } - - /// @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/contracts/exchange/contracts/src/MixinTransferSimulator.sol b/contracts/exchange/contracts/src/MixinTransferSimulator.sol deleted file mode 100644 index 1f4ad789ca..0000000000 --- a/contracts/exchange/contracts/src/MixinTransferSimulator.sol +++ /dev/null @@ -1,60 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./MixinAssetProxyDispatcher.sol"; - - -contract MixinTransferSimulator is - MixinAssetProxyDispatcher -{ - /// @dev This function may be used to simulate any amount of transfers - /// As they would occur through the Exchange contract. Note that this function - /// will always revert, even if all transfers are successful. However, it may - /// be used with eth_call or with a try/catch pattern in order to simulate - /// the results of the transfers. - /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. - /// @param fromAddresses Array containing the `from` addresses that correspond with each transfer. - /// @param toAddresses Array containing the `to` addresses that correspond with each transfer. - /// @param amounts Array containing the amounts that correspond to each transfer. - /// @return This function does not return a value. However, it will always revert with - /// `Error("TRANSFERS_SUCCESSFUL")` if all of the transfers were successful. - function simulateDispatchTransferFromCalls( - bytes[] memory assetData, - address[] memory fromAddresses, - address[] memory toAddresses, - uint256[] memory amounts - ) - public - { - uint256 length = assetData.length; - for (uint256 i = 0; i != length; i++) { - _dispatchTransferFrom( - // The index is passed in as `orderHash` so that a failed transfer can be quickly identified when catching the error - bytes32(i), - assetData[i], - fromAddresses[i], - toAddresses[i], - amounts[i] - ); - } - revert("TRANSFERS_SUCCESSFUL"); - } -} diff --git a/contracts/exchange/contracts/src/MixinWrapperFunctions.sol b/contracts/exchange/contracts/src/MixinWrapperFunctions.sol deleted file mode 100644 index a7ff4c51b1..0000000000 --- a/contracts/exchange/contracts/src/MixinWrapperFunctions.sol +++ /dev/null @@ -1,353 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "./interfaces/IExchangeCore.sol"; -import "./interfaces/IWrapperFunctions.sol"; -import "./MixinExchangeCore.sol"; - - -contract MixinWrapperFunctions is - IWrapperFunctions, - MixinExchangeCore -{ - using LibSafeMath for uint256; - - /// @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. - /// @return fillResults Amounts filled and fees paid. - function fillOrKillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.FillResults memory fillResults) - { - fillResults = _fillOrKillOrder( - order, - takerAssetFillAmount, - signature - ); - return fillResults; - } - - /// @dev 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 fillResults Array of amounts filled and fees paid by makers and taker. - function batchFillOrders( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.FillResults[] memory fillResults) - { - uint256 ordersLength = orders.length; - fillResults = new LibFillResults.FillResults[](ordersLength); - for (uint256 i = 0; i != ordersLength; i++) { - fillResults[i] = _fillOrder( - orders[i], - takerAssetFillAmounts[i], - signatures[i] - ); - } - return fillResults; - } - - /// @dev Executes multiple calls of fillOrKillOrder. - /// @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 fillResults Array of amounts filled and fees paid by makers and taker. - function batchFillOrKillOrders( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - public - payable - refundFinalBalanceNoReentry - returns (LibFillResults.FillResults[] memory fillResults) - { - uint256 ordersLength = orders.length; - fillResults = new LibFillResults.FillResults[](ordersLength); - for (uint256 i = 0; i != ordersLength; i++) { - fillResults[i] = _fillOrKillOrder( - orders[i], - takerAssetFillAmounts[i], - signatures[i] - ); - } - return fillResults; - } - - /// @dev Executes multiple calls of fillOrder. If any fill reverts, the error is caught and ignored. - /// @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 fillResults Array of amounts filled and fees paid by makers and taker. - function batchFillOrdersNoThrow( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - public - payable - disableRefundUntilEnd - returns (LibFillResults.FillResults[] memory fillResults) - { - uint256 ordersLength = orders.length; - fillResults = new LibFillResults.FillResults[](ordersLength); - for (uint256 i = 0; i != ordersLength; i++) { - fillResults[i] = _fillOrderNoThrow( - orders[i], - takerAssetFillAmounts[i], - signatures[i] - ); - } - return fillResults; - } - - /// @dev Executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. - /// If any fill reverts, the error is caught and ignored. - /// NOTE: This function does not enforce that the takerAsset is the same for each order. - /// @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 fillResults Amounts filled and fees paid by makers and taker. - function marketSellOrdersNoThrow( - LibOrder.Order[] memory orders, - uint256 takerAssetFillAmount, - bytes[] memory signatures - ) - public - payable - disableRefundUntilEnd - returns (LibFillResults.FillResults memory fillResults) - { - uint256 ordersLength = orders.length; - for (uint256 i = 0; i != ordersLength; i++) { - - // Calculate the remaining amount of takerAsset to sell - uint256 remainingTakerAssetFillAmount = takerAssetFillAmount.safeSub(fillResults.takerAssetFilledAmount); - - // Attempt to sell the remaining amount of takerAsset - LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( - orders[i], - remainingTakerAssetFillAmount, - signatures[i] - ); - - // Update amounts filled and fees paid by maker and taker - fillResults = LibFillResults.addFillResults(fillResults, singleFillResults); - - // Stop execution if the entire amount of takerAsset has been sold - if (fillResults.takerAssetFilledAmount >= takerAssetFillAmount) { - break; - } - } - return fillResults; - } - - /// @dev Executes multiple calls of fillOrder until total amount of makerAsset is bought by taker. - /// If any fill reverts, the error is caught and ignored. - /// NOTE: This function does not enforce that the makerAsset is the same for each order. - /// @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 fillResults Amounts filled and fees paid by makers and taker. - function marketBuyOrdersNoThrow( - LibOrder.Order[] memory orders, - uint256 makerAssetFillAmount, - bytes[] memory signatures - ) - public - payable - disableRefundUntilEnd - returns (LibFillResults.FillResults memory fillResults) - { - uint256 ordersLength = orders.length; - for (uint256 i = 0; i != ordersLength; i++) { - - // Calculate the remaining amount of makerAsset to buy - uint256 remainingMakerAssetFillAmount = makerAssetFillAmount.safeSub(fillResults.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 = LibMath.getPartialAmountCeil( - orders[i].takerAssetAmount, - orders[i].makerAssetAmount, - remainingMakerAssetFillAmount - ); - - // Attempt to sell the remaining amount of takerAsset - LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( - orders[i], - remainingTakerAssetFillAmount, - signatures[i] - ); - - // Update amounts filled and fees paid by maker and taker - fillResults = LibFillResults.addFillResults(fillResults, singleFillResults); - - // Stop execution if the entire amount of makerAsset has been bought - if (fillResults.makerAssetFilledAmount >= makerAssetFillAmount) { - break; - } - } - return fillResults; - } - - /// @dev Calls marketSellOrdersNoThrow then reverts if < takerAssetFillAmount has been sold. - /// NOTE: This function does not enforce that the takerAsset is the same for each order. - /// @param orders Array of order specifications. - /// @param takerAssetFillAmount Minimum amount of takerAsset to sell. - /// @param signatures Proofs that orders have been signed by makers. - /// @return fillResults Amounts filled and fees paid by makers and taker. - function marketSellOrdersFillOrKill( - LibOrder.Order[] memory orders, - uint256 takerAssetFillAmount, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults memory fillResults) - { - fillResults = marketSellOrdersNoThrow(orders, takerAssetFillAmount, signatures); - if (fillResults.takerAssetFilledAmount < takerAssetFillAmount) { - LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError( - LibExchangeRichErrors.IncompleteFillErrorCode.INCOMPLETE_MARKET_SELL_ORDERS, - takerAssetFillAmount, - fillResults.takerAssetFilledAmount - )); - } - } - - /// @dev Calls marketBuyOrdersNoThrow then reverts if < makerAssetFillAmount has been bought. - /// NOTE: This function does not enforce that the makerAsset is the same for each order. - /// @param orders Array of order specifications. - /// @param makerAssetFillAmount Minimum amount of makerAsset to buy. - /// @param signatures Proofs that orders have been signed by makers. - /// @return fillResults Amounts filled and fees paid by makers and taker. - function marketBuyOrdersFillOrKill( - LibOrder.Order[] memory orders, - uint256 makerAssetFillAmount, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults memory fillResults) - { - fillResults = marketBuyOrdersNoThrow(orders, makerAssetFillAmount, signatures); - if (fillResults.makerAssetFilledAmount < makerAssetFillAmount) { - LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError( - LibExchangeRichErrors.IncompleteFillErrorCode.INCOMPLETE_MARKET_BUY_ORDERS, - makerAssetFillAmount, - fillResults.makerAssetFilledAmount - )); - } - } - - /// @dev Executes multiple calls of cancelOrder. - /// @param orders Array of order specifications. - function batchCancelOrders(LibOrder.Order[] memory orders) - public - payable - refundFinalBalanceNoReentry - { - uint256 ordersLength = orders.length; - for (uint256 i = 0; i != ordersLength; i++) { - _cancelOrder(orders[i]); - } - } - - /// @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 fillResults ignature Proof that order has been created by maker. - function _fillOrKillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - fillResults = _fillOrder( - order, - takerAssetFillAmount, - signature - ); - if (fillResults.takerAssetFilledAmount != takerAssetFillAmount) { - LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError( - LibExchangeRichErrors.IncompleteFillErrorCode.INCOMPLETE_FILL_ORDER, - takerAssetFillAmount, - fillResults.takerAssetFilledAmount - )); - } - return fillResults; - } - - /// @dev Fills the input order. - /// Returns a null FillResults instance 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 fillResults 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) - { - // ABI encode calldata for `fillOrder` - bytes memory fillOrderCalldata = abi.encodeWithSelector( - IExchangeCore(address(0)).fillOrder.selector, - order, - takerAssetFillAmount, - signature - ); - - (bool didSucceed, bytes memory returnData) = address(this).delegatecall(fillOrderCalldata); - if (didSucceed) { - assert(returnData.length == 160); - fillResults = abi.decode(returnData, (LibFillResults.FillResults)); - } - // fillResults values will be 0 by default if call was unsuccessful - return fillResults; - } -} diff --git a/contracts/exchange/contracts/src/interfaces/IAssetProxy.sol b/contracts/exchange/contracts/src/interfaces/IAssetProxy.sol deleted file mode 100644 index 100a936ef4..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IAssetProxy.sol +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract IAssetProxy { - - /// @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 calldata 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/contracts/exchange/contracts/src/interfaces/IAssetProxyDispatcher.sol b/contracts/exchange/contracts/src/interfaces/IAssetProxyDispatcher.sol deleted file mode 100644 index b675473c52..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IAssetProxyDispatcher.sol +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract IAssetProxyDispatcher { - - // Logs registration of new asset proxy - event AssetProxyRegistered( - bytes4 id, // Id of new registered AssetProxy. - address assetProxy // Address of new registered AssetProxy. - ); - - /// @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/contracts/exchange/contracts/src/interfaces/IEIP1271Data.sol b/contracts/exchange/contracts/src/interfaces/IEIP1271Data.sol deleted file mode 100644 index a2d70859cd..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IEIP1271Data.sol +++ /dev/null @@ -1,48 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; - - -// solhint-disable -contract IEIP1271Data { - - /// @dev This function's selector is used when ABI encoding the order - /// and hash into a byte array before calling `isValidSignature`. - /// This function serves no other purpose. - function OrderWithHash( - LibOrder.Order calldata order, - bytes32 orderHash - ) - external - pure; - - /// @dev This function's selector is used when ABI encoding the transaction - /// and hash into a byte array before calling `isValidSignature`. - /// This function serves no other purpose. - function ZeroExTransactionWithHash( - LibZeroExTransaction.ZeroExTransaction calldata transaction, - bytes32 transactionHash - ) - external - pure; -} diff --git a/contracts/exchange/contracts/src/interfaces/IEIP1271Wallet.sol b/contracts/exchange/contracts/src/interfaces/IEIP1271Wallet.sol deleted file mode 100644 index 729e6ce5a5..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IEIP1271Wallet.sol +++ /dev/null @@ -1,38 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; - - -contract IEIP1271Wallet is - LibEIP1271 -{ - /// @dev Verifies that a signature is valid. - /// @param data Arbitrary signed data. - /// @param signature Proof that data has been signed. - /// @return magicValue bytes4(0x20c13b0b) if the signature check succeeds. - function isValidSignature( - bytes calldata data, - bytes calldata signature - ) - external - view - returns (bytes4 magicValue); -} diff --git a/contracts/exchange/contracts/src/interfaces/IExchange.sol b/contracts/exchange/contracts/src/interfaces/IExchange.sol deleted file mode 100644 index e375559f15..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IExchange.sol +++ /dev/null @@ -1,42 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./IExchangeCore.sol"; -import "./IProtocolFees.sol"; -import "./IMatchOrders.sol"; -import "./ISignatureValidator.sol"; -import "./ITransactions.sol"; -import "./IAssetProxyDispatcher.sol"; -import "./IWrapperFunctions.sol"; -import "./ITransferSimulator.sol"; - - -// solhint-disable no-empty-blocks -contract IExchange is - IProtocolFees, - IExchangeCore, - IMatchOrders, - ISignatureValidator, - ITransactions, - IAssetProxyDispatcher, - ITransferSimulator, - IWrapperFunctions -{} diff --git a/contracts/exchange/contracts/src/interfaces/IExchangeCore.sol b/contracts/exchange/contracts/src/interfaces/IExchangeCore.sol deleted file mode 100644 index 2b26f042c6..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IExchangeCore.sol +++ /dev/null @@ -1,98 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; - - -contract 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. - bytes makerAssetData, // Encoded data specific to makerAsset. - bytes takerAssetData, // Encoded data specific to takerAsset. - bytes makerFeeAssetData, // Encoded data specific to makerFeeAsset. - bytes takerFeeAssetData, // Encoded data specific to takerFeeAsset. - bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getTypedDataHash). - 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 makerFeeAssetData paid to feeRecipient by maker. - uint256 takerFeePaid, // Amount of takerFeeAssetData paid to feeRecipient by taker. - uint256 protocolFeePaid // Amount of eth or weth paid to the staking contract. - ); - - // 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. - bytes makerAssetData, // Encoded data specific to makerAsset. - bytes takerAssetData, // Encoded data specific to takerAsset. - address senderAddress, // Address that called the Exchange contract (msg.sender). - bytes32 indexed orderHash // EIP712 hash of order (see LibOrder.getTypedDataHash). - ); - - // 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 orderSenderAddress, // 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 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 - payable; - - /// @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 - payable - 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 - payable; - - /// @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/contracts/exchange/contracts/src/interfaces/IMatchOrders.sol b/contracts/exchange/contracts/src/interfaces/IMatchOrders.sol deleted file mode 100644 index f42c0f6703..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IMatchOrders.sol +++ /dev/null @@ -1,102 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; - - -contract IMatchOrders { - - /// @dev Match complementary orders that have a profitable spread. - /// Each order is filled at their respective price point, and - /// the matcher receives a profit denominated in the left maker asset. - /// @param leftOrders Set of orders with the same maker / taker asset. - /// @param rightOrders Set of orders to match against `leftOrders` - /// @param leftSignatures Proof that left orders were created by the left makers. - /// @param rightSignatures Proof that right orders were created by the right makers. - /// @return batchMatchedFillResults Amounts filled and profit generated. - function batchMatchOrders( - LibOrder.Order[] memory leftOrders, - LibOrder.Order[] memory rightOrders, - bytes[] memory leftSignatures, - bytes[] memory rightSignatures - ) - public - payable - returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults); - - /// @dev Match complementary orders that have a profitable spread. - /// Each order is maximally filled at their respective price point, and - /// the matcher receives a profit denominated in either the left maker asset, - /// right maker asset, or a combination of both. - /// @param leftOrders Set of orders with the same maker / taker asset. - /// @param rightOrders Set of orders to match against `leftOrders` - /// @param leftSignatures Proof that left orders were created by the left makers. - /// @param rightSignatures Proof that right orders were created by the right makers. - /// @return batchMatchedFillResults Amounts filled and profit generated. - function batchMatchOrdersWithMaximalFill( - LibOrder.Order[] memory leftOrders, - LibOrder.Order[] memory rightOrders, - bytes[] memory leftSignatures, - bytes[] memory rightSignatures - ) - public - payable - returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults); - - /// @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 - payable - returns (LibFillResults.MatchedFillResults memory matchedFillResults); - - /// @dev Match two complementary orders that have a profitable spread. - /// Each order is maximally filled at their respective price point, and - /// the matcher receives a profit denominated in either the left maker asset, - /// right maker asset, or a combination of both. - /// @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 by maker and taker of matched orders. - function matchOrdersWithMaximalFill( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - bytes memory leftSignature, - bytes memory rightSignature - ) - public - payable - returns (LibFillResults.MatchedFillResults memory matchedFillResults); -} diff --git a/contracts/exchange/contracts/src/interfaces/IProtocolFees.sol b/contracts/exchange/contracts/src/interfaces/IProtocolFees.sol deleted file mode 100644 index cd0e570c2f..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IProtocolFees.sol +++ /dev/null @@ -1,51 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract IProtocolFees { - - // Logs updates to the protocol fee multiplier. - event ProtocolFeeMultiplier(uint256 oldProtocolFeeMultiplier, uint256 updatedProtocolFeeMultiplier); - - // Logs updates to the protocolFeeCollector address. - event ProtocolFeeCollectorAddress(address oldProtocolFeeCollector, address updatedProtocolFeeCollector); - - /// @dev Allows the owner to update the protocol fee multiplier. - /// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier. - function setProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier) - external; - - /// @dev Allows the owner to update the protocolFeeCollector address. - /// @param updatedProtocolFeeCollector The updated protocolFeeCollector contract address. - function setProtocolFeeCollectorAddress(address updatedProtocolFeeCollector) - external; - - /// @dev Returns the protocolFeeMultiplier - function protocolFeeMultiplier() - external - view - returns (uint256); - - /// @dev Returns the protocolFeeCollector address - function protocolFeeCollector() - external - view - returns (address); -} diff --git a/contracts/exchange/contracts/src/interfaces/ISignatureValidator.sol b/contracts/exchange/contracts/src/interfaces/ISignatureValidator.sol deleted file mode 100644 index d664aad851..0000000000 --- a/contracts/exchange/contracts/src/interfaces/ISignatureValidator.sol +++ /dev/null @@ -1,130 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; - - -contract ISignatureValidator { - - // Allowed signature types. - enum SignatureType { - Illegal, // 0x00, default value - Invalid, // 0x01 - EIP712, // 0x02 - EthSign, // 0x03 - Wallet, // 0x04 - Validator, // 0x05 - PreSigned, // 0x06 - EIP1271Wallet, // 0x07 - NSignatureTypes // 0x08, number of signature types. Always leave at end. - } - - event SignatureValidatorApproval( - address indexed signerAddress, // Address that approves or disapproves a contract to verify signatures. - address indexed validatorAddress, // Address of signature validator contract. - bool isApproved // Approval or disapproval of validator contract. - ); - - /// @dev Approves a hash on-chain. - /// After presigning a hash, the preSign signature type will become valid for that hash and signer. - /// @param hash Any 32-byte hash. - function preSign(bytes32 hash) - external - payable; - - /// @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 - payable; - - /// @dev Verifies that a hash has been signed by the given signer. - /// @param hash Any 32-byte hash. - /// @param signature Proof that the hash has been signed by signer. - /// @return isValid `true` if the signature is valid for the given hash and signer. - function isValidHashSignature( - bytes32 hash, - address signerAddress, - bytes memory signature - ) - public - view - returns (bool isValid); - - /// @dev Verifies that a signature for an order is valid. - /// @param order The order. - /// @param signature Proof that the order has been signed by signer. - /// @return isValid true if the signature is valid for the given order and signer. - function isValidOrderSignature( - LibOrder.Order memory order, - bytes memory signature - ) - public - view - returns (bool isValid); - - /// @dev Verifies that a signature for a transaction is valid. - /// @param transaction The transaction. - /// @param signature Proof that the order has been signed by signer. - /// @return isValid true if the signature is valid for the given transaction and signer. - function isValidTransactionSignature( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature - ) - public - view - returns (bool isValid); - - /// @dev Verifies that an order, with provided order hash, has been signed - /// by the given signer. - /// @param order The order. - /// @param orderHash The hash of the order. - /// @param signature Proof that the hash has been signed by signer. - /// @return isValid True if the signature is valid for the given order and signer. - function _isValidOrderWithHashSignature( - LibOrder.Order memory order, - bytes32 orderHash, - bytes memory signature - ) - internal - view - returns (bool isValid); - - /// @dev Verifies that a transaction, with provided order hash, has been signed - /// by the given signer. - /// @param transaction The transaction. - /// @param transactionHash The hash of the transaction. - /// @param signature Proof that the hash has been signed by signer. - /// @return isValid True if the signature is valid for the given transaction and signer. - function _isValidTransactionWithHashSignature( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes32 transactionHash, - bytes memory signature - ) - internal - view - returns (bool isValid); -} diff --git a/contracts/exchange/contracts/src/interfaces/ITransactions.sol b/contracts/exchange/contracts/src/interfaces/ITransactions.sol deleted file mode 100644 index 7cb638a14c..0000000000 --- a/contracts/exchange/contracts/src/interfaces/ITransactions.sol +++ /dev/null @@ -1,63 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; - - -contract ITransactions { - - // TransactionExecution event is emitted when a ZeroExTransaction is executed. - event TransactionExecution(bytes32 indexed transactionHash); - - /// @dev Executes an Exchange method call in the context of signer. - /// @param transaction 0x transaction containing salt, signerAddress, and data. - /// @param signature Proof that transaction has been signed by signer. - /// @return ABI encoded return data of the underlying Exchange function call. - function executeTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature - ) - public - payable - returns (bytes memory); - - /// @dev Executes a batch of Exchange method calls in the context of signer(s). - /// @param transactions Array of 0x transactions containing salt, signerAddress, and data. - /// @param signatures Array of proofs that transactions have been signed by signer(s). - /// @return Array containing ABI encoded return data for each of the underlying Exchange function calls. - function batchExecuteTransactions( - LibZeroExTransaction.ZeroExTransaction[] memory transactions, - bytes[] memory signatures - ) - public - payable - returns (bytes[] memory); - - /// @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/contracts/exchange/contracts/src/interfaces/ITransferSimulator.sol b/contracts/exchange/contracts/src/interfaces/ITransferSimulator.sol deleted file mode 100644 index bc2cf29f4d..0000000000 --- a/contracts/exchange/contracts/src/interfaces/ITransferSimulator.sol +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -contract ITransferSimulator { - - /// @dev This function may be used to simulate any amount of transfers - /// As they would occur through the Exchange contract. Note that this function - /// will always revert, even if all transfers are successful. However, it may - /// be used with eth_call or with a try/catch pattern in order to simulate - /// the results of the transfers. - /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. - /// @param fromAddresses Array containing the `from` addresses that correspond with each transfer. - /// @param toAddresses Array containing the `to` addresses that correspond with each transfer. - /// @param amounts Array containing the amounts that correspond to each transfer. - /// @return This function does not return a value. However, it will always revert with - /// `Error("TRANSFERS_SUCCESSFUL")` if all of the transfers were successful. - function simulateDispatchTransferFromCalls( - bytes[] memory assetData, - address[] memory fromAddresses, - address[] memory toAddresses, - uint256[] memory amounts - ) - public; -} diff --git a/contracts/exchange/contracts/src/interfaces/IWallet.sol b/contracts/exchange/contracts/src/interfaces/IWallet.sol deleted file mode 100644 index 50a58d0e5e..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IWallet.sol +++ /dev/null @@ -1,38 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; - - -contract IWallet { - - /// @dev Validates a hash with the `Wallet` signature type. - /// @param hash Message hash that is signed. - /// @param signature Proof of signing. - /// @return magicValue `bytes4(0xb0671381)` if the signature check succeeds. - function isValidSignature( - bytes32 hash, - bytes calldata signature - ) - external - view - returns (bytes4 magicValue); -} diff --git a/contracts/exchange/contracts/src/interfaces/IWrapperFunctions.sol b/contracts/exchange/contracts/src/interfaces/IWrapperFunctions.sol deleted file mode 100644 index b0273d72e6..0000000000 --- a/contracts/exchange/contracts/src/interfaces/IWrapperFunctions.sol +++ /dev/null @@ -1,150 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; - - -contract IWrapperFunctions { - - /// @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 - payable - returns (LibFillResults.FillResults memory fillResults); - - /// @dev 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 Array of amounts filled and fees paid by makers and taker. - function batchFillOrders( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults[] memory fillResults); - - /// @dev Executes multiple calls of fillOrKillOrder. - /// @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 Array of amounts filled and fees paid by makers and taker. - function batchFillOrKillOrders( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults[] memory fillResults); - - /// @dev Executes multiple calls of fillOrder. If any fill reverts, the error is caught and ignored. - /// @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 Array of amounts filled and fees paid by makers and taker. - function batchFillOrdersNoThrow( - LibOrder.Order[] memory orders, - uint256[] memory takerAssetFillAmounts, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults[] memory fillResults); - - /// @dev Executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. - /// If any fill reverts, the error is caught and ignored. - /// NOTE: This function does not enforce that the takerAsset is the same for each order. - /// @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 - payable - returns (LibFillResults.FillResults memory fillResults); - - /// @dev Executes multiple calls of fillOrder until total amount of makerAsset is bought by taker. - /// If any fill reverts, the error is caught and ignored. - /// NOTE: This function does not enforce that the makerAsset is the same for each order. - /// @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 - payable - returns (LibFillResults.FillResults memory fillResults); - - /// @dev Calls marketSellOrdersNoThrow then reverts if < takerAssetFillAmount has been sold. - /// NOTE: This function does not enforce that the takerAsset is the same for each order. - /// @param orders Array of order specifications. - /// @param takerAssetFillAmount Minimum 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 marketSellOrdersFillOrKill( - LibOrder.Order[] memory orders, - uint256 takerAssetFillAmount, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults memory fillResults); - - /// @dev Calls marketBuyOrdersNoThrow then reverts if < makerAssetFillAmount has been bought. - /// NOTE: This function does not enforce that the makerAsset is the same for each order. - /// @param orders Array of order specifications. - /// @param makerAssetFillAmount Minimum 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 marketBuyOrdersFillOrKill( - LibOrder.Order[] memory orders, - uint256 makerAssetFillAmount, - bytes[] memory signatures - ) - public - payable - returns (LibFillResults.FillResults memory fillResults); - - /// @dev Executes multiple calls of cancelOrder. - /// @param orders Array of order specifications. - function batchCancelOrders(LibOrder.Order[] memory orders) - public - payable; -} diff --git a/contracts/exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol b/contracts/exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol deleted file mode 100644 index 8d0e77fdd1..0000000000 --- a/contracts/exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol +++ /dev/null @@ -1,356 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -library LibExchangeRichErrorDecoder { - - using LibBytes for bytes; - - /// @dev Decompose an ABI-encoded SignatureError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return signerAddress The expected signer of the hash. - /// @return signature The full signature. - function decodeSignatureError(bytes memory encoded) - internal - pure - returns ( - LibExchangeRichErrors.SignatureErrorCodes errorCode, - bytes32 hash, - address signerAddress, - bytes memory signature - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureErrorSelector()); - uint8 _errorCode; - (_errorCode, hash, signerAddress, signature) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (uint8, bytes32, address, bytes) - ); - errorCode = LibExchangeRichErrors.SignatureErrorCodes(_errorCode); - } - - /// @dev Decompose an ABI-encoded SignatureValidatorError. - /// @param encoded ABI-encoded revert error. - /// @return signerAddress The expected signer of the hash. - /// @return signature The full signature bytes. - /// @return errorData The revert data thrown by the validator contract. - function decodeEIP1271SignatureError(bytes memory encoded) - internal - pure - returns ( - address verifyingContractAddress, - bytes memory data, - bytes memory signature, - bytes memory errorData - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.EIP1271SignatureErrorSelector()); - (verifyingContractAddress, data, signature, errorData) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (address, bytes, bytes, bytes) - ); - } - - /// @dev Decompose an ABI-encoded SignatureValidatorNotApprovedError. - /// @param encoded ABI-encoded revert error. - /// @return signerAddress The expected signer of the hash. - /// @return validatorAddress The expected validator. - function decodeSignatureValidatorNotApprovedError(bytes memory encoded) - internal - pure - returns ( - address signerAddress, - address validatorAddress - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureValidatorNotApprovedErrorSelector()); - (signerAddress, validatorAddress) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (address, address) - ); - } - - /// @dev Decompose an ABI-encoded SignatureWalletError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return signerAddress The expected signer of the hash. - /// @return signature The full signature bytes. - /// @return errorData The revert data thrown by the validator contract. - function decodeSignatureWalletError(bytes memory encoded) - internal - pure - returns ( - bytes32 hash, - address signerAddress, - bytes memory signature, - bytes memory errorData - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureWalletErrorSelector()); - (hash, signerAddress, signature, errorData) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (bytes32, address, bytes, bytes) - ); - } - - /// @dev Decompose an ABI-encoded OrderStatusError. - /// @param encoded ABI-encoded revert error. - /// @return orderHash The order hash. - /// @return orderStatus The order status. - function decodeOrderStatusError(bytes memory encoded) - internal - pure - returns ( - bytes32 orderHash, - LibOrder.OrderStatus orderStatus - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.OrderStatusErrorSelector()); - uint8 _orderStatus; - (orderHash, _orderStatus) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (bytes32, uint8) - ); - orderStatus = LibOrder.OrderStatus(_orderStatus); - } - - /// @dev Decompose an ABI-encoded OrderStatusError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode Error code that corresponds to invalid maker, taker, or sender. - /// @return orderHash The order hash. - /// @return contextAddress The maker, taker, or sender address - function decodeExchangeInvalidContextError(bytes memory encoded) - internal - pure - returns ( - LibExchangeRichErrors.ExchangeContextErrorCodes errorCode, - bytes32 orderHash, - address contextAddress - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.ExchangeInvalidContextErrorSelector()); - uint8 _errorCode; - (_errorCode, orderHash, contextAddress) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (uint8, bytes32, address) - ); - errorCode = LibExchangeRichErrors.ExchangeContextErrorCodes(_errorCode); - } - - /// @dev Decompose an ABI-encoded FillError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return orderHash The order hash. - function decodeFillError(bytes memory encoded) - internal - pure - returns ( - LibExchangeRichErrors.FillErrorCodes errorCode, - bytes32 orderHash - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.FillErrorSelector()); - uint8 _errorCode; - (_errorCode, orderHash) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (uint8, bytes32) - ); - errorCode = LibExchangeRichErrors.FillErrorCodes(_errorCode); - } - - /// @dev Decompose an ABI-encoded OrderEpochError. - /// @param encoded ABI-encoded revert error. - /// @return makerAddress The order maker. - /// @return orderSenderAddress The order sender. - /// @return currentEpoch The current epoch for the maker. - function decodeOrderEpochError(bytes memory encoded) - internal - pure - returns ( - address makerAddress, - address orderSenderAddress, - uint256 currentEpoch - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.OrderEpochErrorSelector()); - (makerAddress, orderSenderAddress, currentEpoch) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (address, address, uint256) - ); - } - - /// @dev Decompose an ABI-encoded AssetProxyExistsError. - /// @param encoded ABI-encoded revert error. - /// @return assetProxyId Id of asset proxy. - /// @return assetProxyAddress The address of the asset proxy. - function decodeAssetProxyExistsError(bytes memory encoded) - internal - pure - returns ( - bytes4 assetProxyId, address assetProxyAddress) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyExistsErrorSelector()); - (assetProxyId, assetProxyAddress) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (bytes4, address) - ); - } - - /// @dev Decompose an ABI-encoded AssetProxyDispatchError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return orderHash Hash of the order being dispatched. - /// @return assetData Asset data of the order being dispatched. - function decodeAssetProxyDispatchError(bytes memory encoded) - internal - pure - returns ( - LibExchangeRichErrors.AssetProxyDispatchErrorCodes errorCode, - bytes32 orderHash, - bytes memory assetData - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyDispatchErrorSelector()); - uint8 _errorCode; - (_errorCode, orderHash, assetData) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (uint8, bytes32, bytes) - ); - errorCode = LibExchangeRichErrors.AssetProxyDispatchErrorCodes(_errorCode); - } - - /// @dev Decompose an ABI-encoded AssetProxyTransferError. - /// @param encoded ABI-encoded revert error. - /// @return orderHash Hash of the order being dispatched. - /// @return assetData Asset data of the order being dispatched. - /// @return errorData ABI-encoded revert data from the asset proxy. - function decodeAssetProxyTransferError(bytes memory encoded) - internal - pure - returns ( - bytes32 orderHash, - bytes memory assetData, - bytes memory errorData - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyTransferErrorSelector()); - (orderHash, assetData, errorData) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (bytes32, bytes, bytes) - ); - } - - /// @dev Decompose an ABI-encoded NegativeSpreadError. - /// @param encoded ABI-encoded revert error. - /// @return leftOrderHash Hash of the left order being matched. - /// @return rightOrderHash Hash of the right order being matched. - function decodeNegativeSpreadError(bytes memory encoded) - internal - pure - returns ( - bytes32 leftOrderHash, - bytes32 rightOrderHash - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.NegativeSpreadErrorSelector()); - (leftOrderHash, rightOrderHash) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (bytes32, bytes32) - ); - } - - /// @dev Decompose an ABI-encoded TransactionError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return transactionHash Hash of the transaction. - function decodeTransactionError(bytes memory encoded) - internal - pure - returns ( - LibExchangeRichErrors.TransactionErrorCodes errorCode, - bytes32 transactionHash - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionErrorSelector()); - uint8 _errorCode; - (_errorCode, transactionHash) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (uint8, bytes32) - ); - errorCode = LibExchangeRichErrors.TransactionErrorCodes(_errorCode); - } - - /// @dev Decompose an ABI-encoded TransactionExecutionError. - /// @param encoded ABI-encoded revert error. - /// @return transactionHash Hash of the transaction. - /// @return errorData Error thrown by exeucteTransaction(). - function decodeTransactionExecutionError(bytes memory encoded) - internal - pure - returns ( - bytes32 transactionHash, - bytes memory errorData - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionExecutionErrorSelector()); - (transactionHash, errorData) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (bytes32, bytes) - ); - } - - /// @dev Decompose an ABI-encoded IncompleteFillError. - /// @param encoded ABI-encoded revert error. - /// @return orderHash Hash of the order being filled. - function decodeIncompleteFillError(bytes memory encoded) - internal - pure - returns ( - LibExchangeRichErrors.IncompleteFillErrorCode errorCode, - uint256 expectedAssetFillAmount, - uint256 actualAssetFillAmount - ) - { - _assertSelectorBytes(encoded, LibExchangeRichErrors.IncompleteFillErrorSelector()); - uint8 _errorCode; - (_errorCode, expectedAssetFillAmount, actualAssetFillAmount) = abi.decode( - encoded.sliceDestructive(4, encoded.length), - (uint8, uint256, uint256) - ); - errorCode = LibExchangeRichErrors.IncompleteFillErrorCode(_errorCode); - } - - /// @dev Revert if the leading 4 bytes of `encoded` is not `selector`. - function _assertSelectorBytes(bytes memory encoded, bytes4 selector) - private - pure - { - bytes4 actualSelector = LibBytes.readBytes4(encoded, 0); - require( - actualSelector == selector, - "BAD_SELECTOR" - ); - } -} diff --git a/contracts/exchange/contracts/test/IsolatedExchange.sol b/contracts/exchange/contracts/test/IsolatedExchange.sol deleted file mode 100644 index fd54230559..0000000000 --- a/contracts/exchange/contracts/test/IsolatedExchange.sol +++ /dev/null @@ -1,86 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "../src/Exchange.sol"; - - -/// @dev A version of the Exchange contract with simplified signature validation -/// and a `_dispatchTransferFrom()` that only logs arguments. -/// See the `IsolatedExchangeWrapper` and `isolated_fill_order` tests -/// for example usage. -contract IsolatedExchange is - Exchange -{ - // solhint-disable no-unused-vars - event DispatchTransferFromCalled( - bytes32 orderHash, - bytes assetData, - address from, - address to, - uint256 amount - ); - - // solhint-disable no-empty-blocks - constructor () - public - Exchange(1337) - {} - - /// @dev Overridden to only log arguments and revert on certain assetDatas. - function _dispatchTransferFrom( - bytes32 orderHash, - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - emit DispatchTransferFromCalled( - orderHash, - assetData, - from, - to, - amount - ); - - // Fail if the first byte is 0. - if (assetData.length > 0 && assetData[0] == 0x00) { - revert("TRANSFER_FAILED"); - } - } - - /// @dev Overridden to simplify signature validation. - /// Unfortunately, this is `view`, so it can't log arguments. - function _isValidOrderWithHashSignature( - LibOrder.Order memory, - bytes32, - bytes memory signature - ) - internal - view - returns (bool isValid) - { - // '0x01' in the first byte is valid. - return signature.length == 2 && signature[0] == 0x01; - } -} diff --git a/contracts/exchange/contracts/test/ReentrancyTester.sol b/contracts/exchange/contracts/test/ReentrancyTester.sol deleted file mode 100644 index 85405e7807..0000000000 --- a/contracts/exchange/contracts/test/ReentrancyTester.sol +++ /dev/null @@ -1,201 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibReentrancyGuardRichErrors.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "../src/Exchange.sol"; - - -/// @dev A version of the Exchange that exposes a `testReentrancyGuard()` -/// function which is used to test whether a function is protected by the -/// `nonReentrant` modifier. Several internal functions have also been -/// overridden to simplify constructing valid calls to external functions. -contract ReentrancyTester is - Exchange -{ - using LibBytes for bytes; - - // solhint-disable no-empty-blocks - // solhint-disable no-unused-vars - constructor () - public - // Initialize the exchange with a fixed chainId ("test" in hex). - Exchange(0x74657374) - {} - - /// @dev Calls a public function to check if it is reentrant. - /// Because this function uses the `nonReentrant` modifier, if - /// the function being called is also guarded by the `nonReentrant` modifier, - /// it will revert when it returns. - function isReentrant(bytes calldata fnCallData) - external - nonReentrant - returns (bool allowsReentrancy) - { - (bool didSucceed, bytes memory resultData) = address(this).delegatecall(fnCallData); - if (didSucceed) { - allowsReentrancy = true; - } else { - if (resultData.equals(LibReentrancyGuardRichErrors.IllegalReentrancyError())) { - allowsReentrancy = false; - } else { - allowsReentrancy = true; - } - } - } - - /// @dev Overridden to revert on unsuccessful fillOrder call. - function _fillOrderNoThrow( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - // ABI encode calldata for `fillOrder` - bytes memory fillOrderCalldata = abi.encodeWithSelector( - IExchangeCore(address(0)).fillOrder.selector, - order, - takerAssetFillAmount, - signature - ); - - (bool didSucceed, bytes memory returnData) = address(this).delegatecall(fillOrderCalldata); - if (didSucceed) { - assert(returnData.length == 128); - fillResults = abi.decode(returnData, (LibFillResults.FillResults)); - return fillResults; - } - // Revert and rethrow error if unsuccessful - assembly { - revert(add(returnData, 32), mload(returnData)) - } - } - - /// @dev Overridden to always succeed. - function _fillOrder( - LibOrder.Order memory order, - uint256, - bytes memory - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - fillResults.makerAssetFilledAmount = order.makerAssetAmount; - fillResults.takerAssetFilledAmount = order.takerAssetAmount; - fillResults.makerFeePaid = order.makerFee; - fillResults.takerFeePaid = order.takerFee; - } - - /// @dev Overridden to always succeed. - function _fillOrKillOrder( - LibOrder.Order memory order, - uint256, - bytes memory - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - fillResults.makerAssetFilledAmount = order.makerAssetAmount; - fillResults.takerAssetFilledAmount = order.takerAssetAmount; - fillResults.makerFeePaid = order.makerFee; - fillResults.takerFeePaid = order.takerFee; - } - - /// @dev Overridden to always succeed. - function _executeTransaction( - LibZeroExTransaction.ZeroExTransaction memory, - bytes memory - ) - internal - returns (bytes memory resultData) - { - // Should already point to an empty array. - return resultData; - } - - /// @dev Overridden to always succeed. - function _batchMatchOrders( - LibOrder.Order[] memory leftOrders, - LibOrder.Order[] memory rightOrders, - bytes[] memory, - bytes[] memory, - bool - ) - internal - returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) - { - uint256 numOrders = leftOrders.length; - batchMatchedFillResults.left = new LibFillResults.FillResults[](numOrders); - batchMatchedFillResults.right = new LibFillResults.FillResults[](numOrders); - for (uint256 i = 0; i < numOrders; ++i) { - batchMatchedFillResults.left[i] = LibFillResults.FillResults({ - makerAssetFilledAmount: leftOrders[i].makerAssetAmount, - takerAssetFilledAmount: leftOrders[i].takerAssetAmount, - makerFeePaid: leftOrders[i].makerFee, - takerFeePaid: leftOrders[i].takerFee, - protocolFeePaid: 0 - }); - batchMatchedFillResults.right[i] = LibFillResults.FillResults({ - makerAssetFilledAmount: rightOrders[i].makerAssetAmount, - takerAssetFilledAmount: rightOrders[i].takerAssetAmount, - makerFeePaid: rightOrders[i].makerFee, - takerFeePaid: rightOrders[i].takerFee, - protocolFeePaid: 0 - }); - } - } - - /// @dev Overridden to always succeed. - function _matchOrders( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - bytes memory, - bytes memory, - bool - ) - internal - returns (LibFillResults.MatchedFillResults memory matchedFillResults) - { - matchedFillResults.left = LibFillResults.FillResults({ - makerAssetFilledAmount: leftOrder.makerAssetAmount, - takerAssetFilledAmount: leftOrder.takerAssetAmount, - makerFeePaid: leftOrder.makerFee, - takerFeePaid: leftOrder.takerFee, - protocolFeePaid: 0 - }); - matchedFillResults.right = LibFillResults.FillResults({ - makerAssetFilledAmount: rightOrder.makerAssetAmount, - takerAssetFilledAmount: rightOrder.takerAssetAmount, - makerFeePaid: rightOrder.makerFee, - takerFeePaid: rightOrder.takerFee, - protocolFeePaid: 0 - }); - } - - /// @dev Overridden to do nothing. - function _cancelOrder(LibOrder.Order memory order) - internal - {} -} diff --git a/contracts/exchange/contracts/test/TestAssetProxyDispatcher.sol b/contracts/exchange/contracts/test/TestAssetProxyDispatcher.sol deleted file mode 100644 index 9b5c08453a..0000000000 --- a/contracts/exchange/contracts/test/TestAssetProxyDispatcher.sol +++ /dev/null @@ -1,41 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "../src/MixinAssetProxyDispatcher.sol"; -import "../src/MixinTransferSimulator.sol"; - - -contract TestAssetProxyDispatcher is - MixinAssetProxyDispatcher, - MixinTransferSimulator -{ - function dispatchTransferFrom( - bytes32 orderHash, - bytes memory assetData, - address from, - address to, - uint256 amount - ) - public - { - _dispatchTransferFrom(orderHash, assetData, from, to, amount); - } -} diff --git a/contracts/exchange/contracts/test/TestExchangeInternals.sol b/contracts/exchange/contracts/test/TestExchangeInternals.sol deleted file mode 100644 index 991928b13e..0000000000 --- a/contracts/exchange/contracts/test/TestExchangeInternals.sol +++ /dev/null @@ -1,130 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "../src/Exchange.sol"; - - -// solhint-disable no-empty-blocks -contract TestExchangeInternals is - Exchange -{ - event DispatchTransferFromCalled( - bytes32 orderHash, - bytes assetData, - address from, - address to, - uint256 amount - ); - - constructor (uint256 chainId) - public - Exchange(chainId) - {} - - function assertValidMatch( - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder - ) - public - view - { - _assertValidMatch( - leftOrder, - rightOrder, - leftOrder.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH), - rightOrder.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH) - ); - } - - /// @dev Call `_updateFilledState()` but first set `filled[order]` to - /// `orderTakerAssetFilledAmount`. - function testUpdateFilledState( - LibOrder.Order memory order, - address takerAddress, - bytes32 orderHash, - uint256 orderTakerAssetFilledAmount, - LibFillResults.FillResults memory fillResults - ) - public - payable - { - filled[LibOrder.getTypedDataHash(order, EIP712_EXCHANGE_DOMAIN_HASH)] = orderTakerAssetFilledAmount; - _updateFilledState( - order, - takerAddress, - orderHash, - orderTakerAssetFilledAmount, - fillResults - ); - } - - function settleOrder( - bytes32 orderHash, - LibOrder.Order memory order, - address takerAddress, - LibFillResults.FillResults memory fillResults - ) - public - { - _settleOrder(orderHash, order, takerAddress, fillResults); - } - - function settleMatchOrders( - bytes32 leftOrderHash, - bytes32 rightOrderHash, - LibOrder.Order memory leftOrder, - LibOrder.Order memory rightOrder, - address takerAddress, - LibFillResults.MatchedFillResults memory matchedFillResults - ) - public - { - _settleMatchedOrders( - leftOrderHash, - rightOrderHash, - leftOrder, - rightOrder, - takerAddress, - matchedFillResults - ); - } - - /// @dev Overidden to only log arguments so we can test `_settleOrder()`. - function _dispatchTransferFrom( - bytes32 orderHash, - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - emit DispatchTransferFromCalled( - orderHash, - assetData, - from, - to, - amount - ); - } -} diff --git a/contracts/exchange/contracts/test/TestFillRounding.sol b/contracts/exchange/contracts/test/TestFillRounding.sol deleted file mode 100644 index 4e2876b396..0000000000 --- a/contracts/exchange/contracts/test/TestFillRounding.sol +++ /dev/null @@ -1,61 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "../src/Exchange.sol"; - - -// Exchange contract with settlement disabled so we can just check `_fillOrder()`` -// calculations. -contract TestFillRounding is - Exchange -{ - // solhint-disable no-empty-blocks - constructor () - public - // Initialize the exchange with a fixed chainId ("test" in hex). - Exchange(0x74657374) - {} - - function _settleOrder( - bytes32 orderHash, - LibOrder.Order memory order, - address takerAddress, - LibFillResults.FillResults memory fillResults - ) - internal - { - // No-op. - } - - function _assertFillableOrder( - LibOrder.Order memory order, - LibOrder.OrderInfo memory orderInfo, - address takerAddress, - bytes memory signature - ) - internal - view - { - // No-op. - } -} diff --git a/contracts/exchange/contracts/test/TestLibExchangeRichErrorDecoder.sol b/contracts/exchange/contracts/test/TestLibExchangeRichErrorDecoder.sol deleted file mode 100644 index afd9b22572..0000000000 --- a/contracts/exchange/contracts/test/TestLibExchangeRichErrorDecoder.sol +++ /dev/null @@ -1,270 +0,0 @@ -/* - - Copyright 2019 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.5.5; - -import "../src/libs/LibExchangeRichErrorDecoder.sol"; - - -// solhint-disable no-empty-blocks -contract TestLibExchangeRichErrorDecoder -{ - /// @dev Decompose an ABI-encoded SignatureError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return signerAddress The expected signer of the hash. - /// @return signature The full signature. - function decodeSignatureError(bytes memory encoded) - public - pure - returns ( - LibExchangeRichErrors.SignatureErrorCodes errorCode, - bytes32 hash, - address signerAddress, - bytes memory signature - ) - - { - return LibExchangeRichErrorDecoder.decodeSignatureError(encoded); - } - - /// @dev Decompose an ABI-encoded SignatureValidatorError. - /// @param encoded ABI-encoded revert error. - /// @return signerAddress The expected signer of the hash. - /// @return signature The full signature bytes. - /// @return errorData The revert data thrown by the validator contract. - function decodeEIP1271SignatureError(bytes memory encoded) - public - pure - returns ( - address verifyingContractAddress, - bytes memory data, - bytes memory signature, - bytes memory errorData - ) - - { - return LibExchangeRichErrorDecoder.decodeEIP1271SignatureError(encoded); - } - - /// @dev Decompose an ABI-encoded SignatureValidatorNotApprovedError. - /// @param encoded ABI-encoded revert error. - /// @return signerAddress The expected signer of the hash. - /// @return validatorAddress The expected validator. - function decodeSignatureValidatorNotApprovedError(bytes memory encoded) - public - pure - returns ( - address signerAddress, - address validatorAddress - ) - { - return LibExchangeRichErrorDecoder.decodeSignatureValidatorNotApprovedError(encoded); - } - - /// @dev Decompose an ABI-encoded SignatureWalletError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return signerAddress The expected signer of the hash. - /// @return signature The full signature bytes. - /// @return errorData The revert data thrown by the validator contract. - function decodeSignatureWalletError(bytes memory encoded) - public - pure - returns ( - bytes32 hash, - address signerAddress, - bytes memory signature, - bytes memory errorData - ) - - { - return LibExchangeRichErrorDecoder.decodeSignatureWalletError(encoded); - } - - /// @dev Decompose an ABI-encoded OrderStatusError. - /// @param encoded ABI-encoded revert error. - /// @return orderHash The order hash. - /// @return orderStatus The order status. - function decodeOrderStatusError(bytes memory encoded) - public - pure - returns ( - bytes32 orderHash, - LibOrder.OrderStatus orderStatus - ) - { - return LibExchangeRichErrorDecoder.decodeOrderStatusError(encoded); - } - - /// @dev Decompose an ABI-encoded OrderStatusError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode Error code that corresponds to invalid maker, taker, or sender. - /// @return orderHash The order hash. - /// @return contextAddress The maker, taker, or sender address - function decodeExchangeInvalidContextError(bytes memory encoded) - public - pure - returns ( - LibExchangeRichErrors.ExchangeContextErrorCodes errorCode, - bytes32 orderHash, - address contextAddress - ) - { - return LibExchangeRichErrorDecoder.decodeExchangeInvalidContextError(encoded); - } - - /// @dev Decompose an ABI-encoded FillError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return orderHash The order hash. - function decodeFillError(bytes memory encoded) - public - pure - returns ( - LibExchangeRichErrors.FillErrorCodes errorCode, - bytes32 orderHash - ) - { - return LibExchangeRichErrorDecoder.decodeFillError(encoded); - } - - /// @dev Decompose an ABI-encoded OrderEpochError. - /// @param encoded ABI-encoded revert error. - /// @return makerAddress The order maker. - /// @return orderSenderAddress The order sender. - /// @return currentEpoch The current epoch for the maker. - function decodeOrderEpochError(bytes memory encoded) - public - pure - returns ( - address makerAddress, - address orderSenderAddress, - uint256 currentEpoch - ) - { - return LibExchangeRichErrorDecoder.decodeOrderEpochError(encoded); - } - - /// @dev Decompose an ABI-encoded AssetProxyExistsError. - /// @param encoded ABI-encoded revert error. - /// @return assetProxyId Id of asset proxy. - /// @return assetProxyAddress The address of the asset proxy. - function decodeAssetProxyExistsError(bytes memory encoded) - public - pure - returns ( - bytes4 assetProxyId, address assetProxyAddress) - { - return LibExchangeRichErrorDecoder.decodeAssetProxyExistsError(encoded); - } - - /// @dev Decompose an ABI-encoded AssetProxyDispatchError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return orderHash Hash of the order being dispatched. - /// @return assetData Asset data of the order being dispatched. - function decodeAssetProxyDispatchError(bytes memory encoded) - public - pure - returns ( - LibExchangeRichErrors.AssetProxyDispatchErrorCodes errorCode, - bytes32 orderHash, - bytes memory assetData - ) - { - return LibExchangeRichErrorDecoder.decodeAssetProxyDispatchError(encoded); - } - - /// @dev Decompose an ABI-encoded AssetProxyTransferError. - /// @param encoded ABI-encoded revert error. - /// @return orderHash Hash of the order being dispatched. - /// @return assetData Asset data of the order being dispatched. - /// @return errorData ABI-encoded revert data from the asset proxy. - function decodeAssetProxyTransferError(bytes memory encoded) - public - pure - returns ( - bytes32 orderHash, - bytes memory assetData, - bytes memory errorData - ) - { - return LibExchangeRichErrorDecoder.decodeAssetProxyTransferError(encoded); - } - - /// @dev Decompose an ABI-encoded NegativeSpreadError. - /// @param encoded ABI-encoded revert error. - /// @return leftOrderHash Hash of the left order being matched. - /// @return rightOrderHash Hash of the right order being matched. - function decodeNegativeSpreadError(bytes memory encoded) - public - pure - returns ( - bytes32 leftOrderHash, - bytes32 rightOrderHash - ) - { - return LibExchangeRichErrorDecoder.decodeNegativeSpreadError(encoded); - } - - /// @dev Decompose an ABI-encoded TransactionError. - /// @param encoded ABI-encoded revert error. - /// @return errorCode The error code. - /// @return transactionHash Hash of the transaction. - function decodeTransactionError(bytes memory encoded) - public - pure - returns ( - LibExchangeRichErrors.TransactionErrorCodes errorCode, - bytes32 transactionHash - ) - { - return LibExchangeRichErrorDecoder.decodeTransactionError(encoded); - } - - /// @dev Decompose an ABI-encoded TransactionExecutionError. - /// @param encoded ABI-encoded revert error. - /// @return transactionHash Hash of the transaction. - /// @return errorData Error thrown by exeucteTransaction(). - function decodeTransactionExecutionError(bytes memory encoded) - public - pure - returns ( - bytes32 transactionHash, - bytes memory errorData - ) - { - return LibExchangeRichErrorDecoder.decodeTransactionExecutionError(encoded); - } - - /// @dev Decompose an ABI-encoded IncompleteFillError. - /// @param encoded ABI-encoded revert error. - /// @return orderHash Hash of the order being filled. - function decodeIncompleteFillError(bytes memory encoded) - public - pure - returns ( - LibExchangeRichErrors.IncompleteFillErrorCode errorCode, - uint256 expectedAssetFillAmount, - uint256 actualAssetFillAmount - ) - { - return LibExchangeRichErrorDecoder.decodeIncompleteFillError(encoded); - } -} diff --git a/contracts/exchange/contracts/test/TestProtocolFeeCollector.sol b/contracts/exchange/contracts/test/TestProtocolFeeCollector.sol deleted file mode 100644 index 2f1b33959b..0000000000 --- a/contracts/exchange/contracts/test/TestProtocolFeeCollector.sol +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; - - - // solhint-disable no-unused-vars, no-empty-blocks -contract TestProtocolFeeCollector { - - address private _wethAddress; - - constructor ( - address wethAddress - ) - public - { - _wethAddress = wethAddress; - } - - function () - external - payable - {} - - /// @dev Pays a protocol fee in WETH (Forwarder orders will always pay protocol fees in WETH). - /// @param makerAddress The address of the order's maker. - /// @param payerAddress The address of the protocol fee payer. - /// @param protocolFeePaid The protocol fee that should be paid. - function payProtocolFee( - address makerAddress, - address payerAddress, - uint256 protocolFeePaid - ) - external - payable - { - if (msg.value != protocolFeePaid) { - require( - msg.value == 0, - "No value should be forwarded to collector when paying fee in WETH" - ); - - // Transfer the protocol fee to this address in WETH. - IEtherToken(_wethAddress).transferFrom( - payerAddress, - address(this), - protocolFeePaid - ); - } - } -} diff --git a/contracts/exchange/contracts/test/TestProtocolFees.sol b/contracts/exchange/contracts/test/TestProtocolFees.sol deleted file mode 100644 index e7655c11b4..0000000000 --- a/contracts/exchange/contracts/test/TestProtocolFees.sol +++ /dev/null @@ -1,74 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "../src/Exchange.sol"; - - -contract TestProtocolFees is - Exchange -{ - // solhint-disable no-empty-blocks - constructor () - public - Exchange(1337) - {} - - // @dev Expose a setter to the `protocolFeeCollector` state variable. - // @param newProtocolFeeCollector The address that should be made the `protocolFeeCollector`. - function setProtocolFeeCollector(address newProtocolFeeCollector) - external - { - protocolFeeCollector = newProtocolFeeCollector; - } - - // @dev Expose a setter to the `protocolFeeMultiplier` state variable. - // @param newProtocolFeeMultiplier The number that should be made the `protocolFeeMultiplier`. - function setProtocolFeeMultiplier(uint256 newProtocolFeeMultiplier) - external - { - protocolFeeMultiplier = newProtocolFeeMultiplier; - } - - // @dev Stub out the `_assertFillableOrder` function because we don't actually - // care about order validation in these tests. - function _assertFillableOrder( - LibOrder.Order memory, - LibOrder.OrderInfo memory, - address, - bytes memory - ) - internal - view - {} // solhint-disable-line no-empty-blocks - - // @dev Stub out the `_assertFillableOrder` function because we don't actually - // care about transfering through proxies in these tests. - function _dispatchTransferFrom( - bytes32 orderHash, - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - {} // solhint-disable-line no-empty-blocks -} diff --git a/contracts/exchange/contracts/test/TestProtocolFeesReceiver.sol b/contracts/exchange/contracts/test/TestProtocolFeesReceiver.sol deleted file mode 100644 index 7b205a39c7..0000000000 --- a/contracts/exchange/contracts/test/TestProtocolFeesReceiver.sol +++ /dev/null @@ -1,347 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "./TestProtocolFees.sol"; - - -// Disable solhint to allow for more informative comments. -// solhint-disable -contract TestProtocolFeesReceiver { - - // Attach LibSafeMath to uint256 - using LibSafeMath for uint256; - - /* Testing Constants */ - - // A constant to represent a maker address. - address internal constant makerAddress1 = address(1); - - // A constant to represent a maker address that is distinct from the - // other maker address. - address internal constant makerAddress2 = address(2); - - /* Testing State */ - - // A struct that provides a schema for test data that should be logged. - struct TestLog { - address loggedMaker; - address loggedPayer; - uint256 loggedProtocolFeePaid; - uint256 loggedValue; - } - - // The array of testLogs that will be added to by `payProtocolFee` and processed by the tests. - TestLog[] testLogs; - - /* Testing Functions */ - - /// @dev Tests the `batchFillOrders` function's payment of protocol fees. - /// @param testProtocolFees The TestProtocolFees that should be tested against. - /// @param protocolFeeMultiplier The protocol fee multiplier that should be registered - /// in the test suite before executing `batchFillOrders`. - /// @param numberOfOrders The number of orders that should be created and executed for this test. - /// @param shouldSetProtocolFeeCollector A boolean value indicating whether or not this contract - /// should be registered as the `protocolFeeCollector`. - function testBatchFillOrdersProtocolFees( - TestProtocolFees testProtocolFees, - uint256 protocolFeeMultiplier, - uint256 numberOfOrders, - bool shouldSetProtocolFeeCollector - ) - external - payable - handleState(testProtocolFees, protocolFeeMultiplier, shouldSetProtocolFeeCollector) - { - // Create empty arrays for taker asset filled amounts and signatures, which will suffice for this test. - uint256[] memory takerAssetFilledAmounts = new uint256[](numberOfOrders); - bytes[] memory signatures = new bytes[](numberOfOrders); - - // Construct an array of orders in which every even-indexed order has a makerAddress of makerAddress1 and - // every odd-indexed order has a makerAddress of makerAddress2. This is done to make sure that the correct - // makers are being logged. - LibOrder.Order[] memory orders = new LibOrder.Order[](numberOfOrders); - for (uint256 i = 0; i < numberOfOrders; i++) { - orders[i] = createOrder(i % 2 == 0 ? makerAddress1 : makerAddress2); - } - - // Forward all of the value sent to the contract to `batchFillOrders()`. - testProtocolFees.batchFillOrders.value(msg.value)(orders, takerAssetFilledAmounts, signatures); - - // If the `protocolFeeCollector` was set, ensure that the protocol fees were paid correctly. - // Otherwise, the protocol fees should not have been paid. - if (shouldSetProtocolFeeCollector) { - // Ensure that the correct number of test logs were recorded. - require(testLogs.length == numberOfOrders, "Incorrect number of test logs in batchFillOrders test"); - - // Calculate the expected protocol fee. - uint256 expectedProtocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier); - - // Set the expected available balance for the first log. - uint256 expectedAvailableBalance = msg.value; - - // Verify all of the test logs. - for (uint256 i = 0; i < testLogs.length; i++) { - // Verify the logged data. - verifyTestLog( - testLogs[i], - expectedAvailableBalance, // expectedAvailableBalance - i % 2 == 0 ? makerAddress1 : makerAddress2, // expectedMakerAddress - address(this), // expectedPayerAddress - expectedProtocolFeePaid // expectedProtocolFeePaid - ); - - // Set the expected available balance for the next log. - expectedAvailableBalance = expectedAvailableBalance >= expectedProtocolFeePaid ? - expectedAvailableBalance - expectedProtocolFeePaid : - expectedAvailableBalance; - } - } else { - // Ensure that zero test logs were created. - require(testLogs.length == 0, "Incorrect number of test logs in batchFillOrders test"); - } - } - - /// @dev Tests the `fillOrder` function's payment of protocol fees. - /// @param testProtocolFees The TestProtocolFees that should be tested against. - /// @param protocolFeeMultiplier The protocol fee multiplier that should be registered - /// in the test suite before executing `fillOrder`. - /// @param shouldSetProtocolFeeCollector A boolean value indicating whether or not this contract - /// should be registered as the `protocolFeeCollector`. - function testFillOrderProtocolFees( - TestProtocolFees testProtocolFees, - uint256 protocolFeeMultiplier, - bool shouldSetProtocolFeeCollector - ) - external - payable - handleState(testProtocolFees, protocolFeeMultiplier, shouldSetProtocolFeeCollector) - { - // Create empty values for the takerAssetFilledAmount and the signature since these values don't - // matter for this test. - uint256 takerAssetFilledAmount = 0; - bytes memory signature = new bytes(0); - - // Construct an of order with distinguishing information. - LibOrder.Order memory order = createOrder(makerAddress1); - - // Forward all of the value sent to the contract to `fillOrder()`. - testProtocolFees.fillOrder.value(msg.value)(order, takerAssetFilledAmount, signature); - - // If the `protocolFeeCollector` was set, ensure that the protocol fee was paid correctly. - // Otherwise, the protocol fee should not have been paid. - if (shouldSetProtocolFeeCollector) { - // Ensure that only one test log was created by the call to `fillOrder()`. - require(testLogs.length == 1, "Incorrect number of test logs in fillOrder test"); - - // Calculate the expected protocol fee. - uint256 expectedProtocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier); - - // Verify that the test log that was created is correct. - verifyTestLog( - testLogs[0], - msg.value, // expectedAvailableBalance - makerAddress1, // expectedMakerAddress - address(this), // expectedPayerAddress - expectedProtocolFeePaid // expectedProtocolFeePaid - ); - } else { - // Ensure that zero test logs were created. - require(testLogs.length == 0, "Incorrect number of test logs in fillOrder test"); - } - } - - /// @dev Tests the `matchOrders` function's payment of protocol fees. - /// @param testProtocolFees The TestProtocolFees that should be tested against. - /// @param protocolFeeMultiplier The protocol fee multiplier that should be registered - /// in the test suite before executing `matchOrders`. - /// @param shouldSetProtocolFeeCollector A boolean value indicating whether or not this contract - /// should be registered as the `protocolFeeCollector`. - function testMatchOrdersProtocolFees( - TestProtocolFees testProtocolFees, - uint256 protocolFeeMultiplier, - bool shouldSetProtocolFeeCollector - ) - external - payable - handleState(testProtocolFees, protocolFeeMultiplier, shouldSetProtocolFeeCollector) - { - // Create two empty signatures since signatures are not used in this test. - bytes memory leftSignature = new bytes(0); - bytes memory rightSignature = new bytes(0); - - // Construct a distinguished left order. - LibOrder.Order memory leftOrder = createOrder(makerAddress1); - - // Construct a distinguished right order. - LibOrder.Order memory rightOrder = createOrder(makerAddress2); - - // Forward all of the value sent to the contract to `matchOrders()`. - testProtocolFees.matchOrders.value(msg.value)(leftOrder, rightOrder, leftSignature, rightSignature); - - // If the `protocolFeeCollector` was set, ensure that the protocol fee was paid correctly. - // Otherwise, the protocol fee should not have been paid. - if (shouldSetProtocolFeeCollector) { - // Ensure that only one test log was created by the call to `fillOrder()`. - require(testLogs.length == 2, "Incorrect number of test logs in matchOrders test"); - - // Calculate the expected protocol fee. - uint256 expectedProtocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier); - - // Set the expected available balance for the first log. - uint256 expectedAvailableBalance = msg.value; - - // Verify that the first test log that was created is correct. - verifyTestLog( - testLogs[0], - expectedAvailableBalance, // expectedAvailableBalance - makerAddress1, // expectedMakerAddress - address(this), // expectedPayerAddress - expectedProtocolFeePaid // expectedProtocolFeePaid - ); - - // Set the expected available balance for the second log. - expectedAvailableBalance = expectedAvailableBalance >= expectedProtocolFeePaid ? - expectedAvailableBalance - expectedProtocolFeePaid : - expectedAvailableBalance; - - // Verify that the second test log that was created is correct. - verifyTestLog( - testLogs[1], - expectedAvailableBalance, // expectedAvailableBalance - makerAddress2, // expectedMakerAddress - address(this), // expectedPayerAddress - expectedProtocolFeePaid // expectedProtocolFeePaid - ); - } else { - // Ensure that zero test logs were created. - require(testLogs.length == 0, "Incorrect number of test logs in matchOrders test"); - } - } - - /* Verification Functions */ - - /// @dev Verifies a test log against expected values. - /// @param expectedAvailableBalance The balance that should be available when this call is made. - /// This is important especially for tests on wrapper functions. - /// @param expectedMakerAddress The expected maker address to be recorded in `payProtocolFee`. - /// @param expectedPayerAddress The expected payer address to be recorded in `payProtocolFee`. - /// @param expectedProtocolFeePaid The expected protocol fee paidto be recorded in `payProtocolFee`. - function verifyTestLog( - TestLog memory log, - uint256 expectedAvailableBalance, - address expectedMakerAddress, - address expectedPayerAddress, - uint256 expectedProtocolFeePaid - ) - internal - pure - { - // If the expected available balance was sufficient to pay the protocol fee, the protocol fee - // should have been paid in ether. Otherwise, no ether should be sent to pay the protocol fee. - if (expectedAvailableBalance >= expectedProtocolFeePaid) { - // Ensure that the protocol fee was paid in ether. - require( - log.loggedValue == expectedProtocolFeePaid, - "Incorrect eth was received during fillOrder test when adequate ETH was sent" - ); - } else { - // Ensure that the protocol fee was not paid in ether. - require( - log.loggedValue == 0, - "Incorrect eth was received during fillOrder test when inadequate ETH was sent" - ); - } - - // Ensure that the correct data was logged. - require(log.loggedMaker == expectedMakerAddress, "Incorrect maker address was logged"); - require(log.loggedPayer == expectedPayerAddress, "Incorrect taker address was logged"); - require(log.loggedProtocolFeePaid == expectedProtocolFeePaid, "Incorrect protocol fee was logged"); - } - - /* Testing Convenience Functions */ - - /// @dev Sets up state that is necessary for tests and then cleans up the state that was written - /// to so that test cases can be thought of as atomic. - /// @param testProtocolFees The TestProtocolFees contract that is being used during testing. - /// @param protocolFeeMultiplier The protocolFeeMultiplier of this test case. - /// @param shouldSetProtocolFeeCollector A boolean value that indicates whether or not this address - /// should be made the protocol fee collector. - modifier handleState( - TestProtocolFees testProtocolFees, - uint256 protocolFeeMultiplier, - bool shouldSetProtocolFeeCollector - ) - { - // If necessary, set the protocol fee collector field in the exchange. - if (shouldSetProtocolFeeCollector) { - testProtocolFees.setProtocolFeeCollector(address(this)); - } - // Set the protocol fee multiplier in the exchange. - testProtocolFees.setProtocolFeeMultiplier(protocolFeeMultiplier); - - // Execute the test. - _; - } - - /// @dev Constructs an order with a specified maker address. - /// @param makerAddress The maker address of the order. - function createOrder(address makerAddress) - internal - pure - returns (LibOrder.Order memory order) - { - order.makerAddress = makerAddress; - order.makerAssetAmount = 1; // This is 1 so that it doesn't trigger a `DivionByZero()` error. - order.takerAssetAmount = 1; // This is 1 so that it doesn't trigger a `DivionByZero()` error. - } - - /* Protocol Fee Receiver and Fallback */ - - /// @dev Receives payments of protocol fees from a TestProtocolFees contract - /// and records the data provided and the message value sent. - /// @param makerAddress The maker address that should be recorded. - /// @param payerAddress The payer address that should be recorded. - /// @param protocolFeePaid The protocol fee that should be recorded. - function payProtocolFee( - address makerAddress, - address payerAddress, - uint256 protocolFeePaid - ) - external - payable - { - // Push the collected data into `testLogs`. - testLogs.push(TestLog({ - loggedMaker: makerAddress, - loggedPayer: payerAddress, - loggedProtocolFeePaid: protocolFeePaid, - loggedValue: msg.value - })); - } - - /// @dev A payable fallback function that makes this contract "payable". This is necessary to allow - /// this contract to gracefully handle refunds from TestProtocolFees contracts. - function () - external - payable - {} -} diff --git a/contracts/exchange/contracts/test/TestTransactions.sol b/contracts/exchange/contracts/test/TestTransactions.sol deleted file mode 100644 index 465987e0aa..0000000000 --- a/contracts/exchange/contracts/test/TestTransactions.sol +++ /dev/null @@ -1,123 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "../src/Exchange.sol"; - - -contract TestTransactions is - Exchange -{ - event ExecutableCalled( - bytes data, - bytes returnData, - address contextAddress - ); - - constructor () - public - Exchange(1337) - {} // solhint-disable-line no-empty-blocks - - function setCurrentContextAddress(address context) - external - { - currentContextAddress = context; - } - - function setTransactionExecuted(bytes32 hash) - external - { - transactionsExecuted[hash] = true; - } - - function setCurrentContextAddressIfRequired(address signerAddress, address context) - external - { - _setCurrentContextAddressIfRequired(signerAddress, context); - } - - function getCurrentContextAddress() - external - view - returns (address) - { - return _getCurrentContextAddress(); - } - - function assertExecutableTransaction( - LibZeroExTransaction.ZeroExTransaction memory transaction, - bytes memory signature - ) - public - view - { - return _assertExecutableTransaction( - transaction, - signature, - transaction.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH) - ); - } - - // This function will execute arbitrary calldata via a delegatecall. This is highly unsafe to use in production, and this - // is only meant to be used during testing. - function executable( - bool shouldSucceed, - bytes memory data, - bytes memory returnData - ) - public - returns (bytes memory) - { - emit ExecutableCalled( - data, - returnData, - currentContextAddress - ); - require(shouldSucceed, "EXECUTABLE_FAILED"); - if (data.length != 0) { - (bool didSucceed, bytes memory callResultData) = address(this).delegatecall(data); // This is a delegatecall to preserve the `msg.sender` field - if (!didSucceed) { - assembly { revert(add(callResultData, 0x20), mload(callResultData)) } - } - } - return returnData; - } - - function _isValidTransactionWithHashSignature( - LibZeroExTransaction.ZeroExTransaction memory, - bytes32, - bytes memory signature - ) - internal - view - returns (bool) - { - if ( - signature.length == 2 && - signature[0] == 0x0 && - signature[1] == 0x0 - ) { - return false; - } - return true; - } -} diff --git a/contracts/exchange/contracts/test/TestValidatorWallet.sol b/contracts/exchange/contracts/test/TestValidatorWallet.sol deleted file mode 100644 index d034f0686d..0000000000 --- a/contracts/exchange/contracts/test/TestValidatorWallet.sol +++ /dev/null @@ -1,228 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; -import "../src/interfaces/IEIP1271Data.sol"; - - -// solhint-disable no-unused-vars -contract TestValidatorWallet is - LibEIP1271 -{ - using LibBytes for bytes; - - // Magic bytes to be returned by `Wallet` signature type validators. - // bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)")) - bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; - - /// @dev Revert reason for `Revert` `ValidatorAction`. - string constant public REVERT_REASON = "you shall not pass"; - - enum ValidatorAction { - // Return failure (default) - Reject, - // Return success - Accept, - // Revert - Revert, - // Update state - UpdateState, - // Ensure the signature hash matches what was prepared - MatchSignatureHash, - // Return boolean `true`, - ReturnTrue, - // Return no data. - ReturnNothing, - NTypes - } - - /// @dev The Exchange domain hash.. - LibEIP712ExchangeDomain internal _exchange; - /// @dev Internal state to modify. - uint256 internal _state = 1; - /// @dev What action to execute when a hash is validated . - mapping (bytes32 => ValidatorAction) internal _hashActions; - /// @dev keccak256 of the expected signature data for a hash. - mapping (bytes32 => bytes32) internal _hashSignatureHashes; - - constructor(address exchange) public { - _exchange = LibEIP712ExchangeDomain(exchange); - } - - /// @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 Prepares this contract to validate a signature. - /// @param hash The hash. - /// @param action Action to take. - /// @param signatureHash keccak256 of the expected signature data. - function prepare( - bytes32 hash, - ValidatorAction action, - bytes32 signatureHash - ) - external - { - if (uint8(action) >= uint8(ValidatorAction.NTypes)) { - revert("UNSUPPORTED_VALIDATOR_ACTION"); - } - _hashActions[hash] = action; - _hashSignatureHashes[hash] = signatureHash; - } - - /// @dev Validates data signed by either `EIP1271Wallet` or `Validator` signature types. - /// @param data Abi-encoded data (Order or ZeroExTransaction) and a hash. - /// @param signature Signature for `data`. - /// @return magicValue `EIP1271_MAGIC_VALUE` if the signature check succeeds. - function isValidSignature( - bytes memory data, - bytes memory signature - ) - public - returns (bytes4 magicValue) - { - bytes32 hash = _decodeAndValidateHashFromEncodedData(data); - ValidatorAction action = _hashActions[hash]; - if (action == ValidatorAction.Reject) { - magicValue = 0x0; - } else if (action == ValidatorAction.Accept) { - magicValue = EIP1271_MAGIC_VALUE; - } else if (action == ValidatorAction.Revert) { - revert(REVERT_REASON); - } else if (action == ValidatorAction.UpdateState) { - _updateState(); - } else if (action == ValidatorAction.ReturnNothing) { - assembly { - return(0x0, 0) - } - } else if (action == ValidatorAction.ReturnTrue) { - assembly { - mstore(0x0, 1) - return(0x0, 32) - } - } else { - assert(action == ValidatorAction.MatchSignatureHash); - bytes32 expectedSignatureHash = _hashSignatureHashes[hash]; - if (keccak256(signature) == expectedSignatureHash) { - magicValue = EIP1271_MAGIC_VALUE; - } - } - } - - /// @dev Validates a hash with the `Wallet` signature type. - /// @param hash Message hash that is signed. - /// @param signature Proof of signing. - /// @return `LEGACY_WALLET_MAGIC_VALUE` if the signature check succeeds. - function isValidSignature( - bytes32 hash, - bytes memory signature - ) - public - returns (bytes4 magicValue) - { - ValidatorAction action = _hashActions[hash]; - if (action == ValidatorAction.Reject) { - magicValue = bytes4(0); - } else if (action == ValidatorAction.Accept) { - magicValue = LEGACY_WALLET_MAGIC_VALUE; - } else if (action == ValidatorAction.Revert) { - revert(REVERT_REASON); - } else if (action == ValidatorAction.UpdateState) { - _updateState(); - } else if (action == ValidatorAction.ReturnNothing) { - assembly { - return(0x0, 0) - } - } else if (action == ValidatorAction.ReturnTrue) { - assembly { - mstore(0x0, 1) - return(0x0, 32) - } - } else { - assert(action == ValidatorAction.MatchSignatureHash); - bytes32 expectedSignatureHash = _hashSignatureHashes[hash]; - if (keccak256(signature) == expectedSignatureHash) { - magicValue = LEGACY_WALLET_MAGIC_VALUE; - } - } - } - - /// @dev Increments state variable to trigger a state change. - function _updateState() - private - { - _state++; - } - - function _decodeAndValidateHashFromEncodedData(bytes memory data) - private - view - returns (bytes32 hash) - { - bytes4 dataId = data.readBytes4(0); - if (dataId == IEIP1271Data(address(0)).OrderWithHash.selector) { - // Decode the order and hash - LibOrder.Order memory order; - (order, hash) = abi.decode( - data.slice(4, data.length), - (LibOrder.Order, bytes32) - ); - // Use the Exchange to calculate the hash of the order and assert - // that it matches the one we extracted previously. - require( - LibOrder.getTypedDataHash(order, _exchange.EIP712_EXCHANGE_DOMAIN_HASH()) == hash, - "UNEXPECTED_ORDER_HASH" - ); - } else if (dataId == IEIP1271Data(address(0)).ZeroExTransactionWithHash.selector) { - // Decode the transaction and hash - LibZeroExTransaction.ZeroExTransaction memory transaction; - (transaction, hash) = abi.decode( - data.slice(4, data.length), - (LibZeroExTransaction.ZeroExTransaction, bytes32) - ); - // Use the Exchange to calculate the hash of the transaction and assert - // that it matches the one we extracted previously. - require( - LibZeroExTransaction.getTypedDataHash(transaction, _exchange.EIP712_EXCHANGE_DOMAIN_HASH()) == hash, - "UNEXPECTED_TRANSACTION_HASH" - ); - } else { - revert("EXPECTED_NO_DATA_TYPE"); - } - return hash; - } -} diff --git a/contracts/exchange/contracts/test/TestWrapperFunctions.sol b/contracts/exchange/contracts/test/TestWrapperFunctions.sol deleted file mode 100644 index f1ec7e1e2f..0000000000 --- a/contracts/exchange/contracts/test/TestWrapperFunctions.sol +++ /dev/null @@ -1,128 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "../src/Exchange.sol"; - - -/// @dev A version of the Exchange contract with`_fillOrder()`, -/// `_cancelOrder()`, and `getOrderInfo()` overridden to test -/// `MixinWrapperFunctions`. -contract TestWrapperFunctions is - Exchange -{ - LibOrder.OrderStatus internal constant MAX_ORDER_STATUS = LibOrder.OrderStatus.CANCELLED; - uint256 internal constant ALWAYS_FAILING_SALT = uint256(-1); - string internal constant ALWAYS_FAILING_SALT_REVERT_REASON = "ALWAYS_FAILING_SALT"; - - // solhint-disable no-unused-vars - event FillOrderCalled( - LibOrder.Order order, - uint256 takerAssetFillAmount, - bytes signature - ); - - event CancelOrderCalled( - LibOrder.Order order - ); - - // solhint-disable no-empty-blocks - constructor () - public - // Initialize the exchange with a fixed chainId ("test" in hex). - Exchange(0x74657374) - {} - - /// @dev Overridden to be deterministic and simplified. - function getOrderInfo(LibOrder.Order memory order) - public - view - returns (LibOrder.OrderInfo memory orderInfo) - { - // Lower uint128 of `order.salt` is the `orderTakerAssetFilledAmount`. - orderInfo.orderTakerAssetFilledAmount = uint128(order.salt); - // High byte of `order.salt` is the `orderStatus`. - orderInfo.orderStatus = LibOrder.OrderStatus(uint8(order.salt >> 248) % (uint8(MAX_ORDER_STATUS) + 1)); - orderInfo.orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); - } - - function fillOrderNoThrow( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - public - returns (LibFillResults.FillResults memory fillResults) - { - return _fillOrderNoThrow( - order, - takerAssetFillAmount, - signature - ); - } - - /// @dev Overridden to log arguments, be deterministic, and revert with certain inputs. - function _fillOrder( - LibOrder.Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - internal - returns (LibFillResults.FillResults memory fillResults) - { - emit FillOrderCalled( - order, - takerAssetFillAmount, - signature - ); - - // Fail if the salt is ALWAYS_FAILING_SALT. - if (order.salt == ALWAYS_FAILING_SALT) { - revert(ALWAYS_FAILING_SALT_REVERT_REASON); - } - - // We aren't interested in correctness here because we are testing the - // behavior of the caller, not `_fillOrder()` itself. We just need some - // values that the caller can aggregate together. - fillResults.makerAssetFilledAmount = order.makerAssetAmount; - fillResults.takerAssetFilledAmount = order.takerAssetAmount; - fillResults.makerFeePaid = order.makerFee; - fillResults.takerFeePaid = order.takerFee; - fillResults.protocolFeePaid = protocolFeeMultiplier; - } - - /// @dev Overridden to only log arguments and revert with certain inputs. - function _cancelOrder( - LibOrder.Order memory order - ) - internal - { - emit CancelOrderCalled( - order - ); - - // Fail if the salt is ALWAYS_FAILING_SALT. - if (order.salt == ALWAYS_FAILING_SALT) { - revert(ALWAYS_FAILING_SALT_REVERT_REASON); - } - } -} diff --git a/contracts/exchange/package.json b/contracts/exchange/package.json deleted file mode 100644 index 79e8920c78..0000000000 --- a/contracts/exchange/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "@0x/contracts-exchange", - "version": "3.2.38", - "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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "Exchange,IExchange", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(Exchange|IAssetProxy|IAssetProxyDispatcher|IEIP1271Data|IEIP1271Wallet|IExchange|IExchangeCore|IMatchOrders|IProtocolFees|ISignatureValidator|ITransactions|ITransferSimulator|IWallet|IWrapperFunctions|IsolatedExchange|LibExchangeRichErrorDecoder|MixinAssetProxyDispatcher|MixinExchangeCore|MixinMatchOrders|MixinProtocolFees|MixinSignatureValidator|MixinTransactions|MixinTransferSimulator|MixinWrapperFunctions|ReentrancyTester|TestAssetProxyDispatcher|TestExchangeInternals|TestFillRounding|TestLibExchangeRichErrorDecoder|TestProtocolFeeCollector|TestProtocolFees|TestProtocolFeesReceiver|TestTransactions|TestValidatorWallet|TestWrapperFunctions).json" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-multisig": "^4.1.38", - "@0x/contracts-staking": "^2.0.45", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "ethereum-types": "^3.5.0", - "ethereumjs-util": "^7.0.10", - "js-combinatorics": "^0.5.3", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/contracts-dev-utils": "^1.3.36", - "@0x/contracts-erc1155": "^2.1.37", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-erc721": "^3.1.37", - "@0x/order-utils": "^10.4.28", - "@0x/utils": "^6.4.3", - "lodash": "^4.17.11" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/exchange/src/artifacts.ts b/contracts/exchange/src/artifacts.ts deleted file mode 100644 index 37310d8640..0000000000 --- a/contracts/exchange/src/artifacts.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Exchange from '../generated-artifacts/Exchange.json'; -import * as IExchange from '../generated-artifacts/IExchange.json'; -export const artifacts = { Exchange: Exchange as ContractArtifact, IExchange: IExchange as ContractArtifact }; diff --git a/contracts/exchange/src/exchange_data_encoder.ts b/contracts/exchange/src/exchange_data_encoder.ts deleted file mode 100644 index 68259b207f..0000000000 --- a/contracts/exchange/src/exchange_data_encoder.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { constants, ExchangeFunctionName, orderHashUtils, provider } from '@0x/contracts-test-utils'; -import { SignedOrder } from '@0x/types'; - -import { IExchangeContract } from './wrappers'; - -export const exchangeDataEncoder = { - encodeOrdersToExchangeData(fnName: ExchangeFunctionName, orders: SignedOrder[] = []): string { - const exchangeInstance = new IExchangeContract(constants.NULL_ADDRESS, provider); - let data; - if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) { - data = (exchangeInstance as any) - [fnName](orders[0], orders[0].takerAssetAmount, orders[0].signature) - .getABIEncodedTransactionData(); - } else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) { - data = (exchangeInstance as any) - [fnName]( - orders, - orders.map(order => order.takerAssetAmount), - orders.map(order => order.signature), - ) - .getABIEncodedTransactionData(); - } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) { - const fillAsset = /Buy/.test(fnName) ? 'makerAssetAmount' : 'takerAssetAmount'; - data = (exchangeInstance as any) - [fnName]( - orders, - orders.map(order => order[fillAsset]).reduce((prev, curr) => prev.plus(curr)), - orders.map(order => order.signature), - ) - .getABIEncodedTransactionData(); - } else if (constants.MATCH_ORDER_FN_NAMES.indexOf(fnName) !== -1) { - data = exchangeInstance - .matchOrders(orders[0], orders[1], orders[0].signature, orders[1].signature) - .getABIEncodedTransactionData(); - } else if (fnName === ExchangeFunctionName.CancelOrder) { - data = exchangeInstance.cancelOrder(orders[0]).getABIEncodedTransactionData(); - } else if (fnName === ExchangeFunctionName.BatchCancelOrders) { - data = exchangeInstance.batchCancelOrders(orders).getABIEncodedTransactionData(); - } else if (fnName === ExchangeFunctionName.CancelOrdersUpTo) { - data = exchangeInstance.cancelOrdersUpTo(constants.ZERO_AMOUNT).getABIEncodedTransactionData(); - } else if (fnName === ExchangeFunctionName.PreSign) { - data = exchangeInstance.preSign(orderHashUtils.getOrderHashHex(orders[0])).getABIEncodedTransactionData(); - } else if (fnName === ExchangeFunctionName.SetSignatureValidatorApproval) { - data = exchangeInstance - .setSignatureValidatorApproval(constants.NULL_ADDRESS, true) - .getABIEncodedTransactionData(); - } else { - throw new Error(`Error: ${fnName} not a supported function`); - } - return data; - }, -}; diff --git a/contracts/exchange/src/index.ts b/contracts/exchange/src/index.ts deleted file mode 100644 index db3e0301e6..0000000000 --- a/contracts/exchange/src/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -export { artifacts } from './artifacts'; -export { - IExchangeContract, - IExchangeEvents, - IExchangeFillEventArgs, - ExchangeEventArgs, - ExchangeEvents, - ExchangeSignatureValidatorApprovalEventArgs, - ExchangeFillEventArgs, - ExchangeCancelEventArgs, - ExchangeCancelUpToEventArgs, - ExchangeAssetProxyRegisteredEventArgs, - ExchangeContract, - ExchangeProtocolFeeCollectorAddressEventArgs, - ExchangeProtocolFeeMultiplierEventArgs, - ExchangeTransactionExecutionEventArgs, -} from './wrappers'; -export { ExchangeRevertErrors } from '@0x/utils'; -export { exchangeDataEncoder } from './exchange_data_encoder'; -export { SignedOrder } from '@0x/types'; -export { ExchangeFunctionName } from '@0x/contracts-test-utils'; -export { DevUtilsContract } from '@0x/contracts-dev-utils'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/exchange/src/wrappers.ts b/contracts/exchange/src/wrappers.ts deleted file mode 100644 index acb3e1d6c0..0000000000 --- a/contracts/exchange/src/wrappers.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/exchange'; -export * from '../generated-wrappers/i_exchange'; diff --git a/contracts/exchange/test/artifacts.ts b/contracts/exchange/test/artifacts.ts deleted file mode 100644 index d3fb1e0506..0000000000 --- a/contracts/exchange/test/artifacts.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as Exchange from '../test/generated-artifacts/Exchange.json'; -import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; -import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; -import * as IEIP1271Data from '../test/generated-artifacts/IEIP1271Data.json'; -import * as IEIP1271Wallet from '../test/generated-artifacts/IEIP1271Wallet.json'; -import * as IExchange from '../test/generated-artifacts/IExchange.json'; -import * as IExchangeCore from '../test/generated-artifacts/IExchangeCore.json'; -import * as IMatchOrders from '../test/generated-artifacts/IMatchOrders.json'; -import * as IProtocolFees from '../test/generated-artifacts/IProtocolFees.json'; -import * as ISignatureValidator from '../test/generated-artifacts/ISignatureValidator.json'; -import * as IsolatedExchange from '../test/generated-artifacts/IsolatedExchange.json'; -import * as ITransactions from '../test/generated-artifacts/ITransactions.json'; -import * as ITransferSimulator from '../test/generated-artifacts/ITransferSimulator.json'; -import * as IWallet from '../test/generated-artifacts/IWallet.json'; -import * as IWrapperFunctions from '../test/generated-artifacts/IWrapperFunctions.json'; -import * as LibExchangeRichErrorDecoder from '../test/generated-artifacts/LibExchangeRichErrorDecoder.json'; -import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json'; -import * as MixinExchangeCore from '../test/generated-artifacts/MixinExchangeCore.json'; -import * as MixinMatchOrders from '../test/generated-artifacts/MixinMatchOrders.json'; -import * as MixinProtocolFees from '../test/generated-artifacts/MixinProtocolFees.json'; -import * as MixinSignatureValidator from '../test/generated-artifacts/MixinSignatureValidator.json'; -import * as MixinTransactions from '../test/generated-artifacts/MixinTransactions.json'; -import * as MixinTransferSimulator from '../test/generated-artifacts/MixinTransferSimulator.json'; -import * as MixinWrapperFunctions from '../test/generated-artifacts/MixinWrapperFunctions.json'; -import * as ReentrancyTester from '../test/generated-artifacts/ReentrancyTester.json'; -import * as TestAssetProxyDispatcher from '../test/generated-artifacts/TestAssetProxyDispatcher.json'; -import * as TestExchangeInternals from '../test/generated-artifacts/TestExchangeInternals.json'; -import * as TestFillRounding from '../test/generated-artifacts/TestFillRounding.json'; -import * as TestLibExchangeRichErrorDecoder from '../test/generated-artifacts/TestLibExchangeRichErrorDecoder.json'; -import * as TestProtocolFeeCollector from '../test/generated-artifacts/TestProtocolFeeCollector.json'; -import * as TestProtocolFees from '../test/generated-artifacts/TestProtocolFees.json'; -import * as TestProtocolFeesReceiver from '../test/generated-artifacts/TestProtocolFeesReceiver.json'; -import * as TestTransactions from '../test/generated-artifacts/TestTransactions.json'; -import * as TestValidatorWallet from '../test/generated-artifacts/TestValidatorWallet.json'; -import * as TestWrapperFunctions from '../test/generated-artifacts/TestWrapperFunctions.json'; -export const artifacts = { - Exchange: Exchange as ContractArtifact, - MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact, - MixinExchangeCore: MixinExchangeCore as ContractArtifact, - MixinMatchOrders: MixinMatchOrders as ContractArtifact, - MixinProtocolFees: MixinProtocolFees as ContractArtifact, - MixinSignatureValidator: MixinSignatureValidator as ContractArtifact, - MixinTransactions: MixinTransactions as ContractArtifact, - MixinTransferSimulator: MixinTransferSimulator as ContractArtifact, - MixinWrapperFunctions: MixinWrapperFunctions as ContractArtifact, - IAssetProxy: IAssetProxy as ContractArtifact, - IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, - IEIP1271Data: IEIP1271Data as ContractArtifact, - IEIP1271Wallet: IEIP1271Wallet as ContractArtifact, - IExchange: IExchange as ContractArtifact, - IExchangeCore: IExchangeCore as ContractArtifact, - IMatchOrders: IMatchOrders as ContractArtifact, - IProtocolFees: IProtocolFees as ContractArtifact, - ISignatureValidator: ISignatureValidator as ContractArtifact, - ITransactions: ITransactions as ContractArtifact, - ITransferSimulator: ITransferSimulator as ContractArtifact, - IWallet: IWallet as ContractArtifact, - IWrapperFunctions: IWrapperFunctions as ContractArtifact, - LibExchangeRichErrorDecoder: LibExchangeRichErrorDecoder as ContractArtifact, - IsolatedExchange: IsolatedExchange as ContractArtifact, - ReentrancyTester: ReentrancyTester as ContractArtifact, - TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact, - TestExchangeInternals: TestExchangeInternals as ContractArtifact, - TestFillRounding: TestFillRounding as ContractArtifact, - TestLibExchangeRichErrorDecoder: TestLibExchangeRichErrorDecoder as ContractArtifact, - TestProtocolFeeCollector: TestProtocolFeeCollector as ContractArtifact, - TestProtocolFees: TestProtocolFees as ContractArtifact, - TestProtocolFeesReceiver: TestProtocolFeesReceiver as ContractArtifact, - TestTransactions: TestTransactions as ContractArtifact, - TestValidatorWallet: TestValidatorWallet as ContractArtifact, - TestWrapperFunctions: TestWrapperFunctions as ContractArtifact, -}; diff --git a/contracts/exchange/test/codesize.ts b/contracts/exchange/test/codesize.ts deleted file mode 100644 index a3091c6e6c..0000000000 --- a/contracts/exchange/test/codesize.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { chaiSetup, constants, getCodesizeFromArtifact } from '@0x/contracts-test-utils'; -import * as chai from 'chai'; - -chaiSetup.configure(); -const expect = chai.expect; - -import { artifacts } from './artifacts'; - -describe('Contract Size Checks', () => { - describe('Exchange', () => { - it('should have a codesize less than the maximum', async () => { - const actualSize = getCodesizeFromArtifact(artifacts.Exchange); - expect(actualSize).to.be.lt(constants.MAX_CODE_SIZE); - }); - }); -}); diff --git a/contracts/exchange/test/dispatcher.ts b/contracts/exchange/test/dispatcher.ts deleted file mode 100644 index fdddc21e95..0000000000 --- a/contracts/exchange/test/dispatcher.ts +++ /dev/null @@ -1,386 +0,0 @@ -import { - artifacts as proxyArtifacts, - encodeERC20AssetData, - ERC20ProxyContract, - ERC20Wrapper, - ERC721ProxyContract, - ERC721Wrapper, -} from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { - chaiSetup, - constants, - LogDecoder, - orderUtils, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { OwnableRevertErrors } from '@0x/contracts-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { AssetProxyId, RevertReason } from '@0x/types'; -import { BigNumber, ExchangeRevertErrors, StringRevertError } from '@0x/utils'; -import * as chai from 'chai'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { dependencyArtifacts } from './utils/dependency_artifacts'; -import { TestAssetProxyDispatcherAssetProxyRegisteredEventArgs, TestAssetProxyDispatcherContract } from './wrappers'; - -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 erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: 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 = 2; - [erc20TokenA, erc20TokenB] = 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, - dependencyArtifacts, - ); - await erc20Proxy.addAuthorizedAddress(assetProxyDispatcher.address).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc721Proxy.addAuthorizedAddress(assetProxyDispatcher.address).awaitTransactionSuccessAsync({ - from: owner, - }); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('registerAssetProxy', () => { - it('should record proxy upon registration', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const proxyAddress = await assetProxyDispatcher.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(proxyAddress).to.be.equal(erc20Proxy.address); - }); - - it('should be able to record multiple proxies', async () => { - // Record first proxy - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - let proxyAddress = await assetProxyDispatcher.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(proxyAddress).to.be.equal(erc20Proxy.address); - // Record another proxy - await assetProxyDispatcher.registerAssetProxy(erc721Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - proxyAddress = await assetProxyDispatcher.getAssetProxy(AssetProxyId.ERC721).callAsync(); - expect(proxyAddress).to.be.equal(erc721Proxy.address); - }); - - it('should revert if a proxy with the same id is already registered', async () => { - // Initial registration - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const proxyAddress = await assetProxyDispatcher.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(proxyAddress).to.be.equal(erc20Proxy.address); - // Deploy a new version of the ERC20 Transfer Proxy contract - const newErc20TransferProxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( - proxyArtifacts.ERC20Proxy, - provider, - txDefaults, - dependencyArtifacts, - ); - const expectedError = new ExchangeRevertErrors.AssetProxyExistsError(AssetProxyId.ERC20, proxyAddress); - const tx = assetProxyDispatcher.registerAssetProxy(newErc20TransferProxy.address).sendTransactionAsync({ - from: owner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if requesting address is not owner', async () => { - const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwner, owner); - const tx = assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).sendTransactionAsync({ - from: notOwner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the proxy is not a contract address', async () => { - const errMessage = 'VM Exception while processing transaction: revert'; - const tx = assetProxyDispatcher.registerAssetProxy(notOwner).sendTransactionAsync({ - from: owner, - }); - return expect(tx).to.be.rejectedWith(errMessage); - }); - - it('should log an event with correct arguments when an asset proxy is registered', async () => { - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).sendTransactionAsync({ - from: owner, - }), - ); - const logs = txReceipt.logs; - const log = logs[0] as LogWithDecodedArgs; - 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 assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const proxyAddress = await assetProxyDispatcher.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(proxyAddress).to.be.equal(erc20Proxy.address); - }); - - it('should return NULL address if requesting non-existent proxy', async () => { - const proxyAddress = await assetProxyDispatcher.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(proxyAddress).to.be.equal(constants.NULL_ADDRESS); - }); - }); - - describe('dispatchTransferFrom', () => { - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - it('should dispatch transfer to registered proxy', async () => { - // Register ERC20 proxy - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - // Construct metadata for ERC20 proxy - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - - // Perform a transfer from makerAddress to takerAddress - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const amount = new BigNumber(10); - await assetProxyDispatcher - .dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount) - .awaitTransactionSuccessAsync({ from: owner }); - // Verify transfer was successful - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances[makerAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][erc20TokenA.address].minus(amount), - ); - expect(newBalances[takerAddress][erc20TokenA.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][erc20TokenA.address].plus(amount), - ); - }); - - it('should not dispatch a transfer if amount == 0', async () => { - // Register ERC20 proxy - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - // Construct metadata for ERC20 proxy - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - - // Perform a transfer from makerAddress to takerAddress - const erc20Balances = await erc20Wrapper.getBalancesAsync(); - const amount = constants.ZERO_AMOUNT; - const txReceipt = await assetProxyDispatcher - .dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount) - .awaitTransactionSuccessAsync({ from: owner }); - expect(txReceipt.logs.length).to.be.equal(0); - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances).to.deep.equal(erc20Balances); - }); - - it('should revert if dispatching to unregistered proxy', async () => { - // Construct metadata for ERC20 proxy - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - - // Perform a transfer from makerAddress to takerAddress - const amount = new BigNumber(10); - const expectedError = new ExchangeRevertErrors.AssetProxyDispatchError( - ExchangeRevertErrors.AssetProxyDispatchErrorCode.UnknownAssetProxy, - orderHash, - encodedAssetData, - ); - const tx = assetProxyDispatcher - .dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert with the correct error when assetData length < 4 bytes', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address).slice(0, 8); - const amount = new BigNumber(1); - const expectedError = new ExchangeRevertErrors.AssetProxyDispatchError( - ExchangeRevertErrors.AssetProxyDispatchErrorCode.InvalidAssetDataLength, - orderHash, - encodedAssetData, - ); - const tx = assetProxyDispatcher - .dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if assetData is not padded to 32 bytes (excluding the id)', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - // Shave off the last byte - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address).slice(0, 72); - const amount = new BigNumber(1); - const expectedError = new ExchangeRevertErrors.AssetProxyDispatchError( - ExchangeRevertErrors.AssetProxyDispatchErrorCode.InvalidAssetDataLength, - orderHash, - encodedAssetData, - ); - const tx = assetProxyDispatcher - .dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert with the reason provided by the AssetProxy when a transfer fails', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20TokenA.approve(erc20Proxy.address, constants.ZERO_AMOUNT).awaitTransactionSuccessAsync({ - from: makerAddress, - }); - const encodedAssetData = encodeERC20AssetData(erc20TokenA.address); - const amount = new BigNumber(1); - const nestedError = new StringRevertError(RevertReason.TransferFailed); - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHash, - encodedAssetData, - nestedError.encode(), - ); - const tx = assetProxyDispatcher - .dispatchTransferFrom(orderHash, encodedAssetData, makerAddress, takerAddress, amount) - .sendTransactionAsync({ from: owner }); - return expect(tx).to.revertWith(expectedError); - }); - }); - describe('simulateDispatchTransferFromCalls', () => { - it('should revert with the information specific to the failed transfer', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const assetDataA = encodeERC20AssetData(erc20TokenA.address); - const assetDataB = encodeERC20AssetData(erc20TokenB.address); - await erc20TokenB.approve(erc20Proxy.address, constants.ZERO_AMOUNT).awaitTransactionSuccessAsync({ - from: makerAddress, - }); - const transferIndexAsBytes32 = '0x0000000000000000000000000000000000000000000000000000000000000001'; - const nestedError = new StringRevertError(RevertReason.TransferFailed); - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - transferIndexAsBytes32, - assetDataB, - nestedError.encode(), - ); - const tx = assetProxyDispatcher - .simulateDispatchTransferFromCalls( - [assetDataA, assetDataB], - [makerAddress, makerAddress], - [takerAddress, takerAddress], - [new BigNumber(1), new BigNumber(1)], - ) - .sendTransactionAsync(); - return expect(tx).to.revertWith(expectedError); - }); - it('should forward the revert reason from the underlying failed transfer', async () => { - const assetDataA = encodeERC20AssetData(erc20TokenA.address); - const assetDataB = encodeERC20AssetData(erc20TokenB.address); - const transferIndexAsBytes32 = '0x0000000000000000000000000000000000000000000000000000000000000000'; - const expectedError = new ExchangeRevertErrors.AssetProxyDispatchError( - ExchangeRevertErrors.AssetProxyDispatchErrorCode.UnknownAssetProxy, - transferIndexAsBytes32, - assetDataA, - ); - const tx = assetProxyDispatcher - .simulateDispatchTransferFromCalls( - [assetDataA, assetDataB], - [makerAddress, makerAddress], - [takerAddress, takerAddress], - [new BigNumber(1), new BigNumber(1)], - ) - .sendTransactionAsync(); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert with TRANSFERS_SUCCESSFUL if no transfers fail', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const assetDataA = encodeERC20AssetData(erc20TokenA.address); - const assetDataB = encodeERC20AssetData(erc20TokenB.address); - const tx = assetProxyDispatcher - .simulateDispatchTransferFromCalls( - [assetDataA, assetDataB], - [makerAddress, makerAddress], - [takerAddress, takerAddress], - [new BigNumber(1), new BigNumber(1)], - ) - .sendTransactionAsync(); - return expect(tx).to.revertWith(RevertReason.TransfersSuccessful); - }); - it('should not modify balances if all transfers are successful', async () => { - await assetProxyDispatcher.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - const assetDataA = encodeERC20AssetData(erc20TokenA.address); - const assetDataB = encodeERC20AssetData(erc20TokenB.address); - const balances = await erc20Wrapper.getBalancesAsync(); - try { - await assetProxyDispatcher - .simulateDispatchTransferFromCalls( - [assetDataA, assetDataB], - [makerAddress, makerAddress], - [takerAddress, takerAddress], - [new BigNumber(1), new BigNumber(1)], - ) - .awaitTransactionSuccessAsync(); - } catch (err) { - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect(newBalances).to.deep.equal(balances); - } - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/exchange/test/exchange_transfer_simulator_test.ts b/contracts/exchange/test/exchange_transfer_simulator_test.ts deleted file mode 100644 index 95c083f849..0000000000 --- a/contracts/exchange/test/exchange_transfer_simulator_test.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { artifacts as assetProxyArtifacts, encodeERC20AssetData, ERC20ProxyContract } from '@0x/contracts-asset-proxy'; -import { artifacts as erc20Artifacts, DummyERC20TokenContract, ERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { ExchangeContractErrs } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { ExchangeTransferSimulator } from './utils/exchange_transfer_simulator'; -import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './utils/simple_erc20_balance_and_proxy_allowance_fetcher'; -import { BalanceAndProxyAllowanceLazyStore } from './utils/store/balance_and_proxy_allowance_lazy_store'; -import { TradeSide, TransferType } from './utils/types'; - -const GAS_LIMIT = 9e6; - -blockchainTests.resets('ExchangeTransferSimulator', env => { - const transferAmount = new BigNumber(5); - let userAddresses: string[]; - let dummyERC20Token: DummyERC20TokenContract; - let coinbase: string; - let sender: string; - let recipient: string; - let exampleAssetData: string; - let exchangeTransferSimulator: ExchangeTransferSimulator; - let erc20ProxyAddress: string; - before(async function(): Promise { - const mochaTestTimeoutMs = 20000; - this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this - - userAddresses = await env.web3Wrapper.getAvailableAddressesAsync(); - [coinbase, sender, recipient] = userAddresses; - - const txDefaults = { - gas: GAS_LIMIT, - from: userAddresses[0], - }; - - const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC20Proxy, - env.provider, - txDefaults, - assetProxyArtifacts, - ); - erc20ProxyAddress = erc20Proxy.address; - - const totalSupply = new BigNumber(100000000000000000000); - const name = 'Test'; - const symbol = 'TST'; - const decimals = new BigNumber(18); - // tslint:disable-next-line:no-unused-variable - dummyERC20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyERC20Token, - env.provider, - txDefaults, - erc20Artifacts, - name, - symbol, - decimals, - totalSupply, - ); - - exampleAssetData = encodeERC20AssetData(dummyERC20Token.address); - }); - describe('#transferFromAsync', function(): void { - // HACK: For some reason these tests need a slightly longer timeout - const mochaTestTimeoutMs = 3000; - this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this - beforeEach(() => { - const simpleERC20BalanceAndProxyAllowanceFetcher = new SimpleERC20BalanceAndProxyAllowanceFetcher( - (dummyERC20Token as any) as ERC20TokenContract, - erc20ProxyAddress, - ); - const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( - simpleERC20BalanceAndProxyAllowanceFetcher, - ); - exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore); - }); - it("throws if the user doesn't have enough allowance", async () => { - return expect( - exchangeTransferSimulator.transferFromAsync( - exampleAssetData, - sender, - recipient, - transferAmount, - TradeSide.Taker, - TransferType.Trade, - ), - ).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance); - }); - it("throws if the user doesn't have enough balance", async () => { - await dummyERC20Token.approve(erc20ProxyAddress, transferAmount).awaitTransactionSuccessAsync({ - from: sender, - }); - return expect( - exchangeTransferSimulator.transferFromAsync( - exampleAssetData, - sender, - recipient, - transferAmount, - TradeSide.Maker, - TransferType.Trade, - ), - ).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance); - }); - it('updates balances and proxyAllowance after transfer', async () => { - await dummyERC20Token.transfer(sender, transferAmount).awaitTransactionSuccessAsync({ - from: coinbase, - }); - await dummyERC20Token.approve(erc20ProxyAddress, transferAmount).awaitTransactionSuccessAsync({ - from: sender, - }); - - await exchangeTransferSimulator.transferFromAsync( - exampleAssetData, - sender, - recipient, - transferAmount, - TradeSide.Taker, - TransferType.Trade, - ); - const store = (exchangeTransferSimulator as any)._store; - const senderBalance = await store.getBalanceAsync(exampleAssetData, sender); - const recipientBalance = await store.getBalanceAsync(exampleAssetData, recipient); - const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleAssetData, sender); - expect(senderBalance).to.be.bignumber.equal(0); - expect(recipientBalance).to.be.bignumber.equal(transferAmount); - expect(senderProxyAllowance).to.be.bignumber.equal(0); - }); - it("doesn't update proxyAllowance after transfer if unlimited", async () => { - await dummyERC20Token.transfer(sender, transferAmount).awaitTransactionSuccessAsync({ - from: coinbase, - }); - await dummyERC20Token - .approve(erc20ProxyAddress, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS) - .awaitTransactionSuccessAsync({ - from: sender, - }); - await exchangeTransferSimulator.transferFromAsync( - exampleAssetData, - sender, - recipient, - transferAmount, - TradeSide.Taker, - TransferType.Trade, - ); - const store = (exchangeTransferSimulator as any)._store; - const senderBalance = await store.getBalanceAsync(exampleAssetData, sender); - const recipientBalance = await store.getBalanceAsync(exampleAssetData, recipient); - const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleAssetData, sender); - expect(senderBalance).to.be.bignumber.equal(0); - expect(recipientBalance).to.be.bignumber.equal(transferAmount); - expect(senderProxyAllowance).to.be.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - }); - }); -}); diff --git a/contracts/exchange/test/fill_order.ts b/contracts/exchange/test/fill_order.ts deleted file mode 100644 index 7837b6d20b..0000000000 --- a/contracts/exchange/test/fill_order.ts +++ /dev/null @@ -1,678 +0,0 @@ -import { blockchainTests, describe } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { - FillOrderCombinatorialUtils, - fillOrderCombinatorialUtilsFactoryAsync, -} from './utils/fill_order_combinatorial_utils'; -import { - AllowanceAmountScenario, - AssetDataScenario, - BalanceAmountScenario, - ExpirationTimeSecondsScenario, - FeeAssetDataScenario, - FeeRecipientAddressScenario, - OrderAssetAmountScenario, - TakerAssetFillAmountScenario, - TakerScenario, -} from './utils/fill_order_scenarios'; - -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.ERC20EighteenDecimals, - takerAssetDataScenario: AssetDataScenario.ERC20EighteenDecimals, - makerFeeAssetDataScenario: FeeAssetDataScenario.ERC20EighteenDecimals, - takerFeeAssetDataScenario: FeeAssetDataScenario.ERC20EighteenDecimals, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.LessThanTakerAssetAmount, - makerStateScenario: { - traderAssetBalance: BalanceAmountScenario.Higher, - traderAssetAllowance: AllowanceAmountScenario.Unlimited, - feeBalance: BalanceAmountScenario.Higher, - feeAllowance: AllowanceAmountScenario.Unlimited, - }, - takerStateScenario: { - traderAssetBalance: BalanceAmountScenario.Higher, - traderAssetAllowance: AllowanceAmountScenario.Unlimited, - feeBalance: BalanceAmountScenario.Higher, - feeAllowance: AllowanceAmountScenario.Unlimited, - }, -}; - -blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => { - let fillOrderCombinatorialUtils: FillOrderCombinatorialUtils; - - before(async () => { - fillOrderCombinatorialUtils = await fillOrderCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults); - }); - - describe('Fill tests', () => { - it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetAmountScenario: OrderAssetAmountScenario.Small, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetAmountScenario: OrderAssetAmountScenario.Small, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(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.testFillOrderScenarioSuccessAsync(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.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should transfer the correct amounts maker == feeRecipient', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - feeRecipientScenario: FeeRecipientAddressScenario.MakerAddress, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should transfer the correct amounts maker == feeRecipient and makerFeeAsset == takerAsset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - feeRecipientScenario: FeeRecipientAddressScenario.MakerAddress, - makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should transfer the correct amounts taker == feeRecipient', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - feeRecipientScenario: FeeRecipientAddressScenario.TakerAddress, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should transfer the correct amounts taker == feeRecipient and takerFeeAsset == makerAsset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - feeRecipientScenario: FeeRecipientAddressScenario.TakerAddress, - takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => { - const fillScenario = { - ...defaultFillScenario, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should revert when taker is specified and order is claimed by other', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerScenario: TakerScenario.IncorrectlySpecified, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if makerAssetAmount is 0', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetAmountScenario: OrderAssetAmountScenario.Zero, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if takerAssetAmount is 0', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetAmountScenario: OrderAssetAmountScenario.Zero, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if an order is expired', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - }); - - describe('ERC20', () => { - const assetCombinations = getAllPossiblePairs([ - AssetDataScenario.ERC20ZeroDecimals, - AssetDataScenario.ERC20FiveDecimals, - AssetDataScenario.ERC20EighteenDecimals, - ]); - for (const [makerAsset, takerAsset] of assetCombinations) { - it(`should transfer correct amounts between ${makerAsset} and ${takerAsset}`, async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: makerAsset, - takerAssetDataScenario: takerAsset, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - } - it('should be able to pay maker fee with taker asset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should be able to pay taker fee with maker asset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should not be able to pay maker fee with maker asset if none is left over (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - traderAssetBalance: BalanceAmountScenario.Exact, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should not be able to pay taker fee with taker asset if none is left over (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - traderAssetBalance: BalanceAmountScenario.Exact, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should be able to pay taker fee with maker asset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should revert if maker balance is too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - traderAssetBalance: BalanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if taker balance is too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - takerStateScenario: { - ...defaultFillScenario.makerStateScenario, - traderAssetBalance: BalanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if maker allowances are too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - traderAssetAllowance: AllowanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if taker allowances are too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - takerStateScenario: { - ...defaultFillScenario.makerStateScenario, - traderAssetAllowance: AllowanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if maker fee balance is too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if taker fee balance is too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - takerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if maker fee allowances are too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeAllowance: AllowanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should revert if taker fee allowances are too low to fill order', async () => { - const fillScenario = { - ...defaultFillScenario, - takerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeAllowance: AllowanceAmountScenario.TooLow, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - }); - - describe('ERC721', () => { - it('should be able to pay maker fee with taker ERC721', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetDataScenario: AssetDataScenario.ERC721, - makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should be able to pay taker fee with maker ERC721', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: AssetDataScenario.ERC721, - takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should not be able to pay maker fee with maker ERC721 (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: AssetDataScenario.ERC721, - makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should be able to pay taker fee with taker ERC721 (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetDataScenario: AssetDataScenario.ERC721, - takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - }); - - describe('ERC1155', () => { - const assetTypes = [AssetDataScenario.ERC1155Fungible, AssetDataScenario.ERC1155NonFungible]; - for (const assetType of assetTypes) { - describe(_.startCase(_.toLower((/ERC1155(.+)/.exec(assetType) as string[])[1])), () => { - it('should be able to pay maker fee with taker asset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetDataScenario: assetType, - makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should be able to pay taker fee with maker asset', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: assetType, - takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should not be able to pay maker fee with maker asset if not enough left (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: assetType, - makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - traderAssetBalance: BalanceAmountScenario.Exact, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should be able to pay taker fee with taker asset if not enough left (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetDataScenario: assetType, - takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - traderAssetBalance: BalanceAmountScenario.Exact, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - }); - } - }); - - describe('MultiAssetProxy', () => { - it('should be able to pay maker fee with taker MAP', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetDataScenario: AssetDataScenario.MultiAssetERC20, - makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should be able to pay taker fee with maker MAP', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: AssetDataScenario.MultiAssetERC20, - takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - - it('should not be able to pay maker fee with maker MAP (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: AssetDataScenario.MultiAssetERC20, - makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - makerStateScenario: { - ...defaultFillScenario.makerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - - it('should be able to pay taker fee with taker MAP (double-spend)', async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - takerAssetDataScenario: AssetDataScenario.MultiAssetERC20, - takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - takerStateScenario: { - ...defaultFillScenario.takerStateScenario, - feeBalance: BalanceAmountScenario.Zero, - }, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario); - }); - }); - - describe('Maker/taker asset combinations', () => { - const assetDataScenarios = [ - AssetDataScenario.ERC20EighteenDecimals, - AssetDataScenario.ERC721, - AssetDataScenario.ERC1155Fungible, - AssetDataScenario.ERC1155NonFungible, - AssetDataScenario.MultiAssetERC20, - ]; - for (const [makerAsset, takerAsset] of getAllPossiblePairs(assetDataScenarios)) { - it(`should successfully exchange ${makerAsset} for ${takerAsset}`, async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerAssetDataScenario: makerAsset, - takerAssetDataScenario: takerAsset, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - } - }); - - describe('Maker/taker fee asset combinations', () => { - const feeAssetPairs = getAllPossiblePairs([ - FeeAssetDataScenario.ERC20EighteenDecimals, - FeeAssetDataScenario.ERC721, - FeeAssetDataScenario.ERC1155Fungible, - FeeAssetDataScenario.ERC1155NonFungible, - FeeAssetDataScenario.MultiAssetERC20, - ]); - for (const [makerFeeAsset, takerFeeAsset] of feeAssetPairs) { - it(`should successfully pay maker fee ${makerFeeAsset} and taker fee ${takerFeeAsset}`, async () => { - const fillScenario = { - ...defaultFillScenario, - orderScenario: { - ...defaultFillScenario.orderScenario, - makerFeeAssetDataScenario: makerFeeAsset, - takerFeeAssetDataScenario: takerFeeAsset, - }, - takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - }; - await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario); - }); - } - }); - - describe.optional('Combinatorially generated fills orders', () => { - const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations(); - for (const fillScenario of allFillScenarios) { - const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`; - it(description, async () => { - await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(fillScenario); - }); - } - }); -}); - -function getAllPossiblePairs(choices: T[]): Array<[T, T]> { - const pairs: Array<[T, T]> = []; - for (const i of _.times(choices.length)) { - for (const j of _.times(choices.length)) { - pairs.push([choices[i], choices[j]]); - } - } - return pairs; -} -// tslint:disable: max-file-line-count diff --git a/contracts/exchange/test/global_hooks.ts b/contracts/exchange/test/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/exchange/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/exchange/test/internal.ts b/contracts/exchange/test/internal.ts deleted file mode 100644 index 98fca2e9fd..0000000000 --- a/contracts/exchange/test/internal.ts +++ /dev/null @@ -1,637 +0,0 @@ -import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, expect, orderHashUtils } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { Order } from '@0x/types'; -import { BigNumber, ExchangeRevertErrors, hexUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { - TestExchangeInternalsContract, - TestExchangeInternalsDispatchTransferFromCalledEventArgs, - TestExchangeInternalsFillEventArgs, -} from './wrappers'; -blockchainTests('Exchange core internal functions', env => { - const CHAIN_ID = 1337; - const ONE_ETHER = constants.ONE_ETHER; - const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH); - const randomHash = () => hexUtils.random(constants.WORD_LENGTH); - const randomAssetData = () => hexUtils.random(36); - let testExchange: TestExchangeInternalsContract; - let senderAddress: string; - const DEFAULT_PROTOCOL_MULTIPLIER = new BigNumber(150000); - const DEFAULT_GAS_PRICE = new BigNumber(200000); - - before(async () => { - const accounts = await env.getAccountAddressesAsync(); - senderAddress = accounts[0]; - - testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync( - artifacts.TestExchangeInternals, - env.provider, - env.txDefaults, - {}, - new BigNumber(CHAIN_ID), - ); - }); - - blockchainTests('assertValidMatch', () => { - const ORDER_DEFAULTS = { - senderAddress: randomAddress(), - makerAddress: randomAddress(), - takerAddress: randomAddress(), - makerFee: ONE_ETHER.times(0.001), - takerFee: ONE_ETHER.times(0.003), - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(0.5), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - salt: new BigNumber(_.random(0, 1e8)), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: new BigNumber(_.random(0, 1e8)), - exchangeAddress: constants.NULL_ADDRESS, - chainId: 1337, // The chain id for the isolated exchange - }; - - function makeOrder(details?: Partial): Order { - return _.assign({}, ORDER_DEFAULTS, details); - } - - before(async () => { - ORDER_DEFAULTS.exchangeAddress = testExchange.address; - }); - - it('should revert if the maker asset multiplication should overflow', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: constants.MAX_UINT256, - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: constants.MAX_UINT256_ROOT, - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - }); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - leftOrder.makerAssetAmount, - rightOrder.makerAssetAmount, - ); - return expect(testExchange.assertValidMatch(leftOrder, rightOrder).callAsync()).to.revertWith( - expectedError, - ); - }); - - it('should revert if the taker asset multiplication should overflow', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - takerAssetAmount: constants.MAX_UINT256, - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - takerAssetAmount: constants.MAX_UINT256_ROOT, - }); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - leftOrder.takerAssetAmount, - rightOrder.takerAssetAmount, - ); - return expect(testExchange.assertValidMatch(leftOrder, rightOrder).callAsync()).to.revertWith( - expectedError, - ); - }); - - it('should revert if the prices of the left order is less than the price of the right order', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(49, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - }); - const orderHashHexLeft = orderHashUtils.getOrderHashHex(leftOrder); - const orderHashHexRight = orderHashUtils.getOrderHashHex(rightOrder); - const expectedError = new ExchangeRevertErrors.NegativeSpreadError(orderHashHexLeft, orderHashHexRight); - return expect(testExchange.assertValidMatch(leftOrder, rightOrder).callAsync()).to.revertWith( - expectedError, - ); - }); - - it('should succeed if the prices of the left and right orders are equal', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - }); - return expect(testExchange.assertValidMatch(leftOrder, rightOrder).callAsync()).to.be.fulfilled(''); - }); - - it('should succeed if the price of the left order is higher than the price of the right', async () => { - const leftOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - }); - const rightOrder = makeOrder({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(100, 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(50, 18), - }); - return expect(testExchange.assertValidMatch(leftOrder, rightOrder).callAsync()).to.be.fulfilled(''); - }); - }); - - blockchainTests.resets('updateFilledState', async () => { - const ORDER_DEFAULTS = { - senderAddress: randomAddress(), - makerAddress: randomAddress(), - takerAddress: randomAddress(), - makerFee: ONE_ETHER.times(0.001), - takerFee: ONE_ETHER.times(0.003), - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(0.5), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - salt: new BigNumber(_.random(0, 1e8)), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: new BigNumber(_.random(0, 1e8)), - chainId: 1337, - exchangeAddress: constants.NULL_ADDRESS, - }; - - function makeOrder(details?: Partial): Order { - return _.assign({}, ORDER_DEFAULTS, details); - } - - async function testUpdateFilledStateAsync( - order: Order, - orderTakerAssetFilledAmount: BigNumber, - takerAddress: string, - takerAssetFillAmount: BigNumber, - protocolFeeMultiplier: BigNumber, - gasPrice: BigNumber, - ): Promise { - const orderHash = randomHash(); - const fillResults = LibReferenceFunctions.calculateFillResults( - order, - takerAssetFillAmount, - protocolFeeMultiplier, - gasPrice, - ); - const expectedFilledState = orderTakerAssetFilledAmount.plus(takerAssetFillAmount); - // CAll `testUpdateFilledState()`, which will set the `filled` - // state for this order to `orderTakerAssetFilledAmount` before - // calling `_updateFilledState()`. - const receipt = await testExchange - .testUpdateFilledState(order, takerAddress, orderHash, orderTakerAssetFilledAmount, fillResults) - .awaitTransactionSuccessAsync(); - - // Grab the new `filled` state for this order. - const actualFilledState = await testExchange.filled(orderHash).callAsync(); - // Assert the `filled` state for this order. - expect(actualFilledState).to.bignumber.eq(expectedFilledState); - // Assert the logs. - // tslint:disable-next-line: no-unnecessary-type-assertion - const fillEvent = receipt.logs[0] as LogWithDecodedArgs; - expect(fillEvent.event).to.eq('Fill'); - expect(fillEvent.args.makerAddress).to.eq(order.makerAddress); - expect(fillEvent.args.feeRecipientAddress).to.eq(order.feeRecipientAddress); - expect(fillEvent.args.orderHash).to.eq(orderHash); - expect(fillEvent.args.takerAddress).to.eq(takerAddress); - expect(fillEvent.args.senderAddress).to.eq(senderAddress); - expect(fillEvent.args.makerAssetFilledAmount).to.bignumber.eq(fillResults.makerAssetFilledAmount); - expect(fillEvent.args.takerAssetFilledAmount).to.bignumber.eq(fillResults.takerAssetFilledAmount); - expect(fillEvent.args.makerFeePaid).to.bignumber.eq(fillResults.makerFeePaid); - expect(fillEvent.args.takerFeePaid).to.bignumber.eq(fillResults.takerFeePaid); - expect(fillEvent.args.makerAssetData).to.eq(order.makerAssetData); - expect(fillEvent.args.takerAssetData).to.eq(order.takerAssetData); - expect(fillEvent.args.makerFeeAssetData).to.eq(order.makerFeeAssetData); - expect(fillEvent.args.takerFeeAssetData).to.eq(order.takerFeeAssetData); - expect(fillEvent.args.protocolFeePaid).to.bignumber.eq(fillResults.protocolFeePaid); - } - - it('emits a `Fill` event and updates `filled` state correctly', async () => { - const order = makeOrder(); - return testUpdateFilledStateAsync( - order, - order.takerAssetAmount.times(0.1), - randomAddress(), - order.takerAssetAmount.times(0.25), - DEFAULT_PROTOCOL_MULTIPLIER, - DEFAULT_GAS_PRICE, - ); - }); - - it('reverts if `leftOrderTakerAssetFilledAmount + fillResults.takerAssetFilledAmount` overflows', async () => { - const order = makeOrder(); - const orderTakerAssetFilledAmount = constants.MAX_UINT256.dividedToIntegerBy(2); - const takerAssetFillAmount = constants.MAX_UINT256.dividedToIntegerBy(2).plus(2); - const fillResults = { - makerAssetFilledAmount: constants.ZERO_AMOUNT, - takerAssetFilledAmount: takerAssetFillAmount, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: constants.ZERO_AMOUNT, - }; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - orderTakerAssetFilledAmount, - takerAssetFillAmount, - ); - return expect( - testExchange - .testUpdateFilledState( - order, - randomAddress(), - randomHash(), - orderTakerAssetFilledAmount, - fillResults, - ) - .awaitTransactionSuccessAsync(), - ).to.revertWith(expectedError); - }); - }); - - blockchainTests('settleOrder', () => { - const DEFAULT_ORDER = { - senderAddress: randomAddress(), - makerAddress: randomAddress(), - takerAddress: randomAddress(), - makerFee: ONE_ETHER.times(0.001), - takerFee: ONE_ETHER.times(0.003), - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(0.5), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - salt: new BigNumber(_.random(0, 1e8)), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: new BigNumber(_.random(0, 1e8)), - }; - - it('calls `_dispatchTransferFrom()` in the right order with the correct arguments', async () => { - const order = DEFAULT_ORDER; - const orderHash = randomHash(); - const takerAddress = randomAddress(); - const fillResults = { - makerAssetFilledAmount: ONE_ETHER.times(2), - takerAssetFilledAmount: ONE_ETHER.times(10), - makerFeePaid: ONE_ETHER.times(0.01), - takerFeePaid: ONE_ETHER.times(0.025), - protocolFeePaid: constants.ZERO_AMOUNT, - }; - const receipt = await testExchange - .settleOrder(orderHash, order, takerAddress, fillResults) - .awaitTransactionSuccessAsync(); - const logs = receipt.logs as Array< - LogWithDecodedArgs - >; - expect(logs.length === 4); - expect(_.every(logs, log => log.event === 'DispatchTransferFromCalled')).to.be.true(); - // taker -> maker - expect(logs[0].args.orderHash).to.eq(orderHash); - expect(logs[0].args.assetData).to.eq(order.takerAssetData); - expect(logs[0].args.from).to.eq(takerAddress); - expect(logs[0].args.to).to.eq(order.makerAddress); - expect(logs[0].args.amount).to.bignumber.eq(fillResults.takerAssetFilledAmount); - // maker -> taker - expect(logs[1].args.orderHash).to.eq(orderHash); - expect(logs[1].args.assetData).to.eq(order.makerAssetData); - expect(logs[1].args.from).to.eq(order.makerAddress); - expect(logs[1].args.to).to.eq(takerAddress); - expect(logs[1].args.amount).to.bignumber.eq(fillResults.makerAssetFilledAmount); - // taker fee -> feeRecipient - expect(logs[2].args.orderHash).to.eq(orderHash); - expect(logs[2].args.assetData).to.eq(order.takerFeeAssetData); - expect(logs[2].args.from).to.eq(takerAddress); - expect(logs[2].args.to).to.eq(order.feeRecipientAddress); - expect(logs[2].args.amount).to.bignumber.eq(fillResults.takerFeePaid); - // maker fee -> feeRecipient - expect(logs[3].args.orderHash).to.eq(orderHash); - expect(logs[3].args.assetData).to.eq(order.makerFeeAssetData); - expect(logs[3].args.from).to.eq(order.makerAddress); - expect(logs[3].args.to).to.eq(order.feeRecipientAddress); - expect(logs[3].args.amount).to.bignumber.eq(fillResults.makerFeePaid); - }); - }); - - blockchainTests('settleMatchOrders', () => { - const getOrder = () => { - return { - senderAddress: randomAddress(), - makerAddress: randomAddress(), - takerAddress: randomAddress(), - makerFee: ONE_ETHER.times(0.001), - takerFee: ONE_ETHER.times(0.003), - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(0.5), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - salt: new BigNumber(_.random(0, 1e8)), - feeRecipientAddress: randomAddress(), - expirationTimeSeconds: new BigNumber(_.random(0, 1e8)), - }; - }; - - it('should revert if the taker fee paid fields addition overflow and left.feeRecipient == right.feeRecipient && left.takerFeeAssetData == right.takerFeeAssetData', async () => { - // Get the arguments for the call to `settleMatchOrders()`. - const leftOrder = getOrder(); - const rightOrder = getOrder(); - const leftOrderHash = randomHash(); - const rightOrderHash = randomHash(); - const takerAddress = randomAddress(); - const matchedFillResults = { - left: { - makerAssetFilledAmount: ONE_ETHER.times(2), - takerAssetFilledAmount: ONE_ETHER.times(10), - makerFeePaid: ONE_ETHER.times(0.01), - takerFeePaid: constants.MAX_UINT256, - protocolFeePaid: constants.ZERO_AMOUNT, - }, - right: { - takerAssetFilledAmount: ONE_ETHER.times(20), - makerAssetFilledAmount: ONE_ETHER.times(4), - makerFeePaid: ONE_ETHER.times(0.02), - takerFeePaid: constants.MAX_UINT256_ROOT, - protocolFeePaid: constants.ZERO_AMOUNT, - }, - profitInLeftMakerAsset: ONE_ETHER, - profitInRightMakerAsset: ONE_ETHER.times(2), - }; - - // Set the fee recipient addresses and the taker fee asset data fields to be the same - rightOrder.feeRecipientAddress = leftOrder.feeRecipientAddress; - rightOrder.takerFeeAssetData = leftOrder.takerFeeAssetData; - - // The expected error that should be thrown by the function. - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - matchedFillResults.left.takerFeePaid, - matchedFillResults.right.takerFeePaid, - ); - - // Ensure that the call to `settleMatchOrders()` fails with the expected error. - const tx = testExchange - .settleMatchOrders( - leftOrderHash, - rightOrderHash, - leftOrder, - rightOrder, - takerAddress, - matchedFillResults, - ) - .sendTransactionAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should succeed if the taker fee paid fields addition overflow and left.feeRecipient != right.feeRecipient || left.takerFeeAssetData != right.takerFeeAssetData', async () => { - // Get the arguments for the call to `settleMatchOrders()`. - const leftOrder = getOrder(); - const rightOrder = getOrder(); - const leftOrderHash = randomHash(); - const rightOrderHash = randomHash(); - const takerAddress = randomAddress(); - const matchedFillResults = { - left: { - makerAssetFilledAmount: ONE_ETHER.times(2), - takerAssetFilledAmount: ONE_ETHER.times(10), - makerFeePaid: ONE_ETHER.times(0.01), - takerFeePaid: constants.MAX_UINT256, - protocolFeePaid: constants.ZERO_AMOUNT, - }, - right: { - takerAssetFilledAmount: ONE_ETHER.times(20), - makerAssetFilledAmount: ONE_ETHER.times(4), - makerFeePaid: ONE_ETHER.times(0.02), - takerFeePaid: constants.MAX_UINT256_ROOT, - protocolFeePaid: constants.ZERO_AMOUNT, - }, - profitInLeftMakerAsset: ONE_ETHER, - profitInRightMakerAsset: ONE_ETHER.times(2), - }; - - // The call to `settleMatchOrders()` should be successful. - return expect( - testExchange - .settleMatchOrders( - leftOrderHash, - rightOrderHash, - leftOrder, - rightOrder, - takerAddress, - matchedFillResults, - ) - .sendTransactionAsync(), - ).to.be.fulfilled(''); - }); - - it('calls `_dispatchTransferFrom()` to collect fees from the left order when left.feeRecipient == right.feeRecipient && left.takerFeeAssetData == right.takerFeeAssetData', async () => { - const leftOrder = getOrder(); - const rightOrder = getOrder(); - const leftOrderHash = randomHash(); - const rightOrderHash = randomHash(); - const takerAddress = randomAddress(); - const matchedFillResults = { - left: { - makerAssetFilledAmount: ONE_ETHER.times(2), - takerAssetFilledAmount: ONE_ETHER.times(10), - makerFeePaid: ONE_ETHER.times(0.01), - takerFeePaid: ONE_ETHER.times(0.025), - protocolFeePaid: constants.ZERO_AMOUNT, - }, - right: { - takerAssetFilledAmount: ONE_ETHER.times(20), - makerAssetFilledAmount: ONE_ETHER.times(4), - makerFeePaid: ONE_ETHER.times(0.02), - takerFeePaid: ONE_ETHER.times(0.05), - protocolFeePaid: constants.ZERO_AMOUNT, - }, - profitInLeftMakerAsset: ONE_ETHER, - profitInRightMakerAsset: ONE_ETHER.times(2), - }; - - // Set the fee recipient addresses and the taker fee asset data fields to be the same - rightOrder.feeRecipientAddress = leftOrder.feeRecipientAddress; - rightOrder.takerFeeAssetData = leftOrder.takerFeeAssetData; - - // Call settleMatchOrders and collect the logs - const receipt = await testExchange - .settleMatchOrders( - leftOrderHash, - rightOrderHash, - leftOrder, - rightOrder, - takerAddress, - matchedFillResults, - ) - .awaitTransactionSuccessAsync(); - const logs = receipt.logs as Array< - LogWithDecodedArgs - >; - - // Ensure that the logs have the correct lengths and names - expect(logs.length).to.be.eq(7); - expect(_.every(logs, log => log.event === 'DispatchTransferFromCalled')).to.be.true(); - - // Right maker asset -> left maker - expect(logs[0].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[0].args.assetData).to.be.eq(rightOrder.makerAssetData); - expect(logs[0].args.from).to.be.eq(rightOrder.makerAddress); - expect(logs[0].args.to).to.be.eq(leftOrder.makerAddress); - expect(logs[0].args.amount).bignumber.to.be.eq(matchedFillResults.left.takerAssetFilledAmount); - - // Left maker asset -> right maker - expect(logs[1].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[1].args.assetData).to.be.eq(leftOrder.makerAssetData); - expect(logs[1].args.from).to.be.eq(leftOrder.makerAddress); - expect(logs[1].args.to).to.be.eq(rightOrder.makerAddress); - expect(logs[1].args.amount).bignumber.to.be.eq(matchedFillResults.right.takerAssetFilledAmount); - - // Right maker fee -> right fee recipient - expect(logs[2].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[2].args.assetData).to.be.eq(rightOrder.makerFeeAssetData); - expect(logs[2].args.from).to.be.eq(rightOrder.makerAddress); - expect(logs[2].args.to).to.be.eq(rightOrder.feeRecipientAddress); - expect(logs[2].args.amount).bignumber.to.be.eq(matchedFillResults.right.makerFeePaid); - - // Left maker fee -> left fee recipient - expect(logs[3].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[3].args.assetData).to.be.eq(leftOrder.makerFeeAssetData); - expect(logs[3].args.from).to.be.eq(leftOrder.makerAddress); - expect(logs[3].args.to).to.be.eq(leftOrder.feeRecipientAddress); - expect(logs[3].args.amount).bignumber.to.be.eq(matchedFillResults.left.makerFeePaid); - - // Left maker -> taker profit - expect(logs[4].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[4].args.assetData).to.be.eq(leftOrder.makerAssetData); - expect(logs[4].args.from).to.be.eq(leftOrder.makerAddress); - expect(logs[4].args.to).to.be.eq(takerAddress); - expect(logs[4].args.amount).bignumber.to.be.eq(matchedFillResults.profitInLeftMakerAsset); - - // right maker -> taker profit - expect(logs[5].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[5].args.assetData).to.be.eq(rightOrder.makerAssetData); - expect(logs[5].args.from).to.be.eq(rightOrder.makerAddress); - expect(logs[5].args.to).to.be.eq(takerAddress); - expect(logs[5].args.amount).bignumber.to.be.eq(matchedFillResults.profitInRightMakerAsset); - - // taker fees -> fee recipient - expect(logs[6].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[6].args.assetData).to.be.eq(leftOrder.takerFeeAssetData); - expect(logs[6].args.from).to.be.eq(takerAddress); - expect(logs[6].args.to).to.be.eq(leftOrder.feeRecipientAddress); - expect(logs[6].args.amount).bignumber.to.be.eq(ONE_ETHER.times(0.075)); - }); - - it('calls `_dispatchTransferFrom()` from in the right order when the fee recipients and taker fee asset data are not the same', async () => { - const leftOrder = getOrder(); - const rightOrder = getOrder(); - const leftOrderHash = randomHash(); - const rightOrderHash = randomHash(); - const takerAddress = randomAddress(); - const matchedFillResults = { - left: { - makerAssetFilledAmount: ONE_ETHER.times(2), - takerAssetFilledAmount: ONE_ETHER.times(10), - makerFeePaid: ONE_ETHER.times(0.01), - takerFeePaid: ONE_ETHER.times(0.025), - protocolFeePaid: constants.ZERO_AMOUNT, - }, - right: { - takerAssetFilledAmount: ONE_ETHER.times(20), - makerAssetFilledAmount: ONE_ETHER.times(4), - makerFeePaid: ONE_ETHER.times(0.02), - takerFeePaid: ONE_ETHER.times(0.05), - protocolFeePaid: constants.ZERO_AMOUNT, - }, - profitInLeftMakerAsset: ONE_ETHER, - profitInRightMakerAsset: ONE_ETHER.times(2), - }; - - // Call settleMatchOrders and collect the logs - const receipt = await testExchange - .settleMatchOrders( - leftOrderHash, - rightOrderHash, - leftOrder, - rightOrder, - takerAddress, - matchedFillResults, - ) - .awaitTransactionSuccessAsync(); - const logs = receipt.logs as Array< - LogWithDecodedArgs - >; - - // Ensure that the logs have the correct lengths and names - expect(logs.length).to.be.eq(8); - expect(_.every(logs, log => log.event === 'DispatchTransferFromCalled')).to.be.true(); - - // Right maker asset -> left maker - expect(logs[0].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[0].args.assetData).to.be.eq(rightOrder.makerAssetData); - expect(logs[0].args.from).to.be.eq(rightOrder.makerAddress); - expect(logs[0].args.to).to.be.eq(leftOrder.makerAddress); - expect(logs[0].args.amount).bignumber.to.be.eq(matchedFillResults.left.takerAssetFilledAmount); - - // Left maker asset -> right maker - expect(logs[1].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[1].args.assetData).to.be.eq(leftOrder.makerAssetData); - expect(logs[1].args.from).to.be.eq(leftOrder.makerAddress); - expect(logs[1].args.to).to.be.eq(rightOrder.makerAddress); - expect(logs[1].args.amount).bignumber.to.be.eq(matchedFillResults.right.takerAssetFilledAmount); - - // Right maker fee -> right fee recipient - expect(logs[2].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[2].args.assetData).to.be.eq(rightOrder.makerFeeAssetData); - expect(logs[2].args.from).to.be.eq(rightOrder.makerAddress); - expect(logs[2].args.to).to.be.eq(rightOrder.feeRecipientAddress); - expect(logs[2].args.amount).bignumber.to.be.eq(matchedFillResults.right.makerFeePaid); - - // Left maker fee -> left fee recipient - expect(logs[3].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[3].args.assetData).to.be.eq(leftOrder.makerFeeAssetData); - expect(logs[3].args.from).to.be.eq(leftOrder.makerAddress); - expect(logs[3].args.to).to.be.eq(leftOrder.feeRecipientAddress); - expect(logs[3].args.amount).bignumber.to.be.eq(matchedFillResults.left.makerFeePaid); - - // Left maker -> taker profit - expect(logs[4].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[4].args.assetData).to.be.eq(leftOrder.makerAssetData); - expect(logs[4].args.from).to.be.eq(leftOrder.makerAddress); - expect(logs[4].args.to).to.be.eq(takerAddress); - expect(logs[4].args.amount).bignumber.to.be.eq(matchedFillResults.profitInLeftMakerAsset); - - // right maker -> taker profit - expect(logs[5].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[5].args.assetData).to.be.eq(rightOrder.makerAssetData); - expect(logs[5].args.from).to.be.eq(rightOrder.makerAddress); - expect(logs[5].args.to).to.be.eq(takerAddress); - expect(logs[5].args.amount).bignumber.to.be.eq(matchedFillResults.profitInRightMakerAsset); - - // Right taker fee -> right fee recipient - expect(logs[6].args.orderHash).to.be.eq(rightOrderHash); - expect(logs[6].args.assetData).to.be.eq(rightOrder.takerFeeAssetData); - expect(logs[6].args.from).to.be.eq(takerAddress); - expect(logs[6].args.to).to.be.eq(rightOrder.feeRecipientAddress); - expect(logs[6].args.amount).bignumber.to.be.eq(matchedFillResults.right.takerFeePaid); - - // Right taker fee -> right fee recipient - expect(logs[7].args.orderHash).to.be.eq(leftOrderHash); - expect(logs[7].args.assetData).to.be.eq(leftOrder.takerFeeAssetData); - expect(logs[7].args.from).to.be.eq(takerAddress); - expect(logs[7].args.to).to.be.eq(leftOrder.feeRecipientAddress); - expect(logs[7].args.amount).bignumber.to.be.eq(matchedFillResults.left.takerFeePaid); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/exchange/test/isolated_fill_order.ts b/contracts/exchange/test/isolated_fill_order.ts deleted file mode 100644 index 7a6f736d17..0000000000 --- a/contracts/exchange/test/isolated_fill_order.ts +++ /dev/null @@ -1,608 +0,0 @@ -import { LibMathRevertErrors, ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { FillResults, OrderInfo, OrderStatus, SignatureType } from '@0x/types'; -import { BigNumber, ExchangeRevertErrors, hexUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { - AssetBalances, - createBadAssetData, - createBadSignature, - createGoodAssetData, - createGoodSignature, - IsolatedExchangeWrapper, - Order, -} from './utils/isolated_exchange_wrapper'; - -blockchainTests('Isolated fillOrder() tests', env => { - const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH); - const getCurrentTime = () => Math.floor(_.now() / 1000); - const { ZERO_AMOUNT, ONE_ETHER, MAX_UINT256_ROOT } = constants; - const ONE_DAY = 60 * 60 * 24; - const TOMORROW = getCurrentTime() + ONE_DAY; - const DEFAULT_ORDER: Order = { - senderAddress: constants.NULL_ADDRESS, - makerAddress: randomAddress(), - takerAddress: constants.NULL_ADDRESS, - feeRecipientAddress: randomAddress(), - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER.times(2), - makerFee: ONE_ETHER.times(0.0015), - takerFee: ONE_ETHER.times(0.0025), - salt: ZERO_AMOUNT, - expirationTimeSeconds: new BigNumber(TOMORROW), - makerAssetData: createGoodAssetData(), - takerAssetData: createGoodAssetData(), - makerFeeAssetData: createGoodAssetData(), - takerFeeAssetData: createGoodAssetData(), - exchangeAddress: constants.NULL_ADDRESS, - chainId: 1, - }; - const DEFAULT_GAS_PRICE = new BigNumber(20000); - const DEFAULT_PROTOCOL_FEE_MULTIPLIER = new BigNumber(15000); - let takerAddress: string; - let notTakerAddress: string; - let exchange: IsolatedExchangeWrapper; - let nextSaltValue = 1; - - before(async () => { - [takerAddress, notTakerAddress] = await env.getAccountAddressesAsync(); - exchange = await IsolatedExchangeWrapper.deployAsync(env.web3Wrapper, { - ...env.txDefaults, - from: takerAddress, - }); - }); - - function createOrder(details: Partial = {}): Order { - return { - ...DEFAULT_ORDER, - salt: new BigNumber(nextSaltValue++), - ...details, - }; - } - - interface FillOrderAndAssertResultsResults { - fillResults: FillResults; - orderInfo: OrderInfo; - } - - async function fillOrderAndAssertResultsAsync( - order: Order, - takerAssetFillAmount: BigNumber, - signature?: string, - ): Promise { - const orderInfo = await exchange.getOrderInfoAsync(order); - const efr = calculateExpectedFillResults( - order, - orderInfo, - takerAssetFillAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ); - const eoi = calculateExpectedOrderInfo(order, orderInfo, efr); - const efb = calculateExpectedFillBalances(order, efr); - // Fill the order. - const fillResults = await exchange.fillOrderAsync(order, takerAssetFillAmount, signature); - const newOrderInfo = await exchange.getOrderInfoAsync(order); - // Check returned fillResults. - expect(fillResults.makerAssetFilledAmount).to.bignumber.eq(efr.makerAssetFilledAmount); - expect(fillResults.takerAssetFilledAmount).to.bignumber.eq(efr.takerAssetFilledAmount); - expect(fillResults.makerFeePaid).to.bignumber.eq(efr.makerFeePaid); - expect(fillResults.takerFeePaid).to.bignumber.eq(efr.takerFeePaid); - // Check balances. - for (const assetData of Object.keys(efb)) { - for (const address of Object.keys(efb[assetData])) { - expect( - exchange.getBalanceChange(assetData, address), - `checking balance of assetData: ${assetData}, address: ${address}`, - ).to.bignumber.eq(efb[assetData][address]); - } - } - // Check order info. - expect(newOrderInfo.orderStatus).to.eq(eoi.orderStatus); - expect(newOrderInfo.orderTakerAssetFilledAmount).to.bignumber.eq(eoi.orderTakerAssetFilledAmount); - // Check that there wasn't an overfill. - expect(newOrderInfo.orderTakerAssetFilledAmount.lte(order.takerAssetAmount), 'checking for overfill').to.be.ok( - '', - ); - return { - fillResults, - orderInfo: newOrderInfo, - }; - } - - function calculateExpectedFillResults( - order: Order, - orderInfo: OrderInfo, - takerAssetFillAmount: BigNumber, - protocolFeeMultiplier: BigNumber, - gasPrice: BigNumber, - ): FillResults { - const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount); - return LibReferenceFunctions.calculateFillResults( - order, - BigNumber.min(takerAssetFillAmount, remainingTakerAssetAmount), - protocolFeeMultiplier, - gasPrice, - ); - } - - function calculateExpectedOrderInfo(order: Order, orderInfo: OrderInfo, fillResults: FillResults): OrderInfo { - const orderTakerAssetFilledAmount = orderInfo.orderTakerAssetFilledAmount.plus( - fillResults.takerAssetFilledAmount, - ); - const orderStatus = orderTakerAssetFilledAmount.gte(order.takerAssetAmount) - ? OrderStatus.FullyFilled - : OrderStatus.Fillable; - return { - orderHash: exchange.getOrderHash(order), - orderStatus, - orderTakerAssetFilledAmount, - }; - } - - function calculateExpectedFillBalances(order: Order, fillResults: FillResults): AssetBalances { - const balances: AssetBalances = {}; - const addBalance = (assetData: string, address: string, amount: BigNumber) => { - balances[assetData] = balances[assetData] || {}; - const balance = balances[assetData][address] || ZERO_AMOUNT; - balances[assetData][address] = balance.plus(amount); - }; - addBalance(order.makerAssetData, order.makerAddress, fillResults.makerAssetFilledAmount.negated()); - addBalance(order.makerAssetData, takerAddress, fillResults.makerAssetFilledAmount); - addBalance(order.takerAssetData, order.makerAddress, fillResults.takerAssetFilledAmount); - addBalance(order.takerAssetData, takerAddress, fillResults.takerAssetFilledAmount.negated()); - addBalance(order.makerFeeAssetData, order.makerAddress, fillResults.makerFeePaid.negated()); - addBalance(order.makerFeeAssetData, order.feeRecipientAddress, fillResults.makerFeePaid); - addBalance(order.takerFeeAssetData, takerAddress, fillResults.takerFeePaid.negated()); - addBalance(order.takerFeeAssetData, order.feeRecipientAddress, fillResults.takerFeePaid); - return balances; - } - - function splitAmount(total: BigNumber, n: number = 2): BigNumber[] { - const splitSize = total.dividedToIntegerBy(n); - const splits = _.times(n - 1, () => splitSize); - splits.push(total.minus(splitSize.times(n - 1))); - return splits; - } - - describe('full fills', () => { - it('can fully fill an order', async () => { - const order = createOrder(); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, order.takerAssetAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it("can't overfill an order", async () => { - const order = createOrder(); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, order.takerAssetAmount.times(1.01)); - expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('no fees', async () => { - const order = createOrder({ - makerFee: ZERO_AMOUNT, - takerFee: ZERO_AMOUNT, - }); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, order.takerAssetAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('only maker fees', async () => { - const order = createOrder({ - takerFee: ZERO_AMOUNT, - }); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, order.takerAssetAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('only taker fees', async () => { - const order = createOrder({ - makerFee: ZERO_AMOUNT, - }); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, order.takerAssetAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled); - }); - }); - - describe('partial fills', () => { - const takerAssetFillAmount = DEFAULT_ORDER.takerAssetAmount.dividedToIntegerBy(2); - - it('can partially fill an order', async () => { - const order = createOrder(); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, takerAssetFillAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.Fillable); - }); - - it('no fees', async () => { - const order = createOrder({ - makerFee: ZERO_AMOUNT, - takerFee: ZERO_AMOUNT, - }); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, takerAssetFillAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.Fillable); - }); - - it('only maker fees', async () => { - const order = createOrder({ - takerFee: ZERO_AMOUNT, - }); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, takerAssetFillAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.Fillable); - }); - - it('only taker fees', async () => { - const order = createOrder({ - makerFee: ZERO_AMOUNT, - }); - const { orderInfo } = await fillOrderAndAssertResultsAsync(order, takerAssetFillAmount); - expect(orderInfo.orderStatus).to.eq(OrderStatus.Fillable); - }); - }); - - describe('multiple fills', () => { - it('can fully fill an order in two fills', async () => { - const order = createOrder(); - const fillAmounts = splitAmount(order.takerAssetAmount); - const orderInfos = [ - (await fillOrderAndAssertResultsAsync(order, fillAmounts[0])).orderInfo, - (await fillOrderAndAssertResultsAsync(order, fillAmounts[1])).orderInfo, - ]; - expect(orderInfos[0].orderStatus).to.eq(OrderStatus.Fillable); - expect(orderInfos[1].orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('can partially fill an order in two fills', async () => { - const order = createOrder(); - const fillAmounts = splitAmount(order.takerAssetAmount.dividedToIntegerBy(2)); - const orderInfos = [ - (await fillOrderAndAssertResultsAsync(order, fillAmounts[0])).orderInfo, - (await fillOrderAndAssertResultsAsync(order, fillAmounts[1])).orderInfo, - ]; - expect(orderInfos[0].orderStatus).to.eq(OrderStatus.Fillable); - expect(orderInfos[1].orderStatus).to.eq(OrderStatus.Fillable); - }); - - it("can't overfill an order in two fills", async () => { - const order = createOrder(); - const fillAmounts = splitAmount(order.takerAssetAmount); - fillAmounts[0] = fillAmounts[0].times(1.01); - const orderInfos = [ - (await fillOrderAndAssertResultsAsync(order, fillAmounts[0])).orderInfo, - (await fillOrderAndAssertResultsAsync(order, fillAmounts[1])).orderInfo, - ]; - expect(orderInfos[0].orderStatus).to.eq(OrderStatus.Fillable); - expect(orderInfos[1].orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('can fully fill an order with no fees in two fills', async () => { - const order = createOrder({ - makerFee: ZERO_AMOUNT, - takerFee: ZERO_AMOUNT, - }); - const fillAmounts = splitAmount(order.takerAssetAmount); - const orderInfos = [ - (await fillOrderAndAssertResultsAsync(order, fillAmounts[0])).orderInfo, - (await fillOrderAndAssertResultsAsync(order, fillAmounts[1])).orderInfo, - ]; - expect(orderInfos[0].orderStatus).to.eq(OrderStatus.Fillable); - expect(orderInfos[1].orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('can fully fill an order with only maker fees in two fills', async () => { - const order = createOrder({ - takerFee: ZERO_AMOUNT, - }); - const fillAmounts = splitAmount(order.takerAssetAmount); - const orderInfos = [ - (await fillOrderAndAssertResultsAsync(order, fillAmounts[0])).orderInfo, - (await fillOrderAndAssertResultsAsync(order, fillAmounts[1])).orderInfo, - ]; - expect(orderInfos[0].orderStatus).to.eq(OrderStatus.Fillable); - expect(orderInfos[1].orderStatus).to.eq(OrderStatus.FullyFilled); - }); - - it('can fully fill an order with only taker fees in two fills', async () => { - const order = createOrder({ - makerFee: ZERO_AMOUNT, - }); - const fillAmounts = splitAmount(order.takerAssetAmount); - const orderInfos = [ - (await fillOrderAndAssertResultsAsync(order, fillAmounts[0])).orderInfo, - (await fillOrderAndAssertResultsAsync(order, fillAmounts[1])).orderInfo, - ]; - expect(orderInfos[0].orderStatus).to.eq(OrderStatus.Fillable); - expect(orderInfos[1].orderStatus).to.eq(OrderStatus.FullyFilled); - }); - }); - - describe('bad fills', () => { - it("can't fill an order with zero takerAssetAmount", async () => { - const order = createOrder({ - takerAssetAmount: ZERO_AMOUNT, - }); - const expectedError = new ExchangeRevertErrors.OrderStatusError( - exchange.getOrderHash(order), - OrderStatus.InvalidTakerAssetAmount, - ); - return expect(exchange.fillOrderAsync(order, ONE_ETHER)).to.revertWith(expectedError); - }); - - it("can't fill an order with zero makerAssetAmount", async () => { - const order = createOrder({ - makerAssetAmount: ZERO_AMOUNT, - }); - const expectedError = new ExchangeRevertErrors.OrderStatusError( - exchange.getOrderHash(order), - OrderStatus.InvalidMakerAssetAmount, - ); - return expect(exchange.fillOrderAsync(order, ONE_ETHER)).to.revertWith(expectedError); - }); - - it("can't fill an order that is fully filled", async () => { - const order = createOrder(); - const expectedError = new ExchangeRevertErrors.OrderStatusError( - exchange.getOrderHash(order), - OrderStatus.FullyFilled, - ); - await exchange.fillOrderAsync(order, order.takerAssetAmount); - return expect(exchange.fillOrderAsync(order, 1)).to.revertWith(expectedError); - }); - - it("can't fill an order that is expired", async () => { - const order = createOrder({ - expirationTimeSeconds: new BigNumber(getCurrentTime() - 60), - }); - const expectedError = new ExchangeRevertErrors.OrderStatusError( - exchange.getOrderHash(order), - OrderStatus.Expired, - ); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order that is cancelled by `cancelOrder()`", async () => { - const order = createOrder({ - makerAddress: notTakerAddress, - }); - const expectedError = new ExchangeRevertErrors.OrderStatusError( - exchange.getOrderHash(order), - OrderStatus.Cancelled, - ); - await exchange.cancelOrderAsync(order, { from: notTakerAddress }); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order that is cancelled by `cancelOrdersUpTo()`", async () => { - const order = createOrder({ - makerAddress: notTakerAddress, - }); - const expectedError = new ExchangeRevertErrors.OrderStatusError( - exchange.getOrderHash(order), - OrderStatus.Cancelled, - ); - await exchange.cancelOrdersUpToAsync(order.salt, { from: notTakerAddress }); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order if taker is not `takerAddress`", async () => { - const order = createOrder({ - takerAddress: randomAddress(), - }); - const expectedError = new ExchangeRevertErrors.ExchangeInvalidContextError( - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidTaker, - exchange.getOrderHash(order), - takerAddress, - ); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order if sender is not `senderAddress`", async () => { - const order = createOrder({ - senderAddress: randomAddress(), - }); - const expectedError = new ExchangeRevertErrors.ExchangeInvalidContextError( - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidSender, - exchange.getOrderHash(order), - takerAddress, - ); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order with a taker amount that results in a maker asset rounding error", async () => { - const order = createOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: ONE_ETHER, - }); - const takerAssetFillAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const expectedError = new LibMathRevertErrors.RoundingError( - takerAssetFillAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order with a taker amount that results in a maker fee rounding error", async () => { - const order = createOrder({ - makerAssetAmount: ONE_ETHER.times(2), - takerAssetAmount: ONE_ETHER, - makerFee: new BigNumber(100), - }); - const takerAssetFillAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const expectedError = new LibMathRevertErrors.RoundingError( - takerAssetFillAmount, - order.takerAssetAmount, - order.makerFee, - ); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order with a taker amount that results in a taker fee rounding error", async () => { - const order = createOrder({ - makerAssetAmount: ONE_ETHER.times(2), - takerAssetAmount: ONE_ETHER, - takerFee: new BigNumber(100), - }); - const takerAssetFillAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const expectedError = new LibMathRevertErrors.RoundingError( - takerAssetFillAmount, - order.takerAssetAmount, - order.takerFee, - ); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order that results in a `makerAssetFilledAmount` overflow.", async () => { - // All values need to be large to ensure we don't trigger a Rounding. - const order = createOrder({ - makerAssetAmount: MAX_UINT256_ROOT.times(2), - takerAssetAmount: MAX_UINT256_ROOT, - }); - const takerAssetFillAmount = MAX_UINT256_ROOT; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - takerAssetFillAmount, - order.makerAssetAmount, - ); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order that results in a `makerFeePaid` overflow.", async () => { - // All values need to be large to ensure we don't trigger a Rounding. - const order = createOrder({ - makerAssetAmount: MAX_UINT256_ROOT, - takerAssetAmount: MAX_UINT256_ROOT, - makerFee: MAX_UINT256_ROOT.times(11), - }); - const takerAssetFillAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10); - const makerAssetFilledAmount = LibReferenceFunctions.getPartialAmountFloor( - takerAssetFillAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - makerAssetFilledAmount, - order.makerFee, - ); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order that results in a `takerFeePaid` overflow.", async () => { - // All values need to be large to ensure we don't trigger a Rounding. - const order = createOrder({ - makerAssetAmount: MAX_UINT256_ROOT, - takerAssetAmount: MAX_UINT256_ROOT, - takerFee: MAX_UINT256_ROOT.times(11), - }); - const takerAssetFillAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - takerAssetFillAmount, - order.takerFee, - ); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError); - }); - - it("can't fill an order with a bad signature", async () => { - const order = createOrder(); - const signature = createBadSignature(); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - exchange.getOrderHash(order), - order.makerAddress, - signature, - ); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount, signature)).to.revertWith( - expectedError, - ); - }); - - it("can't complementary fill an order with a bad signature that is always checked", async () => { - const order = createOrder(); - const takerAssetFillAmounts = splitAmount(order.takerAssetAmount); - const goodSignature = createGoodSignature(SignatureType.Wallet); - const badSignature = createBadSignature(SignatureType.Wallet); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - exchange.getOrderHash(order), - order.makerAddress, - badSignature, - ); - await exchange.fillOrderAsync(order, takerAssetFillAmounts[0], goodSignature); - return expect(exchange.fillOrderAsync(order, takerAssetFillAmounts[1], badSignature)).to.revertWith( - expectedError, - ); - }); - - const TRANSFER_ERROR = 'TRANSFER_FAILED'; - - it("can't fill an order with a maker asset that fails to transfer", async () => { - const order = createOrder({ - makerAssetData: createBadAssetData(), - }); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR); - }); - - it("can't fill an order with a taker asset that fails to transfer", async () => { - const order = createOrder({ - takerAssetData: createBadAssetData(), - }); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR); - }); - - it("can't fill an order with a maker fee asset that fails to transfer", async () => { - const order = createOrder({ - makerFeeAssetData: createBadAssetData(), - }); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR); - }); - - it("can't fill an order with a taker fee asset that fails to transfer", async () => { - const order = createOrder({ - takerFeeAssetData: createBadAssetData(), - }); - return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR); - }); - }); - - describe('permitted fills', () => { - it('should allow takerAssetFillAmount to be zero', async () => { - const order = createOrder(); - return fillOrderAndAssertResultsAsync(order, constants.ZERO_AMOUNT); - }); - - it('can fill an order if taker is `takerAddress`', async () => { - const order = createOrder({ - takerAddress, - }); - return fillOrderAndAssertResultsAsync(order, order.takerAssetAmount); - }); - - it('can fill an order if sender is `senderAddress`', async () => { - const order = createOrder({ - senderAddress: takerAddress, - }); - return fillOrderAndAssertResultsAsync(order, order.takerAssetAmount); - }); - - it('cannot fill an order with a bad signature that has already been partially filled', async () => { - const order = createOrder(); - const takerAssetFillAmounts = splitAmount(order.takerAssetAmount); - const goodSignature = createGoodSignature(SignatureType.EthSign); - const badSignature = createBadSignature(SignatureType.EthSign); - await fillOrderAndAssertResultsAsync(order, takerAssetFillAmounts[0], goodSignature); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - exchange.getOrderHash(order), - order.makerAddress, - badSignature, - ); - return expect(fillOrderAndAssertResultsAsync(order, takerAssetFillAmounts[1], badSignature)).to.revertWith( - expectedError, - ); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/exchange/test/lib_exchange_rich_error_decoder.ts b/contracts/exchange/test/lib_exchange_rich_error_decoder.ts deleted file mode 100644 index 51eda2344b..0000000000 --- a/contracts/exchange/test/lib_exchange_rich_error_decoder.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { blockchainTests, constants, expect, OrderStatus, orderUtils, randomAddress } from '@0x/contracts-test-utils'; -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { BigNumber, ExchangeRevertErrors, hexUtils, RevertError } from '@0x/utils'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { TestLibExchangeRichErrorDecoderContract } from './wrappers'; - -blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults }) => { - const ASSET_PROXY_ID_LENGTH = 4; - const SIGNATURE_LENGTH = 66; - const ASSET_DATA_LENGTH = 36; - const ERROR_DATA_LENGTH = 100; - const { WORD_LENGTH } = constants; - let decoder: TestLibExchangeRichErrorDecoderContract; - - before(async () => { - decoder = await TestLibExchangeRichErrorDecoderContract.deployFrom0xArtifactAsync( - artifacts.TestLibExchangeRichErrorDecoder, - provider, - txDefaults, - {}, - ); - }); - - function createDecodeTest(revertType: new (...args: any[]) => RevertError, parameters: any[]): void { - const revert = new revertType(...parameters); - const encoded = revert.encode(); - // Exploit the fact that `RevertError` types have the same names as their - // Solidity counterparts. - const endpointName = `decode${revert.name}`; - const callAsync = (_encoded: string) => { - const wrapperFunctions = (decoder as any)[endpointName](_encoded); - return wrapperFunctions.callAsync.bind(wrapperFunctions).call((decoder as any)[endpointName]); - }; - describe(`${endpointName}()`, async () => { - it('decodes encoded parameters', async () => { - let results = await callAsync(encoded); - if (!_.isArray(results)) { - results = [results]; - } - return expect(results).to.deep.equal(parameters); - }); - it('reverts if selector does not match', async () => { - // Replace the selector with null bytes. - const NULL_SELECTOR = '00000000'; - const withBadSelector = `0x${NULL_SELECTOR}${encoded.substr(10)}`; - return expect(callAsync(withBadSelector)).to.revertWith('BAD_SELECTOR'); - }); - }); - } - - (() => { - const errorCode = ExchangeRevertErrors.SignatureErrorCode.Illegal; - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - const signer = randomAddress(); - const validator = randomAddress(); - const data = hexUtils.random(ERROR_DATA_LENGTH); - const signature = hexUtils.random(SIGNATURE_LENGTH); - const errorData = hexUtils.random(ERROR_DATA_LENGTH); - createDecodeTest(ExchangeRevertErrors.SignatureError, [errorCode, orderHash, signer, signature]); - createDecodeTest(ExchangeRevertErrors.SignatureValidatorNotApprovedError, [signer, validator]); - createDecodeTest(ExchangeRevertErrors.EIP1271SignatureError, [validator, data, signature, errorData]); - createDecodeTest(ExchangeRevertErrors.SignatureWalletError, [orderHash, signer, signature, errorData]); - })(); - - (() => { - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - const orderStatus = OrderStatus.FullyFilled; - createDecodeTest(ExchangeRevertErrors.OrderStatusError, [orderHash, orderStatus]); - })(); - - (() => { - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - const address = randomAddress(); - createDecodeTest(ExchangeRevertErrors.ExchangeInvalidContextError, [ - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker, - orderHash, - address, - ]); - createDecodeTest(ExchangeRevertErrors.ExchangeInvalidContextError, [ - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidTaker, - orderHash, - address, - ]); - createDecodeTest(ExchangeRevertErrors.ExchangeInvalidContextError, [ - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidSender, - orderHash, - address, - ]); - })(); - - (() => { - const errorCode = ExchangeRevertErrors.FillErrorCode.TakerOverpay; - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - createDecodeTest(ExchangeRevertErrors.FillError, [errorCode, orderHash]); - })(); - - (() => { - const maker = randomAddress(); - const sender = randomAddress(); - const currentEpoch = generatePseudoRandomSalt(); - createDecodeTest(ExchangeRevertErrors.OrderEpochError, [maker, sender, currentEpoch]); - })(); - - (() => { - const assetProxyAddress = randomAddress(); - createDecodeTest(ExchangeRevertErrors.AssetProxyExistsError, [ - hexUtils.random(ASSET_PROXY_ID_LENGTH), - assetProxyAddress, - ]); - })(); - - (() => { - const errorCode = ExchangeRevertErrors.AssetProxyDispatchErrorCode.UnknownAssetProxy; - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - const assetData = hexUtils.random(ASSET_DATA_LENGTH); - createDecodeTest(ExchangeRevertErrors.AssetProxyDispatchError, [errorCode, orderHash, assetData]); - })(); - - (() => { - const orderHash = orderUtils.generatePseudoRandomOrderHash(); - const assetData = hexUtils.random(ASSET_DATA_LENGTH); - const errorData = hexUtils.random(ERROR_DATA_LENGTH); - createDecodeTest(ExchangeRevertErrors.AssetProxyTransferError, [orderHash, assetData, errorData]); - })(); - - (() => { - const leftOrderHash = orderUtils.generatePseudoRandomOrderHash(); - const rightOrderHash = orderUtils.generatePseudoRandomOrderHash(); - createDecodeTest(ExchangeRevertErrors.NegativeSpreadError, [leftOrderHash, rightOrderHash]); - })(); - - (() => { - const errorCode = ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted; - const transactionHash = orderUtils.generatePseudoRandomOrderHash(); - createDecodeTest(ExchangeRevertErrors.TransactionError, [errorCode, transactionHash]); - })(); - - (() => { - const transactionHash = orderUtils.generatePseudoRandomOrderHash(); - const errorData = hexUtils.random(ERROR_DATA_LENGTH); - createDecodeTest(ExchangeRevertErrors.TransactionExecutionError, [transactionHash, errorData]); - })(); - - (() => { - const errorCode = ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteMarketSellOrders; - const expectedAmount = new BigNumber(hexUtils.random(WORD_LENGTH)); - const actualAmount = new BigNumber(hexUtils.random(WORD_LENGTH)); - createDecodeTest(ExchangeRevertErrors.IncompleteFillError, [errorCode, expectedAmount, actualAmount]); - })(); -}); diff --git a/contracts/exchange/test/protocol_fees.ts b/contracts/exchange/test/protocol_fees.ts deleted file mode 100644 index a3a18f366e..0000000000 --- a/contracts/exchange/test/protocol_fees.ts +++ /dev/null @@ -1,254 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { artifacts } from './artifacts'; -import { TestProtocolFeesContract, TestProtocolFeesReceiverContract } from './wrappers'; - -// The contents of this test suite does not inform the reader about the assertions made in these -// tests. For more information and a more accurate view of the tests, check out -// "contracts/test/TestProtocolFeesReceiver.sol". -blockchainTests('Protocol Fee Payments', env => { - let testProtocolFees: TestProtocolFeesContract; - let testProtocolFeesReceiver: TestProtocolFeesReceiverContract; - - const DEFAULT_GAS_PRICE = new BigNumber(20000); - const DEFAULT_PROTOCOL_FEE_MULTIPLIER = new BigNumber(150); - const DEFAULT_PROTOCOL_FEE = DEFAULT_GAS_PRICE.times(DEFAULT_PROTOCOL_FEE_MULTIPLIER); - - before(async () => { - testProtocolFees = await TestProtocolFeesContract.deployFrom0xArtifactAsync( - artifacts.TestProtocolFees, - env.provider, - env.txDefaults, - {}, - ); - testProtocolFeesReceiver = await TestProtocolFeesReceiverContract.deployFrom0xArtifactAsync( - artifacts.TestProtocolFeesReceiver, - env.provider, - env.txDefaults, - {}, - ); - }); - - blockchainTests.resets('fillOrder Protocol Fees', () => { - it('should not pay protocol fee when there is no registered protocol fee collector', async () => { - await testProtocolFeesReceiver - .testFillOrderProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, false) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should not forward ETH when too little value is sent', async () => { - await testProtocolFeesReceiver - .testFillOrderProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.minus(10), - }); - }); - - it('should pay protocol fee in ETH when the correct value is sent', async () => { - await testProtocolFeesReceiver - .testFillOrderProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should pay protocol fee in ETH when extra value is sent', async () => { - await testProtocolFeesReceiver - .testFillOrderProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.plus(10), - }); - }); - }); - - blockchainTests.resets('matchOrders Protocol Fees', () => { - it('should not pay protocol fee when there is no registered protocol fee collector', async () => { - await testProtocolFeesReceiver - .testMatchOrdersProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, false) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should not forward ETH twice when too little value is sent', async () => { - await testProtocolFeesReceiver - .testMatchOrdersProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.minus(10), - }); - }); - - it('should pay protocol fee in ETH and then not forward ETH when exactly one protocol fee is sent', async () => { - await testProtocolFeesReceiver - .testMatchOrdersProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should pay protocol fee in ETH and then not forward ETH when a bit more than one protocol fee is sent', async () => { - await testProtocolFeesReceiver - .testMatchOrdersProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.plus(10), - }); - }); - - it('should pay protocol fee in ETH when exactly double the protocol fee is sent', async () => { - await testProtocolFeesReceiver - .testMatchOrdersProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.times(2), - }); - }); - - it('should pay protocol fee in ETH when more than double the protocol fee is sent', async () => { - await testProtocolFeesReceiver - .testMatchOrdersProtocolFees(testProtocolFees.address, DEFAULT_PROTOCOL_FEE_MULTIPLIER, true) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.times(2).plus(10), - }); - }); - }); - - blockchainTests.resets('batchFillOrder ProtocolFees', () => { - it('should not pay protocol fees when there is not a protocolFeeCollector registered', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(2), // If successful, create a `batchFillOrders` with 2 orders. - false, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should not forward ETH when less than one protocol fee is sent and only one order is in the batch', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(1), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.minus(10), - }); - }); - - it('should pay one protocol fee in ETH when the exact protocol fee is sent and only one order is in the batch', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(1), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should pay one protocol fee in ETH when more than the exact protocol fee is sent and only one order is in the batch', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(1), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.plus(10), - }); - }); - - it('should not forward ETH twice when an insuffiecent amount of ETH for one protocol fee is sent', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(2), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.minus(10), - }); - }); - - it('should pay a protocol in ETH and not forward ETH for the second when exactly one protocol fee in ETH is sent', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(2), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE, - }); - }); - - it('should pay both protocol fees in ETH when exactly two protocol fees in ETH is sent', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(2), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.times(2), - }); - }); - - it('should pay two protocol fees in ETH and then not forward ETH for a third when exactly two protocol fees in ETH is sent', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(3), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.times(2), - }); - }); - - it('should pay three protocol fees in ETH when more than three protocol fees in ETH is sent', async () => { - await testProtocolFeesReceiver - .testBatchFillOrdersProtocolFees( - testProtocolFees.address, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - new BigNumber(3), - true, - ) - .awaitTransactionSuccessAsync({ - gasPrice: DEFAULT_GAS_PRICE, - value: DEFAULT_PROTOCOL_FEE.times(3).plus(10), - }); - }); - }); -}); diff --git a/contracts/exchange/test/protocol_fees_manager.ts b/contracts/exchange/test/protocol_fees_manager.ts deleted file mode 100644 index b0ba3ac508..0000000000 --- a/contracts/exchange/test/protocol_fees_manager.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { OwnableRevertErrors } from '@0x/contracts-utils'; -import { BigNumber } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; - -import { artifacts } from './artifacts'; -import { - ExchangeContract, - ExchangeProtocolFeeCollectorAddressEventArgs, - ExchangeProtocolFeeMultiplierEventArgs, -} from './wrappers'; - -blockchainTests.resets('MixinProtocolFees', env => { - let accounts: string[]; - let exchange: ExchangeContract; - let nonOwner: string; - let owner: string; - let protocolFeeCollector: string; - - // The protocolFeeMultiplier that will be used to test the update functions. - const protocolFeeMultiplier = new BigNumber(15000); - - before(async () => { - accounts = await env.web3Wrapper.getAvailableAddressesAsync(); - owner = accounts[0]; - nonOwner = accounts[1]; - protocolFeeCollector = accounts[2]; - - // Update the from address of the txDefaults. This is the address that will become the owner. - env.txDefaults.from = owner; - - // Deploy the exchange contract. - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - artifacts.Exchange, - env.provider, - env.txDefaults, - {}, - new BigNumber(1337), - ); - }); - - blockchainTests.resets('setProtocolFeeMultiplier', () => { - it('should revert if msg.sender != owner', async () => { - const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner); - - // Ensure that the transaction reverts with the expected rich error. - const tx = exchange.setProtocolFeeCollectorAddress(protocolFeeCollector).sendTransactionAsync({ - from: nonOwner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should succeed and emit an ProtocolFeeMultiplier event if msg.sender == owner', async () => { - // Call the `setProtocolFeeMultiplier()` function and get the receipt. - const receipt = await exchange - .setProtocolFeeMultiplier(protocolFeeMultiplier) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // Verify that the protocolFeeCollector address was actually updated to the correct address. - const updated = await exchange.protocolFeeMultiplier().callAsync(); - expect(updated).bignumber.to.be.eq(protocolFeeMultiplier); - - // Ensure that the correct `ProtocolFeeCollectorAddress` event was logged. - // tslint:disable:no-unnecessary-type-assertion - const updatedEvent = receipt.logs[0] as LogWithDecodedArgs; - expect(updatedEvent.event).to.be.eq('ProtocolFeeMultiplier'); - expect(updatedEvent.args.oldProtocolFeeMultiplier).bignumber.to.be.eq(constants.ZERO_AMOUNT); - expect(updatedEvent.args.updatedProtocolFeeMultiplier).bignumber.to.be.eq(protocolFeeMultiplier); - }); - }); - - blockchainTests.resets('setProtocolFeeCollectorAddress', () => { - it('should revert if msg.sender != owner', async () => { - const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner); - - // Ensure that the transaction reverts with the expected rich error. - const tx = exchange.setProtocolFeeCollectorAddress(protocolFeeCollector).sendTransactionAsync({ - from: nonOwner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should succeed and emit an ProtocolFeeCollectorAddress event if msg.sender == owner', async () => { - // Call the `setProtocolFeeCollectorAddress()` function and get the receipt. - const receipt = await exchange - .setProtocolFeeCollectorAddress(protocolFeeCollector) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // Verify that the protocolFeeCollector address was actually updated to the correct address. - const updated = await exchange.protocolFeeCollector().callAsync(); - expect(updated).to.be.eq(protocolFeeCollector); - - // Ensure that the correct `UpdatedProtocolFeeCollectorAddress` event was logged. - // tslint:disable:no-unnecessary-type-assertion - const updatedEvent = receipt.logs[0] as LogWithDecodedArgs; - expect(updatedEvent.event).to.be.eq('ProtocolFeeCollectorAddress'); - expect(updatedEvent.args.oldProtocolFeeCollector).to.be.eq(constants.NULL_ADDRESS); - expect(updatedEvent.args.updatedProtocolFeeCollector).to.be.eq(protocolFeeCollector); - }); - }); - - blockchainTests.resets('detachProtocolFeeCollector', () => { - it('should revert if msg.sender != owner', async () => { - const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner); - - // Ensure that the transaction reverts with the expected rich error. - const tx = exchange.detachProtocolFeeCollector().sendTransactionAsync({ - from: nonOwner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should succeed and emit an ProtocolFeeCollectorAddress event if msg.sender == owner', async () => { - await exchange.setProtocolFeeCollectorAddress(protocolFeeCollector).awaitTransactionSuccessAsync({ - from: owner, - }); - - const receipt = await exchange.detachProtocolFeeCollector().awaitTransactionSuccessAsync({ - from: owner, - }); - - // Verify that the protocolFeeCollector address was actually updated to the correct address. - const updated = await exchange.protocolFeeCollector().callAsync(); - expect(updated).to.be.eq(constants.NULL_ADDRESS); - - // Ensure that the correct `UpdatedProtocolFeeCollectorAddress` event was logged. - // tslint:disable:no-unnecessary-type-assertion - const updatedEvent = receipt.logs[0] as LogWithDecodedArgs; - expect(updatedEvent.event).to.be.eq('ProtocolFeeCollectorAddress'); - expect(updatedEvent.args.oldProtocolFeeCollector).to.be.eq(protocolFeeCollector); - expect(updatedEvent.args.updatedProtocolFeeCollector).to.be.eq(constants.NULL_ADDRESS); - }); - }); -}); diff --git a/contracts/exchange/test/reentrancy_tests.ts b/contracts/exchange/test/reentrancy_tests.ts deleted file mode 100644 index 0286b42565..0000000000 --- a/contracts/exchange/test/reentrancy_tests.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { blockchainTests, constants, describe, expect } from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { DataItem, MethodAbi, TupleDataItem } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { ReentrancyTesterContract } from './wrappers'; - -import { constants as TestConstants } from './utils/constants'; - -blockchainTests.resets('Reentrancy Tests', env => { - const { ONE_ETHER } = constants; - // Extract all mutator public functions from the Exchange contract. - const [NON_REENTRANT_FUNCTIONS, REENTRANT_FUNCTIONS] = (() => { - const reentrantFunctions = [] as MethodAbi[]; - const nonReentrantFunctions = [] as MethodAbi[]; - for (const method of artifacts.Exchange.compilerOutput.abi as MethodAbi[]) { - if ( - method.type === 'function' && - !method.constant && - !_.includes(['view', 'pure'], method.stateMutability) - ) { - if (_.includes(TestConstants.REENTRANT_FUNCTIONS as string[], method.name)) { - reentrantFunctions.push(method); - } else { - nonReentrantFunctions.push(method); - } - } - } - return [_.sortBy(nonReentrantFunctions, m => m.name), _.sortBy(reentrantFunctions, m => m.name)]; - })(); - let testerContract: ReentrancyTesterContract; - - // Generates well-constructed input data for an exchange function. - function createFunctionInputs(item: DataItem[] | DataItem): any { - if (item instanceof Array) { - return item.map(createFunctionInputs); - } - // Handle tuples. - if (item.type === 'tuple') { - const tuple = item as TupleDataItem; - return _.zipObject( - tuple.components.map(c => c.name), - tuple.components.map(createFunctionInputs), - ); - } - // Handle strings. - if (item.type === 'string') { - return _.sampleSize('abcdefghijklmnopqrstuvwxyz'.split(''), 8).join(''); - } - // Handle bytes. - if (item.type === 'bytes') { - return hexUtils.random(36); - } - // Handle addresses. - if (item.type === 'address') { - return hexUtils.random(constants.ADDRESS_LENGTH); - } - // Handle bools. - if (item.type === 'bool') { - return _.sample([true, false]); - } - // Handle arrays. - let m = /^(.+)(\[(\d*)\])$/.exec(item.type); - if (m) { - const length = parseInt(m[3], 10) || 1; - const subType = item.type.substr(0, item.type.length - m[2].length); - return _.times(length, () => - createFunctionInputs({ - ...item, - type: subType, - }), - ); - } - // Handle integers. - m = /^u?int(\d+)?$/.exec(item.type); - if (m) { - const size = parseInt(m[1], 10) || 256; - const isSigned = item.type[0] === 'i'; - let n = ONE_ETHER.mod(new BigNumber(2).pow(size)); - if (isSigned) { - n = n.dividedToIntegerBy(2).times(_.sample([-1, 1]) as number); - } - return n; - } - // Handle fixed size bytes. - m = /^bytes(\d+)$/.exec(item.type); - if (m) { - const size = parseInt(m[1], 10) || 32; - return hexUtils.random(size); - } - throw new Error(`Unhandled input type: ${item.type}`); - } - - before(async () => { - testerContract = await ReentrancyTesterContract.deployFrom0xArtifactAsync( - artifacts.ReentrancyTester, - env.provider, - env.txDefaults, - {}, - ); - }); - - describe('non-reentrant functions', () => { - for (const fn of NON_REENTRANT_FUNCTIONS) { - it(`${fn.name}()`, async () => { - const inputs = createFunctionInputs(fn.inputs); - const callData = (testerContract as any)[fn.name](...inputs).getABIEncodedTransactionData(); - const isReentrant = await testerContract.isReentrant(callData).callAsync(); - expect(isReentrant).to.be.false(); - }); - } - }); - - describe('reentrant functions', () => { - for (const fn of REENTRANT_FUNCTIONS) { - it(`${fn.name}()`, async () => { - const inputs = createFunctionInputs(fn.inputs); - const callData = (testerContract as any)[fn.name](...inputs).getABIEncodedTransactionData(); - const isReentrant = await testerContract.isReentrant(callData).callAsync(); - expect(isReentrant).to.be.true(); - }); - } - }); -}); diff --git a/contracts/exchange/test/reference_functions.ts b/contracts/exchange/test/reference_functions.ts deleted file mode 100644 index 0512dc3fd4..0000000000 --- a/contracts/exchange/test/reference_functions.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { LibMathRevertErrors, ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { constants, describe, expect } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -describe('Reference functions', () => { - const ONE_ETHER = constants.ONE_ETHER; - const DEFAULT_GAS_PRICE = new BigNumber(2); - const DEFAULT_PROTOCOL_FEE_MULTIPLIER = new BigNumber(150); - const EMPTY_ORDER: Order = { - senderAddress: constants.NULL_ADDRESS, - makerAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerAssetAmount: constants.ZERO_AMOUNT, - takerAssetAmount: constants.ZERO_AMOUNT, - makerAssetData: constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - salt: constants.ZERO_AMOUNT, - feeRecipientAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: constants.ZERO_AMOUNT, - chainId: 1, - exchangeAddress: constants.NULL_ADDRESS, - }; - - describe('calculateFillResults', () => { - const MAX_UINT256_ROOT = constants.MAX_UINT256_ROOT; - function makeOrder(details?: Partial): Order { - return _.assign({}, EMPTY_ORDER, details); - } - - it('reverts if computing `fillResults.makerAssetFilledAmount` overflows', () => { - // All values need to be large to ensure we don't trigger a RoundingError. - const order = makeOrder({ - makerAssetAmount: MAX_UINT256_ROOT.times(2), - takerAssetAmount: MAX_UINT256_ROOT, - }); - const takerAssetFilledAmount = MAX_UINT256_ROOT; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - takerAssetFilledAmount, - order.makerAssetAmount, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if computing `fillResults.makerFeePaid` overflows', () => { - // All values need to be large to ensure we don't trigger a RoundingError. - const order = makeOrder({ - makerAssetAmount: MAX_UINT256_ROOT, - takerAssetAmount: MAX_UINT256_ROOT, - makerFee: MAX_UINT256_ROOT.times(11), - }); - const takerAssetFilledAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10); - const makerAssetFilledAmount = LibReferenceFunctions.getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - makerAssetFilledAmount, - order.makerFee, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if computing `fillResults.takerFeePaid` overflows', () => { - // All values need to be large to ensure we don't trigger a RoundingError. - const order = makeOrder({ - makerAssetAmount: MAX_UINT256_ROOT, - takerAssetAmount: MAX_UINT256_ROOT, - takerFee: MAX_UINT256_ROOT.times(11), - }); - const takerAssetFilledAmount = MAX_UINT256_ROOT.dividedToIntegerBy(10); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - takerAssetFilledAmount, - order.takerFee, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if `order.takerAssetAmount` is 0', () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: constants.ZERO_AMOUNT, - }); - const takerAssetFilledAmount = ONE_ETHER; - const expectedError = new LibMathRevertErrors.DivisionByZeroError(); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', () => { - const order = makeOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: ONE_ETHER, - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const expectedError = new LibMathRevertErrors.RoundingError( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if there is a rounding error computing `makerFeePaid`', () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER, - makerFee: new BigNumber(100), - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const makerAssetFilledAmount = LibReferenceFunctions.getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new LibMathRevertErrors.RoundingError( - makerAssetFilledAmount, - order.makerAssetAmount, - order.makerFee, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if there is a rounding error computing `takerFeePaid`', () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER, - takerFee: new BigNumber(100), - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const makerAssetFilledAmount = LibReferenceFunctions.getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const expectedError = new LibMathRevertErrors.RoundingError( - makerAssetFilledAmount, - order.makerAssetAmount, - order.takerFee, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - DEFAULT_PROTOCOL_FEE_MULTIPLIER, - DEFAULT_GAS_PRICE, - ), - ).to.throw(expectedError.message); - }); - - it('reverts if there is an overflow computing `protocolFeePaid`', () => { - const order = makeOrder({ - makerAssetAmount: ONE_ETHER, - takerAssetAmount: ONE_ETHER, - takerFee: constants.ZERO_AMOUNT, - }); - const takerAssetFilledAmount = order.takerAssetAmount.dividedToIntegerBy(3); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - MAX_UINT256_ROOT, - MAX_UINT256_ROOT, - ); - return expect(() => - LibReferenceFunctions.calculateFillResults( - order, - takerAssetFilledAmount, - MAX_UINT256_ROOT, - MAX_UINT256_ROOT, - ), - ).to.throw(expectedError.message); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/exchange/test/signature_validator.ts b/contracts/exchange/test/signature_validator.ts deleted file mode 100644 index f610cf63a2..0000000000 --- a/contracts/exchange/test/signature_validator.ts +++ /dev/null @@ -1,1292 +0,0 @@ -import { encodeERC20AssetData, ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { - blockchainTests, - constants, - expect, - LogDecoder, - OrderFactory, - orderHashUtils, - orderUtils, - randomAddress, - TransactionFactory, - transactionHashUtils, -} from '@0x/contracts-test-utils'; -import { SignatureType, SignedOrder, SignedZeroExTransaction } from '@0x/types'; -import { BigNumber, ExchangeRevertErrors, hexUtils, StringRevertError } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import ethUtil = require('ethereumjs-util'); - -import { artifacts } from './artifacts'; -import { - ExchangeContract, - ExchangeSignatureValidatorApprovalEventArgs, - IEIP1271DataContract, - TestValidatorWalletContract, -} from './wrappers'; - -enum ValidatorWalletAction { - Reject = 0, - Accept = 1, - Revert = 2, - UpdateState = 3, - MatchSignatureHash = 4, - ReturnTrue = 5, - ReturnNothing = 6, - NTypes = 7, -} - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('MixinSignatureValidator', env => { - let chainId: number; - let exchange: ExchangeContract; - let validatorWallet: TestValidatorWalletContract; - let validatorWalletRevertReason: string; - let signerAddress: string; - let signerPrivateKey: Buffer; - let notSignerAddress: string; - let accounts: string[]; - let owner: string; - let makerAddress: string; - let takerAddress: string; - let feeRecipientAddress: string; - - const eip1271Data = new IEIP1271DataContract(constants.NULL_ADDRESS, env.provider, env.txDefaults); - before(async () => { - chainId = await env.getChainIdAsync(); - accounts = await env.getAccountAddressesAsync(); - [owner, signerAddress, notSignerAddress, makerAddress, takerAddress, feeRecipientAddress] = accounts; - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - artifacts.Exchange, - env.provider, - env.txDefaults, - {}, - new BigNumber(chainId), - ); - validatorWallet = await TestValidatorWalletContract.deployFrom0xArtifactAsync( - artifacts.TestValidatorWallet, - env.provider, - env.txDefaults, - {}, - exchange.address, - ); - validatorWalletRevertReason = await validatorWallet.REVERT_REASON().callAsync(); - - // Approve the validator for both signers. - await Promise.all( - [signerAddress, notSignerAddress].map(async (addr: string) => { - return exchange - .setSignatureValidatorApproval(validatorWallet.address, true) - .awaitTransactionSuccessAsync({ from: addr }); - }), - ); - - signerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(signerAddress)]; - }); - - const SIGNATURE_LENGTH = 65; - const generateRandomSignature = (): string => hexUtils.random(SIGNATURE_LENGTH); - const hashBytes = (bytesHex: string): string => hexUtils.hash(bytesHex); - const signDataHex = (dataHex: string, privateKey: Buffer): string => { - const ecSignature = ethUtil.ecsign(ethUtil.toBuffer(dataHex), privateKey); - return hexUtils.concat(ecSignature.v, ecSignature.r, ecSignature.s); - }; - - type ValidateHashSignatureAsync = ( - hashHex: string, - signerAddress: string, - signatureHex: string, - validatorAction?: ValidatorWalletAction, - validatorExpectedSignatureHex?: string, - ) => Promise; - - const createHashSignatureTests = ( - getCurrentHashHex: (signerAddress?: string) => string, - validateAsync: ValidateHashSignatureAsync, - ) => { - it('should revert when signature is empty', async () => { - const hashHex = getCurrentHashHex(); - const emptySignature = constants.NULL_BYTES; - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidLength, - hashHex, - signerAddress, - emptySignature, - ); - const tx = validateAsync(hashHex, signerAddress, emptySignature); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when signature type is unsupported', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(SignatureType.NSignatureTypes); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.Unsupported, - hashHex, - signerAddress, - signatureHex, - ); - const tx = validateAsync(hashHex, signerAddress, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when SignatureType=Illegal', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(SignatureType.Illegal); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.Illegal, - hashHex, - signerAddress, - signatureHex, - ); - const tx = validateAsync(hashHex, signerAddress, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return false when SignatureType=Invalid and signature has a length of zero', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(SignatureType.Invalid); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when SignatureType=Invalid and signature length is non-zero', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat('0xdeadbeef', SignatureType.Invalid); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidLength, - hashHex, - signerAddress, - signatureHex, - ); - const tx = validateAsync(hashHex, signerAddress, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return true when SignatureType=EIP712 and signature is valid', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(signDataHex(hashHex, signerPrivateKey), SignatureType.EIP712); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=EIP712 and signature is invalid', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP712); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.false(); - }); - - it('should return true when SignatureType=EthSign and signature is valid', async () => { - // Create EthSign signature - const hashHex = getCurrentHashHex(); - const orderHashWithEthSignPrefixHex = ethUtil.bufferToHex( - ethUtil.hashPersonalMessage(ethUtil.toBuffer(hashHex)), - ); - const signatureHex = hexUtils.concat( - signDataHex(orderHashWithEthSignPrefixHex, signerPrivateKey), - SignatureType.EthSign, - ); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=EthSign and signature is invalid', async () => { - const hashHex = getCurrentHashHex(); - // Create EthSign signature - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EthSign); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.false(); - }); - - it('should return true when SignatureType=Wallet and signature is valid', async () => { - const hashHex = getCurrentHashHex(validatorWallet.address); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.Wallet); - const isValidSignature = await validateAsync( - hashHex, - validatorWallet.address, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=Wallet and signature is invalid', async () => { - const hashHex = getCurrentHashHex(validatorWallet.address); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const notSignatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(notSignatureDataHex, SignatureType.Wallet); - // Validate signature - const isValidSignature = await validateAsync( - hashHex, - validatorWallet.address, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when validator attempts to update state and SignatureType=Wallet', async () => { - const hashHex = getCurrentHashHex(validatorWallet.address); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.Wallet); - const expectedError = new ExchangeRevertErrors.SignatureWalletError( - hashHex, - validatorWallet.address, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(hashHex, validatorWallet.address, signatureHex, ValidatorWalletAction.UpdateState); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when signer is an EOA and SignatureType=Wallet', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(SignatureType.Wallet); - const expectedError = new ExchangeRevertErrors.SignatureWalletError( - hashHex, - signerAddress, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(hashHex, signerAddress, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return false when validator returns `true` and SignatureType=Wallet', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(SignatureType.Wallet); - const isValidSignature = await validateAsync( - hashHex, - validatorWallet.address, - signatureHex, - ValidatorWalletAction.ReturnTrue, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when validator returns nothing and SignatureType=Wallet', async () => { - const hashHex = getCurrentHashHex(validatorWallet.address); - const signatureHex = hexUtils.concat(SignatureType.Wallet); - const expectedError = new ExchangeRevertErrors.SignatureWalletError( - hashHex, - validatorWallet.address, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync( - hashHex, - validatorWallet.address, - signatureHex, - ValidatorWalletAction.ReturnNothing, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator reverts and SignatureType=Wallet', async () => { - const hashHex = getCurrentHashHex(validatorWallet.address); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.Wallet); - const expectedError = new ExchangeRevertErrors.SignatureWalletError( - hashHex, - validatorWallet.address, - signatureHex, - new StringRevertError(validatorWalletRevertReason).encode(), - ); - const tx = validateAsync(hashHex, validatorWallet.address, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return true when SignatureType=Presigned and signer has presigned hash', async () => { - const hashHex = getCurrentHashHex(); - // Presign the hash - await exchange.preSign(hashHex).awaitTransactionSuccessAsync({ from: signerAddress }); - // Validate presigned signature - const signatureHex = hexUtils.concat(SignatureType.PreSigned); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=Presigned and signer has not presigned hash', async () => { - const hashHex = getCurrentHashHex(); - const signatureHex = hexUtils.concat(SignatureType.PreSigned); - const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex); - expect(isValidSignature).to.be.false(); - }); - }; - - describe('isValidHashSignature', () => { - let hashHex: string; - - beforeEach(async () => { - hashHex = orderUtils.generatePseudoRandomOrderHash(); - }); - - const validateAsync = async ( - _hashHex: string, - _signerAddress: string, - signatureHex: string, - validatorAction?: ValidatorWalletAction, - validatorExpectedSignatureHex?: string, - ) => { - const expectedSignatureHashHex = - validatorExpectedSignatureHex === undefined - ? constants.NULL_BYTES - : hashBytes(validatorExpectedSignatureHex); - if (validatorAction !== undefined) { - await validatorWallet - .prepare(_hashHex, validatorAction, expectedSignatureHashHex) - .awaitTransactionSuccessAsync(); - } - return exchange.isValidHashSignature(_hashHex, _signerAddress, signatureHex).callAsync(); - }; - - it('should revert when signerAddress == 0', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP712); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidSigner, - hashHex, - constants.NULL_ADDRESS, - signatureHex, - ); - const tx = validateAsync(hashHex, constants.NULL_ADDRESS, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when SignatureType=Validator', async () => { - const signatureHex = hexUtils.concat(SignatureType.Validator); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InappropriateSignatureType, - hashHex, - signerAddress, - signatureHex, - ); - const tx = validateAsync(hashHex, signerAddress, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when SignatureType=EIP1271Wallet', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InappropriateSignatureType, - hashHex, - signerAddress, - signatureHex, - ); - const tx = validateAsync(hashHex, signerAddress, signatureHex); - return expect(tx).to.revertWith(expectedError); - }); - - 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 exchange.isValidHashSignature(messageHash, signer, signatureHex).callAsync(); - 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 exchange.isValidHashSignature(messageHash, signer, signatureHex).callAsync(); - expect(isValidSignature).to.be.true(); - }); - - createHashSignatureTests((_signerAddress?: string) => hashHex, validateAsync); - }); - - describe('isValidOrderSignature', () => { - let orderFactory: OrderFactory; - let signedOrder: SignedOrder; - - before(async () => { - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress: signerAddress, - feeRecipientAddress: randomAddress(), - makerAssetData: encodeERC20AssetData(randomAddress()), - takerAssetData: encodeERC20AssetData(randomAddress()), - makerFeeAssetData: encodeERC20AssetData(randomAddress()), - takerFeeAssetData: encodeERC20AssetData(randomAddress()), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - exchangeAddress: exchange.address, - chainId, - }; - orderFactory = new OrderFactory(signerPrivateKey, defaultOrderParams); - }); - - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - }); - - const validateAsync = async ( - order: SignedOrder, - signatureHex: string, - validatorAction?: ValidatorWalletAction, - validatorExpectedSignatureHex?: string, - ) => { - const orderHashHex = orderHashUtils.getOrderHashHex(order); - const expectedSignatureHashHex = - validatorExpectedSignatureHex === undefined - ? constants.NULL_BYTES - : hashBytes(validatorExpectedSignatureHex); - if (validatorAction !== undefined) { - await validatorWallet - .prepare(orderHashHex, validatorAction, expectedSignatureHashHex) - .awaitTransactionSuccessAsync(); - } - return exchange.isValidOrderSignature(order, signatureHex).callAsync(); - }; - - it('should revert when signerAddress == 0', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP712); - const nullMakerOrder = { - ...signedOrder, - makerAddress: constants.NULL_ADDRESS, - }; - const orderHashHex = orderHashUtils.getOrderHashHex(nullMakerOrder); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidSigner, - orderHashHex, - constants.NULL_ADDRESS, - signatureHex, - ); - const tx = exchange.isValidOrderSignature(nullMakerOrder, signatureHex).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const isValidSignature = await validateAsync( - signedOrder, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=Validator, signature is invalid and validator is approved', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const notSignatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(notSignatureDataHex, validatorWallet.address, SignatureType.Validator); - const isValidSignature = await validateAsync( - signedOrder, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should return false when validator returns `true` and SignatureType=Validator', async () => { - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const isValidSignature = await validateAsync( - signedOrder, - signatureHex, - ValidatorWalletAction.ReturnTrue, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when validator returns nothing and SignatureType=Validator', async () => { - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.ReturnNothing, signatureDataHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator attempts to update state and SignatureType=Validator', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.UpdateState); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator reverts and SignatureType=Validator', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - new StringRevertError(validatorWalletRevertReason).encode(), - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when SignatureType=Validator and signature is shorter than 21 bytes', async () => { - // Set approval of signature validator to false - await exchange - .setSignatureValidatorApproval(validatorWallet.address, false) - .awaitTransactionSuccessAsync({ from: signedOrder.makerAddress }); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(SignatureType.Validator); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidLength, - orderHashHex, - signedOrder.makerAddress, - signatureHex, - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.MatchSignatureHash); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when SignatureType=Validator, signature is valid and validator is not approved', async () => { - // Set approval of signature validator to false - await exchange - .setSignatureValidatorApproval(validatorWallet.address, false) - .awaitTransactionSuccessAsync({ from: signedOrder.makerAddress }); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const expectedError = new ExchangeRevertErrors.SignatureValidatorNotApprovedError( - signedOrder.makerAddress, - validatorWallet.address, - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return true when SignatureType=EIP1271Wallet and signature is valid', async () => { - signedOrder.makerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet); - // Validate signature - const isValidSignature = await validateAsync( - signedOrder, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=EIP1271Wallet and signature is invalid', async () => { - signedOrder.makerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const notSignatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(notSignatureDataHex, SignatureType.EIP1271Wallet); - // Validate signature - const isValidSignature = await validateAsync( - signedOrder, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should return false when validator returns `true` and SignatureType=EIP1271Wallet', async () => { - signedOrder.makerAddress = validatorWallet.address; - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet); - // Validate signature - const isValidSignature = await validateAsync( - signedOrder, - signatureHex, - ValidatorWalletAction.ReturnTrue, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when validator returns nothing and SignatureType=EIP1271Wallet', async () => { - signedOrder.makerAddress = validatorWallet.address; - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.ReturnNothing, signatureDataHex); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator attempts to update state and SignatureType=EIP1271Wallet', async () => { - signedOrder.makerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP1271Wallet); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.UpdateState); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator reverts and SignatureType=EIP1271Wallet', async () => { - signedOrder.makerAddress = validatorWallet.address; - const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - new StringRevertError(validatorWalletRevertReason).encode(), - ); - const tx = validateAsync(signedOrder, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when signer is an EOA and SignatureType=EIP1271Wallet', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet); - signedOrder.makerAddress = notSignerAddress; - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - notSignerAddress, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = exchange.isValidOrderSignature(signedOrder, signatureHex).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when signer is an EOA and SignatureType=Validator', async () => { - const signatureHex = hexUtils.concat(notSignerAddress, SignatureType.Validator); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - notSignerAddress, - data, - signatureHex, - constants.NULL_BYTES, - ); - // Register an EOA as a validator. - await exchange - .setSignatureValidatorApproval(notSignerAddress, true) - .awaitTransactionSuccessAsync({ from: signerAddress }); - const tx = exchange.isValidOrderSignature(signedOrder, signatureHex).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - // Run hash-only signature type tests as well. - const validateOrderHashAsync = async ( - _hashHex: string, - _signerAddress: string, - signatureHex: string, - validatorAction?: ValidatorWalletAction, - validatorExpectedSignatureHex?: string, - ): Promise => { - signedOrder.makerAddress = _signerAddress; - return validateAsync(signedOrder, signatureHex, validatorAction, validatorExpectedSignatureHex); - }; - createHashSignatureTests((_signerAddress?: string) => { - signedOrder.makerAddress = _signerAddress === undefined ? signerAddress : _signerAddress; - return orderHashUtils.getOrderHashHex(signedOrder); - }, validateOrderHashAsync); - }); - - describe('isValidTransactionSignature', () => { - let transactionFactory: TransactionFactory; - let signedTransaction: SignedZeroExTransaction; - const TRANSACTION_DATA_LENGTH = 100; - - before(async () => { - transactionFactory = new TransactionFactory(signerPrivateKey, exchange.address, chainId); - }); - - beforeEach(async () => { - // We don't actually do anything with the transaction so we can just - // fill it with random data. - signedTransaction = await transactionFactory.newSignedTransactionAsync({ - data: hexUtils.random(TRANSACTION_DATA_LENGTH), - }); - }); - - const validateAsync = async ( - transaction: SignedZeroExTransaction, - signatureHex: string, - validatorAction?: ValidatorWalletAction, - validatorExpectedSignatureHex?: string, - ) => { - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const expectedSignatureHashHex = - validatorExpectedSignatureHex === undefined - ? constants.NULL_BYTES - : hashBytes(validatorExpectedSignatureHex); - if (validatorAction !== undefined) { - await validatorWallet - .prepare(transactionHashHex, validatorAction, expectedSignatureHashHex) - .awaitTransactionSuccessAsync(); - } - return exchange.isValidTransactionSignature(transaction, signatureHex).callAsync(); - }; - - it('should revert when signerAddress == 0', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP712); - const nullSignerTransaction = { - ...signedTransaction, - signerAddress: constants.NULL_ADDRESS, - }; - const transactionHashHex = transactionHashUtils.getTransactionHashHex(nullSignerTransaction); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidSigner, - transactionHashHex, - constants.NULL_ADDRESS, - signatureHex, - ); - const tx = exchange.isValidTransactionSignature(nullSignerTransaction, signatureHex).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const isValidSignature = await validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=Validator, signature is invalid and validator is approved', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const notSignatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(notSignatureDataHex, validatorWallet.address, SignatureType.Validator); - const isValidSignature = await validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should return false when validator returns `true` and SignatureType=Validator', async () => { - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const isValidSignature = await validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.ReturnTrue, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when SignatureType=Validator and signature is shorter than 21 bytes', async () => { - // Set approval of signature validator to false - await exchange - .setSignatureValidatorApproval(validatorWallet.address, false) - .awaitTransactionSuccessAsync({ from: signedTransaction.signerAddress }); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(SignatureType.Validator); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidLength, - transactionHashHex, - signedTransaction.signerAddress, - signatureHex, - ); - const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.MatchSignatureHash); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator returns nothing and SignatureType=Validator', async () => { - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.ReturnNothing, - signatureDataHex, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator attempts to update state and SignatureType=Validator', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.UpdateState); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator reverts and SignatureType=Validator', async () => { - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - new StringRevertError(validatorWalletRevertReason).encode(), - ); - const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when SignatureType=Validator, signature is valid and validator is not approved', async () => { - // Set approval of signature validator to false - await exchange - .setSignatureValidatorApproval(validatorWallet.address, false) - .awaitTransactionSuccessAsync({ from: signedTransaction.signerAddress }); - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator); - const expectedError = new ExchangeRevertErrors.SignatureValidatorNotApprovedError( - signedTransaction.signerAddress, - validatorWallet.address, - ); - const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should return true when SignatureType=EIP1271Wallet and signature is valid', async () => { - signedTransaction.signerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet); - // Validate signature - const isValidSignature = await validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=EIP1271Wallet and signature is invalid', async () => { - signedTransaction.signerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureDataHex = generateRandomSignature(); - const notSignatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(notSignatureDataHex, SignatureType.EIP1271Wallet); - // Validate signature - const isValidSignature = await validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.MatchSignatureHash, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should return false when validator returns `true` and SignatureType=EIP1271Wallet', async () => { - signedTransaction.signerAddress = validatorWallet.address; - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet); - // Validate signature - const isValidSignature = await validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.ReturnTrue, - signatureDataHex, - ); - expect(isValidSignature).to.be.false(); - }); - - it('should revert when validator returns nothing and SignatureType=EIP1271Wallet', async () => { - signedTransaction.signerAddress = validatorWallet.address; - const signatureDataHex = generateRandomSignature(); - const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync( - signedTransaction, - signatureHex, - ValidatorWalletAction.ReturnNothing, - signatureDataHex, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator attempts to update state and SignatureType=EIP1271Wallet', async () => { - signedTransaction.signerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP1271Wallet); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.UpdateState); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when validator reverts and SignatureType=EIP1271Wallet', async () => { - signedTransaction.signerAddress = validatorWallet.address; - // Doesn't have to contain a real signature since our wallet contract - // just does a hash comparison. - const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP1271Wallet); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - validatorWallet.address, - data, - signatureHex, - new StringRevertError(validatorWalletRevertReason).encode(), - ); - const tx = validateAsync(signedTransaction, signatureHex, ValidatorWalletAction.Revert); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when signer is an EOA and SignatureType=EIP1271Wallet', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - signedTransaction.signerAddress, - data, - signatureHex, - constants.NULL_BYTES, - ); - const tx = exchange.isValidTransactionSignature(signedTransaction, signatureHex).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when signer is an EOA and SignatureType=Validator', async () => { - const signatureHex = hexUtils.concat(notSignerAddress, SignatureType.Validator); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction); - const data = eip1271Data - .ZeroExTransactionWithHash(signedTransaction, transactionHashHex) - .getABIEncodedTransactionData(); - const expectedError = new ExchangeRevertErrors.EIP1271SignatureError( - notSignerAddress, - data, - signatureHex, - constants.NULL_BYTES, - ); - // Register an EOA as a validator. - await exchange - .setSignatureValidatorApproval(notSignerAddress, true) - .awaitTransactionSuccessAsync({ from: signerAddress }); - const tx = exchange.isValidTransactionSignature(signedTransaction, signatureHex).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - // Run hash-only signature type tests as well. - const validateOrderHashAsync = async ( - _hashHex: string, - _signerAddress: string, - signatureHex: string, - validatorAction?: ValidatorWalletAction, - validatorExpectedSignatureHex?: string, - ): Promise => { - signedTransaction.signerAddress = _signerAddress; - return validateAsync(signedTransaction, signatureHex, validatorAction, validatorExpectedSignatureHex); - }; - createHashSignatureTests((_signerAddress?: string) => { - signedTransaction.signerAddress = _signerAddress === undefined ? signerAddress : _signerAddress; - return transactionHashUtils.getTransactionHashHex(signedTransaction); - }, validateOrderHashAsync); - }); - - describe('setSignatureValidatorApproval', () => { - let signatureValidatorLogDecoder: LogDecoder; - - before(async () => { - signatureValidatorLogDecoder = new LogDecoder(env.web3Wrapper, artifacts); - }); - - it('should emit a SignatureValidatorApprovalSet with correct args when a validator is approved', async () => { - const approval = true; - const res = await exchange - .setSignatureValidatorApproval(validatorWallet.address, approval) - .awaitTransactionSuccessAsync({ - from: signerAddress, - }); - expect(res.logs.length).to.equal(1); - const log = signatureValidatorLogDecoder.decodeLogOrThrow(res.logs[0]) as LogWithDecodedArgs< - ExchangeSignatureValidatorApprovalEventArgs - >; - const logArgs = log.args; - expect(logArgs.signerAddress).to.equal(signerAddress); - expect(logArgs.validatorAddress).to.equal(validatorWallet.address); - expect(logArgs.isApproved).to.equal(approval); - }); - it('should emit a SignatureValidatorApprovalSet with correct args when a validator is disapproved', async () => { - const approval = false; - const res = await exchange - .setSignatureValidatorApproval(validatorWallet.address, approval) - .awaitTransactionSuccessAsync({ - from: signerAddress, - }); - expect(res.logs.length).to.equal(1); - const log = signatureValidatorLogDecoder.decodeLogOrThrow(res.logs[0]) as LogWithDecodedArgs< - ExchangeSignatureValidatorApprovalEventArgs - >; - const logArgs = log.args; - expect(logArgs.signerAddress).to.equal(signerAddress); - expect(logArgs.validatorAddress).to.equal(validatorWallet.address); - expect(logArgs.isApproved).to.equal(approval); - }); - }); - - describe('fillOrder integration tests', () => { - let erc20Wrapper: ERC20Wrapper; - let erc20Proxy: ERC20ProxyContract; - let erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: DummyERC20TokenContract; - let feeToken: DummyERC20TokenContract; - let orderFactory: OrderFactory; - let signedOrder: SignedOrder; - - before(async () => { - // Deploy ERC20 proxy and tokens - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - erc20Proxy = await erc20Wrapper.deployProxyAsync(); - const numDummyErc20ToDeploy = 3; - [erc20TokenA, erc20TokenB, feeToken] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - - // Configure ERC20 proxy and exchange - await erc20Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner }); - await exchange.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure order defaults - const defaultMakerAssetAddress = erc20TokenA.address; - const defaultTakerAssetAddress = erc20TokenB.address; - const defaultFeeAssetAddress = feeToken.address; - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress, - feeRecipientAddress, - makerAssetData: encodeERC20AssetData(defaultMakerAssetAddress), - takerAssetData: encodeERC20AssetData(defaultTakerAssetAddress), - makerFeeAssetData: encodeERC20AssetData(defaultFeeAssetAddress), - takerFeeAssetData: encodeERC20AssetData(defaultFeeAssetAddress), - exchangeAddress: exchange.address, - chainId, - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - - // Approve the ERC20 proxy with the test validator wallet. - await validatorWallet - .approveERC20(erc20TokenA.address, erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE) - .awaitTransactionSuccessAsync(); - // Mint some ERC20 tokens to the test validator wallet. - await erc20TokenA - .setBalance(validatorWallet.address, constants.INITIAL_ERC20_BALANCE) - .awaitTransactionSuccessAsync(); - // Approve the validator. - await exchange.setSignatureValidatorApproval(validatorWallet.address, true).awaitTransactionSuccessAsync({ - from: makerAddress, - }); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - }); - - it('should revert if `Validator` signature type rejects during a second fill', async () => { - const signatureHex = hexUtils.concat(validatorWallet.address, SignatureType.Validator); - signedOrder.signature = signatureHex; - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Allow the signature check for the first fill. - await validatorWallet - .prepare(orderHashHex, ValidatorWalletAction.Accept, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const fillAmount = signedOrder.takerAssetAmount.div(10); - await exchange.fillOrder(signedOrder, fillAmount, signedOrder.signature).awaitTransactionSuccessAsync({ - from: takerAddress, - }); - // Reject the signature check for the second fill. - await validatorWallet - .prepare(orderHashHex, ValidatorWalletAction.Reject, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const tx = exchange.fillOrder(signedOrder, fillAmount, signedOrder.signature).awaitTransactionSuccessAsync({ - from: takerAddress, - }); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrder.makerAddress, - signedOrder.signature, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if `Wallet` signature type rejects during a second fill', async () => { - const signatureHex = hexUtils.concat(SignatureType.Wallet); - signedOrder.makerAddress = validatorWallet.address; - signedOrder.signature = signatureHex; - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Allow the signature check for the first fill. - await validatorWallet - .prepare(orderHashHex, ValidatorWalletAction.Accept, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const fillAmount = signedOrder.takerAssetAmount.div(10); - await exchange.fillOrder(signedOrder, fillAmount, signedOrder.signature).awaitTransactionSuccessAsync({ - from: takerAddress, - }); - // Reject the signature check for the second fill. - await validatorWallet - .prepare(orderHashHex, ValidatorWalletAction.Reject, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const tx = exchange.fillOrder(signedOrder, fillAmount, signedOrder.signature).awaitTransactionSuccessAsync({ - from: takerAddress, - }); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrder.makerAddress, - signedOrder.signature, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if `EIP1271Wallet` signature type rejects during a second fill', async () => { - const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet); - signedOrder.makerAddress = validatorWallet.address; - signedOrder.signature = signatureHex; - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Allow the signature check for the first fill. - await validatorWallet - .prepare(orderHashHex, ValidatorWalletAction.Accept, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const fillAmount = signedOrder.takerAssetAmount.div(10); - await exchange.fillOrder(signedOrder, fillAmount, signedOrder.signature).awaitTransactionSuccessAsync({ - from: takerAddress, - }); - // Reject the signature check for the second fill. - await validatorWallet - .prepare(orderHashHex, ValidatorWalletAction.Reject, constants.NULL_BYTES) - .awaitTransactionSuccessAsync(); - const tx = exchange.fillOrder(signedOrder, fillAmount, signedOrder.signature).awaitTransactionSuccessAsync({ - from: takerAddress, - }); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrder.makerAddress, - signedOrder.signature, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); -// tslint:disable:max-file-line-count -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/exchange/test/transactions_unit_tests.ts b/contracts/exchange/test/transactions_unit_tests.ts deleted file mode 100644 index a237bf3853..0000000000 --- a/contracts/exchange/test/transactions_unit_tests.ts +++ /dev/null @@ -1,703 +0,0 @@ -import { blockchainTests, constants, describe, expect, transactionHashUtils } from '@0x/contracts-test-utils'; -import { EIP712DomainWithDefaultSchema, ZeroExTransaction } from '@0x/types'; -import { BigNumber, ExchangeRevertErrors, hexUtils, StringRevertError } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { TestTransactionsContract, TestTransactionsTransactionExecutionEventArgs } from './wrappers'; - -blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDefaults }) => { - let transactionsContract: TestTransactionsContract; - let accounts: string[]; - let domain: EIP712DomainWithDefaultSchema; - - const randomSignature = () => hexUtils.random(66); - - const EMPTY_ZERO_EX_TRANSACTION = { - salt: constants.ZERO_AMOUNT, - expirationTimeSeconds: constants.ZERO_AMOUNT, - gasPrice: constants.ZERO_AMOUNT, - signerAddress: constants.NULL_ADDRESS, - data: constants.NULL_BYTES, - domain: { - verifyingContract: constants.NULL_ADDRESS, - chainId: 0, - }, - }; - - const DEADBEEF_RETURN_DATA = '0xdeadbeef'; - const INVALID_SIGNATURE = '0x0000'; - - before(async () => { - // A list of available addresses to use during testing. - accounts = await web3Wrapper.getAvailableAddressesAsync(); - - // Deploy the transaction test contract. - transactionsContract = await TestTransactionsContract.deployFrom0xArtifactAsync( - artifacts.TestTransactions, - provider, - txDefaults, - {}, - ); - - // Set the default domain. - domain = { - verifyingContract: transactionsContract.address, - chainId: 1337, - }; - }); - - /** - * Generates calldata for a call to `executable()` in the `TestTransactions` contract. - */ - function getExecutableCallData(shouldSucceed: boolean, callData: string, returnData: string): string { - return (transactionsContract as any) - .executable(shouldSucceed, callData, returnData) - .getABIEncodedTransactionData(); - } - - interface GenerateZeroExTransactionParams { - salt?: BigNumber; - expirationTimeSeconds?: BigNumber; - gasPrice?: BigNumber; - signerAddress?: string; - data?: string; - domain?: EIP712DomainWithDefaultSchema; - shouldSucceed?: boolean; - callData?: string; - returnData?: string; - } - - async function generateZeroExTransactionAsync( - opts: GenerateZeroExTransactionParams = {}, - ): Promise { - const shouldSucceed = opts.shouldSucceed === undefined ? true : opts.shouldSucceed; - const callData = opts.callData === undefined ? constants.NULL_BYTES : opts.callData; - const returnData = opts.returnData === undefined ? constants.NULL_BYTES : opts.returnData; - const data = opts.data === undefined ? getExecutableCallData(shouldSucceed, callData, returnData) : opts.data; - const gasPrice = opts.gasPrice === undefined ? new BigNumber(constants.DEFAULT_GAS_PRICE) : opts.gasPrice; - const _domain = opts.domain === undefined ? domain : opts.domain; - const expirationTimeSeconds = - opts.expirationTimeSeconds === undefined ? constants.MAX_UINT256 : opts.expirationTimeSeconds; - const transaction = { - ...EMPTY_ZERO_EX_TRANSACTION, - ...opts, - data, - expirationTimeSeconds, - domain: _domain, - gasPrice, - }; - return transaction; - } - - describe('batchExecuteTransaction', () => { - it('should revert if the only call to executeTransaction fails', async () => { - // Create an expired transaction that will fail when used to call `batchExecuteTransactions()`. - const transaction = await generateZeroExTransactionAsync({ shouldSucceed: false }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - - // Create the StringRevertError that reflects the returndata that will be returned by the failed transaction. - const executableError = new StringRevertError('EXECUTABLE_FAILED'); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHash, - executableError.encode(), - ); - - // Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error. - const tx = transactionsContract - .batchExecuteTransactions([transaction], [randomSignature()]) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the second call to executeTransaction fails', async () => { - // Create a transaction that will succeed when used to call `batchExecuteTransactions()`. - const transaction1 = await generateZeroExTransactionAsync(); - - // Create a transaction that will fail when used to call `batchExecuteTransactions()` because the call to executable will fail. - const transaction2 = await generateZeroExTransactionAsync({ shouldSucceed: false }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction2); - - // Create the StringRevertError that reflects the returndata that will be returned by the failed transaction. - const executableError = new StringRevertError('EXECUTABLE_FAILED'); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHash, - executableError.encode(), - ); - - // Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error. - const tx = transactionsContract - .batchExecuteTransactions([transaction1, transaction2], [randomSignature(), randomSignature()]) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the first call to executeTransaction fails', async () => { - // Create a transaction that will fail when used to call `batchExecuteTransactions()` because the call to executable will fail. - const transaction1 = await generateZeroExTransactionAsync({ shouldSucceed: false }); - - // Create a transaction that will succeed when used to call `batchExecuteTransactions()`. - const transaction2 = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction1); - - // Create the StringRevertError that reflects the returndata that will be returned by the failed transaction. - const executableError = new StringRevertError('EXECUTABLE_FAILED'); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHash, - executableError.encode(), - ); - - // Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error. - const tx = transactionsContract - .batchExecuteTransactions([transaction1, transaction2], [randomSignature(), randomSignature()]) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the same transaction is executed twice in a batch', async () => { - // Create a transaction that will succeed when used to call `batchExecuteTransactions()`. - const transaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[1] }); - - // Duplicate the first transaction. This should cause the call to `batchExecuteTransactions()` to fail - // because this transaction will have the same order hash as transaction1. - const transaction2 = transaction1; - const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2); - - // Call the `batchExecuteTransactions()` function and ensure that it reverts with the expected revert error. - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted, - transactionHash2, - ); - const tx = transactionsContract - .batchExecuteTransactions([transaction1, transaction2], [randomSignature(), randomSignature()]) - .awaitTransactionSuccessAsync({ - from: accounts[0], - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should succeed if the only call to executeTransaction succeeds', async () => { - // Create a transaction that will succeed when used to call `batchExecuteTransactions()`. - const transaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[1], - returnData: DEADBEEF_RETURN_DATA, - }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const validSignature = randomSignature(); - - const contractFn = transactionsContract.batchExecuteTransactions([transaction], [validSignature]); - const result = await contractFn.callAsync({ from: accounts[0] }); - const receipt = await contractFn.awaitTransactionSuccessAsync({ from: accounts[0] }); - - expect(result.length).to.be.eq(1); - const returnData = transactionsContract.getABIDecodedReturnData('executeTransaction', result[0]); - expect(returnData).to.equal(DEADBEEF_RETURN_DATA); - - // Ensure that the correct number of events were logged. - const logs = receipt.logs as Array>; - expect(logs.length).to.be.eq(2); - - // Ensure that the correct events were logged. - expect(logs[0].event).to.be.eq('ExecutableCalled'); - expect(logs[0].args.data).to.be.eq(constants.NULL_BYTES); - expect(logs[0].args.contextAddress).to.be.eq(accounts[1]); - expect(logs[0].args.returnData).to.be.eq(DEADBEEF_RETURN_DATA); - expect(logs[1].event).to.be.eq('TransactionExecution'); - expect(logs[1].args.transactionHash).to.eq(transactionHash); - }); - - it('should succeed if the both calls to executeTransaction succeed', async () => { - // Create two transactions that will succeed when used to call `batchExecuteTransactions()`. - const transaction1 = await generateZeroExTransactionAsync({ - signerAddress: accounts[0], - returnData: DEADBEEF_RETURN_DATA, - }); - const returnData2 = '0xbeefdead'; - const transaction2 = await generateZeroExTransactionAsync({ - signerAddress: accounts[1], - returnData: returnData2, - }); - const transactionHash1 = transactionHashUtils.getTransactionHashHex(transaction1); - const transactionHash2 = transactionHashUtils.getTransactionHashHex(transaction2); - - const contractFn = transactionsContract.batchExecuteTransactions( - [transaction1, transaction2], - [randomSignature(), randomSignature()], - ); - const result = await contractFn.callAsync({ from: accounts[0] }); - - const receipt = await contractFn.awaitTransactionSuccessAsync({ from: accounts[0] }); - expect(result.length).to.be.eq(2); - expect(transactionsContract.getABIDecodedReturnData('executeTransaction', result[0])).to.equal( - DEADBEEF_RETURN_DATA, - ); - expect(transactionsContract.getABIDecodedReturnData('executeTransaction', result[1])).to.equal(returnData2); - - // Verify that the correct number of events were logged. - const logs = receipt.logs as Array>; - expect(logs.length).to.be.eq(4); - - // Ensure that the correct events were logged. - expect(logs[0].event).to.be.eq('ExecutableCalled'); - expect(logs[0].args.data).to.be.eq(constants.NULL_BYTES); - expect(logs[0].args.returnData).to.be.eq(DEADBEEF_RETURN_DATA); - expect(logs[0].args.contextAddress).to.be.eq(constants.NULL_ADDRESS); - expect(logs[1].event).to.be.eq('TransactionExecution'); - expect(logs[1].args.transactionHash).to.eq(transactionHash1); - expect(logs[2].event).to.be.eq('ExecutableCalled'); - expect(logs[2].args.data).to.be.eq(constants.NULL_BYTES); - expect(logs[2].args.returnData).to.be.eq('0xbeefdead'); - expect(logs[2].args.contextAddress).to.be.eq(accounts[1]); - expect(logs[3].event).to.be.eq('TransactionExecution'); - expect(logs[3].args.transactionHash).to.eq(transactionHash2); - }); - it('should not allow recursion if currentContextAddress is already set', async () => { - const innerTransaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - const innerTransaction2 = await generateZeroExTransactionAsync({ signerAddress: accounts[1] }); - const innerBatchExecuteTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[2], - callData: transactionsContract - .batchExecuteTransactions( - [innerTransaction1, innerTransaction2], - [randomSignature(), randomSignature()], - ) - .getABIEncodedTransactionData(), - }); - const outerExecuteTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[1], - callData: transactionsContract - .executeTransaction(innerBatchExecuteTransaction, randomSignature()) - .getABIEncodedTransactionData(), - }); - const innerBatchExecuteTransactionHash = transactionHashUtils.getTransactionHashHex( - innerBatchExecuteTransaction, - ); - const innerExpectedError = new ExchangeRevertErrors.TransactionInvalidContextError( - innerBatchExecuteTransactionHash, - accounts[1], - ); - const outerExecuteTransactionHash = transactionHashUtils.getTransactionHashHex(outerExecuteTransaction); - const outerExpectedError = new ExchangeRevertErrors.TransactionExecutionError( - outerExecuteTransactionHash, - innerExpectedError.encode(), - ); - const tx = transactionsContract - .batchExecuteTransactions([outerExecuteTransaction], [randomSignature()]) - .awaitTransactionSuccessAsync({ from: accounts[2] }); - return expect(tx).to.revertWith(outerExpectedError); - }); - it('should allow recursion as long as currentContextAddress is not set', async () => { - const innerTransaction1 = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - const innerTransaction2 = await generateZeroExTransactionAsync({ signerAddress: accounts[1] }); - // From this point on, all transactions and calls will have the same sender, which does not change currentContextAddress when called - const innerBatchExecuteTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[2], - callData: transactionsContract - .batchExecuteTransactions( - [innerTransaction1, innerTransaction2], - [randomSignature(), randomSignature()], - ) - .getABIEncodedTransactionData(), - }); - const outerExecuteTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[2], - callData: transactionsContract - .executeTransaction(innerBatchExecuteTransaction, randomSignature()) - .getABIEncodedTransactionData(), - }); - return expect( - transactionsContract - .batchExecuteTransactions([outerExecuteTransaction], [randomSignature()]) - .awaitTransactionSuccessAsync({ from: accounts[2] }), - ).to.be.fulfilled(''); - }); - }); - - describe('executeTransaction', () => { - function getExecuteTransactionCallData(transaction: ZeroExTransaction, signature: string): string { - return (transactionsContract as any) - .executeTransaction(transaction, signature) - .getABIEncodedTransactionData(); - } - it('should revert if the current time is past the expiration time', async () => { - const transaction = await generateZeroExTransactionAsync({ - expirationTimeSeconds: constants.ZERO_AMOUNT, - }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.Expired, - transactionHash, - ); - const tx = transactionsContract - .executeTransaction(transaction, randomSignature()) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if the transaction is submitted with a gasPrice that does not equal the required gasPrice', async () => { - const transaction = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const actualGasPrice = transaction.gasPrice.plus(1); - const expectedError = new ExchangeRevertErrors.TransactionGasPriceError( - transactionHash, - actualGasPrice, - transaction.gasPrice, - ); - const tx = transactionsContract - .executeTransaction(transaction, randomSignature()) - .awaitTransactionSuccessAsync({ - gasPrice: actualGasPrice, - }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if reentrancy occurs in the middle of an executeTransaction call and msg.sender != signer for both calls', async () => { - const validSignature = randomSignature(); - const innerTransaction = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - const innerTransactionHash = transactionHashUtils.getTransactionHashHex(innerTransaction); - const outerTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[0], - callData: getExecuteTransactionCallData(innerTransaction, validSignature), - returnData: DEADBEEF_RETURN_DATA, - }); - const outerTransactionHash = transactionHashUtils.getTransactionHashHex(outerTransaction); - const errorData = new ExchangeRevertErrors.TransactionInvalidContextError( - innerTransactionHash, - accounts[0], - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError(outerTransactionHash, errorData); - const tx = transactionsContract - .executeTransaction(outerTransaction, validSignature) - .awaitTransactionSuccessAsync({ - from: accounts[1], // Different then the signing addresses - }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if reentrancy occurs in the middle of an executeTransaction call and msg.sender != signer and then msg.sender == signer', async () => { - const validSignature = randomSignature(); - const innerTransaction = await generateZeroExTransactionAsync({ signerAddress: accounts[1] }); - const innerTransactionHash = transactionHashUtils.getTransactionHashHex(innerTransaction); - const outerTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[0], - callData: getExecuteTransactionCallData(innerTransaction, validSignature), - returnData: DEADBEEF_RETURN_DATA, - }); - const outerTransactionHash = transactionHashUtils.getTransactionHashHex(outerTransaction); - const errorData = new ExchangeRevertErrors.TransactionInvalidContextError( - innerTransactionHash, - accounts[0], - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError(outerTransactionHash, errorData); - const tx = transactionsContract - .executeTransaction(outerTransaction, validSignature) - .awaitTransactionSuccessAsync({ - from: accounts[1], // Different then the signing addresses - }); - return expect(tx).to.revertWith(expectedError); - }); - it('should allow reentrancy in the middle of an executeTransaction call if msg.sender == signer for both calls', async () => { - const validSignature = randomSignature(); - const innerTransaction = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - const outerTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[0], - callData: getExecuteTransactionCallData(innerTransaction, validSignature), - returnData: DEADBEEF_RETURN_DATA, - }); - return expect( - transactionsContract.executeTransaction(outerTransaction, validSignature).awaitTransactionSuccessAsync({ - from: accounts[0], - }), - ).to.be.fulfilled(''); - }); - it('should allow reentrancy in the middle of an executeTransaction call if msg.sender == signer and then msg.sender != signer', async () => { - const validSignature = randomSignature(); - const innerTransaction = await generateZeroExTransactionAsync({ signerAddress: accounts[1] }); - const outerTransaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[0], - callData: getExecuteTransactionCallData(innerTransaction, validSignature), - returnData: DEADBEEF_RETURN_DATA, - }); - return expect( - transactionsContract.executeTransaction(outerTransaction, validSignature).awaitTransactionSuccessAsync({ - from: accounts[0], - }), - ).to.be.fulfilled(''); - }); - it('should revert if the transaction has been executed previously', async () => { - const validSignature = randomSignature(); - const transaction = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - // Use the transaction in execute transaction. - await expect( - transactionsContract.executeTransaction(transaction, validSignature).awaitTransactionSuccessAsync(), - ).to.be.fulfilled(''); - // Use the same transaction to make another call - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted, - transactionHash, - ); - const tx = transactionsContract - .executeTransaction(transaction, validSignature) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if the signer != msg.sender and the signature is not valid', async () => { - const transaction = await generateZeroExTransactionAsync({ signerAddress: accounts[1] }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadTransactionSignature, - transactionHash, - accounts[1], - INVALID_SIGNATURE, - ); - const tx = transactionsContract - .executeTransaction(transaction, INVALID_SIGNATURE) - .awaitTransactionSuccessAsync({ - from: accounts[0], - }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if the signer == msg.sender but the delegatecall fails', async () => { - // This calldata is encoded to fail when it hits the executable function. - const transaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[1], - shouldSucceed: false, - }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const executableError = new StringRevertError('EXECUTABLE_FAILED'); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHash, - executableError.encode(), - ); - const tx = transactionsContract - .executeTransaction(transaction, randomSignature()) - .awaitTransactionSuccessAsync({ - from: accounts[1], - }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if the signer != msg.sender and the signature is valid but the delegatecall fails', async () => { - // This calldata is encoded to fail when it hits the executable function. - const transaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[1], - shouldSucceed: false, - }); - const validSignature = randomSignature(); // Valid because length != 2 - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const executableError = new StringRevertError('EXECUTABLE_FAILED'); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHash, - executableError.encode(), - ); - const tx = transactionsContract - .executeTransaction(transaction, validSignature) - .awaitTransactionSuccessAsync({ - from: accounts[0], - }); - return expect(tx).to.revertWith(expectedError); - }); - it('should succeed with the correct return hash and event emitted when msg.sender != signer', async () => { - // This calldata is encoded to succeed when it hits the executable function. - const validSignature = randomSignature(); // Valid because length != 2 - const transaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[1], - returnData: DEADBEEF_RETURN_DATA, - }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - - const contractFn = transactionsContract.executeTransaction(transaction, validSignature); - const result = await contractFn.callAsync({ from: accounts[0] }); - - const receipt = await contractFn.awaitTransactionSuccessAsync({ from: accounts[0] }); - expect(transactionsContract.getABIDecodedReturnData('executeTransaction', result)).to.equal( - DEADBEEF_RETURN_DATA, - ); - - // Ensure that the correct number of events were logged. - const logs = receipt.logs as Array>; - expect(logs.length).to.be.eq(2); - // Ensure that the correct events were logged. - expect(logs[0].event).to.be.eq('ExecutableCalled'); - expect(logs[0].args.data).to.be.eq(constants.NULL_BYTES); - expect(logs[0].args.returnData).to.be.eq(DEADBEEF_RETURN_DATA); - expect(logs[0].args.contextAddress).to.be.eq(accounts[1]); - expect(logs[1].event).to.be.eq('TransactionExecution'); - expect(logs[1].args.transactionHash).to.eq(transactionHash); - }); - it('should succeed with the correct return hash and event emitted when msg.sender == signer', async () => { - // This calldata is encoded to succeed when it hits the executable function. - const validSignature = randomSignature(); // Valid because length != 2 - const transaction = await generateZeroExTransactionAsync({ - signerAddress: accounts[0], - returnData: DEADBEEF_RETURN_DATA, - }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - - const contractFn = transactionsContract.executeTransaction(transaction, validSignature); - const result = await contractFn.callAsync({ from: accounts[0] }); - - const receipt = await contractFn.awaitTransactionSuccessAsync({ from: accounts[0] }); - expect(transactionsContract.getABIDecodedReturnData('executeTransaction', result)).to.equal( - DEADBEEF_RETURN_DATA, - ); - - // Ensure that the correct number of events were logged. - const logs = receipt.logs as Array>; - expect(logs.length).to.be.eq(2); - // Ensure that the correct events were logged. - expect(logs[0].event).to.be.eq('ExecutableCalled'); - expect(logs[0].args.data).to.be.eq(constants.NULL_BYTES); - expect(logs[0].args.returnData).to.be.eq(DEADBEEF_RETURN_DATA); - expect(logs[0].args.contextAddress).to.be.eq(constants.NULL_ADDRESS); - expect(logs[1].event).to.be.eq('TransactionExecution'); - expect(logs[1].args.transactionHash).to.eq(transactionHash); - }); - }); - - blockchainTests.resets('assertExecutableTransaction', () => { - it('should revert if the transaction is expired', async () => { - const transaction = await generateZeroExTransactionAsync({ - expirationTimeSeconds: constants.ZERO_AMOUNT, - }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.Expired, - transactionHash, - ); - expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync(), - ).to.revertWith(expectedError); - }); - it('should revert if the gasPrice is less than required', async () => { - const transaction = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const actualGasPrice = transaction.gasPrice.minus(1); - const expectedError = new ExchangeRevertErrors.TransactionGasPriceError( - transactionHash, - actualGasPrice, - transaction.gasPrice, - ); - expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync({ - gasPrice: actualGasPrice, - }), - ).to.revertWith(expectedError); - }); - it('should revert if the gasPrice is greater than required', async () => { - const transaction = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const actualGasPrice = transaction.gasPrice.plus(1); - const expectedError = new ExchangeRevertErrors.TransactionGasPriceError( - transactionHash, - actualGasPrice, - transaction.gasPrice, - ); - expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync({ - gasPrice: actualGasPrice, - }), - ).to.revertWith(expectedError); - }); - it('should revert if currentContextAddress is non-zero', async () => { - await transactionsContract.setCurrentContextAddress(accounts[0]).awaitTransactionSuccessAsync(); - const transaction = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.TransactionInvalidContextError(transactionHash, accounts[0]); - expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync(), - ).to.revertWith(expectedError); - }); - it('should revert if the transaction has already been executed', async () => { - const transaction = await generateZeroExTransactionAsync(); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - await transactionsContract.setTransactionExecuted(transactionHash).awaitTransactionSuccessAsync(); - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted, - transactionHash, - ); - expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync(), - ).to.revertWith(expectedError); - }); - it('should revert if signer != msg.sender and the signature is invalid', async () => { - const transaction = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadTransactionSignature, - transactionHash, - accounts[0], - INVALID_SIGNATURE, - ); - expect( - transactionsContract.assertExecutableTransaction(transaction, INVALID_SIGNATURE).callAsync({ - from: accounts[1], - }), - ).to.revertWith(expectedError); - }); - it('should be successful if signer == msg.sender and the signature is invalid', async () => { - const transaction = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - return expect( - transactionsContract.assertExecutableTransaction(transaction, INVALID_SIGNATURE).callAsync({ - from: accounts[0], - }), - ).to.be.fulfilled(''); - }); - it('should be successful if signer == msg.sender and the signature is valid', async () => { - const transaction = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - return expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync({ - from: accounts[0], - }), - ).to.be.fulfilled(''); - }); - it('should be successful if not expired, the gasPrice is correct, the tx has not been executed, currentContextAddress has not been set, signer != msg.sender, and the signature is valid', async () => { - const transaction = await generateZeroExTransactionAsync({ signerAddress: accounts[0] }); - return expect( - transactionsContract.assertExecutableTransaction(transaction, randomSignature()).callAsync({ - from: accounts[1], - }), - ).to.be.fulfilled(''); - }); - }); - - describe('setCurrentContextAddressIfRequired', () => { - it('should set the currentContextAddress if signer not equal to sender', async () => { - const randomAddress = hexUtils.random(20); - await transactionsContract - .setCurrentContextAddressIfRequired(randomAddress, randomAddress) - .awaitTransactionSuccessAsync(); - const currentContextAddress = await transactionsContract.currentContextAddress().callAsync(); - expect(currentContextAddress).to.eq(randomAddress); - }); - it('should not set the currentContextAddress if signer equal to sender', async () => { - const randomAddress = hexUtils.random(20); - await transactionsContract - .setCurrentContextAddressIfRequired(accounts[0], randomAddress) - .awaitTransactionSuccessAsync({ - from: accounts[0], - }); - const currentContextAddress = await transactionsContract.currentContextAddress().callAsync(); - expect(currentContextAddress).to.eq(constants.NULL_ADDRESS); - }); - }); - - describe('getCurrentContext', () => { - it('should return the sender address when there is not a saved context address', async () => { - const currentContextAddress = await transactionsContract.getCurrentContextAddress().callAsync({ - from: accounts[0], - }); - expect(currentContextAddress).to.be.eq(accounts[0]); - }); - - it('should return the sender address when there is a saved context address', async () => { - // Set the current context address to the taker address - await transactionsContract.setCurrentContextAddress(accounts[1]).awaitTransactionSuccessAsync(); - - // Ensure that the queried current context address is the same as the address that was set. - const currentContextAddress = await transactionsContract.getCurrentContextAddress().callAsync({ - from: accounts[0], - }); - expect(currentContextAddress).to.be.eq(accounts[1]); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_fetcher.ts deleted file mode 100644 index ed0ff53b49..0000000000 --- a/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_fetcher.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -/** - * An abstract class to be implemented in order to use OrderStateUtils. The class that - * implements this interface must be capable of fetching the balance and proxyAllowance - * for an Ethereum address and assetData - */ -export abstract class AbstractBalanceAndProxyAllowanceFetcher { - /** - * Get balance of assetData for userAddress - * @param assetData AssetData for which to fetch the balance - * @param userAddress Ethereum address for which to fetch the balance - * @return Balance amount in base units - */ - public abstract getBalanceAsync(assetData: string, userAddress: string): Promise; - /** - * Get the 0x asset proxy allowance of assetData for userAddress - * @param assetData AssetData for which to fetch the allowance - * @param userAddress Ethereum address for which to fetch the allowance - * @return Allowance amount in base units - */ - public abstract getProxyAllowanceAsync(assetData: string, userAddress: string): Promise; -} diff --git a/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts b/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts deleted file mode 100644 index c36b9cd4b6..0000000000 --- a/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export abstract class AbstractBalanceAndProxyAllowanceLazyStore { - public abstract getBalanceAsync(assetData: string, userAddress: string): Promise; - public abstract getProxyAllowanceAsync(assetData: string, userAddress: string): Promise; - public abstract setBalance(assetData: string, userAddress: string, balance: BigNumber): void; - public abstract deleteBalance(assetData: string, userAddress: string): void; - public abstract setProxyAllowance(assetData: string, userAddress: string, proxyAllowance: BigNumber): void; - public abstract deleteProxyAllowance(assetData: string, userAddress: string): void; - public abstract deleteAll(): void; -} diff --git a/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts b/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts deleted file mode 100644 index 6e801fef73..0000000000 --- a/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -/** - * An abstract class to be implemented in order to use OrderStateUtils. The class that - * implements this interface must be capable of fetching the amount filled of an order - * and whether it's been cancelled. - */ -export abstract class AbstractOrderFilledCancelledFetcher { - /** - * Get the amount of the order's takerToken amount already filled - * @param orderHash OrderHash of order we are interested in - * @return FilledTakerAmount - */ - public abstract getFilledTakerAmountAsync(orderHash: string): Promise; -} diff --git a/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts b/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts deleted file mode 100644 index 968d510eb0..0000000000 --- a/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export abstract class AbstractOrderFilledCancelledLazyStore { - public abstract getFilledTakerAmountAsync(orderHash: string): Promise; - public abstract setFilledTakerAmount(orderHash: string, balance: BigNumber): void; - public abstract deleteFilledTakerAmount(orderHash: string): void; - public abstract setIsCancelled(orderHash: string, isCancelled: boolean): void; - public abstract deleteIsCancelled(orderHash: string): void; - public abstract deleteAll(): void; -} diff --git a/contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts deleted file mode 100644 index 302d6b0dab..0000000000 --- a/contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { DevUtilsContract } from '@0x/contracts-dev-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; - -export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { - private readonly _devUtilsContract: DevUtilsContract; - constructor(devUtilsContract: DevUtilsContract) { - this._devUtilsContract = devUtilsContract; - } - public async getBalanceAsync(assetData: string, userAddress: string): Promise { - const balance = await this._devUtilsContract.getBalance(userAddress, assetData).callAsync(); - return balance; - } - public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise { - const proxyAllowance = await this._devUtilsContract.getAssetProxyAllowance(userAddress, assetData).callAsync(); - return proxyAllowance; - } -} diff --git a/contracts/exchange/test/utils/asset_wrapper.ts b/contracts/exchange/test/utils/asset_wrapper.ts deleted file mode 100644 index 62594536b1..0000000000 --- a/contracts/exchange/test/utils/asset_wrapper.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { - decodeERC1155AssetData, - decodeERC721AssetData, - decodeMultiAssetData, - ERC1155ProxyWrapper, - ERC20Wrapper, - ERC721Wrapper, - getAssetDataProxyId, -} from '@0x/contracts-asset-proxy'; -import { AbstractAssetWrapper, constants } from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber, errorUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -interface ProxyIdToAssetWrappers { - [proxyId: string]: AbstractAssetWrapper; -} - -const ONE_NFT_UNIT = new BigNumber(1); -const ZERO_NFT_UNIT = new BigNumber(0); - -/** - * 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[], private readonly _burnerAddress: string) { - this._proxyIdToAssetWrappers = {}; - _.each(assetWrappers, assetWrapper => { - const proxyId = assetWrapper.getProxyId(); - this._proxyIdToAssetWrappers[proxyId] = assetWrapper; - }); - } - public async getBalanceAsync(userAddress: string, assetData: string): Promise { - const proxyId = getAssetDataProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - const balance = await erc20Wrapper.getBalanceAsync(userAddress, assetData); - return balance; - } - case AssetProxyId.ERC721: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - // tslint:disable-next-line:no-unused-variable - const [tokenAddress, tokenId] = decodeERC721AssetData(assetData); - const isOwner = await assetWrapper.isOwnerAsync(userAddress, tokenAddress, tokenId); - const balance = isOwner ? ONE_NFT_UNIT : ZERO_NFT_UNIT; - return balance; - } - case AssetProxyId.ERC1155: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const assetProxyWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC1155ProxyWrapper; - const [ - // tslint:disable-next-line:no-unused-variable - tokenAddress, - tokenIds, - ] = decodeERC1155AssetData(assetData); - const assetWrapper = assetProxyWrapper.getContractWrapper(tokenAddress); - const balances = await Promise.all( - _.map(tokenIds).map(tokenId => assetWrapper.getBalanceAsync(userAddress, tokenId)), - ); - return BigNumber.min(...balances); - } - case AssetProxyId.MultiAsset: { - // tslint:disable-next-line:no-unused-variable - const [amounts, nestedAssetData] = decodeMultiAssetData(assetData); - const nestedBalances = await Promise.all( - nestedAssetData.map(async _nestedAssetData => this.getBalanceAsync(userAddress, _nestedAssetData)), - ); - const scaledBalances = _.zip(amounts, nestedBalances).map(([amount, balance]) => - (balance as BigNumber).div(amount as BigNumber).integerValue(BigNumber.ROUND_HALF_UP), - ); - return BigNumber.min(...scaledBalances); - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } - public async setBalanceAsync(userAddress: string, assetData: string, desiredBalance: BigNumber): Promise { - const proxyId = getAssetDataProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - await erc20Wrapper.setBalanceAsync( - userAddress, - assetData, - desiredBalance.integerValue(BigNumber.ROUND_DOWN), - ); - return; - } - case AssetProxyId.ERC721: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - // tslint:disable-next-line:no-unused-variable - const [tokenAddress, tokenId] = decodeERC721AssetData(assetData); - const doesTokenExist = erc721Wrapper.doesTokenExistAsync(tokenAddress, tokenId); - if (!doesTokenExist && desiredBalance.gte(1)) { - await erc721Wrapper.mintAsync(tokenAddress, tokenId, userAddress); - return; - } else if (!doesTokenExist && desiredBalance.lt(1)) { - return; // noop - } - const tokenOwner = await erc721Wrapper.ownerOfAsync(tokenAddress, tokenId); - if (userAddress !== tokenOwner && desiredBalance.gte(1)) { - await erc721Wrapper.transferFromAsync(tokenAddress, tokenId, tokenOwner, userAddress); - } else if (tokenOwner === userAddress && desiredBalance.lt(1)) { - // Burn token - await erc721Wrapper.transferFromAsync(tokenAddress, tokenId, tokenOwner, this._burnerAddress); - return; - } else if ( - (userAddress !== tokenOwner && desiredBalance.lt(1)) || - (tokenOwner === userAddress && desiredBalance.gte(1)) - ) { - return; // noop - } - break; - } - case AssetProxyId.ERC1155: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const assetProxyWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC1155ProxyWrapper; - const [ - // tslint:disable-next-line:no-unused-variable - tokenAddress, - tokenIds, - tokenValues, - ] = decodeERC1155AssetData(assetData); - const assetWrapper = assetProxyWrapper.getContractWrapper(tokenAddress); - const tokenValuesSum = BigNumber.sum(...tokenValues); - let tokenValueRatios = tokenValues; - if (!tokenValuesSum.eq(0)) { - tokenValueRatios = tokenValues.map(v => v.div(tokenValuesSum)); - } - for (const i of _.times(tokenIds.length)) { - const tokenId = tokenIds[i]; - const tokenValueRatio = tokenValueRatios[i]; - const scaledDesiredBalance = desiredBalance.times(tokenValueRatio); - const isFungible = await assetWrapper.isFungibleItemAsync(tokenId); - if (isFungible) { - // Token is fungible. - const currentBalance = await assetWrapper.getBalanceAsync(userAddress, tokenId); - const difference = scaledDesiredBalance - .minus(currentBalance) - .integerValue(BigNumber.ROUND_DOWN); - if (difference.eq(0)) { - // Just right. Nothing to do. - } else if (difference.lt(0)) { - // Too much. Burn some tokens. - await assetWrapper.safeTransferFromAsync( - userAddress, - this._burnerAddress, - tokenId, - difference.abs(), - ); - } else { - // difference.gt(0) - // Too little. Mint some tokens. - await assetWrapper.mintKnownFungibleTokensAsync(tokenId, [userAddress], [difference]); - } - } else { - const nftOwner = await assetWrapper.getOwnerOfAsync(tokenId); - if (scaledDesiredBalance.gte(1)) { - if (nftOwner === userAddress) { - // Nothing to do. - } else if (nftOwner !== constants.NULL_ADDRESS) { - // Transfer from current owner. - await assetWrapper.safeTransferFromAsync(nftOwner, userAddress, tokenId, ONE_NFT_UNIT); - } else { - throw new Error(`Cannot mint new ERC1155 tokens with a specific token ID.`); - } - } else { - if (nftOwner === userAddress) { - // Burn the token. - await assetWrapper.safeTransferFromAsync( - userAddress, - this._burnerAddress, - tokenId, - ONE_NFT_UNIT, - ); - } else { - // Nothing to do. - } - } - } - } - break; - } - case AssetProxyId.MultiAsset: { - // tslint:disable-next-line:no-unused-variable - const [amounts, nestedAssetData] = decodeMultiAssetData(assetData); - const amountsSum = BigNumber.sum(...amounts); - let assetAmountRatios = amounts; - if (!amountsSum.eq(0)) { - assetAmountRatios = amounts.map(amt => amt.div(amountsSum)); - } - for (const i of _.times(amounts.length)) { - const assetAmountRatio = assetAmountRatios[i]; - await this.setBalanceAsync(userAddress, nestedAssetData[i], desiredBalance.times(assetAmountRatio)); - } - break; - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } - public async setUnscaledBalanceAsync( - userAddress: string, - assetData: string, - desiredBalance: BigNumber, - ): Promise { - const proxyId = getAssetDataProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: - case AssetProxyId.ERC721: - return this.setBalanceAsync(userAddress, assetData, desiredBalance); - case AssetProxyId.ERC1155: - case AssetProxyId.MultiAsset: { - const currentBalance = await this.getBalanceAsync(userAddress, assetData); - return this.setBalanceAsync(userAddress, assetData, desiredBalance.times(currentBalance)); - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } - public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise { - const proxyId = getAssetDataProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const erc20Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC20Wrapper; - const allowance = await erc20Wrapper.getProxyAllowanceAsync(userAddress, assetData); - return allowance; - } - case AssetProxyId.ERC721: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const assetWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - // tslint:disable-next-line:no-unused-variable - const [tokenAddress, tokenId] = decodeERC721AssetData(assetData); - const isProxyApprovedForAll = await assetWrapper.isProxyApprovedForAllAsync(userAddress, tokenAddress); - if (isProxyApprovedForAll) { - return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - } - - const isProxyApproved = await assetWrapper.isProxyApprovedAsync(tokenAddress, tokenId); - const allowance = isProxyApproved ? ONE_NFT_UNIT : ZERO_NFT_UNIT; - return allowance; - } - case AssetProxyId.ERC1155: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const assetProxyWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC1155ProxyWrapper; - // tslint:disable-next-line:no-unused-variable - const [tokenAddress] = decodeERC1155AssetData(assetData); - const isApprovedForAll = await assetProxyWrapper.isProxyApprovedForAllAsync(userAddress, tokenAddress); - if (!isApprovedForAll) { - // ERC1155 is all or nothing. - return constants.ZERO_AMOUNT; - } - return constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - } - case AssetProxyId.MultiAsset: { - // tslint:disable-next-line:no-unused-variable - const [amounts, nestedAssetData] = decodeMultiAssetData(assetData); - const allowances = await Promise.all( - nestedAssetData.map(async _nestedAssetData => - this.getProxyAllowanceAsync(userAddress, _nestedAssetData), - ), - ); - return BigNumber.min(...allowances); - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } - public async setProxyAllowanceAsync( - userAddress: string, - assetData: string, - desiredAllowance: BigNumber, - ): Promise { - const proxyId = getAssetDataProxyId(assetData); - switch (proxyId) { - case AssetProxyId.ERC20: { - // tslint:disable-next-line:no-unnecessary-type-assertion - 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}`, - ); - } - // tslint:disable-next-line:no-unnecessary-type-assertion - const erc721Wrapper = this._proxyIdToAssetWrappers[proxyId] as ERC721Wrapper; - // tslint:disable-next-line:no-unused-variable - const [tokenAddress, tokenId] = decodeERC721AssetData(assetData); - - const doesTokenExist = await erc721Wrapper.doesTokenExistAsync(tokenAddress, tokenId); - if (!doesTokenExist) { - throw new Error(`Cannot setProxyAllowance on non-existent token: ${tokenAddress} ${tokenId}`); - } - const isProxyApprovedForAll = await erc721Wrapper.isProxyApprovedForAllAsync(userAddress, tokenAddress); - if (!isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - const isApproved = true; - await erc721Wrapper.approveProxyForAllAsync(tokenAddress, userAddress, isApproved); - } else if (isProxyApprovedForAll && desiredAllowance.eq(0)) { - const isApproved = false; - await erc721Wrapper.approveProxyForAllAsync(tokenAddress, userAddress, isApproved); - } else if (isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - return; // Noop - } - - const isProxyApproved = await erc721Wrapper.isProxyApprovedAsync(tokenAddress, tokenId); - if (!isProxyApproved && desiredAllowance.eq(1)) { - await erc721Wrapper.approveProxyAsync(tokenAddress, tokenId); - } else if (isProxyApproved && desiredAllowance.eq(0)) { - // Remove approval - await erc721Wrapper.approveAsync(constants.NULL_ADDRESS, tokenAddress, tokenId); - } else if ( - (!isProxyApproved && desiredAllowance.eq(0)) || - (isProxyApproved && desiredAllowance.eq(1)) - ) { - // noop - } - break; - } - case AssetProxyId.ERC1155: { - // tslint:disable-next-line:no-unnecessary-type-assertion - const assetProxyWrapper = this._proxyIdToAssetWrappers[proxyId] as ERC1155ProxyWrapper; - // tslint:disable-next-line:no-unused-variable - const [tokenAddress] = decodeERC1155AssetData(assetData); - // ERC1155 allowances are all or nothing. - const shouldApprovedForAll = desiredAllowance.gt(0); - const currentAllowance = await this.getProxyAllowanceAsync(userAddress, assetData); - if (shouldApprovedForAll && currentAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - // Nothing to do. - } else if (!shouldApprovedForAll && currentAllowance.eq(constants.ZERO_AMOUNT)) { - // Nothing to do. - } else { - assetProxyWrapper.setProxyAllowanceForAllAsync(userAddress, tokenAddress, shouldApprovedForAll); - } - break; - } - case AssetProxyId.MultiAsset: { - // tslint:disable-next-line:no-unused-variable - const [amounts, nestedAssetData] = decodeMultiAssetData(assetData); - await Promise.all( - nestedAssetData.map(async _nestedAssetData => - this.setProxyAllowanceAsync(userAddress, _nestedAssetData, desiredAllowance), - ), - ); - break; - } - default: - throw errorUtils.spawnSwitchErr('proxyId', proxyId); - } - } -} diff --git a/contracts/exchange/test/utils/constants.ts b/contracts/exchange/test/utils/constants.ts deleted file mode 100644 index 903ebe75c0..0000000000 --- a/contracts/exchange/test/utils/constants.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ExchangeFunctionName } from '@0x/contracts-test-utils'; - -export const constants = { - // These are functions not secured by the `nonReentrant`, directly or - // indirectly (by calling a function that has the modifier). - REENTRANT_FUNCTIONS: [ - ExchangeFunctionName.BatchExecuteTransactions, - ExchangeFunctionName.ExecuteTransaction, - ExchangeFunctionName.RegisterAssetProxy, - ExchangeFunctionName.SimulateDispatchTransferFromCalls, - ExchangeFunctionName.TransferOwnership, - ExchangeFunctionName.SetProtocolFeeMultiplier, - ExchangeFunctionName.SetProtocolFeeCollectorAddress, - ExchangeFunctionName.DetachProtocolFeeCollector, - ], -}; diff --git a/contracts/exchange/test/utils/dependency_artifacts.ts b/contracts/exchange/test/utils/dependency_artifacts.ts deleted file mode 100644 index 3e0eb253da..0000000000 --- a/contracts/exchange/test/utils/dependency_artifacts.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { artifacts as erc1155Artifacts } from '@0x/contracts-erc1155'; -import { artifacts as erc20Artifacts } from '@0x/contracts-erc20'; -import { artifacts as erc721Artifacts } from '@0x/contracts-erc721'; - -export const dependencyArtifacts = { - ...erc20Artifacts, - ...erc721Artifacts, - ...erc1155Artifacts, -}; diff --git a/contracts/exchange/test/utils/exchange_transfer_simulator.ts b/contracts/exchange/test/utils/exchange_transfer_simulator.ts deleted file mode 100644 index 7514564d3b..0000000000 --- a/contracts/exchange/test/utils/exchange_transfer_simulator.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { decodeMultiAssetData, getAssetDataProxyId } from '@0x/contracts-asset-proxy'; -import { constants } from '@0x/contracts-test-utils'; -import { AssetProxyId, ExchangeContractErrs } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store'; -import { TradeSide, TransferType } from './types'; - -enum FailureReason { - Balance = 'balance', - ProxyAllowance = 'proxyAllowance', -} - -const ERR_MSG_MAPPING = { - [FailureReason.Balance]: { - [TradeSide.Maker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerBalance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeBalance, - }, - [TradeSide.Taker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerBalance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeBalance, - }, - }, - [FailureReason.ProxyAllowance]: { - [TradeSide.Maker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientMakerAllowance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeAllowance, - }, - [TradeSide.Taker]: { - [TransferType.Trade]: ExchangeContractErrs.InsufficientTakerAllowance, - [TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeAllowance, - }, - }, -}; - -/** - * An exchange transfer simulator which simulates asset transfers exactly how the - * 0x exchange contract would do them. - */ -export class ExchangeTransferSimulator { - private readonly _store: AbstractBalanceAndProxyAllowanceLazyStore; - private static _throwValidationError( - failureReason: FailureReason, - tradeSide: TradeSide, - transferType: TransferType, - ): never { - const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; - throw new Error(errMsg); - } - /** - * Instantiate a ExchangeTransferSimulator - * @param store A class that implements AbstractBalanceAndProxyAllowanceLazyStore - * @return an instance of ExchangeTransferSimulator - */ - constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) { - this._store = store; - } - /** - * Simulates transferFrom call performed by a proxy - * @param assetData Data of the asset being transferred. Includes - * it's identifying information and assetType, - * e.g address for ERC20, address & tokenId for ERC721 - * @param from Owner of the transferred tokens - * @param to Recipient of the transferred tokens - * @param amountInBaseUnits The amount of tokens being transferred - * @param tradeSide Is Maker/Taker transferring - * @param transferType Is it a fee payment or a value transfer - */ - public async transferFromAsync( - assetData: string, - from: string, - to: string, - amountInBaseUnits: BigNumber, - tradeSide: TradeSide, - transferType: TransferType, - ): Promise { - const assetProxyId = getAssetDataProxyId(assetData); - switch (assetProxyId) { - case AssetProxyId.ERC1155: - case AssetProxyId.ERC20: - case AssetProxyId.ERC721: { - // HACK: When simulating an open order (e.g taker is NULL_ADDRESS), we don't want to adjust balances/ - // allowances for the taker. We do however, want to increase the balance of the maker since the maker - // might be relying on those funds to fill subsequent orders or pay the order's fees. - if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) { - await this._increaseBalanceAsync(assetData, to, amountInBaseUnits); - return; - } - const balance = await this._store.getBalanceAsync(assetData, from); - const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, from); - if (proxyAllowance.isLessThan(amountInBaseUnits)) { - ExchangeTransferSimulator._throwValidationError( - FailureReason.ProxyAllowance, - tradeSide, - transferType, - ); - } - if (balance.isLessThan(amountInBaseUnits)) { - ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType); - } - if (assetProxyId !== AssetProxyId.ERC1155) { - // No need to decrease allowance for ERC115 because it's all or nothing. - await this._decreaseProxyAllowanceAsync(assetData, from, amountInBaseUnits); - } - await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits); - await this._increaseBalanceAsync(assetData, to, amountInBaseUnits); - break; - } - case AssetProxyId.MultiAsset: { - const decodedAssetData = decodeMultiAssetData(assetData); - await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits); - await this._increaseBalanceAsync(assetData, to, amountInBaseUnits); - for (const [index, nestedAssetDataElement] of decodedAssetData[1].entries()) { - const amountsElement = decodedAssetData[0][index]; - const totalAmount = amountInBaseUnits.times(amountsElement); - await this.transferFromAsync( - nestedAssetDataElement, - from, - to, - totalAmount, - tradeSide, - transferType, - ); - } - break; - } - default: - throw new Error(`Unhandled asset proxy ID: ${assetProxyId}`); - } - } - private async _decreaseProxyAllowanceAsync( - assetData: string, - userAddress: string, - amountInBaseUnits: BigNumber, - ): Promise { - const proxyAllowance = await this._store.getProxyAllowanceAsync(assetData, userAddress); - // HACK: This code assumes that all tokens with an UNLIMITED_ALLOWANCE_IN_BASE_UNITS set, - // are UnlimitedAllowanceTokens. This is however not true, it just so happens that all - // DummyERC20Tokens we use in tests are. - if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { - this._store.setProxyAllowance(assetData, userAddress, proxyAllowance.minus(amountInBaseUnits)); - } - } - private async _increaseBalanceAsync( - assetData: string, - userAddress: string, - amountInBaseUnits: BigNumber, - ): Promise { - const balance = await this._store.getBalanceAsync(assetData, userAddress); - this._store.setBalance(assetData, userAddress, balance.plus(amountInBaseUnits)); - } - private async _decreaseBalanceAsync( - assetData: string, - userAddress: string, - amountInBaseUnits: BigNumber, - ): Promise { - const balance = await this._store.getBalanceAsync(assetData, userAddress); - this._store.setBalance(assetData, userAddress, balance.minus(amountInBaseUnits)); - } -} diff --git a/contracts/exchange/test/utils/exchange_wrapper.ts b/contracts/exchange/test/utils/exchange_wrapper.ts deleted file mode 100644 index 4baa6f6b0f..0000000000 --- a/contracts/exchange/test/utils/exchange_wrapper.ts +++ /dev/null @@ -1,356 +0,0 @@ -import { BatchMatchOrder, orderUtils } from '@0x/contracts-test-utils'; -import { - BatchMatchedFillResults, - FillResults, - MatchedFillResults, - OrderInfo, - SignedOrder, - SignedZeroExTransaction, -} from '@0x/types'; -import { AbiEncoder, BigNumber } from '@0x/utils'; -import { MethodAbi, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { ExchangeContract } from '../wrappers'; - -import { AbiDecodedFillOrderData } from './types'; - -export class ExchangeWrapper { - constructor(public readonly exchangeContract: ExchangeContract) {} - - public async fillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txReceipt = await this.exchangeContract - .fillOrder(params.order, params.takerAssetFillAmount, params.signature) - .awaitTransactionSuccessAsync({ from }); - return txReceipt; - } - public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise { - const params = orderUtils.createCancel(signedOrder); - const txReceipt = await this.exchangeContract.cancelOrder(params.order).awaitTransactionSuccessAsync({ from }); - return txReceipt; - } - public async fillOrKillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txReceipt = await this.exchangeContract - .fillOrKillOrder(params.order, params.takerAssetFillAmount, params.signature) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - return txReceipt; - } - public async batchFillOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {}, - ): Promise { - return this.exchangeContract - .batchFillOrders( - orders, - opts.takerAssetFillAmounts === undefined - ? orders.map(signedOrder => signedOrder.takerAssetAmount) - : opts.takerAssetFillAmounts, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async batchFillOrKillOrdersAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {}, - ): Promise { - return this.exchangeContract - .batchFillOrKillOrders( - orders, - opts.takerAssetFillAmounts === undefined - ? orders.map(signedOrder => signedOrder.takerAssetAmount) - : opts.takerAssetFillAmounts, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async batchFillOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number; gasPrice?: BigNumber } = {}, - ): Promise { - return this.exchangeContract - .batchFillOrdersNoThrow( - orders, - opts.takerAssetFillAmounts === undefined - ? orders.map(signedOrder => signedOrder.takerAssetAmount) - : opts.takerAssetFillAmounts, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gas: opts.gas, gasPrice: opts.gasPrice }); - } - public async marketSellOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber }, - ): Promise { - return this.exchangeContract - .marketSellOrdersNoThrow( - orders, - opts.takerAssetFillAmount, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gas: opts.gas, gasPrice: opts.gasPrice }); - } - public async marketBuyOrdersNoThrowAsync( - orders: SignedOrder[], - from: string, - opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber }, - ): Promise { - return this.exchangeContract - .marketBuyOrdersNoThrow( - orders, - opts.makerAssetFillAmount, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gas: opts.gas }); - } - public async marketSellOrdersFillOrKillAsync( - orders: SignedOrder[], - from: string, - opts: { takerAssetFillAmount: BigNumber; gas?: number }, - ): Promise { - return this.exchangeContract - .marketSellOrdersFillOrKill( - orders, - opts.takerAssetFillAmount, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gas: opts.gas }); - } - public async marketBuyOrdersFillOrKillAsync( - orders: SignedOrder[], - from: string, - opts: { makerAssetFillAmount: BigNumber; gas?: number }, - ): Promise { - return this.exchangeContract - .marketBuyOrdersFillOrKill( - orders, - opts.makerAssetFillAmount, - orders.map(signedOrder => signedOrder.signature), - ) - .awaitTransactionSuccessAsync({ from, gas: opts.gas }); - } - public async batchCancelOrdersAsync( - orders: SignedOrder[], - from: string, - ): Promise { - return this.exchangeContract.batchCancelOrders(orders).awaitTransactionSuccessAsync({ from }); - } - public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise { - const txReceipt = await this.exchangeContract.cancelOrdersUpTo(salt).awaitTransactionSuccessAsync({ from }); - return txReceipt; - } - public async registerAssetProxyAsync( - assetProxyAddress: string, - from: string, - ): Promise { - const txReceipt = await this.exchangeContract - .registerAssetProxy(assetProxyAddress) - .awaitTransactionSuccessAsync({ - from, - }); - return txReceipt; - } - public async executeTransactionAsync( - signedTransaction: SignedZeroExTransaction, - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - return this.exchangeContract - .executeTransaction(signedTransaction, signedTransaction.signature) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async batchExecuteTransactionsAsync( - signedTransactions: SignedZeroExTransaction[], - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const signatures = signedTransactions.map(signedTransaction => signedTransaction.signature); - return this.exchangeContract - .batchExecuteTransactions(signedTransactions, signatures) - .awaitTransactionSuccessAsync({ - from, - gasPrice: opts.gasPrice, - }); - } - public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise { - const filledAmount = await this.exchangeContract.filled(orderHashHex).callAsync(); - return filledAmount; - } - public async isCancelledAsync(orderHashHex: string): Promise { - const isCancelled = await this.exchangeContract.cancelled(orderHashHex).callAsync(); - return isCancelled; - } - public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise { - const orderEpoch = await this.exchangeContract.orderEpoch(makerAddress, senderAddress).callAsync(); - return orderEpoch; - } - public async getOrderInfoAsync(signedOrder: SignedOrder): Promise { - const orderInfo = await this.exchangeContract.getOrderInfo(signedOrder).callAsync(); - return orderInfo; - } - public async batchMatchOrdersAsync( - signedOrdersLeft: SignedOrder[], - signedOrdersRight: SignedOrder[], - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight); - return this.exchangeContract - .batchMatchOrders(params.leftOrders, params.rightOrders, params.leftSignatures, params.rightSignatures) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async batchMatchOrdersRawAsync( - params: BatchMatchOrder, - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - return this.exchangeContract - .batchMatchOrders(params.leftOrders, params.rightOrders, params.leftSignatures, params.rightSignatures) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async getBatchMatchOrdersResultsAsync( - signedOrdersLeft: SignedOrder[], - signedOrdersRight: SignedOrder[], - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight); - const batchMatchedFillResults = await this.exchangeContract - .batchMatchOrders(params.leftOrders, params.rightOrders, params.leftSignatures, params.rightSignatures) - .callAsync({ from, gasPrice: opts.gasPrice }); - return batchMatchedFillResults; - } - public async batchMatchOrdersWithMaximalFillAsync( - signedOrdersLeft: SignedOrder[], - signedOrdersRight: SignedOrder[], - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight); - return this.exchangeContract - .batchMatchOrdersWithMaximalFill( - params.leftOrders, - params.rightOrders, - params.leftSignatures, - params.rightSignatures, - ) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async batchMatchOrdersWithMaximalFillRawAsync( - params: BatchMatchOrder, - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - return this.exchangeContract - .batchMatchOrdersWithMaximalFill( - params.leftOrders, - params.rightOrders, - params.leftSignatures, - params.rightSignatures, - ) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async getBatchMatchOrdersWithMaximalFillResultsAsync( - signedOrdersLeft: SignedOrder[], - signedOrdersRight: SignedOrder[], - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight); - const batchMatchedFillResults = await this.exchangeContract - .batchMatchOrdersWithMaximalFill( - params.leftOrders, - params.rightOrders, - params.leftSignatures, - params.rightSignatures, - ) - .callAsync({ from, gasPrice: opts.gasPrice }); - return batchMatchedFillResults; - } - public async matchOrdersAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - const txReceipt = await this.exchangeContract - .matchOrders(params.left, params.right, params.leftSignature, params.rightSignature) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - return txReceipt; - } - public async getMatchOrdersResultsAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - const matchedFillResults = await this.exchangeContract - .matchOrders(params.left, params.right, params.leftSignature, params.rightSignature) - .callAsync({ from, gasPrice: opts.gasPrice }); - return matchedFillResults; - } - public async matchOrdersWithMaximalFillAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - from: string, - opts: { gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - return this.exchangeContract - .matchOrdersWithMaximalFill(params.left, params.right, params.leftSignature, params.rightSignature) - .awaitTransactionSuccessAsync({ from, gasPrice: opts.gasPrice }); - } - public async getMatchOrdersWithMaximalFillResultsAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - from: string, - opts: { gasPrice?: BigNumber }, - ): Promise { - const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - const matchedFillResults = await this.exchangeContract - .matchOrdersWithMaximalFill(params.left, params.right, params.leftSignature, params.rightSignature) - .callAsync({ from, gasPrice: opts.gasPrice }); - return matchedFillResults; - } - public async getFillOrderResultsAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {}, - ): Promise { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const fillResults = await this.exchangeContract - .fillOrder(params.order, params.takerAssetFillAmount, params.signature) - .callAsync({ from, gasPrice: opts.gasPrice }); - return fillResults; - } - public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const data = this.exchangeContract - .fillOrder(params.order, params.takerAssetFillAmount, params.signature) - .getABIEncodedTransactionData(); - return data; - } - public abiDecodeFillOrder(data: string): AbiDecodedFillOrderData { - // Lookup fillOrder ABI in exchange abi - const fillOrderAbi = _.find(this.exchangeContract.abi, { name: 'fillOrder' }) as MethodAbi; - // Decode input data - const abiEncoder = new AbiEncoder.Method(fillOrderAbi); - const decodedData = abiEncoder.decode(data) as AbiDecodedFillOrderData; - return decodedData; - } -} diff --git a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts deleted file mode 100644 index 2a8c3f0ba9..0000000000 --- a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts +++ /dev/null @@ -1,1040 +0,0 @@ -import { - artifacts as assetProxyArtifacts, - ERC1155ProxyWrapper, - ERC20Wrapper, - ERC721Wrapper, - MultiAssetProxyContract, -} from '@0x/contracts-asset-proxy'; -import { constants, expect, LogDecoder, orderHashUtils, orderUtils, signingUtils } from '@0x/contracts-test-utils'; -import { FillResults, Order, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber, errorUtils, ExchangeRevertErrors, providerUtils, RevertError, StringRevertError } from '@0x/utils'; -import { SupportedProvider, Web3Wrapper } from '@0x/web3-wrapper'; -import { LogWithDecodedArgs, TxData } from 'ethereum-types'; -import * as _ from 'lodash'; -import 'make-promises-safe'; - -import { artifacts } from '../artifacts'; - -import { ExchangeContract, ExchangeFillEventArgs } from '../wrappers'; - -import { AssetWrapper } from './asset_wrapper'; -import { ExchangeWrapper } from './exchange_wrapper'; -import { - AllowanceAmountScenario, - AssetDataScenario, - BalanceAmountScenario, - ExpirationTimeSecondsScenario, - FeeAssetDataScenario, - FeeRecipientAddressScenario, - FillScenario, - OrderAssetAmountScenario, - OrderScenario, - TakerAssetFillAmountScenario, - TakerScenario, -} from './fill_order_scenarios'; -import { FillOrderError, FillOrderSimulator } from './fill_order_simulator'; -import { OrderFactoryFromScenario } from './order_factory_from_scenario'; -import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher'; -import { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store'; - -const EMPTY_FILL_RESULTS = { - takerAssetFilledAmount: constants.ZERO_AMOUNT, - makerAssetFilledAmount: constants.ZERO_AMOUNT, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: constants.ZERO_AMOUNT, -}; - -enum TestOutlook { - Any, - Success, - Failure, -} - -/** - * 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, -): Promise { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const userAddresses = _.slice(accounts, 0, 5); - const [ownerAddress, makerAddress, takerAddress, burnerAddress] = userAddresses; - const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(makerAddress)]; - - const supportedProvider = web3Wrapper.getProvider(); - const provider = providerUtils.standardizeOrThrow(supportedProvider); - const chainId = await providerUtils.getChainIdAsync(provider); - const erc20Wrapper = new ERC20Wrapper(provider, userAddresses, ownerAddress); - const erc721Wrapper = new ERC721Wrapper(provider, userAddresses, ownerAddress); - const erc1155Wrapper = new ERC1155ProxyWrapper(provider, userAddresses, ownerAddress); - - const erc20EighteenDecimalTokenCount = 4; - const eighteenDecimals = new BigNumber(18); - const erc20EighteenDecimalTokens = await erc20Wrapper.deployDummyTokensAsync( - erc20EighteenDecimalTokenCount, - eighteenDecimals, - ); - - const erc20FiveDecimalTokenCount = 4; - const fiveDecimals = new BigNumber(5); - const erc20FiveDecimalTokens = await erc20Wrapper.deployDummyTokensAsync(erc20FiveDecimalTokenCount, fiveDecimals); - - const erc20ZeroDecimalTokenCount = 4; - const zeroDecimals = new BigNumber(0); - const erc20ZeroDecimalTokens = 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 [erc1155Token] = (await erc1155Wrapper.deployDummyContractsAsync()).map(w => w.getContract()); - const erc1155Proxy = await erc1155Wrapper.deployProxyAsync(); - await erc1155Wrapper.setBalancesAndAllowancesAsync(); - const erc1155Holdings = await erc1155Wrapper.getBalancesAsync(); - - const multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.MultiAssetProxy, - provider, - txDefaults, - {}, - ); - - const assetWrapper = new AssetWrapper([erc20Wrapper, erc721Wrapper, erc1155Wrapper], burnerAddress); - - const exchangeContract = await ExchangeContract.deployFrom0xArtifactAsync( - artifacts.Exchange, - provider, - txDefaults, - {}, - new BigNumber(chainId), - ); - - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const exchangeWrapper = new ExchangeWrapper(exchangeContract); - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress); - await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, ownerAddress); - await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, ownerAddress); - await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, ownerAddress); - - await erc20Proxy.addAuthorizedAddress(exchangeContract.address).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - - await erc721Proxy.addAuthorizedAddress(exchangeContract.address).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - - await erc1155Proxy.addAuthorizedAddress(exchangeContract.address).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - - await multiAssetProxy.addAuthorizedAddress(exchangeContract.address).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - - await erc20Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: ownerAddress }); - - await erc721Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - - await erc1155Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ - from: ownerAddress, - }); - - await multiAssetProxy.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ from: ownerAddress }); - - await multiAssetProxy.registerAssetProxy(erc721Proxy.address).awaitTransactionSuccessAsync({ from: ownerAddress }); - - await multiAssetProxy.registerAssetProxy(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: ownerAddress }); - - const orderFactory = new OrderFactoryFromScenario( - userAddresses, - erc20EighteenDecimalTokens.map(token => token.address), - erc20FiveDecimalTokens.map(token => token.address), - erc20ZeroDecimalTokens.map(token => token.address), - erc721Token.address, - erc1155Token.address, - erc721Balances, - erc1155Holdings, - exchangeContract.address, - chainId, - ); - - const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils( - web3Wrapper.getProvider(), - orderFactory, - ownerAddress, - makerAddress, - makerPrivateKey, - takerAddress, - exchangeWrapper, - assetWrapper, - logDecoder, - ); - return fillOrderCombinatorialUtils; -} - -export class FillOrderCombinatorialUtils { - public provider: SupportedProvider; - public orderFactory: OrderFactoryFromScenario; - public ownerAddress: string; - public makerAddress: string; - public makerPrivateKey: Buffer; - public takerAddress: string; - public exchangeWrapper: ExchangeWrapper; - public assetWrapper: AssetWrapper; - public logDecoder: LogDecoder; - public balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher; - - public static generateFillOrderCombinations(): FillScenario[] { - const takerScenarios = [ - TakerScenario.Unspecified, - // TakerScenario.CorrectlySpecified, - // TakerScenario.IncorrectlySpecified, - ]; - const feeRecipientScenarios = [ - FeeRecipientAddressScenario.EthUserAddress, - FeeRecipientAddressScenario.MakerAddress, - FeeRecipientAddressScenario.TakerAddress, - // 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 = [ - // FeeAssetDataScenario.ERC20ZeroDecimals, - // AssetDataScenario.ERC20FiveDecimals, - AssetDataScenario.ERC20EighteenDecimals, - AssetDataScenario.ERC721, - AssetDataScenario.ERC1155Fungible, - AssetDataScenario.ERC1155NonFungible, - AssetDataScenario.MultiAssetERC20, - ]; - const takerAssetDataScenario = [ - // FeeAssetDataScenario.ERC20ZeroDecimals, - // AssetDataScenario.ERC20FiveDecimals, - AssetDataScenario.ERC20EighteenDecimals, - AssetDataScenario.ERC721, - AssetDataScenario.ERC1155Fungible, - AssetDataScenario.ERC1155NonFungible, - AssetDataScenario.MultiAssetERC20, - ]; - const makerFeeAssetDataScenario = [ - // FeeAssetDataScenario.ERC20ZeroDecimals, - // FeeAssetDataScenario.ERC20FiveDecimals, - FeeAssetDataScenario.ERC20EighteenDecimals, - FeeAssetDataScenario.ERC721, - FeeAssetDataScenario.ERC1155Fungible, - FeeAssetDataScenario.ERC1155NonFungible, - FeeAssetDataScenario.MultiAssetERC20, - FeeAssetDataScenario.MakerToken, - FeeAssetDataScenario.TakerToken, - ]; - const takerFeeAssetDataScenario = [ - // FeeAssetDataScenario.ERC20ZeroDecimals, - // FeeAssetDataScenario.ERC20FiveDecimals, - FeeAssetDataScenario.ERC20EighteenDecimals, - FeeAssetDataScenario.ERC721, - FeeAssetDataScenario.ERC1155Fungible, - FeeAssetDataScenario.ERC1155NonFungible, - FeeAssetDataScenario.MultiAssetERC20, - FeeAssetDataScenario.MakerToken, - FeeAssetDataScenario.TakerToken, - ]; - const takerAssetFillAmountScenario = [ - TakerAssetFillAmountScenario.ExactlyTakerAssetAmount, - // TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount, - // TakerAssetFillAmountScenario.LessThanTakerAssetAmount, - ]; - const makerAssetBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - // BalanceAmountScenario.Zero, - ]; - const makerAssetAllowanceScenario = [ - // AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - AllowanceAmountScenario.Unlimited, - // AllowanceAmountScenario.Zero, - ]; - const makerFeeBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - // BalanceAmountScenario.Zero, - ]; - const makerFeeAllowanceScenario = [ - // AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - AllowanceAmountScenario.Unlimited, - // AllowanceAmountScenario.Zero, - ]; - const takerAssetBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - // BalanceAmountScenario.Zero, - ]; - const takerAssetAllowanceScenario = [ - // AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - AllowanceAmountScenario.Unlimited, - // AllowanceAmountScenario.Zero, - ]; - const takerFeeBalanceScenario = [ - BalanceAmountScenario.Higher, - // BalanceAmountScenario.Exact, - // BalanceAmountScenario.TooLow, - // BalanceAmountScenario.Zero, - ]; - const takerFeeAllowanceScenario = [ - // AllowanceAmountScenario.Higher, - // AllowanceAmountScenario.Exact, - // AllowanceAmountScenario.TooLow, - AllowanceAmountScenario.Unlimited, - // AllowanceAmountScenario.Zero, - ]; - const fillScenarioArrays = FillOrderCombinatorialUtils._getAllCombinations([ - takerScenarios, - feeRecipientScenarios, - makerAssetAmountScenario, - takerAssetAmountScenario, - makerFeeScenario, - takerFeeScenario, - expirationTimeSecondsScenario, - makerAssetDataScenario, - takerAssetDataScenario, - makerFeeAssetDataScenario, - takerFeeAssetDataScenario, - takerAssetFillAmountScenario, - makerAssetBalanceScenario, - makerAssetAllowanceScenario, - makerFeeBalanceScenario, - makerFeeAllowanceScenario, - takerAssetBalanceScenario, - takerAssetAllowanceScenario, - takerFeeBalanceScenario, - takerFeeAllowanceScenario, - ]); - - 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, - makerFeeAssetDataScenario: fillScenarioArray[9] as FeeAssetDataScenario, - takerFeeAssetDataScenario: fillScenarioArray[10] as FeeAssetDataScenario, - }, - takerAssetFillAmountScenario: fillScenarioArray[11] as TakerAssetFillAmountScenario, - makerStateScenario: { - traderAssetBalance: fillScenarioArray[12] as BalanceAmountScenario, - traderAssetAllowance: fillScenarioArray[13] as AllowanceAmountScenario, - feeBalance: fillScenarioArray[14] as BalanceAmountScenario, - feeAllowance: fillScenarioArray[15] as AllowanceAmountScenario, - }, - takerStateScenario: { - traderAssetBalance: fillScenarioArray[16] as BalanceAmountScenario, - traderAssetAllowance: fillScenarioArray[17] as AllowanceAmountScenario, - feeBalance: fillScenarioArray[18] as BalanceAmountScenario, - feeAllowance: fillScenarioArray[19] 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( - provider: SupportedProvider, - orderFactory: OrderFactoryFromScenario, - ownerAddress: string, - makerAddress: string, - makerPrivateKey: Buffer, - takerAddress: string, - exchangeWrapper: ExchangeWrapper, - assetWrapper: AssetWrapper, - logDecoder: LogDecoder, - ) { - this.provider = provider; - this.orderFactory = orderFactory; - this.ownerAddress = ownerAddress; - this.makerAddress = makerAddress; - this.makerPrivateKey = makerPrivateKey; - this.takerAddress = takerAddress; - this.exchangeWrapper = exchangeWrapper; - this.assetWrapper = assetWrapper; - this.logDecoder = logDecoder; - this.balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(assetWrapper); - } - - public async testFillOrderScenarioAsync(fillScenario: FillScenario): Promise { - return this._testFillOrderScenarioAsync(fillScenario, TestOutlook.Any); - } - - public async testFillOrderScenarioSuccessAsync(fillScenario: FillScenario): Promise { - return this._testFillOrderScenarioAsync(fillScenario, TestOutlook.Success); - } - - public async testFillOrderScenarioFailureAsync( - fillScenario: FillScenario, - fillErrorIfExists?: FillOrderError, - ): Promise { - return this._testFillOrderScenarioAsync(fillScenario, TestOutlook.Failure, fillErrorIfExists); - } - - private async _testFillOrderScenarioAsync( - fillScenario: FillScenario, - expectedTestResult: TestOutlook = TestOutlook.Any, - fillErrorIfExists?: FillOrderError, - ): Promise { - const lazyStore = new BalanceAndProxyAllowanceLazyStore(this.balanceAndProxyAllowanceFetcher); - const signedOrder = await this._generateSignedOrderAsync(fillScenario.orderScenario); - const takerAssetFillAmount = getTakerAssetFillAmount(signedOrder, fillScenario); - - await this._modifyTraderStateAsync(fillScenario, signedOrder, takerAssetFillAmount); - - let expectedFillResults = EMPTY_FILL_RESULTS; - let _fillErrorIfExists = fillErrorIfExists; - if (expectedTestResult !== TestOutlook.Failure || fillErrorIfExists === undefined) { - try { - expectedFillResults = await this._simulateFillOrderAsync(signedOrder, takerAssetFillAmount, lazyStore); - } catch (err) { - _fillErrorIfExists = err.message; - if (expectedTestResult === TestOutlook.Success) { - throw new Error(`Expected fillOrder() to succeed, but would fail with ${err.message}`); - } - } - } - - await this._fillOrderAndAssertOutcomeAsync( - signedOrder, - takerAssetFillAmount, - lazyStore, - expectedFillResults, - _fillErrorIfExists as any, - ); - } - - private async _generateSignedOrderAsync(orderScenario: OrderScenario): Promise { - const order = await this.orderFactory.generateOrderAsync(orderScenario); - const orderHashBuff = orderHashUtils.getOrderHashBuffer(order); - const signature = signingUtils.signMessage(orderHashBuff, this.makerPrivateKey, SignatureType.EthSign); - const signedOrder = { - ...order, - signature: `0x${signature.toString('hex')}`, - }; - return signedOrder; - } - - private async _simulateFillOrderAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - lazyStore: BalanceAndProxyAllowanceLazyStore, - ): Promise { - const simulator = new FillOrderSimulator(lazyStore); - return simulator.simulateFillOrderAsync(signedOrder, this.takerAddress, takerAssetFillAmount); - } - - private async _fillOrderAndAssertOutcomeAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - lazyStore: BalanceAndProxyAllowanceLazyStore, - expectedFillResults: FillResults, - fillErrorIfExists?: FillOrderError, - ): Promise { - if (fillErrorIfExists !== undefined) { - const tx = this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { takerAssetFillAmount }); - const revertError = fillErrorToRevertError(signedOrder, fillErrorIfExists); - return expect(tx).to.revertWith(revertError); - } - - const makerAddress = signedOrder.makerAddress; - const makerAssetData = signedOrder.makerAssetData; - const takerAssetData = signedOrder.takerAssetData; - const makerFeeAssetData = signedOrder.makerAssetData; - const takerFeeAssetData = signedOrder.takerAssetData; - const feeRecipient = signedOrder.feeRecipientAddress; - - const [ - expMakerAssetBalanceOfMaker, - expMakerAssetAllowanceOfMaker, - expTakerAssetBalanceOfMaker, - expMakerFeeAssetBalanceOfMaker, - expTakerFeeAssetBalanceOfMaker, - expMakerFeeAssetAllowanceOfMaker, - expTakerAssetBalanceOfTaker, - expTakerAssetAllowanceOfTaker, - expMakerAssetBalanceOfTaker, - expMakerFeeAssetBalanceOfTaker, - expTakerFeeAssetBalanceOfTaker, - expTakerFeeAssetAllowanceOfTaker, - expMakerFeeAssetBalanceOfFeeRecipient, - expTakerFeeAssetBalanceOfFeeRecipient, - ] = await Promise.all([ - lazyStore.getBalanceAsync(makerAssetData, makerAddress), - lazyStore.getProxyAllowanceAsync(makerAssetData, makerAddress), - lazyStore.getBalanceAsync(takerAssetData, makerAddress), - lazyStore.getBalanceAsync(makerFeeAssetData, makerAddress), - lazyStore.getBalanceAsync(takerFeeAssetData, makerAddress), - lazyStore.getProxyAllowanceAsync(makerFeeAssetData, makerAddress), - lazyStore.getBalanceAsync(takerAssetData, this.takerAddress), - lazyStore.getProxyAllowanceAsync(takerAssetData, this.takerAddress), - lazyStore.getBalanceAsync(makerAssetData, this.takerAddress), - lazyStore.getBalanceAsync(makerFeeAssetData, this.takerAddress), - lazyStore.getBalanceAsync(takerFeeAssetData, this.takerAddress), - lazyStore.getProxyAllowanceAsync(takerFeeAssetData, this.takerAddress), - lazyStore.getBalanceAsync(makerFeeAssetData, feeRecipient), - lazyStore.getBalanceAsync(takerFeeAssetData, feeRecipient), - ]); - - const expFilledTakerAmount = expectedFillResults.takerAssetFilledAmount; - const expFilledMakerAmount = expectedFillResults.makerAssetFilledAmount; - const expMakerFeePaid = expectedFillResults.makerFeePaid; - const expTakerFeePaid = expectedFillResults.takerFeePaid; - - const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, { - takerAssetFillAmount, - }); - - expect(fillResults.takerAssetFilledAmount, 'takerAssetFilledAmount').to.be.bignumber.equal( - expFilledTakerAmount, - ); - expect(fillResults.makerAssetFilledAmount, 'makerAssetFilledAmount').to.be.bignumber.equal( - expFilledMakerAmount, - ); - expect(fillResults.takerFeePaid, 'takerFeePaid').to.be.bignumber.equal(expTakerFeePaid); - expect(fillResults.makerFeePaid, 'makerFeePaid').to.be.bignumber.equal(expMakerFeePaid); - - // - Let's fill the order! - const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { - takerAssetFillAmount, - }); - - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const [ - actFilledTakerAmount, - actMakerAssetBalanceOfMaker, - actMakerAssetAllowanceOfMaker, - actTakerAssetBalanceOfMaker, - actMakerFeeAssetBalanceOfMaker, - actMakerFeeAssetAllowanceOfMaker, - actTakerFeeAssetBalanceOfMaker, - actTakerAssetBalanceOfTaker, - actTakerAssetAllowanceOfTaker, - actMakerAssetBalanceOfTaker, - actMakerFeeAssetBalanceOfTaker, - actTakerFeeAssetBalanceOfTaker, - actTakerFeeAssetAllowanceOfTaker, - actMakerFeeAssetBalanceOfFeeRecipient, - actTakerFeeAssetBalanceOfFeeRecipient, - ] = await Promise.all([ - this.exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash), - this.assetWrapper.getBalanceAsync(makerAddress, makerAssetData), - this.assetWrapper.getProxyAllowanceAsync(makerAddress, makerAssetData), - this.assetWrapper.getBalanceAsync(makerAddress, takerAssetData), - this.assetWrapper.getBalanceAsync(makerAddress, makerFeeAssetData), - this.assetWrapper.getProxyAllowanceAsync(makerAddress, makerFeeAssetData), - this.assetWrapper.getBalanceAsync(makerAddress, takerFeeAssetData), - this.assetWrapper.getBalanceAsync(this.takerAddress, takerAssetData), - this.assetWrapper.getProxyAllowanceAsync(this.takerAddress, takerAssetData), - this.assetWrapper.getBalanceAsync(this.takerAddress, makerAssetData), - this.assetWrapper.getBalanceAsync(this.takerAddress, makerFeeAssetData), - this.assetWrapper.getBalanceAsync(this.takerAddress, takerFeeAssetData), - this.assetWrapper.getProxyAllowanceAsync(this.takerAddress, takerFeeAssetData), - this.assetWrapper.getBalanceAsync(feeRecipient, makerFeeAssetData), - this.assetWrapper.getBalanceAsync(feeRecipient, takerFeeAssetData), - ]); - - expect(actFilledTakerAmount, 'filledTakerAmount').to.be.bignumber.equal(expFilledTakerAmount); - - const exchangeLogs = _.filter( - txReceipt.logs, - txLog => txLog.address === this.exchangeWrapper.exchangeContract.address, - ); - expect(exchangeLogs.length).to.be.equal(1, 'logs length'); - // tslint:disable-next-line:no-unnecessary-type-assertion - const log = exchangeLogs[0] as LogWithDecodedArgs; - expect(log.args.makerAddress, 'log.args.makerAddress').to.be.equal(makerAddress); - expect(log.args.takerAddress, 'log.args.takerAddress').to.be.equal(this.takerAddress); - expect(log.args.feeRecipientAddress, 'log.args.feeRecipientAddress').to.be.equal(feeRecipient); - expect(log.args.makerAssetFilledAmount, 'log.args.makerAssetFilledAmount').to.be.bignumber.equal( - expFilledMakerAmount, - ); - expect(log.args.takerAssetFilledAmount, 'log.args.takerAssetFilledAmount').to.be.bignumber.equal( - expFilledTakerAmount, - ); - expect(log.args.makerFeePaid, 'log.args.makerFeePaid').to.be.bignumber.equal(expMakerFeePaid); - expect(log.args.takerFeePaid, 'logs.args.takerFeePaid').to.be.bignumber.equal(expTakerFeePaid); - expect(log.args.orderHash, 'log.args.orderHash').to.be.equal(orderHash); - expect(log.args.makerAssetData, 'log.args.makerAssetData').to.be.equal(makerAssetData); - expect(log.args.takerAssetData, 'log.args.takerAssetData').to.be.equal(takerAssetData); - - expect(actMakerAssetBalanceOfMaker, 'makerAssetBalanceOfMaker').to.be.bignumber.equal( - expMakerAssetBalanceOfMaker, - ); - expect(actMakerAssetAllowanceOfMaker, 'makerAssetAllowanceOfMaker').to.be.bignumber.equal( - expMakerAssetAllowanceOfMaker, - ); - expect(actTakerAssetBalanceOfMaker, 'takerAssetBalanceOfMaker').to.be.bignumber.equal( - expTakerAssetBalanceOfMaker, - ); - expect(actMakerFeeAssetBalanceOfMaker, 'makerFeeAssetBalanceOfMaker').to.be.bignumber.equal( - expMakerFeeAssetBalanceOfMaker, - ); - expect(actMakerFeeAssetAllowanceOfMaker, 'makerFeeAssetAllowanceOfMaker').to.be.bignumber.equal( - expMakerFeeAssetAllowanceOfMaker, - ); - expect(actTakerFeeAssetBalanceOfMaker, 'takerFeeAssetBalanceOfMaker').to.be.bignumber.equal( - expTakerFeeAssetBalanceOfMaker, - ); - expect(actTakerAssetBalanceOfTaker, 'TakerAssetBalanceOfTaker').to.be.bignumber.equal( - expTakerAssetBalanceOfTaker, - ); - expect(actTakerAssetAllowanceOfTaker, 'takerAssetAllowanceOfTaker').to.be.bignumber.equal( - expTakerAssetAllowanceOfTaker, - ); - expect(actMakerAssetBalanceOfTaker, 'makerAssetBalanceOfTaker').to.be.bignumber.equal( - expMakerAssetBalanceOfTaker, - ); - expect(actMakerFeeAssetBalanceOfTaker, 'makerFeeAssetBalanceOfTaker').to.be.bignumber.equal( - expMakerFeeAssetBalanceOfTaker, - ); - expect(actTakerFeeAssetBalanceOfTaker, 'takerFeeAssetBalanceOfTaker').to.be.bignumber.equal( - expTakerFeeAssetBalanceOfTaker, - ); - expect(actTakerFeeAssetAllowanceOfTaker, 'takerFeeAssetAllowanceOfTaker').to.be.bignumber.equal( - expTakerFeeAssetAllowanceOfTaker, - ); - expect(actMakerFeeAssetBalanceOfFeeRecipient, 'makerFeeAssetBalanceOfFeeRecipient').to.be.bignumber.equal( - expMakerFeeAssetBalanceOfFeeRecipient, - ); - expect(actTakerFeeAssetBalanceOfFeeRecipient, 'takerFeeAssetBalanceOfFeeRecipient').to.be.bignumber.equal( - expTakerFeeAssetBalanceOfFeeRecipient, - ); - } - - private async _modifyTraderStateAsync( - fillScenario: FillScenario, - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - ): Promise { - const makerAssetFillAmount = orderUtils.getPartialAmountFloor( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - - const makerFee = orderUtils.getPartialAmountFloor( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.makerFee, - ); - - const takerFee = orderUtils.getPartialAmountFloor( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.takerFee, - ); - - let makerAssetBalance; - switch (fillScenario.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`); - } - makerAssetBalance = makerAssetFillAmount.minus(1); - break; - - case BalanceAmountScenario.Exact: - makerAssetBalance = makerAssetFillAmount; - break; - - case BalanceAmountScenario.Zero: - makerAssetBalance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'makerStateScenario.traderAssetBalance', - fillScenario.makerStateScenario.traderAssetBalance, - ); - } - if (makerAssetBalance !== undefined) { - await this.assetWrapper.setUnscaledBalanceAsync( - signedOrder.makerAddress, - signedOrder.makerAssetData, - makerAssetBalance, - ); - } - - let takerAssetBalance; - switch (fillScenario.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`); - } - takerAssetBalance = takerAssetFillAmount.minus(1); - break; - - case BalanceAmountScenario.Exact: - takerAssetBalance = takerAssetFillAmount; - break; - - case BalanceAmountScenario.Zero: - takerAssetBalance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'takerStateScenario.traderAssetBalance', - fillScenario.takerStateScenario.traderAssetBalance, - ); - } - if (takerAssetBalance !== undefined) { - await this.assetWrapper.setUnscaledBalanceAsync( - this.takerAddress, - signedOrder.takerAssetData, - takerAssetBalance, - ); - } - - const isMakerFeeAssetMakerAsset = - fillScenario.orderScenario.makerFeeAssetDataScenario === FeeAssetDataScenario.MakerToken; - let makerFeeBalance; - switch (fillScenario.makerStateScenario.feeBalance) { - case BalanceAmountScenario.Higher: - break; // Noop since this is already the default - - case BalanceAmountScenario.TooLow: - if (makerFee.eq(0)) { - throw new Error(`Cannot set makerFeeBalanceOfMaker TooLow if makerFee is 0`); - } - makerFeeBalance = makerFee.minus(1); - break; - - case BalanceAmountScenario.Exact: - makerFeeBalance = makerFee; - break; - - case BalanceAmountScenario.Zero: - makerFeeBalance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'makerStateScenario.feeBalance', - fillScenario.makerStateScenario.feeBalance, - ); - } - if (isMakerFeeAssetMakerAsset && makerFeeBalance !== undefined) { - await this.assetWrapper.setUnscaledBalanceAsync( - signedOrder.makerAddress, - signedOrder.makerFeeAssetData, - makerFeeBalance, - ); - } - - const isTakerFeeAssetTakerAsset = - fillScenario.orderScenario.takerFeeAssetDataScenario === FeeAssetDataScenario.TakerToken; - let takerFeeBalance; - switch (fillScenario.takerStateScenario.feeBalance) { - case BalanceAmountScenario.Higher: - break; // Noop since this is already the default - - case BalanceAmountScenario.TooLow: - if (takerFee.eq(0)) { - throw new Error(`Cannot set takerFeeBalanceOfTaker TooLow if takerFee is 0`); - } - takerFeeBalance = takerFee.minus(1); - break; - - case BalanceAmountScenario.Exact: - takerFeeBalance = takerFee; - break; - - case BalanceAmountScenario.Zero: - takerFeeBalance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'takerStateScenario.feeBalance', - fillScenario.takerStateScenario.feeBalance, - ); - } - if (isTakerFeeAssetTakerAsset && takerFeeBalance !== undefined) { - await this.assetWrapper.setUnscaledBalanceAsync( - this.takerAddress, - signedOrder.takerFeeAssetData, - takerFeeBalance, - ); - } - - let makerAssetAllowance; - switch (fillScenario.makerStateScenario.traderAssetAllowance) { - case AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - makerAssetAllowance = makerAssetFillAmount.minus(1); - break; - - case AllowanceAmountScenario.Exact: - makerAssetAllowance = makerAssetFillAmount; - break; - - case AllowanceAmountScenario.Unlimited: - makerAssetAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - break; - - case AllowanceAmountScenario.Zero: - makerAssetAllowance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'makerStateScenario.traderAssetAllowance', - fillScenario.makerStateScenario.traderAssetAllowance, - ); - } - if (makerAssetAllowance !== undefined) { - await this.assetWrapper.setProxyAllowanceAsync( - signedOrder.makerAddress, - signedOrder.makerAssetData, - makerAssetAllowance, - ); - } - - let takerAssetAllowance; - switch (fillScenario.takerStateScenario.traderAssetAllowance) { - case AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - takerAssetAllowance = takerAssetFillAmount.minus(1); - break; - - case AllowanceAmountScenario.Exact: - takerAssetAllowance = takerAssetFillAmount; - break; - - case AllowanceAmountScenario.Unlimited: - takerAssetAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - break; - - case AllowanceAmountScenario.Zero: - takerAssetAllowance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'takerStateScenario.traderAssetAllowance', - fillScenario.takerStateScenario.traderAssetAllowance, - ); - } - if (takerAssetAllowance !== undefined) { - await this.assetWrapper.setProxyAllowanceAsync( - this.takerAddress, - signedOrder.takerAssetData, - takerAssetAllowance, - ); - } - - let makerFeeAllowance; - switch (fillScenario.makerStateScenario.feeAllowance) { - case AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - makerFeeAllowance = makerFee.minus(1); - break; - - case AllowanceAmountScenario.Exact: - makerFeeAllowance = makerFee; - break; - - case AllowanceAmountScenario.Unlimited: - makerFeeAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - break; - - case AllowanceAmountScenario.Zero: - makerFeeAllowance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'makerStateScenario.feeAllowance', - fillScenario.makerStateScenario.feeAllowance, - ); - } - if (isMakerFeeAssetMakerAsset && makerFeeAllowance !== undefined) { - await this.assetWrapper.setProxyAllowanceAsync( - signedOrder.makerAddress, - signedOrder.makerFeeAssetData, - makerFeeAllowance, - ); - } - - let takerFeeAllowance; - switch (fillScenario.takerStateScenario.feeAllowance) { - case AllowanceAmountScenario.Higher: - break; // Noop since this is already the default - - case AllowanceAmountScenario.TooLow: - takerFeeAllowance = takerFee.minus(1); - break; - - case AllowanceAmountScenario.Exact: - takerFeeAllowance = takerFee; - break; - - case AllowanceAmountScenario.Unlimited: - takerFeeAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - break; - - case AllowanceAmountScenario.Zero: - takerFeeAllowance = constants.ZERO_AMOUNT; - break; - - default: - throw errorUtils.spawnSwitchErr( - 'takerStateScenario.feeAllowance', - fillScenario.takerStateScenario.feeAllowance, - ); - } - if (isTakerFeeAssetTakerAsset && takerFeeAllowance !== undefined) { - await this.assetWrapper.setProxyAllowanceAsync( - this.takerAddress, - signedOrder.takerFeeAssetData, - takerFeeAllowance, - ); - } - } -} - -function getTakerAssetFillAmount(signedOrder: SignedOrder, fillScenario: FillScenario): BigNumber { - let takerAssetFillAmount; - switch (fillScenario.takerAssetFillAmountScenario) { - case TakerAssetFillAmountScenario.Zero: - takerAssetFillAmount = new BigNumber(0); - break; - - case TakerAssetFillAmountScenario.ExactlyTakerAssetAmount: - takerAssetFillAmount = signedOrder.takerAssetAmount; - break; - - case TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount: - takerAssetFillAmount = signedOrder.takerAssetAmount.plus(1); - break; - - case TakerAssetFillAmountScenario.LessThanTakerAssetAmount: - takerAssetFillAmount = signedOrder.takerAssetAmount.div(2).integerValue(BigNumber.ROUND_FLOOR); - break; - - default: - throw errorUtils.spawnSwitchErr('TakerAssetFillAmountScenario', fillScenario.takerAssetFillAmountScenario); - } - - return takerAssetFillAmount; -} - -function fillErrorToRevertError(order: Order, error: FillOrderError): RevertError { - const orderHash = orderHashUtils.getOrderHashHex(order); - switch (error) { - case FillOrderError.InvalidTaker: - return new ExchangeRevertErrors.ExchangeInvalidContextError( - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidTaker, - orderHash, - ); - case FillOrderError.InvalidMakerAmount: - case FillOrderError.OrderUnfillable: - return new ExchangeRevertErrors.OrderStatusError(orderHash); - case FillOrderError.InvalidTakerAmount: - return new ExchangeRevertErrors.FillError(ExchangeRevertErrors.FillErrorCode.InvalidTakerAmount, orderHash); - case FillOrderError.InvalidFillPrice: - return new ExchangeRevertErrors.FillError(ExchangeRevertErrors.FillErrorCode.InvalidFillPrice, orderHash); - case FillOrderError.TransferFailed: - return new ExchangeRevertErrors.AssetProxyTransferError(orderHash); - default: - return new StringRevertError(error); - } -} - -// tslint:disable:max-file-line-count diff --git a/contracts/exchange/test/utils/fill_order_scenarios.ts b/contracts/exchange/test/utils/fill_order_scenarios.ts deleted file mode 100644 index e80015d6e8..0000000000 --- a/contracts/exchange/test/utils/fill_order_scenarios.ts +++ /dev/null @@ -1,95 +0,0 @@ -export enum FeeRecipientAddressScenario { - BurnAddress = 'BURN_ADDRESS', - EthUserAddress = 'ETH_USER_ADDRESS', - MakerAddress = 'MAKER_ADDRESS', - TakerAddress = 'TAKER_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', - ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', - ERC20EighteenDecimals = 'ERC20_EIGHTEEN_DECIMALS', - ERC721 = 'ERC721', - ERC1155Fungible = 'ERC1155_FUNGIBLE', - ERC1155NonFungible = 'ERC1155_NON_FUNGIBLE', - MultiAssetERC20 = 'MULTI_ASSET_ERC20', -} - -export enum FeeAssetDataScenario { - ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS', - ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', - ERC20EighteenDecimals = 'ERC20_EIGHTEEN_DECIMALS', - ERC721 = 'ERC721', - ERC1155Fungible = 'ERC1155_FUNGIBLE', - ERC1155NonFungible = 'ERC1155_NON_FUNGIBLE', - MultiAssetERC20 = 'MULTI_ASSET_ERC20', - MakerToken = 'MAKER_TOKEN', - TakerToken = 'TAKER_TOKEN', -} - -export enum TakerAssetFillAmountScenario { - ExactlyTakerAssetAmount = 'EXACTLY_TAKER_ASSET_AMOUNT', - GreaterThanTakerAssetAmount = 'GREATER_THAN_TAKER_ASSET_AMOUNT', - LessThanTakerAssetAmount = 'LESS_THAN_TAKER_ASSET_AMOUNT', - Zero = 'ZERO', -} - -export enum BalanceAmountScenario { - Zero = 'ZERO', - Exact = 'EXACT', - TooLow = 'TOO_LOW', - Higher = 'HIGHER', -} - -export enum AllowanceAmountScenario { - Zero = 'ZERO', - Exact = 'EXACT', - TooLow = 'TOO_LOW', - Higher = 'HIGHER', - Unlimited = 'UNLIMITED', -} - -export interface TraderStateScenario { - traderAssetBalance: BalanceAmountScenario; - traderAssetAllowance: AllowanceAmountScenario; - feeBalance: BalanceAmountScenario; - feeAllowance: AllowanceAmountScenario; -} - -export interface FillScenario { - orderScenario: OrderScenario; - takerAssetFillAmountScenario: TakerAssetFillAmountScenario; - makerStateScenario: TraderStateScenario; - takerStateScenario: TraderStateScenario; -} - -export interface OrderScenario { - takerScenario: TakerScenario; - feeRecipientScenario: FeeRecipientAddressScenario; - makerAssetAmountScenario: OrderAssetAmountScenario; - takerAssetAmountScenario: OrderAssetAmountScenario; - makerFeeScenario: OrderAssetAmountScenario; - takerFeeScenario: OrderAssetAmountScenario; - expirationTimeSecondsScenario: ExpirationTimeSecondsScenario; - makerAssetDataScenario: AssetDataScenario; - takerAssetDataScenario: AssetDataScenario; - makerFeeAssetDataScenario: FeeAssetDataScenario; - takerFeeAssetDataScenario: FeeAssetDataScenario; -} diff --git a/contracts/exchange/test/utils/fill_order_simulator.ts b/contracts/exchange/test/utils/fill_order_simulator.ts deleted file mode 100644 index 10a2affe73..0000000000 --- a/contracts/exchange/test/utils/fill_order_simulator.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { constants, orderUtils } from '@0x/contracts-test-utils'; -import { Order } from '@0x/order-utils'; -import { FillResults } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractBalanceAndProxyAllowanceLazyStore as LazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store'; -import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; -import { TradeSide, TransferType } from './types'; - -export enum FillOrderError { - OrderUnfillable = 'ORDER_UNFILLABLE', - InvalidSender = 'INVALID_SENDER', - InvalidTakerAmount = 'INVALID_TAKER_AMOUNT', - InvalidMakerAmount = 'INVALID_MAKER_AMOUNT', - InvalidTaker = 'INVALID_TAKER', - InvalidFillPrice = 'INVALID_FILL_PRICE', - TransferFailed = 'TRANSFER_FAILED', -} - -/** - * Simplified fill order simulator. - */ -export class FillOrderSimulator { - public readonly lazyStore: LazyStore; - private readonly _transferSimulator: ExchangeTransferSimulator; - - constructor(lazyStore: LazyStore) { - this.lazyStore = lazyStore; - this._transferSimulator = new ExchangeTransferSimulator(lazyStore); - } - - public async simulateFillOrderAsync( - order: Order, - takerAddress: string, - takerAssetFillAmount: BigNumber, - takerAssetFilledAmount: BigNumber = constants.ZERO_AMOUNT, - ): Promise { - const remainingTakerAssetAmount = order.takerAssetAmount.minus(takerAssetFilledAmount); - const makerAssetFilledAmount = orderUtils.getPartialAmountFloor( - takerAssetFilledAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - - validateFill( - order, - takerAddress, - takerAssetFillAmount, - makerAssetFilledAmount, - takerAssetFilledAmount, - remainingTakerAssetAmount, - ); - - const finalTakerAssetFillAmount = BigNumber.min(takerAssetFillAmount, remainingTakerAssetAmount); - const makerAssetFillAmount = orderUtils.getPartialAmountFloor( - finalTakerAssetFillAmount, - order.takerAssetAmount, - order.makerAssetAmount, - ); - const makerFeePaid = orderUtils.getPartialAmountFloor( - makerAssetFillAmount, - order.makerAssetAmount, - order.makerFee, - ); - const takerFeePaid = orderUtils.getPartialAmountFloor( - finalTakerAssetFillAmount, - order.takerAssetAmount, - order.takerFee, - ); - - try { - // Taker -> Maker - await this._transferSimulator.transferFromAsync( - order.takerAssetData, - takerAddress, - order.makerAddress, - finalTakerAssetFillAmount, - TradeSide.Taker, - TransferType.Trade, - ); - // Maker fee -> fee recipient - if (order.makerAddress !== order.feeRecipientAddress) { - await this._transferSimulator.transferFromAsync( - order.makerFeeAssetData, - order.makerAddress, - order.feeRecipientAddress, - makerFeePaid, - TradeSide.Maker, - TransferType.Fee, - ); - } - // Maker -> Taker - await this._transferSimulator.transferFromAsync( - order.makerAssetData, - order.makerAddress, - takerAddress, - makerAssetFillAmount, - TradeSide.Maker, - TransferType.Trade, - ); - // Taker fee -> fee recipient - if (takerAddress !== order.feeRecipientAddress) { - await this._transferSimulator.transferFromAsync( - order.takerFeeAssetData, - takerAddress, - order.feeRecipientAddress, - takerFeePaid, - TradeSide.Taker, - TransferType.Fee, - ); - } - } catch (err) { - throw new Error(FillOrderError.TransferFailed); - } - - return { - takerAssetFilledAmount: finalTakerAssetFillAmount, - makerAssetFilledAmount: makerAssetFillAmount, - makerFeePaid, - takerFeePaid, - protocolFeePaid: constants.ZERO_AMOUNT, - }; - } -} - -function validateFill( - order: Order, - takerAddress: string, - takerAssetFillAmount: BigNumber, - makerAssetFilledAmount: BigNumber, - takerAssetFilledAmount: BigNumber, - remainingTakerAssetAmount: BigNumber, -): void { - const now = Math.floor(_.now() / 1000); - if (remainingTakerAssetAmount.isEqualTo(0) || order.expirationTimeSeconds.isLessThanOrEqualTo(now)) { - throw new Error(FillOrderError.OrderUnfillable); - } - - if (order.senderAddress !== constants.NULL_ADDRESS && order.senderAddress !== takerAddress) { - throw new Error(FillOrderError.InvalidSender); - } - - if (order.takerAddress !== constants.NULL_ADDRESS && order.takerAddress !== takerAddress) { - throw new Error(FillOrderError.InvalidTaker); - } - - if (order.makerAssetAmount.isEqualTo(0)) { - throw new Error(FillOrderError.InvalidMakerAmount); - } - - if (takerAssetFillAmount.isEqualTo(0)) { - throw new Error(FillOrderError.InvalidTakerAmount); - } - - if ( - makerAssetFilledAmount - .times(order.takerAssetAmount) - .isGreaterThan(takerAssetFilledAmount.times(order.makerAssetAmount)) - ) { - throw new Error(FillOrderError.InvalidFillPrice); - } -} diff --git a/contracts/exchange/test/utils/isolated_exchange_wrapper.ts b/contracts/exchange/test/utils/isolated_exchange_wrapper.ts deleted file mode 100644 index 0ad7574f65..0000000000 --- a/contracts/exchange/test/utils/isolated_exchange_wrapper.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { - constants, - filterLogsToArguments, - orderHashUtils, - txDefaults as testTxDefaults, -} from '@0x/contracts-test-utils'; -import { FillResults, Order, OrderInfo, SignatureType } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TxData, Web3Wrapper } from '@0x/web3-wrapper'; -import * as crypto from 'crypto'; -import { LogEntry } from 'ethereum-types'; - -import { artifacts } from '../artifacts'; - -import { - IsolatedExchangeContract, - IsolatedExchangeDispatchTransferFromCalledEventArgs as DispatchTransferFromCallArgs, - IsolatedExchangeFillEventArgs as FillEventArgs, -} from '../wrappers'; - -export { Order } from '@0x/types'; -export interface AssetBalances { - [assetData: string]: { [address: string]: BigNumber }; -} - -export interface IsolatedExchangeEvents { - fillEvents: FillEventArgs[]; - transferFromCalls: DispatchTransferFromCallArgs[]; -} - -export type Numberish = string | number | BigNumber; - -export const DEFAULT_GOOD_SIGNATURE = createGoodSignature(); -export const DEFAULT_BAD_SIGNATURE = createBadSignature(); - -/** - * @dev Convenience wrapper for the `IsolatedExchange` contract. - */ -export class IsolatedExchangeWrapper { - public static readonly CHAIN_ID = 1337; - public readonly instance: IsolatedExchangeContract; - public lastTxEvents: IsolatedExchangeEvents = createEmptyEvents(); - public lastTxBalanceChanges: AssetBalances = {}; - - public static async deployAsync( - web3Wrapper: Web3Wrapper, - txDefaults: Partial = testTxDefaults, - ): Promise { - const provider = web3Wrapper.getProvider(); - const instance = await IsolatedExchangeContract.deployFrom0xArtifactAsync( - artifacts.IsolatedExchange, - provider, - txDefaults, - {}, - ); - return new IsolatedExchangeWrapper(web3Wrapper, instance); - } - - public static fromAddress( - address: string, - web3Wrapper: Web3Wrapper, - txDefaults: Partial = testTxDefaults, - ): IsolatedExchangeWrapper { - const provider = web3Wrapper.getProvider(); - const instance = new IsolatedExchangeContract(address, provider, txDefaults); - return new IsolatedExchangeWrapper(web3Wrapper, instance); - } - - public constructor(web3Wrapper: Web3Wrapper, instance: IsolatedExchangeContract) { - this.instance = instance; - } - - public async getTakerAssetFilledAmountAsync(order: Order): Promise { - return this.instance.filled(this.getOrderHash(order)).callAsync(); - } - - public async cancelOrderAsync(order: Order, txOpts?: TxData): Promise { - await this.instance.cancelOrder(order).awaitTransactionSuccessAsync(txOpts); - } - - public async cancelOrdersUpToAsync(epoch: BigNumber, txOpts?: TxData): Promise { - await this.instance.cancelOrdersUpTo(epoch).awaitTransactionSuccessAsync(txOpts); - } - - public async fillOrderAsync( - order: Order, - takerAssetFillAmount: Numberish, - signature: string = DEFAULT_GOOD_SIGNATURE, - txOpts?: TxData, - ): Promise { - this.lastTxEvents = createEmptyEvents(); - this.lastTxBalanceChanges = {}; - const fillOrderFn = this.instance.fillOrder(order, new BigNumber(takerAssetFillAmount), signature); - const result = await fillOrderFn.callAsync(); - const receipt = await fillOrderFn.awaitTransactionSuccessAsync(txOpts); - this.lastTxEvents = extractEvents(receipt.logs); - this.lastTxBalanceChanges = getBalanceChangesFromTransferFromCalls(this.lastTxEvents.transferFromCalls); - return result; - } - - public getOrderHash(order: Order): string { - const domainInfo = { - exchangeAddress: this.instance.address, - chainId: IsolatedExchangeWrapper.CHAIN_ID, - }; - return orderHashUtils.getOrderHashHex({ ...order, ...domainInfo }); - } - - public async getOrderInfoAsync(order: Order): Promise { - return this.instance.getOrderInfo(order).callAsync(); - } - - public getBalanceChange(assetData: string, address: string): BigNumber { - if (assetData in this.lastTxBalanceChanges) { - const balances = this.lastTxBalanceChanges[assetData]; - if (address in balances) { - return balances[address]; - } - } - return constants.ZERO_AMOUNT; - } -} - -/** - * Create a signature for the `IsolatedExchange` contract that will pass. - */ -export function createGoodSignature(type: SignatureType = SignatureType.EIP712): string { - return `0x01${Buffer.from([type]).toString('hex')}`; -} - -/** - * Create a signature for the `IsolatedExchange` contract that will fail. - */ -export function createBadSignature(type: SignatureType = SignatureType.EIP712): string { - return `0x00${Buffer.from([type]).toString('hex')}`; -} - -const ERC20_ASSET_DATA_LENGTH = 36; - -/** - * Create asset data for the `IsolatedExchange` contract that will pass. - */ -export function createGoodAssetData(length: number = ERC20_ASSET_DATA_LENGTH): string { - return `0x01${crypto.randomBytes(length - 1).toString('hex')}`; -} - -/** - * Create asset data for the `IsolatedExchange` contract that will fail. - */ -export function createBadAssetData(length: number = ERC20_ASSET_DATA_LENGTH): string { - return `0x00${crypto.randomBytes(length - 1).toString('hex')}`; -} - -function createEmptyEvents(): IsolatedExchangeEvents { - return { fillEvents: [], transferFromCalls: [] }; -} - -function extractEvents(logs: LogEntry[]): IsolatedExchangeEvents { - return { - fillEvents: filterLogsToArguments(logs, 'Fill'), - transferFromCalls: filterLogsToArguments(logs, 'DispatchTransferFromCalled'), - }; -} - -// Executes transferFrom calls to compute relative balances for addresses. -function getBalanceChangesFromTransferFromCalls(calls: DispatchTransferFromCallArgs[]): AssetBalances { - const changes: AssetBalances = {}; - for (const call of calls) { - const { assetData, from, to, amount } = call; - const balances = (changes[assetData] = changes[assetData] || {}); - const fromBalance = balances[from] || constants.ZERO_AMOUNT; - const toBalance = balances[to] || constants.ZERO_AMOUNT; - balances[from] = fromBalance.minus(amount); - balances[to] = toBalance.plus(amount); - } - return changes; -} diff --git a/contracts/exchange/test/utils/order_factory_from_scenario.ts b/contracts/exchange/test/utils/order_factory_from_scenario.ts deleted file mode 100644 index d721e004bf..0000000000 --- a/contracts/exchange/test/utils/order_factory_from_scenario.ts +++ /dev/null @@ -1,506 +0,0 @@ -import { - encodeERC1155AssetData, - encodeERC20AssetData, - encodeERC721AssetData, - encodeMultiAssetData, -} from '@0x/contracts-asset-proxy'; -import { constants, ERC1155HoldingsByOwner, ERC721TokenIdsByOwner } from '@0x/contracts-test-utils'; -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { Order } from '@0x/types'; -import { BigNumber, errorUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { - AssetDataScenario, - ExpirationTimeSecondsScenario, - FeeAssetDataScenario, - FeeRecipientAddressScenario, - OrderAssetAmountScenario, - OrderScenario, - TakerScenario, -} from './fill_order_scenarios'; - -const TEN_UNITS_EIGHTEEN_DECIMALS = new BigNumber('10e18'); -const FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber('5e18'); -const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber('0.1e18'); -const ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber('1e18'); -const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber('0.05e18'); -const TEN_UNITS_FIVE_DECIMALS = new BigNumber('10e5'); -const FIVE_UNITS_FIVE_DECIMALS = new BigNumber('5e5'); -const POINT_ONE_UNITS_FIVE_DECIMALS = new BigNumber('0.1e5'); -const ONE_UNITS_FIVE_DECIMALS = new BigNumber('1e5'); -const POINT_ZERO_FIVE_UNITS_FIVE_DECIMALS = new BigNumber('0.05e5'); -const ONE_THOUSAND_UNITS_ZERO_DECIMALS = new BigNumber(1000); -const TEN_UNITS_ZERO_DECIMALS = new BigNumber(10); -const FIVE_UNITS_ZERO_DECIMALS = new BigNumber(5); -const ONE_UNITS_ZERO_DECIMALS = new BigNumber(1); -const ONE_NFT_UNIT = new BigNumber(1); -const ZERO_UNITS = new BigNumber(0); - -export class OrderFactoryFromScenario { - constructor( - private readonly _userAddresses: string[], - private readonly _erc20EighteenDecimalTokenAddresses: string[], - private readonly _erc20FiveDecimalTokenAddresses: string[], - private readonly _erc20ZeroDecimalTokenAddresses: string[], - private readonly _erc721TokenAddress: string, - private readonly _erc1155TokenAddress: string, - private readonly _erc721Balances: ERC721TokenIdsByOwner, - private readonly _erc1155Holdings: ERC1155HoldingsByOwner, - private readonly _exchangeAddress: string, - private readonly _chainId: number, - ) { - return; - } - public async generateOrderAsync(orderScenario: OrderScenario): Promise { - const makerAddress = this._userAddresses[1]; - let takerAddress = this._userAddresses[2]; - const erc721MakerAssetIds = this._erc721Balances[makerAddress][this._erc721TokenAddress]; - const erc721TakerAssetIds = this._erc721Balances[takerAddress][this._erc721TokenAddress]; - const erc1155FungibleMakerTokenIds = getERC1155FungibleOwnerTokenIds( - this._erc1155Holdings.fungible[makerAddress][this._erc1155TokenAddress], - ); - const erc1155NonFungibleMakerTokenIds = getERC1155NonFungibleOwnerTokenIds( - this._erc1155Holdings.nonFungible[makerAddress][this._erc1155TokenAddress], - ); - const erc1155FungibleTakerTokenIds = getERC1155FungibleOwnerTokenIds( - this._erc1155Holdings.fungible[takerAddress][this._erc1155TokenAddress], - ); - const erc1155NonFungibleTakerTokenIds = getERC1155NonFungibleOwnerTokenIds( - this._erc1155Holdings.nonFungible[takerAddress][this._erc1155TokenAddress], - ); - const erc1155CallbackData = constants.NULL_BYTES; - let feeRecipientAddress; - let makerAssetAmount; - let takerAssetAmount; - let makerFee; - let takerFee; - let expirationTimeSeconds; - let makerAssetData = constants.NULL_BYTES; - let takerAssetData = constants.NULL_BYTES; - let makerFeeAssetData = constants.NULL_BYTES; - let takerFeeAssetData = constants.NULL_BYTES; - - switch (orderScenario.feeRecipientScenario) { - case FeeRecipientAddressScenario.BurnAddress: - feeRecipientAddress = constants.NULL_ADDRESS; - break; - case FeeRecipientAddressScenario.EthUserAddress: - feeRecipientAddress = this._userAddresses[4]; - break; - case FeeRecipientAddressScenario.MakerAddress: - feeRecipientAddress = makerAddress; - break; - case FeeRecipientAddressScenario.TakerAddress: - feeRecipientAddress = takerAddress; - break; - default: - throw errorUtils.spawnSwitchErr('FeeRecipientAddressScenario', orderScenario.feeRecipientScenario); - } - - switch (orderScenario.makerAssetDataScenario) { - case AssetDataScenario.ERC20EighteenDecimals: - makerAssetData = encodeERC20AssetData(this._erc20EighteenDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetData = encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC721: - makerAssetData = encodeERC721AssetData(this._erc721TokenAddress, erc721MakerAssetIds[0]); - break; - case AssetDataScenario.ERC20ZeroDecimals: - makerAssetData = encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]); - break; - case AssetDataScenario.ERC1155Fungible: - makerAssetData = encodeERC1155AssetData( - this._erc1155TokenAddress, - [erc1155FungibleMakerTokenIds[0]], - [ONE_UNITS_ZERO_DECIMALS], - erc1155CallbackData, - ); - break; - case AssetDataScenario.ERC1155NonFungible: - makerAssetData = encodeERC1155AssetData( - this._erc1155TokenAddress, - [erc1155NonFungibleMakerTokenIds[0]], - [ONE_UNITS_ZERO_DECIMALS], - erc1155CallbackData, - ); - break; - case AssetDataScenario.MultiAssetERC20: - makerAssetData = encodeMultiAssetData( - [ONE_UNITS_EIGHTEEN_DECIMALS, ONE_UNITS_FIVE_DECIMALS], - [ - encodeERC20AssetData(this._erc20EighteenDecimalTokenAddresses[0]), - encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[0]), - ], - ); - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); - } - - switch (orderScenario.takerAssetDataScenario) { - case AssetDataScenario.ERC20EighteenDecimals: - takerAssetData = encodeERC20AssetData(this._erc20EighteenDecimalTokenAddresses[1]); - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetData = encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]); - break; - case AssetDataScenario.ERC721: - takerAssetData = encodeERC721AssetData(this._erc721TokenAddress, erc721TakerAssetIds[0]); - break; - case AssetDataScenario.ERC20ZeroDecimals: - takerAssetData = encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]); - break; - case AssetDataScenario.ERC1155Fungible: - takerAssetData = encodeERC1155AssetData( - this._erc1155TokenAddress, - [erc1155FungibleTakerTokenIds[1]], - [ONE_UNITS_ZERO_DECIMALS], - erc1155CallbackData, - ); - break; - case AssetDataScenario.ERC1155NonFungible: - takerAssetData = encodeERC1155AssetData( - this._erc1155TokenAddress, - [erc1155NonFungibleTakerTokenIds[0]], - [ONE_UNITS_ZERO_DECIMALS], - erc1155CallbackData, - ); - break; - case AssetDataScenario.MultiAssetERC20: - takerAssetData = encodeMultiAssetData( - [ONE_UNITS_EIGHTEEN_DECIMALS, ONE_UNITS_FIVE_DECIMALS], - [ - encodeERC20AssetData(this._erc20EighteenDecimalTokenAddresses[1]), - encodeERC20AssetData(this._erc20FiveDecimalTokenAddresses[1]), - ], - ); - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); - } - - switch (orderScenario.makerAssetAmountScenario) { - case OrderAssetAmountScenario.Large: - switch (orderScenario.makerAssetDataScenario) { - case AssetDataScenario.ERC20EighteenDecimals: - case AssetDataScenario.ERC1155Fungible: - makerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetAmount = TEN_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - case AssetDataScenario.ERC1155NonFungible: - makerAssetAmount = ONE_NFT_UNIT; - break; - case AssetDataScenario.ERC20ZeroDecimals: - makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS; - break; - case AssetDataScenario.MultiAssetERC20: - makerAssetAmount = TEN_UNITS_ZERO_DECIMALS; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); - } - break; - case OrderAssetAmountScenario.Small: - switch (orderScenario.makerAssetDataScenario) { - case AssetDataScenario.ERC20EighteenDecimals: - case AssetDataScenario.ERC1155Fungible: - makerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - makerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - case AssetDataScenario.ERC1155NonFungible: - makerAssetAmount = ONE_NFT_UNIT; - break; - case AssetDataScenario.ERC20ZeroDecimals: - makerAssetAmount = TEN_UNITS_ZERO_DECIMALS; - break; - case AssetDataScenario.MultiAssetERC20: - makerAssetAmount = ONE_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.ERC20EighteenDecimals: - case AssetDataScenario.ERC1155Fungible: - takerAssetAmount = TEN_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetAmount = TEN_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - case AssetDataScenario.ERC1155NonFungible: - takerAssetAmount = ONE_NFT_UNIT; - break; - case AssetDataScenario.ERC20ZeroDecimals: - takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS; - break; - case AssetDataScenario.MultiAssetERC20: - takerAssetAmount = TEN_UNITS_ZERO_DECIMALS; - break; - default: - throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); - } - break; - case OrderAssetAmountScenario.Small: - switch (orderScenario.takerAssetDataScenario) { - case AssetDataScenario.ERC20EighteenDecimals: - case AssetDataScenario.ERC1155Fungible: - takerAssetAmount = FIVE_UNITS_EIGHTEEN_DECIMALS; - break; - case AssetDataScenario.ERC20FiveDecimals: - takerAssetAmount = FIVE_UNITS_FIVE_DECIMALS; - break; - case AssetDataScenario.ERC721: - case AssetDataScenario.ERC1155NonFungible: - takerAssetAmount = ONE_NFT_UNIT; - break; - case AssetDataScenario.ERC20ZeroDecimals: - takerAssetAmount = TEN_UNITS_ZERO_DECIMALS; - break; - case AssetDataScenario.MultiAssetERC20: - takerAssetAmount = ONE_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); - } - - const feeFromScenario = async ( - feeAmountScenario: OrderAssetAmountScenario, - feeAssetDataScenario: FeeAssetDataScenario, - erc20EighteenDecimalTokenAddress: string, - erc20FiveDecimalTokenAddress: string, - erc20ZeroDecimalTokenAddress: string, - erc721AssetId: BigNumber, - erc1155FungibleTokenId: BigNumber, - erc1155NonFungibleAssetId: BigNumber, - ): Promise<[BigNumber, string]> => { - const feeAmount = getFeeAmountFromScenario(orderScenario, feeAssetDataScenario, feeAmountScenario); - switch (feeAssetDataScenario) { - case FeeAssetDataScenario.MakerToken: - return [feeAmount, makerAssetData]; - case FeeAssetDataScenario.TakerToken: - return [feeAmount, takerAssetData]; - case FeeAssetDataScenario.ERC20EighteenDecimals: - return [feeAmount, encodeERC20AssetData(erc20EighteenDecimalTokenAddress)]; - case FeeAssetDataScenario.ERC20FiveDecimals: - return [feeAmount, encodeERC20AssetData(erc20FiveDecimalTokenAddress)]; - case FeeAssetDataScenario.ERC20ZeroDecimals: - return [feeAmount, encodeERC20AssetData(erc20ZeroDecimalTokenAddress)]; - case FeeAssetDataScenario.ERC721: - return [feeAmount, encodeERC721AssetData(this._erc721TokenAddress, erc721AssetId)]; - case FeeAssetDataScenario.ERC1155Fungible: - return [ - feeAmount, - encodeERC1155AssetData( - this._erc1155TokenAddress, - [erc1155FungibleTokenId], - [ONE_UNITS_ZERO_DECIMALS], - erc1155CallbackData, - ), - ]; - case FeeAssetDataScenario.ERC1155NonFungible: - return [ - feeAmount, - encodeERC1155AssetData( - this._erc1155TokenAddress, - [erc1155NonFungibleAssetId], - [ONE_UNITS_ZERO_DECIMALS], - erc1155CallbackData, - ), - ]; - case FeeAssetDataScenario.MultiAssetERC20: - return [ - feeAmount, - encodeMultiAssetData( - [POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS, POINT_ZERO_FIVE_UNITS_FIVE_DECIMALS], - [ - encodeERC20AssetData(erc20EighteenDecimalTokenAddress), - encodeERC20AssetData(erc20FiveDecimalTokenAddress), - ], - ), - ]; - default: - throw errorUtils.spawnSwitchErr('FeeAssetDataScenario', feeAssetDataScenario); - } - }; - - [makerFee, makerFeeAssetData] = await feeFromScenario( - orderScenario.makerFeeScenario, - orderScenario.makerFeeAssetDataScenario, - this._erc20EighteenDecimalTokenAddresses[2], - this._erc20FiveDecimalTokenAddresses[2], - this._erc20ZeroDecimalTokenAddresses[2], - erc721MakerAssetIds[1], - erc1155FungibleMakerTokenIds[2], - erc1155NonFungibleMakerTokenIds[1], - ); - [takerFee, takerFeeAssetData] = await feeFromScenario( - orderScenario.takerFeeScenario, - orderScenario.takerFeeAssetDataScenario, - this._erc20EighteenDecimalTokenAddresses[3], - this._erc20FiveDecimalTokenAddresses[3], - this._erc20ZeroDecimalTokenAddresses[3], - erc721TakerAssetIds[1], - erc1155FungibleTakerTokenIds[3], - erc1155NonFungibleTakerTokenIds[1], - ); - - 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, - makerFeeAssetData, - takerFeeAssetData, - salt: generatePseudoRandomSalt(), - feeRecipientAddress, - expirationTimeSeconds, - exchangeAddress: this._exchangeAddress, - chainId: this._chainId, - }; - - return order; - } -} - -function getFeeAmountFromScenario( - orderScenario: OrderScenario, - feeAssetDataScenario: AssetDataScenario | FeeAssetDataScenario, - feeAmountScenario: OrderAssetAmountScenario, -): BigNumber { - switch (feeAssetDataScenario) { - case FeeAssetDataScenario.ERC721: - case FeeAssetDataScenario.ERC1155NonFungible: - switch (feeAmountScenario) { - case OrderAssetAmountScenario.Zero: - return ZERO_UNITS; - case OrderAssetAmountScenario.Small: - case OrderAssetAmountScenario.Large: - return ONE_NFT_UNIT; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', feeAmountScenario); - } - case FeeAssetDataScenario.ERC20ZeroDecimals: - switch (feeAmountScenario) { - case OrderAssetAmountScenario.Zero: - return ZERO_UNITS; - case OrderAssetAmountScenario.Small: - case OrderAssetAmountScenario.Large: - return ONE_UNITS_ZERO_DECIMALS; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', feeAmountScenario); - } - case FeeAssetDataScenario.ERC20FiveDecimals: - switch (feeAmountScenario) { - case OrderAssetAmountScenario.Zero: - return ZERO_UNITS; - case OrderAssetAmountScenario.Small: - return POINT_ZERO_FIVE_UNITS_FIVE_DECIMALS; - case OrderAssetAmountScenario.Large: - return POINT_ONE_UNITS_FIVE_DECIMALS; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', feeAmountScenario); - } - case FeeAssetDataScenario.ERC20EighteenDecimals: - case FeeAssetDataScenario.ERC1155Fungible: - switch (feeAmountScenario) { - case OrderAssetAmountScenario.Zero: - return ZERO_UNITS; - case OrderAssetAmountScenario.Small: - return POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS; - case OrderAssetAmountScenario.Large: - return POINT_ONE_UNITS_EIGHTEEN_DECIMALS; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', feeAmountScenario); - } - case FeeAssetDataScenario.MultiAssetERC20: - switch (feeAmountScenario) { - case OrderAssetAmountScenario.Zero: - return ZERO_UNITS; - case OrderAssetAmountScenario.Small: - return ONE_UNITS_ZERO_DECIMALS; - case OrderAssetAmountScenario.Large: - return FIVE_UNITS_ZERO_DECIMALS; - default: - throw errorUtils.spawnSwitchErr('OrderAssetAmountScenario', feeAmountScenario); - } - case FeeAssetDataScenario.MakerToken: - return getFeeAmountFromScenario(orderScenario, orderScenario.makerAssetDataScenario, feeAmountScenario); - case FeeAssetDataScenario.TakerToken: - return getFeeAmountFromScenario(orderScenario, orderScenario.takerAssetDataScenario, feeAmountScenario); - default: - throw errorUtils.spawnSwitchErr('FeeAssetDataScenario', feeAssetDataScenario); - } -} - -function getERC1155FungibleOwnerTokenIds(holdings: { [tokenId: string]: BigNumber }): BigNumber[] { - return _.keys(holdings).map(id => new BigNumber(id)); -} - -function getERC1155NonFungibleOwnerTokenIds(holdings: { [tokenId: string]: BigNumber[] }): BigNumber[] { - return _.values(holdings).map(group => group[0]); -} - -// tslint:disable: max-file-line-count diff --git a/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts deleted file mode 100644 index 998b6aa9dd..0000000000 --- a/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; -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 { - const balance = await this._assetWrapper.getBalanceAsync(userAddress, assetData); - return balance; - } - public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise { - const proxyAllowance = await this._assetWrapper.getProxyAllowanceAsync(userAddress, assetData); - return proxyAllowance; - } -} diff --git a/contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts deleted file mode 100644 index 172e8d0203..0000000000 --- a/contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { BigNumber } from '@0x/utils'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; - -export class SimpleERC20BalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { - private readonly _erc20TokenContract: ERC20TokenContract; - private readonly _erc20ProxyAddress: string; - constructor(erc20TokenWrapper: ERC20TokenContract, erc20ProxyAddress: string) { - this._erc20TokenContract = erc20TokenWrapper; - this._erc20ProxyAddress = erc20ProxyAddress; - } - public async getBalanceAsync(_assetData: string, userAddress: string): Promise { - // HACK: We cheat and don't pass in the assetData since it's always the same token used - // in our tests. - const balance = await this._erc20TokenContract.balanceOf(userAddress).callAsync(); - return balance; - } - public async getProxyAllowanceAsync(_assetData: string, userAddress: string): Promise { - // HACK: We cheat and don't pass in the assetData since it's always the same token used - // in our tests. - const proxyAllowance = await this._erc20TokenContract - .allowance(userAddress, this._erc20ProxyAddress) - .callAsync(); - return proxyAllowance; - } -} diff --git a/contracts/exchange/test/utils/store/balance_and_proxy_allowance_lazy_store.ts b/contracts/exchange/test/utils/store/balance_and_proxy_allowance_lazy_store.ts deleted file mode 100644 index 9f76189dac..0000000000 --- a/contracts/exchange/test/utils/store/balance_and_proxy_allowance_lazy_store.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from '../abstract/abstract_balance_and_proxy_allowance_fetcher'; -import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store'; - -/** - * Copy on read store for balances/proxyAllowances of tokens/accounts - */ -export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceLazyStore { - private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher; - private _balance: { - [assetData: string]: { - [userAddress: string]: BigNumber; - }; - }; - private _proxyAllowance: { - [assetData: string]: { - [userAddress: string]: BigNumber; - }; - }; - /** - * Instantiates a BalanceAndProxyAllowanceLazyStore - * @param balanceAndProxyAllowanceFetcher Class the implements the AbstractBalanceAndProxyAllowanceFetcher - * @return Instance of BalanceAndProxyAllowanceLazyStore - */ - constructor(balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher) { - this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher; - this._balance = {}; - this._proxyAllowance = {}; - } - /** - * Get a users balance of an asset - * @param assetData AssetData of interest - * @param userAddress Ethereum address of interest - */ - public async getBalanceAsync(assetData: string, userAddress: string): Promise { - if (this._balance[assetData] === undefined || this._balance[assetData][userAddress] === undefined) { - const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, userAddress); - this.setBalance(assetData, userAddress, balance); - } - const cachedBalance = this._balance[assetData][userAddress]; - return cachedBalance; - } - /** - * Set the balance of an asset for a user - * @param assetData AssetData of interest - * @param userAddress Ethereum address of interest - */ - public setBalance(assetData: string, userAddress: string, balance: BigNumber): void { - if (this._balance[assetData] === undefined) { - this._balance[assetData] = {}; - } - this._balance[assetData][userAddress] = balance; - } - /** - * Clear the balance of an asset for a user - * @param assetData AssetData of interest - * @param userAddress Ethereum address of interest - */ - public deleteBalance(assetData: string, userAddress: string): void { - if (this._balance[assetData] !== undefined) { - delete this._balance[assetData][userAddress]; - if (_.isEmpty(this._balance[assetData])) { - delete this._balance[assetData]; - } - } - } - /** - * Get the 0x asset proxy allowance - * @param assetData AssetData of interest - * @param userAddress Ethereum address of interest - */ - public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise { - if ( - this._proxyAllowance[assetData] === undefined || - this._proxyAllowance[assetData][userAddress] === undefined - ) { - const proxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - assetData, - userAddress, - ); - this.setProxyAllowance(assetData, userAddress, proxyAllowance); - } - const cachedProxyAllowance = this._proxyAllowance[assetData][userAddress]; - return cachedProxyAllowance; - } - /** - * Set the 0x asset proxy allowance - * @param assetData AssetData of interest - * @param userAddress Ethereum address of interest - */ - public setProxyAllowance(assetData: string, userAddress: string, proxyAllowance: BigNumber): void { - if (this._proxyAllowance[assetData] === undefined) { - this._proxyAllowance[assetData] = {}; - } - this._proxyAllowance[assetData][userAddress] = proxyAllowance; - } - /** - * Clear the 0x asset proxy allowance - * @param assetData AssetData of interest - * @param userAddress Ethereum address of interest - */ - public deleteProxyAllowance(assetData: string, userAddress: string): void { - if (this._proxyAllowance[assetData] !== undefined) { - delete this._proxyAllowance[assetData][userAddress]; - if (_.isEmpty(this._proxyAllowance[assetData])) { - delete this._proxyAllowance[assetData]; - } - } - } - /** - * Delete all balances & allowances - */ - public deleteAll(): void { - this._balance = {}; - this._proxyAllowance = {}; - } -} diff --git a/contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts b/contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts deleted file mode 100644 index 7564011668..0000000000 --- a/contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractOrderFilledCancelledFetcher } from '../abstract/abstract_order_filled_cancelled_fetcher'; -import { AbstractOrderFilledCancelledLazyStore } from '../abstract/abstract_order_filled_cancelled_lazy_store'; - -/** - * Copy on read store for balances/proxyAllowances of tokens/accounts - */ -export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancelledLazyStore { - private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher; - private _filledTakerAmount: { - [orderHash: string]: BigNumber; - }; - private _isCancelled: { - [orderHash: string]: boolean; - }; - /** - * Instantiate a OrderFilledCancelledLazyStore - * @param orderFilledCancelledFetcher Class instance that implements the AbstractOrderFilledCancelledFetcher - * @returns An instance of OrderFilledCancelledLazyStore - */ - constructor(orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher) { - this._orderFilledCancelledFetcher = orderFilledCancelledFetcher; - this._filledTakerAmount = {}; - this._isCancelled = {}; - } - /** - * Get the filledTakerAssetAmount of an order - * @param orderHash OrderHash from order of interest - * @return filledTakerAssetAmount - */ - public async getFilledTakerAmountAsync(orderHash: string): Promise { - if (this._filledTakerAmount[orderHash] === undefined) { - const filledTakerAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash); - this.setFilledTakerAmount(orderHash, filledTakerAmount); - } - const cachedFilledTakerAmount = this._filledTakerAmount[orderHash]; - return cachedFilledTakerAmount; - } - /** - * Set the filledTakerAssetAmount of an order - * @param orderHash OrderHash from order of interest - * @param filledTakerAmount Desired filledTakerAssetAmount - */ - public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void { - this._filledTakerAmount[orderHash] = filledTakerAmount; - } - /** - * Clear the filledTakerAssetAmount of an order - * @param orderHash OrderHash from order of interest - */ - public deleteFilledTakerAmount(orderHash: string): void { - delete this._filledTakerAmount[orderHash]; - } - /** - * Set whether an order has been cancelled or not - * @param orderHash OrderHash from order of interest - * @param isCancelled Whether this order should be cancelled or not - */ - public setIsCancelled(orderHash: string, isCancelled: boolean): void { - this._isCancelled[orderHash] = isCancelled; - } - /** - * Clear whether the order has been cancelled if already set - * @param orderHash OrderHash from order of interest - */ - public deleteIsCancelled(orderHash: string): void { - delete this._isCancelled[orderHash]; - } - /** - * Clear all filled/cancelled state - */ - public deleteAll(): void { - this.deleteAllFilled(); - this.deleteAllIsCancelled(); - } - /** - * Clear all cancelled state - */ - public deleteAllIsCancelled(): void { - this._isCancelled = {}; - } - /** - * Clear all filled state - */ - public deleteAllFilled(): void { - this._filledTakerAmount = {}; - } -} diff --git a/contracts/exchange/test/utils/types.ts b/contracts/exchange/test/utils/types.ts deleted file mode 100644 index 8cd6df9377..0000000000 --- a/contracts/exchange/test/utils/types.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -export interface AbiDecodedFillOrderData { - order: SignedOrder; - takerAssetFillAmount: BigNumber; - signature: string; -} - -export enum ExchangeFunctionName { - BatchCancelOrders = 'batchCancelOrders', - BatchExecuteTransactions = 'batchExecuteTransactions', - BatchFillOrKillOrders = 'batchFillOrKillOrders', - BatchFillOrders = 'batchFillOrders', - BatchFillOrdersNoThrow = 'batchFillOrdersNoThrow', - BatchMatchOrders = 'batchMatchOrders', - BatchMatchOrdersWithMaximalFill = 'batchMatchOrdersWithMaximalFill', - CancelOrder = 'cancelOrder', - CancelOrdersUpTo = 'cancelOrdersUpTo', - ExecuteTransaction = 'executeTransaction', - FillOrKillOrder = 'fillOrKillOrder', - FillOrder = 'fillOrder', - FillOrderNoThrow = 'fillOrderNoThrow', - MarketBuyOrdersNoThrow = 'marketBuyOrdersNoThrow', - MarketSellOrdersNoThrow = 'marketSellOrdersNoThrow', - MarketBuyOrdersFillOrKill = 'marketBuyOrdersFillOrKill', - MarketSellOrdersFillOrKill = 'marketSellOrdersFillOrKill', - MatchOrders = 'matchOrders', - MatchOrdersWithMaximalFill = 'matchOrdersWithMaximalFill', - PreSign = 'preSign', - RegisterAssetProxy = 'registerAssetProxy', - SetSignatureValidatorApproval = 'setSignatureValidatorApproval', - SimulateDispatchTransferFromCalls = 'simulateDispatchTransferFromCalls', - TransferOwnership = 'transferOwnership', - SetProtocolFeeMultiplier = 'setProtocolFeeMultiplier', - SetProtocolFeeCollectorAddress = 'setProtocolFeeCollectorAddress', - DetachProtocolFeeCollector = 'detachProtocolFeeCollector', -} - -export enum TradeSide { - Maker = 'maker', - Taker = 'taker', -} - -export enum TransferType { - Trade = 'trade', - Fee = 'fee', -} diff --git a/contracts/exchange/test/wrapper_unit_tests.ts b/contracts/exchange/test/wrapper_unit_tests.ts deleted file mode 100644 index 25a8d89be1..0000000000 --- a/contracts/exchange/test/wrapper_unit_tests.ts +++ /dev/null @@ -1,1280 +0,0 @@ -import { ContractTxFunctionObj } from '@0x/base-contract'; -import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - blockchainTests, - constants, - describe, - expect, - getRandomPortion, - orderHashUtils, -} from '@0x/contracts-test-utils'; -import { ReferenceFunctions as UtilReferenceFunctions, SafeMathRevertErrors } from '@0x/contracts-utils'; -import { FillResults, Order } from '@0x/types'; -import { AnyRevertError, BigNumber, ExchangeRevertErrors, hexUtils, StringRevertError } from '@0x/utils'; -import { LogEntry, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { - TestFillRoundingContract, - TestWrapperFunctionsCancelOrderCalledEventArgs as CancelOrderCalledEventArgs, - TestWrapperFunctionsContract, - TestWrapperFunctionsFillOrderCalledEventArgs as FillOrderCalledEventArgs, -} from './wrappers'; - -blockchainTests('Exchange wrapper functions unit tests.', env => { - const CHAIN_ID = 0x74657374; - const { ONE_ETHER, MAX_UINT256 } = constants; - const { addFillResults, getPartialAmountCeil } = LibReferenceFunctions; - const { safeSub } = UtilReferenceFunctions; - const protocolFeeMultiplier = new BigNumber(150000); - const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH); - const randomAssetData = () => hexUtils.random(34); - const randomAmount = (maxAmount: BigNumber = ONE_ETHER) => maxAmount.times(_.random(0, 100, true).toFixed(12)); - const randomTimestamp = () => new BigNumber(Math.floor(_.now() / 1000) + _.random(0, 34560)); - const randomSalt = () => new BigNumber(hexUtils.random(constants.WORD_LENGTH).substr(2), 16); - const ALWAYS_FAILING_SALT = constants.MAX_UINT256; - const ALWAYS_FAILING_SALT_REVERT_ERROR = new StringRevertError('ALWAYS_FAILING_SALT'); - const EMPTY_FILL_RESULTS = { - makerAssetFilledAmount: constants.ZERO_AMOUNT, - takerAssetFilledAmount: constants.ZERO_AMOUNT, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: constants.ZERO_AMOUNT, - }; - let testContract: TestWrapperFunctionsContract; - let owner: string; - let senderAddress: string; - - before(async () => { - [owner, senderAddress] = await env.getAccountAddressesAsync(); - testContract = await TestWrapperFunctionsContract.deployFrom0xArtifactAsync( - artifacts.TestWrapperFunctions, - env.provider, - { - ...env.txDefaults, - from: owner, - }, - {}, - ); - - // Set the protocol fee multiplier. - await testContract.setProtocolFeeMultiplier(protocolFeeMultiplier).awaitTransactionSuccessAsync({ - from: owner, - }); - }); - - function randomOrder(fields?: Partial): Order { - return { - makerAddress: randomAddress(), - takerAddress: randomAddress(), - feeRecipientAddress: randomAddress(), - senderAddress: randomAddress(), - takerAssetAmount: randomAmount(), - makerAssetAmount: randomAmount(), - makerFee: randomAmount(), - takerFee: randomAmount(), - expirationTimeSeconds: randomTimestamp(), - salt: randomSalt(), - makerAssetData: randomAssetData(), - takerAssetData: randomAssetData(), - makerFeeAssetData: randomAssetData(), - takerFeeAssetData: randomAssetData(), - exchangeAddress: constants.NULL_ADDRESS, - chainId: CHAIN_ID, - ...(fields || {}), - }; - } - - // Computes the expected (fake) fill results from `TestWrapperFunctions` `_fillOrder` implementation. - function getExpectedFillResults(order: Order, signature: string): FillResults { - if (order.salt === ALWAYS_FAILING_SALT) { - return EMPTY_FILL_RESULTS; - } - return { - makerAssetFilledAmount: order.makerAssetAmount, - takerAssetFilledAmount: order.takerAssetAmount, - makerFeePaid: order.makerFee, - takerFeePaid: order.takerFee, - protocolFeePaid: protocolFeeMultiplier, - }; - } - - // Creates a deterministic order signature, even though no signature validation - // actually occurs in the test contract. - function createOrderSignature(order: Order): string { - return hexUtils.hash(orderHashUtils.getOrderHashHex(order)); - } - - // Asserts that `_fillOrder()` was called in the same order and with the same - // arguments as given by examining receipt logs. - function assertFillOrderCallsFromLogs(logs: LogEntry[], calls: Array<[Order, BigNumber, string]>): void { - expect(logs.length).to.eq(calls.length); - for (const i of _.times(calls.length)) { - const log = (logs[i] as any) as LogWithDecodedArgs; - const [expectedOrder, expectedTakerAssetFillAmount, expectedSignature] = calls[i]; - expect(log.event).to.eq('FillOrderCalled'); - assertSameOrderFromEvent(log.args.order as any, expectedOrder); - expect(log.args.takerAssetFillAmount).to.bignumber.eq(expectedTakerAssetFillAmount); - expect(log.args.signature).to.eq(expectedSignature); - } - } - - function assertSameOrderFromEvent(actual: any, expected: Order): void { - expect(actual.makerAddress).to.be.eq(expected.makerAddress); - expect(actual.takerAddress).to.be.eq(expected.takerAddress); - expect(actual.feeRecipientAddress).to.be.eq(expected.feeRecipientAddress); - expect(actual.senderAddress).to.be.eq(expected.senderAddress); - expect(actual.makerAssetAmount).to.bignumber.eq(expected.makerAssetAmount); - expect(actual.takerAssetAmount).to.bignumber.eq(expected.takerAssetAmount); - expect(actual.makerFee).to.bignumber.eq(expected.makerFee); - expect(actual.takerFee).to.bignumber.eq(expected.takerFee); - expect(actual.expirationTimeSeconds).to.bignumber.eq(expected.expirationTimeSeconds); - expect(actual.salt).to.bignumber.eq(expected.salt); - expect(actual.makerAssetData).to.eq(expected.makerAssetData); - expect(actual.takerAssetData).to.eq(expected.takerAssetData); - expect(actual.makerFeeAssetData).to.eq(expected.makerFeeAssetData); - expect(actual.takerFeeAssetData).to.eq(expected.takerFeeAssetData); - } - - describe('fillOrKillOrder', () => { - it('works if the order is filled by exactly `takerAssetFillAmount`', async () => { - const fillAmount = randomAmount(); - const order = randomOrder({ - // `_fillOrder()` is overridden to always return `order.takerAssetAmount` as - // the `takerAssetFilledAmount`. - takerAssetAmount: fillAmount, - }); - const signature = createOrderSignature(order); - const expectedResult = getExpectedFillResults(order, signature); - const expectedCalls = [[order, fillAmount, signature]]; - const contractFn = testContract.fillOrKillOrder(order, fillAmount, signature); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('reverts if the order is filled by less than `takerAssetFillAmount`', async () => { - const fillAmount = randomAmount(); - const order = randomOrder({ - // `_fillOrder()` is overridden to always return `order.takerAssetAmount` as - // the `takerAssetFilledAmount`. - takerAssetAmount: fillAmount.minus(1), - }); - const signature = createOrderSignature(order); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteFillOrder, - fillAmount, - fillAmount.minus(1), - ); - const tx = testContract.fillOrKillOrder(order, fillAmount, signature).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if the order is filled by greater than `takerAssetFillAmount`', async () => { - const fillAmount = randomAmount(); - const order = randomOrder({ - // `_fillOrder()` is overridden to always return `order.takerAssetAmount` as - // the `takerAssetFilledAmount`. - takerAssetAmount: fillAmount.plus(1), - }); - const signature = createOrderSignature(order); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteFillOrder, - fillAmount, - fillAmount.plus(1), - ); - const tx = testContract.fillOrKillOrder(order, fillAmount, signature).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if `_fillOrder()` reverts', async () => { - const fillAmount = randomAmount(); - const order = randomOrder({ - salt: ALWAYS_FAILING_SALT, - }); - const signature = createOrderSignature(order); - const expectedError = ALWAYS_FAILING_SALT_REVERT_ERROR; - const tx = testContract.fillOrKillOrder(order, fillAmount, signature).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('fillOrderNoThrow', () => { - it('calls `fillOrder()` and returns its result', async () => { - const fillAmount = randomAmount(); - const order = randomOrder(); - const signature = createOrderSignature(order); - const expectedResult = getExpectedFillResults(order, signature); - const expectedCalls = [[order, fillAmount, signature]]; - const contractFn = testContract.fillOrderNoThrow(order, fillAmount, signature); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('does not revert if `fillOrder()` reverts', async () => { - const fillAmount = randomAmount(); - const order = randomOrder({ - salt: ALWAYS_FAILING_SALT, - }); - const signature = createOrderSignature(order); - const expectedResult = EMPTY_FILL_RESULTS; - const contractFn = testContract.fillOrderNoThrow(order, fillAmount, signature); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, []); - }); - }); - - describe('batchFillOrders', () => { - it('works with no fills', async () => { - const contractFn = testContract.batchFillOrders([], [], []); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq([]); - assertFillOrderCallsFromLogs(receipt.logs, []); - }); - - it('works with one fill', async () => { - const COUNT = 1; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrders(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works with many fills', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrders(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works with duplicate orders', async () => { - const NUM_UNIQUE_ORDERS = 2; - const COUNT = 4; - const uniqueOrders = _.times(NUM_UNIQUE_ORDERS, () => randomOrder()); - const orders = _.shuffle(_.flatten(_.times(COUNT / NUM_UNIQUE_ORDERS, () => uniqueOrders))); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount.dividedToIntegerBy(COUNT)); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrders(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('reverts if there are more orders than fill amounts', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT - 1, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedError = new AnyRevertError(); // Just a generic revert. - const tx = testContract.batchFillOrders(orders, fillAmounts, signatures).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if there are more orders than signatures', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT - 1, i => createOrderSignature(orders[i])); - const expectedError = new AnyRevertError(); // Just a generic revert. - const tx = testContract.batchFillOrders(orders, fillAmounts, signatures).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('batchFillOrKillOrders', () => { - it('works with no fills', async () => { - const contractFn = testContract.batchFillOrKillOrders([], [], []); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq([]); - assertFillOrderCallsFromLogs(receipt.logs, []); - }); - - it('works with one fill', async () => { - const COUNT = 1; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrKillOrders(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works with many fills', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrKillOrders(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works with duplicate orders', async () => { - const NUM_UNIQUE_ORDERS = 2; - const COUNT = 4; - const uniqueOrders = _.times(NUM_UNIQUE_ORDERS, () => randomOrder()); - const orders = _.shuffle(_.flatten(_.times(COUNT / NUM_UNIQUE_ORDERS, () => uniqueOrders))); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrKillOrders(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('reverts if any fill sells less than its takerAssetFillAmount', async () => { - const COUNT = 8; - const FAILING_ORDER_INDEX = 6; - const orders = _.times(COUNT, () => randomOrder()); - const failingOrder = orders[FAILING_ORDER_INDEX]; - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const failingAmount = fillAmounts[FAILING_ORDER_INDEX]; - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - // `_fillOrder()` is overridden to always return `order.takerAssetAmount` as - // the `takerAssetFilledAmount`. - failingOrder.takerAssetAmount = failingOrder.takerAssetAmount.minus(1); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteFillOrder, - failingAmount, - failingAmount.minus(1), - ); - const tx = testContract - .batchFillOrKillOrders(orders, fillAmounts, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if any fill sells more than its takerAssetFillAmount', async () => { - const COUNT = 8; - const FAILING_ORDER_INDEX = 6; - const orders = _.times(COUNT, () => randomOrder()); - const failingOrder = orders[FAILING_ORDER_INDEX]; - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const failingAmount = fillAmounts[FAILING_ORDER_INDEX]; - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - // `_fillOrder()` is overridden to always return `order.takerAssetAmount` as - // the `takerAssetFilledAmount`. - failingOrder.takerAssetAmount = failingOrder.takerAssetAmount.plus(1); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteFillOrder, - failingAmount, - failingAmount.plus(1), - ); - const tx = testContract - .batchFillOrKillOrders(orders, fillAmounts, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if there are more orders than fill amounts', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT - 1, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedError = new AnyRevertError(); // Just a generic revert. - const tx = testContract - .batchFillOrKillOrders(orders, fillAmounts, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if there are more orders than signatures', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT - 1, i => createOrderSignature(orders[i])); - const expectedError = new AnyRevertError(); // Just a generic revert. - const tx = testContract - .batchFillOrKillOrders(orders, fillAmounts, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('batchFillOrdersNoThrow', () => { - it('works with no fills', async () => { - const contractFn = testContract.batchFillOrdersNoThrow([], [], []); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq([]); - assertFillOrderCallsFromLogs(receipt.logs, []); - }); - - it('works with one fill', async () => { - const COUNT = 1; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrdersNoThrow(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works with many fills', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrdersNoThrow(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works with duplicate orders', async () => { - const NUM_UNIQUE_ORDERS = 2; - const COUNT = 4; - const uniqueOrders = _.times(NUM_UNIQUE_ORDERS, () => randomOrder()); - const orders = _.shuffle(_.flatten(_.times(COUNT / NUM_UNIQUE_ORDERS, () => uniqueOrders))); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount.dividedToIntegerBy(COUNT)); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - const contractFn = testContract.batchFillOrdersNoThrow(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('works if a fill fails', async () => { - const COUNT = 8; - const FAILING_ORDER_INDEX = 6; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const failingOrder = orders[FAILING_ORDER_INDEX]; - failingOrder.salt = ALWAYS_FAILING_SALT; - const expectedResult = _.times(COUNT, i => getExpectedFillResults(orders[i], signatures[i])); - const expectedCalls = _.zip(orders, fillAmounts, signatures); - expectedCalls.splice(FAILING_ORDER_INDEX, 1); - const contractFn = testContract.batchFillOrdersNoThrow(orders, fillAmounts, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls as any); - }); - - it('reverts if there are more orders than fill amounts', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT - 1, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const expectedError = new AnyRevertError(); // Just a generic revert. - const tx = testContract - .batchFillOrdersNoThrow(orders, fillAmounts, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts if there are more orders than signatures', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const fillAmounts = _.times(COUNT, i => orders[i].takerAssetAmount); - const signatures = _.times(COUNT - 1, i => createOrderSignature(orders[i])); - const expectedError = new AnyRevertError(); // Just a generic revert. - const tx = testContract - .batchFillOrdersNoThrow(orders, fillAmounts, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - type ExpectedFillOrderCallArgs = [Order, BigNumber, string]; - type MarketSellBuyArgs = [Order[], BigNumber, string[], ...any[]]; - type MarketSellBuyContractFn = (...args: MarketSellBuyArgs) => ContractTxFunctionObj; - type MarketSellBuySimulator = (...args: MarketSellBuyArgs) => [FillResults, ExpectedFillOrderCallArgs[]]; - - describe('marketSell*', () => { - function defineCommonMarketSellOrdersTests( - getContractFn: () => MarketSellBuyContractFn, - simulator: MarketSellBuySimulator, - ): void { - it('works with one order', async () => { - const COUNT = 1; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, takerAssetFillAmount, signatures); - expect(expectedCalls.length).to.eq(COUNT); - const fnWithArgs = getContractFn()(orders, takerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('works with many orders', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, takerAssetFillAmount, signatures); - expect(expectedCalls.length).to.eq(COUNT); - const fnWithArgs = getContractFn()(orders, takerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('works with duplicate orders', async () => { - const NUM_UNIQUE_ORDERS = 2; - const COUNT = 4; - const uniqueOrders = _.times(NUM_UNIQUE_ORDERS, () => randomOrder()); - const orders = _.shuffle(_.flatten(_.times(COUNT / NUM_UNIQUE_ORDERS, () => uniqueOrders))); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, takerAssetFillAmount, signatures); - expect(expectedCalls.length).to.eq(COUNT); - const fnWithArgs = getContractFn()(orders, takerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('stops when filled == `takerAssetFillAmount`', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - // Skip the last order in our `takerAssetFillAmount` calculation. - const takerAssetFillAmount = _.reduce( - orders.slice(0, COUNT - 1), - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, takerAssetFillAmount, signatures); - // It should stop filling after the penultimate order. - expect(expectedCalls.length).to.eq(COUNT - 1); - const fnWithArgs = getContractFn()(orders, takerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('stops when filled > `takerAssetFillAmount`', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - // Because `TestWrapperFunctions` always fills `takerAssetAmount` - // setting the first order's `takerAssetAmount` to larger than - // `takerAssetFillAmount` will cause an overfill. - orders[0].takerAssetAmount = takerAssetFillAmount.plus(1); - const [expectedResult, expectedCalls] = simulator(orders, takerAssetFillAmount, signatures); - // It should stop filling after first order. - expect(expectedCalls.length).to.eq(1); - const fnWithArgs = getContractFn()(orders, takerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('reverts when an overflow occurs when summing fill results', async () => { - const COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - orders[1].takerAssetAmount = MAX_UINT256; - const takerAssetFillAmount = MAX_UINT256; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - orders[0].takerAssetAmount, - orders[1].takerAssetAmount, - ); - const tx = getContractFn()(orders, takerAssetFillAmount, signatures).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('returns empty fill results with no orders', async () => { - const [expectedResult, expectedCalls] = simulator([], constants.ZERO_AMOUNT, []); - expect(expectedCalls.length).to.eq(0); - const fnWithArgs = getContractFn()([], constants.ZERO_AMOUNT, []); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - } - - function simulateMarketSellOrders( - orders: Order[], - takerAssetFillAmount: BigNumber, - signatures: string[], - ): [FillResults, ExpectedFillOrderCallArgs[]] { - const fillOrderCalls = []; - let fillResults = _.cloneDeep(EMPTY_FILL_RESULTS); - for (const [order, signature] of _.zip(orders, signatures) as [[Order, string]]) { - const remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, fillResults.takerAssetFilledAmount); - if (order.salt !== ALWAYS_FAILING_SALT) { - fillOrderCalls.push([order, remainingTakerAssetFillAmount, signature]); - } - fillResults = addFillResults(fillResults, getExpectedFillResults(order, signature)); - if (fillResults.takerAssetFilledAmount.gte(takerAssetFillAmount)) { - break; - } - } - return [fillResults, fillOrderCalls as any]; - } - - describe('marketSellOrdersNoThrow', () => { - defineCommonMarketSellOrdersTests( - () => testContract.marketSellOrdersNoThrow.bind(testContract), - simulateMarketSellOrders, - ); - - it('works when any fills revert', async () => { - const COUNT = 4; - const BAD_ORDERS_COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const badOrders = _.sampleSize(orders, BAD_ORDERS_COUNT); - for (const order of badOrders) { - order.salt = ALWAYS_FAILING_SALT; - } - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulateMarketSellOrders( - orders, - takerAssetFillAmount, - signatures, - ); - expect(expectedCalls.length).to.eq(COUNT - BAD_ORDERS_COUNT); - const contractFn = testContract.marketSellOrdersNoThrow(orders, takerAssetFillAmount, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('works when all fills revert', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder({ salt: ALWAYS_FAILING_SALT })); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulateMarketSellOrders( - orders, - takerAssetFillAmount, - signatures, - ); - expect(expectedCalls.length).to.eq(0); - const contractFn = testContract.marketSellOrdersNoThrow(orders, takerAssetFillAmount, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - }); - - describe('marketSellOrdersFillOrKill', () => { - defineCommonMarketSellOrdersTests( - () => testContract.marketSellOrdersNoThrow.bind(testContract), - simulateMarketSellOrders, - ); - - it('reverts when filled < `takerAssetFillAmount`', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ).plus(1); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteMarketSellOrders, - takerAssetFillAmount, - takerAssetFillAmount.minus(1), - ); - const tx = testContract - .marketSellOrdersFillOrKill(orders, takerAssetFillAmount, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('works when fills fail but can still sell `takerAssetFillAmount`', async () => { - const COUNT = 4; - const BAD_ORDERS_COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const badOrders = _.sampleSize(orders, BAD_ORDERS_COUNT); - for (const order of badOrders) { - order.salt = ALWAYS_FAILING_SALT; - } - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ).minus(_.reduce(badOrders, (total, o) => o.takerAssetAmount.plus(total), constants.ZERO_AMOUNT)); - const [expectedResult, expectedCalls] = simulateMarketSellOrders( - orders, - takerAssetFillAmount, - signatures, - ); - expect(expectedCalls.length).to.eq(COUNT - BAD_ORDERS_COUNT); - const contractFn = testContract.marketSellOrdersFillOrKill(orders, takerAssetFillAmount, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('reverts when a failed fill results in selling less than `takerAssetFillAmount`', async () => { - const COUNT = 4; - const BAD_ORDERS_COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const badOrders = _.sampleSize(orders, BAD_ORDERS_COUNT); - for (const order of badOrders) { - order.salt = ALWAYS_FAILING_SALT; - } - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const badOrdersAmount = _.reduce( - badOrders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const takerAssetFillAmount = _.reduce( - orders, - (total, o) => o.takerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ) - .minus(badOrdersAmount) - .plus(1); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteMarketSellOrders, - takerAssetFillAmount, - takerAssetFillAmount.minus(1), - ); - const tx = testContract - .marketSellOrdersFillOrKill(orders, takerAssetFillAmount, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - }); - - describe('marketBuy*', () => { - function defineCommonMarketBuyOrdersTests( - getContractFn: () => MarketSellBuyContractFn, - simulator: MarketSellBuySimulator, - ): void { - it('works with one order', async () => { - const COUNT = 1; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, makerAssetFillAmount, signatures); - expect(expectedCalls.length).to.eq(COUNT); - const fnWithArgs = getContractFn()(orders, makerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('works with many orders', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, makerAssetFillAmount, signatures); - expect(expectedCalls.length).to.eq(COUNT); - const fnWithArgs = getContractFn()(orders, makerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('works with duplicate orders', async () => { - const NUM_UNIQUE_ORDERS = 2; - const COUNT = 4; - const uniqueOrders = _.times(NUM_UNIQUE_ORDERS, () => randomOrder()); - const orders = _.shuffle(_.flatten(_.times(COUNT / NUM_UNIQUE_ORDERS, () => uniqueOrders))); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, makerAssetFillAmount, signatures); - expect(expectedCalls.length).to.eq(COUNT); - const fnWithArgs = getContractFn()(orders, makerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('stops when filled == `makerAssetFillAmount`', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - // Skip the last order in our `makerAssetFillAmount` calculation. - const makerAssetFillAmount = _.reduce( - orders.slice(0, COUNT - 1), - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulator(orders, makerAssetFillAmount, signatures); - // It should stop filling after the penultimate order. - expect(expectedCalls.length).to.eq(COUNT - 1); - const fnWithArgs = getContractFn()(orders, makerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('stops when filled > `makerAssetFillAmount`', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - // Because `TestWrapperFunctions` always fills `makerAssetAmount` - // setting the first order's `makerAssetAmount` to larger than - // `makerAssetFillAmount` will cause an overfill. - orders[0].makerAssetAmount = makerAssetFillAmount.plus(1); - const [expectedResult, expectedCalls] = simulator(orders, makerAssetFillAmount, signatures); - // It should stop filling after first order. - expect(expectedCalls.length).to.eq(1); - const fnWithArgs = getContractFn()(orders, makerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('reverts when an overflow occurs when computing `remainingTakerAssetFillAmount`', async () => { - const orders = [randomOrder({ takerAssetAmount: MAX_UINT256 })]; - const signatures = _.times(orders.length, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = new BigNumber(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - orders[0].takerAssetAmount, - makerAssetFillAmount, - ); - const tx = getContractFn()(orders, makerAssetFillAmount, signatures).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it("reverts when an order's `makerAssetAmount` is zero", async () => { - const orders = [randomOrder({ makerAssetAmount: constants.ZERO_AMOUNT })]; - const signatures = _.times(orders.length, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = ONE_ETHER; - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - constants.ZERO_AMOUNT, - new BigNumber(1), - ); - const tx = getContractFn()(orders, makerAssetFillAmount, signatures).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('reverts when an overflow occurs when summing fill results', async () => { - const orders = [ - randomOrder({ - takerAssetAmount: new BigNumber(1), - makerAssetAmount: new BigNumber(1), - }), - randomOrder({ - takerAssetAmount: new BigNumber(1), - makerAssetAmount: MAX_UINT256, - }), - ]; - const signatures = _.times(orders.length, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = new BigNumber(2); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - orders[0].makerAssetAmount, - orders[1].makerAssetAmount, - ); - const tx = getContractFn()(orders, makerAssetFillAmount, signatures).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('returns empty fill results with no orders', async () => { - const [expectedResult, expectedCalls] = simulator([], constants.ZERO_AMOUNT, []); - expect(expectedCalls.length).to.eq(0); - const fnWithArgs = getContractFn()([], constants.ZERO_AMOUNT, []); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - } - - function simulateMarketBuyOrdersNoThrow( - orders: Order[], - makerAssetFillAmount: BigNumber, - signatures: string[], - ): [FillResults, ExpectedFillOrderCallArgs[]] { - const fillOrderCalls = []; - let fillResults = _.cloneDeep(EMPTY_FILL_RESULTS); - for (const [order, signature] of _.zip(orders, signatures) as [[Order, string]]) { - const remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, fillResults.makerAssetFilledAmount); - const remainingTakerAssetFillAmount = getPartialAmountCeil( - order.takerAssetAmount, - order.makerAssetAmount, - remainingMakerAssetFillAmount, - ); - if (order.salt !== ALWAYS_FAILING_SALT) { - fillOrderCalls.push([order, remainingTakerAssetFillAmount, signature]); - } - fillResults = addFillResults(fillResults, getExpectedFillResults(order, signature)); - if (fillResults.makerAssetFilledAmount.gte(makerAssetFillAmount)) { - break; - } - } - return [fillResults, fillOrderCalls as any]; - } - - describe('marketBuyOrdersNoThrow', () => { - defineCommonMarketBuyOrdersTests( - () => testContract.marketBuyOrdersNoThrow.bind(testContract), - simulateMarketBuyOrdersNoThrow, - ); - - it('works when any fills revert', async () => { - const COUNT = 4; - const BAD_ORDERS_COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const badOrders = _.sampleSize(orders, BAD_ORDERS_COUNT); - for (const order of badOrders) { - order.salt = ALWAYS_FAILING_SALT; - } - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulateMarketBuyOrdersNoThrow( - orders, - makerAssetFillAmount, - signatures, - ); - expect(expectedCalls.length).to.eq(COUNT - BAD_ORDERS_COUNT); - const contractFn = testContract.marketBuyOrdersNoThrow(orders, makerAssetFillAmount, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('works when all fills revert', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder({ salt: ALWAYS_FAILING_SALT })); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const [expectedResult, expectedCalls] = simulateMarketBuyOrdersNoThrow( - orders, - makerAssetFillAmount, - signatures, - ); - expect(expectedCalls.length).to.eq(0); - const contractFn = testContract.marketBuyOrdersNoThrow(orders, makerAssetFillAmount, signatures); - const actualResult = await contractFn.callAsync(); - const receipt = await contractFn.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - describe('partial fills', () => { - let roundingTestContract: TestFillRoundingContract; - // Use another test contract with `_fillOrder()` preserved so the - // correct fill results are returned and we can test partial fills. - // TODO(dorothy-zbornak): Consolidate these contracts into one. - before(async () => { - roundingTestContract = await TestFillRoundingContract.deployFrom0xArtifactAsync( - artifacts.TestFillRounding, - env.provider, - { - ...env.txDefaults, - }, - {}, - ); - }); - - it('small quantities', async () => { - const orders = [ - randomOrder({ - makerAssetAmount: new BigNumber(30000), - takerAssetAmount: new BigNumber(20000), - }), - ]; - const signatures = [hexUtils.random()]; - const fillAmount = new BigNumber(10000); - const fillResults = await roundingTestContract - .marketBuyOrdersNoThrow(orders, fillAmount, signatures) - .callAsync(); - expect(fillResults.makerAssetFilledAmount).to.bignumber.eq(10000); - }); - - it('large quantities', async () => { - const orders = [ - randomOrder({ - makerAssetAmount: new BigNumber('21400000000000000000'), - takerAssetAmount: new BigNumber('6300000000000000000'), - }), - ]; - const signatures = [hexUtils.random()]; - const fillAmount = new BigNumber('2400000000000000000'); - const fillResults = await roundingTestContract - .marketBuyOrdersNoThrow(orders, fillAmount, signatures) - .callAsync(); - expect(fillResults.makerAssetFilledAmount).to.bignumber.eq('2400000000000000002'); - }); - - it('large full precision quantities', async () => { - const orders = [ - randomOrder({ - makerAssetAmount: new BigNumber('942848588381848588533'), - takerAssetAmount: new BigNumber('103048102885858024121'), - }), - ]; - const signatures = [hexUtils.random()]; - const fillAmount = new BigNumber('84819838457312347759'); - const fillResults = await roundingTestContract - .marketBuyOrdersNoThrow(orders, fillAmount, signatures) - .callAsync(); - expect(fillResults.makerAssetFilledAmount).to.bignumber.eq('84819838457312347760'); - }); - - describe.optional('full precision fuzzing', () => { - const FUZZ_COUNT = 256; - for (const i of _.times(FUZZ_COUNT)) { - it(`${i + 1}/${FUZZ_COUNT}`, async () => { - const ordersCount = _.random(1, 10); - const orders = _.times(ordersCount, () => randomOrder()); - const signatures = orders.map(() => hexUtils.random()); - const totalMakerAssetAmount = BigNumber.sum(...orders.map(o => o.makerAssetAmount)); - const fillAmount = getRandomPortion(totalMakerAssetAmount); - const fillResults = await roundingTestContract - .marketBuyOrdersNoThrow(orders, fillAmount, signatures) - .callAsync(); - expect(fillResults.makerAssetFilledAmount).to.bignumber.gte(fillAmount); - }); - } - }); - }); - }); - - describe('marketBuyOrdersFillOrKill', () => { - defineCommonMarketBuyOrdersTests( - () => testContract.marketBuyOrdersFillOrKill.bind(testContract), - simulateMarketBuyOrdersNoThrow, - ); - - it('reverts when filled < `makerAssetFillAmount`', async () => { - const COUNT = 4; - const orders = _.times(COUNT, () => randomOrder()); - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ).plus(1); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteMarketBuyOrders, - makerAssetFillAmount, - makerAssetFillAmount.minus(1), - ); - const tx = testContract - .marketBuyOrdersFillOrKill(orders, makerAssetFillAmount, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('works when fills fail but can still buy `makerAssetFillAmount`', async () => { - const COUNT = 4; - const BAD_ORDERS_COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const badOrders = _.sampleSize(orders, BAD_ORDERS_COUNT); - for (const order of badOrders) { - order.salt = ALWAYS_FAILING_SALT; - } - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ).minus(_.reduce(badOrders, (total, o) => o.makerAssetAmount.plus(total), constants.ZERO_AMOUNT)); - const [expectedResult, expectedCalls] = simulateMarketBuyOrdersNoThrow( - orders, - makerAssetFillAmount, - signatures, - ); - expect(expectedCalls.length).to.eq(COUNT - BAD_ORDERS_COUNT); - const fnWithArgs = testContract.marketBuyOrdersFillOrKill(orders, makerAssetFillAmount, signatures); - const actualResult = await fnWithArgs.callAsync(); - const receipt = await fnWithArgs.awaitTransactionSuccessAsync(); - expect(actualResult).to.deep.eq(expectedResult); - assertFillOrderCallsFromLogs(receipt.logs, expectedCalls); - }); - - it('reverts when a failed fill results in buying less than `makerAssetFillAmount`', async () => { - const COUNT = 4; - const BAD_ORDERS_COUNT = 2; - const orders = _.times(COUNT, () => randomOrder()); - const badOrders = _.sampleSize(orders, BAD_ORDERS_COUNT); - for (const order of badOrders) { - order.salt = ALWAYS_FAILING_SALT; - } - const signatures = _.times(COUNT, i => createOrderSignature(orders[i])); - const badOrdersAmount = _.reduce( - badOrders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ); - const makerAssetFillAmount = _.reduce( - orders, - (total, o) => o.makerAssetAmount.plus(total), - constants.ZERO_AMOUNT, - ) - .minus(badOrdersAmount) - .plus(1); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteMarketBuyOrders, - makerAssetFillAmount, - makerAssetFillAmount.minus(1), - ); - const tx = testContract - .marketBuyOrdersFillOrKill(orders, makerAssetFillAmount, signatures) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - }); - - describe('batchCancelOrders', () => { - // Asserts that `_cancelOrder()` was called in the same order and with the same - // arguments as given by examining receipt logs. - function assertCancelOrderCallsFromLogs(logs: LogEntry[], calls: Order[]): void { - expect(logs.length).to.eq(calls.length); - for (const i of _.times(calls.length)) { - const log = (logs[i] as any) as LogWithDecodedArgs; - const expectedOrder = calls[i]; - expect(log.event).to.eq('CancelOrderCalled'); - assertSameOrderFromEvent(log.args.order as any, expectedOrder); - } - } - - it('works with no orders', async () => { - const { logs } = await testContract.batchCancelOrders([]).awaitTransactionSuccessAsync(); - assertCancelOrderCallsFromLogs(logs, []); - }); - - it('works with many orders', async () => { - const COUNT = 8; - const orders = _.times(COUNT, () => randomOrder({ makerAddress: senderAddress })); - const { logs } = await testContract.batchCancelOrders(orders).awaitTransactionSuccessAsync(); - assertCancelOrderCallsFromLogs(logs, orders); - }); - - it('works with duplicate orders', async () => { - const UNIQUE_ORDERS = 2; - const COUNT = 6; - const uniqueOrders = _.times(UNIQUE_ORDERS, () => randomOrder({ makerAddress: senderAddress })); - const orders = _.shuffle(_.flatten(_.times(COUNT / UNIQUE_ORDERS, () => uniqueOrders))); - const { logs } = await testContract.batchCancelOrders(orders).awaitTransactionSuccessAsync(); - assertCancelOrderCallsFromLogs(logs, orders); - }); - - it('reverts if one `_cancelOrder()` reverts', async () => { - const COUNT = 8; - const FAILING_ORDER_INDEX = 4; - const orders = _.times(COUNT, () => randomOrder({ makerAddress: senderAddress })); - const failingOrder = orders[FAILING_ORDER_INDEX]; - failingOrder.salt = ALWAYS_FAILING_SALT; - const expectedError = ALWAYS_FAILING_SALT_REVERT_ERROR; - const tx = testContract.batchCancelOrders(orders).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); -// tslint:disable-next-line: max-file-line-count diff --git a/contracts/exchange/test/wrappers.ts b/contracts/exchange/test/wrappers.ts deleted file mode 100644 index cfc716abe1..0000000000 --- a/contracts/exchange/test/wrappers.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/exchange'; -export * from '../test/generated-wrappers/i_asset_proxy'; -export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; -export * from '../test/generated-wrappers/i_e_i_p1271_data'; -export * from '../test/generated-wrappers/i_e_i_p1271_wallet'; -export * from '../test/generated-wrappers/i_exchange'; -export * from '../test/generated-wrappers/i_exchange_core'; -export * from '../test/generated-wrappers/i_match_orders'; -export * from '../test/generated-wrappers/i_protocol_fees'; -export * from '../test/generated-wrappers/i_signature_validator'; -export * from '../test/generated-wrappers/i_transactions'; -export * from '../test/generated-wrappers/i_transfer_simulator'; -export * from '../test/generated-wrappers/i_wallet'; -export * from '../test/generated-wrappers/i_wrapper_functions'; -export * from '../test/generated-wrappers/isolated_exchange'; -export * from '../test/generated-wrappers/lib_exchange_rich_error_decoder'; -export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher'; -export * from '../test/generated-wrappers/mixin_exchange_core'; -export * from '../test/generated-wrappers/mixin_match_orders'; -export * from '../test/generated-wrappers/mixin_protocol_fees'; -export * from '../test/generated-wrappers/mixin_signature_validator'; -export * from '../test/generated-wrappers/mixin_transactions'; -export * from '../test/generated-wrappers/mixin_transfer_simulator'; -export * from '../test/generated-wrappers/mixin_wrapper_functions'; -export * from '../test/generated-wrappers/reentrancy_tester'; -export * from '../test/generated-wrappers/test_asset_proxy_dispatcher'; -export * from '../test/generated-wrappers/test_exchange_internals'; -export * from '../test/generated-wrappers/test_fill_rounding'; -export * from '../test/generated-wrappers/test_lib_exchange_rich_error_decoder'; -export * from '../test/generated-wrappers/test_protocol_fee_collector'; -export * from '../test/generated-wrappers/test_protocol_fees'; -export * from '../test/generated-wrappers/test_protocol_fees_receiver'; -export * from '../test/generated-wrappers/test_transactions'; -export * from '../test/generated-wrappers/test_validator_wallet'; -export * from '../test/generated-wrappers/test_wrapper_functions'; diff --git a/contracts/exchange/truffle-config.js b/contracts/exchange/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/exchange/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/exchange/tsconfig.json b/contracts/exchange/tsconfig.json deleted file mode 100644 index e4bbba0643..0000000000 --- a/contracts/exchange/tsconfig.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/Exchange.json", - "generated-artifacts/IExchange.json", - "test/generated-artifacts/Exchange.json", - "test/generated-artifacts/IAssetProxy.json", - "test/generated-artifacts/IAssetProxyDispatcher.json", - "test/generated-artifacts/IEIP1271Data.json", - "test/generated-artifacts/IEIP1271Wallet.json", - "test/generated-artifacts/IExchange.json", - "test/generated-artifacts/IExchangeCore.json", - "test/generated-artifacts/IMatchOrders.json", - "test/generated-artifacts/IProtocolFees.json", - "test/generated-artifacts/ISignatureValidator.json", - "test/generated-artifacts/ITransactions.json", - "test/generated-artifacts/ITransferSimulator.json", - "test/generated-artifacts/IWallet.json", - "test/generated-artifacts/IWrapperFunctions.json", - "test/generated-artifacts/IsolatedExchange.json", - "test/generated-artifacts/LibExchangeRichErrorDecoder.json", - "test/generated-artifacts/MixinAssetProxyDispatcher.json", - "test/generated-artifacts/MixinExchangeCore.json", - "test/generated-artifacts/MixinMatchOrders.json", - "test/generated-artifacts/MixinProtocolFees.json", - "test/generated-artifacts/MixinSignatureValidator.json", - "test/generated-artifacts/MixinTransactions.json", - "test/generated-artifacts/MixinTransferSimulator.json", - "test/generated-artifacts/MixinWrapperFunctions.json", - "test/generated-artifacts/ReentrancyTester.json", - "test/generated-artifacts/TestAssetProxyDispatcher.json", - "test/generated-artifacts/TestExchangeInternals.json", - "test/generated-artifacts/TestFillRounding.json", - "test/generated-artifacts/TestLibExchangeRichErrorDecoder.json", - "test/generated-artifacts/TestProtocolFeeCollector.json", - "test/generated-artifacts/TestProtocolFees.json", - "test/generated-artifacts/TestProtocolFeesReceiver.json", - "test/generated-artifacts/TestTransactions.json", - "test/generated-artifacts/TestValidatorWallet.json", - "test/generated-artifacts/TestWrapperFunctions.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/exchange/tslint.json b/contracts/exchange/tslint.json deleted file mode 100644 index 2a304eb78b..0000000000 --- a/contracts/exchange/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - }, - "linterOptions": { - "exclude": ["src/artifacts.ts"] - } -} diff --git a/contracts/exchange/typedoc-tsconfig.json b/contracts/exchange/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/exchange/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/extensions/.npmignore b/contracts/extensions/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/extensions/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json deleted file mode 100644 index 51308191da..0000000000 --- a/contracts/extensions/CHANGELOG.json +++ /dev/null @@ -1,789 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "6.2.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "6.2.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "6.2.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "6.2.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "6.2.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "6.2.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "6.2.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "6.2.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "6.2.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "6.2.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "6.2.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "6.2.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "6.2.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "6.2.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "6.2.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "6.2.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "6.2.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "6.2.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "6.2.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "6.2.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "6.2.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "6.2.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "6.2.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "6.2.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "6.2.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "6.2.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "6.2.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "6.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "6.2.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "6.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "6.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "6.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "6.2.0", - "changes": [ - { - "note": "Add MaximumGasPrice contract, tooling, and unit tests", - "pr": 2511 - } - ], - "timestamp": 1592969527 - }, - { - "timestamp": 1583220306, - "version": "6.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "6.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "6.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "6.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "6.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "6.1.0", - "changes": [ - { - "note": "Export `EvmBytecodeOutputLinkReferences` type.", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "version": "6.0.0", - "changes": [ - { - "note": "New year, new me: remove everything, add MixinWethUtils and LibAssetDataTransfer", - "pr": 2455 - } - ], - "timestamp": 1580988106 - }, - { - "timestamp": 1580811564, - "version": "5.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "5.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "5.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "5.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "5.1.0", - "changes": [ - { - "note": "Export function `encodeDutchAuctionAssetData`", - "pr": 2373 - } - ], - "timestamp": 1575931811 - }, - { - "version": "5.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Replaced the use of `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1575296764 - }, - { - "version": "4.1.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "4.1.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "4.1.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - } - ], - "timestamp": 1574030254 - }, - { - "version": "4.1.0-beta.1", - "changes": [ - { - "note": "Replaced the use of `SafeMath` with `LibSafeMath`", - "pr": 2254 - } - ], - "timestamp": 1573159180 - }, - { - "version": "4.1.0-beta.0", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "4.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "4.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "4.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "4.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.4", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564607468 - }, - { - "timestamp": 1563957393, - "version": "4.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "4.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "4.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Move `OrderValidator` to contracts/dev-utils package as `OrderValidationUtils`", - "pr": 1848 - }, - { - "note": "Remove unused `LibOrder` inheritance", - "pr": 1742 - }, - { - "note": "Refactor BalanceThresholdFilter to use new ITransactions interface", - "pr": 1753 - }, - { - "note": "Update tests for rich reverts", - "pr": 1761 - } - ], - "timestamp": 1563006338 - }, - { - "timestamp": 1558712885, - "version": "3.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "3.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557799313, - "version": "3.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557507213, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Do not reexport external dependencies", - "pr": 1682 - }, - { - "note": "Upgrade contracts to Solidity 0.5.5", - "pr": 1682 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "2.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "2.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "2.0.2", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - }, - { - "note": "Move Forwarder contract into new package", - "pr": 1539 - }, - { - "note": "Nest extensions under src directory", - "pr": 1539 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547747677, - "version": "1.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547561734, - "version": "1.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "1.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.2.0", - "changes": [ - { - "note": "Added Dutch Auction Wrapper", - "pr": 1465 - } - ], - "timestamp": 1547040760 - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Added Balance Threshold Filter", - "pr": 1383 - }, - { - "note": "Add OrderMatcher", - "pr": 1117 - }, - { - "note": "Add OrderValidator", - "pr": 1464 - } - ] - }, - { - "timestamp": 1544741676, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - } -] diff --git a/contracts/extensions/CHANGELOG.md b/contracts/extensions/CHANGELOG.md deleted file mode 100644 index 64d58ca16e..0000000000 --- a/contracts/extensions/CHANGELOG.md +++ /dev/null @@ -1,343 +0,0 @@ - - -CHANGELOG - -## v6.2.32 - _August 16, 2021_ - - * Dependencies updated - -## v6.2.31 - _August 11, 2021_ - - * Dependencies updated - -## v6.2.30 - _August 6, 2021_ - - * Dependencies updated - -## v6.2.29 - _June 22, 2021_ - - * Dependencies updated - -## v6.2.28 - _June 11, 2021_ - - * Dependencies updated - -## v6.2.27 - _June 2, 2021_ - - * Dependencies updated - -## v6.2.26 - _May 25, 2021_ - - * Dependencies updated - -## v6.2.25 - _May 21, 2021_ - - * Dependencies updated - -## v6.2.24 - _May 5, 2021_ - - * Dependencies updated - -## v6.2.23 - _April 28, 2021_ - - * Dependencies updated - -## v6.2.22 - _April 1, 2021_ - - * Dependencies updated - -## v6.2.21 - _March 17, 2021_ - - * Dependencies updated - -## v6.2.20 - _February 24, 2021_ - - * Dependencies updated - -## v6.2.19 - _February 10, 2021_ - - * Dependencies updated - -## v6.2.18 - _January 26, 2021_ - - * Dependencies updated - -## v6.2.17 - _January 13, 2021_ - - * Dependencies updated - -## v6.2.16 - _January 4, 2021_ - - * Dependencies updated - -## v6.2.15 - _December 23, 2020_ - - * Dependencies updated - -## v6.2.14 - _December 17, 2020_ - - * Dependencies updated - -## v6.2.13 - _December 16, 2020_ - - * Dependencies updated - -## v6.2.12 - _December 9, 2020_ - - * Dependencies updated - -## v6.2.11 - _December 7, 2020_ - - * Dependencies updated - -## v6.2.10 - _December 3, 2020_ - - * Dependencies updated - -## v6.2.9 - _November 19, 2020_ - - * Dependencies updated - -## v6.2.8 - _November 13, 2020_ - - * Dependencies updated - -## v6.2.7 - _November 3, 2020_ - - * Dependencies updated - -## v6.2.6 - _November 3, 2020_ - - * Dependencies updated - -## v6.2.5 - _November 2, 2020_ - - * Dependencies updated - -## v6.2.4 - _October 28, 2020_ - - * Dependencies updated - -## v6.2.3 - _October 27, 2020_ - - * Dependencies updated - -## v6.2.2 - _October 21, 2020_ - - * Dependencies updated - -## v6.2.1 - _July 15, 2020_ - - * Dependencies updated - -## v6.2.0 - _June 24, 2020_ - - * Add MaximumGasPrice contract, tooling, and unit tests (#2511) - -## v6.1.5 - _March 3, 2020_ - - * Dependencies updated - -## v6.1.4 - _February 27, 2020_ - - * Dependencies updated - -## v6.1.3 - _February 26, 2020_ - - * Dependencies updated - -## v6.1.2 - _February 25, 2020_ - - * Dependencies updated - -## v6.1.1 - _February 15, 2020_ - - * Dependencies updated - -## v6.1.0 - _February 8, 2020_ - - * Export `EvmBytecodeOutputLinkReferences` type. (#2462) - -## v6.0.0 - _February 6, 2020_ - - * New year, new me: remove everything, add MixinWethUtils and LibAssetDataTransfer (#2455) - -## v5.1.4 - _February 4, 2020_ - - * Dependencies updated - -## v5.1.3 - _January 22, 2020_ - - * Dependencies updated - -## v5.1.2 - _January 6, 2020_ - - * Dependencies updated - -## v5.1.1 - _December 17, 2019_ - - * Dependencies updated - -## v5.1.0 - _December 9, 2019_ - - * Export function `encodeDutchAuctionAssetData` (#2373) - -## v5.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Replaced the use of `SafeMath` with `LibSafeMath` (#2254) - -## v4.1.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v4.1.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v4.1.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - -## v4.1.0-beta.1 - _November 7, 2019_ - - * Replaced the use of `SafeMath` with `LibSafeMath` (#2254) - -## v4.1.0-beta.0 - _October 3, 2019_ - - * Dependencies updated - -## v4.0.8 - _September 17, 2019_ - - * Dependencies updated - -## v4.0.7 - _September 3, 2019_ - - * Dependencies updated - -## v4.0.6 - _August 22, 2019_ - - * Dependencies updated - -## v4.0.5 - _August 8, 2019_ - - * Dependencies updated - -## v4.0.4 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v4.0.3 - _July 24, 2019_ - - * Dependencies updated - -## v4.0.2 - _July 15, 2019_ - - * Dependencies updated - -## v4.0.1 - _July 13, 2019_ - - * Dependencies updated - -## v4.0.0 - _July 13, 2019_ - - * Move `OrderValidator` to contracts/dev-utils package as `OrderValidationUtils` (#1848) - * Remove unused `LibOrder` inheritance (#1742) - * Refactor BalanceThresholdFilter to use new ITransactions interface (#1753) - * Update tests for rich reverts (#1761) - -## v3.1.5 - _May 24, 2019_ - - * Dependencies updated - -## v3.1.4 - _May 15, 2019_ - - * Dependencies updated - -## v3.1.3 - _May 14, 2019_ - - * Dependencies updated - -## v3.1.2 - _May 10, 2019_ - - * Dependencies updated - -## v3.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v3.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v3.0.0 - _March 20, 2019_ - - * Do not reexport external dependencies (#1682) - * Upgrade contracts to Solidity 0.5.5 (#1682) - -## v2.0.8 - _March 1, 2019_ - - * Dependencies updated - -## v2.0.7 - _February 27, 2019_ - - * Dependencies updated - -## v2.0.6 - _February 26, 2019_ - - * Dependencies updated - -## v2.0.5 - _February 25, 2019_ - - * Dependencies updated - -## v2.0.4 - _February 9, 2019_ - - * Dependencies updated - -## v2.0.3 - _February 7, 2019_ - - * Dependencies updated - -## v2.0.2 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v2.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v2.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - * Move Forwarder contract into new package (#1539) - * Nest extensions under src directory (#1539) - -## v1.2.3 - _January 17, 2019_ - - * Dependencies updated - -## v1.2.2 - _January 15, 2019_ - - * Dependencies updated - -## v1.2.1 - _January 11, 2019_ - - * Dependencies updated - -## v1.2.0 - _January 9, 2019_ - - * Added Dutch Auction Wrapper (#1465) - -## v1.1.0 - _Invalid date_ - - * Added Balance Threshold Filter (#1383) - * Add OrderMatcher (#1117) - * Add OrderValidator (#1464) - -## v1.0.2 - _December 13, 2018_ - - * Dependencies updated diff --git a/contracts/extensions/DEPLOYS.json b/contracts/extensions/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/extensions/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/extensions/README.md b/contracts/extensions/README.md deleted file mode 100644 index 9197920098..0000000000 --- a/contracts/extensions/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## Extensions - -This package includes utility smart contracts that may be useful for developing on top of the core 0x Exchange. For example, `MixinWethUtils` includes functions to pay affiliate fees in ETH, wrap ETH to be used for 0x trades and protocol fees, and unwrap WETH to refund the sender. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-extensions --save -``` - -## Bug bounty - -A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program). - -## 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=@0x/contracts-extensions yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-extensions yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/extensions/compiler.json b/contracts/extensions/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/extensions/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/extensions/contracts/src/LibAssetDataTransfer.sol b/contracts/extensions/contracts/src/LibAssetDataTransfer.sol deleted file mode 100644 index 7f68b5bc7e..0000000000 --- a/contracts/extensions/contracts/src/LibAssetDataTransfer.sol +++ /dev/null @@ -1,258 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; -import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "./rich-errors/LibAssetDataTransferRichErrors.sol"; - - -library LibAssetDataTransfer { - - using LibBytes for bytes; - using LibSafeMath for uint256; - using LibAssetDataTransfer for bytes; - - /// @dev Transfers given amount of asset to sender. - /// @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 to sender. - function transferFrom( - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - if (amount == 0) { - return; - } - - bytes4 proxyId = assetData.readBytes4(0); - - if ( - proxyId == IAssetData(address(0)).ERC20Token.selector || - proxyId == IAssetData(address(0)).ERC20Bridge.selector - ) { - assetData.transferERC20Token( - from, - to, - amount - ); - } else if (proxyId == IAssetData(address(0)).ERC721Token.selector) { - assetData.transferERC721Token( - from, - to, - amount - ); - } else if (proxyId == IAssetData(address(0)).ERC1155Assets.selector) { - assetData.transferERC1155Assets( - from, - to, - amount - ); - } else if (proxyId == IAssetData(address(0)).MultiAsset.selector) { - assetData.transferMultiAsset( - from, - to, - amount - ); - } else if (proxyId != IAssetData(address(0)).StaticCall.selector) { - LibRichErrors.rrevert(LibAssetDataTransferRichErrors.UnsupportedAssetProxyError( - proxyId - )); - } - } - - ///@dev Transfer asset from sender to this contract. - /// @param assetData Byte array encoded for the respective asset proxy. - /// @param amount Amount of asset to transfer to sender. - function transferIn( - bytes memory assetData, - uint256 amount - ) - internal - { - assetData.transferFrom( - msg.sender, - address(this), - amount - ); - } - - ///@dev Transfer asset from this contract to sender. - /// @param assetData Byte array encoded for the respective asset proxy. - /// @param amount Amount of asset to transfer to sender. - function transferOut( - bytes memory assetData, - uint256 amount - ) - internal - { - assetData.transferFrom( - address(this), - msg.sender, - amount - ); - } - - /// @dev Decodes ERC20 or ERC20Bridge assetData and transfers given amount to sender. - /// @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 to sender. - function transferERC20Token( - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - address token = assetData.readAddress(16); - // Transfer tokens. - if (from == address(this)) { - LibERC20Token.transfer( - token, - to, - amount - ); - } else { - LibERC20Token.transferFrom( - token, - from, - to, - amount - ); - } - } - - /// @dev Decodes ERC721 assetData and transfers given amount to sender. - /// @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 to sender. - function transferERC721Token( - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - if (amount != 1) { - LibRichErrors.rrevert(LibAssetDataTransferRichErrors.Erc721AmountMustEqualOneError( - amount - )); - } - // Decode asset data. - address token = assetData.readAddress(16); - uint256 tokenId = assetData.readUint256(36); - - // Perform transfer. - IERC721Token(token).transferFrom( - from, - to, - tokenId - ); - } - - /// @dev Decodes ERC1155 assetData and transfers given amounts to sender. - /// @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 to sender. - function transferERC1155Assets( - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - // Decode assetData - // solhint-disable - ( - address token, - uint256[] memory ids, - uint256[] memory values, - bytes memory data - ) = abi.decode( - assetData.slice(4, assetData.length), - (address, uint256[], uint256[], bytes) - ); - // solhint-enable - - // Scale up values by `amount` - uint256 length = values.length; - uint256[] memory scaledValues = new uint256[](length); - for (uint256 i = 0; i != length; i++) { - scaledValues[i] = values[i].safeMul(amount); - } - - // Execute `safeBatchTransferFrom` call - // Either succeeds or throws - IERC1155(token).safeBatchTransferFrom( - from, - to, - ids, - scaledValues, - data - ); - } - - /// @dev Decodes MultiAsset assetData and recursively transfers assets to sender. - /// @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 to sender. - function transferMultiAsset( - bytes memory assetData, - address from, - address to, - uint256 amount - ) - internal - { - // solhint-disable indent - (uint256[] memory nestedAmounts, bytes[] memory nestedAssetData) = abi.decode( - assetData.slice(4, assetData.length), - (uint256[], bytes[]) - ); - // solhint-enable indent - - uint256 numNestedAssets = nestedAssetData.length; - for (uint256 i = 0; i != numNestedAssets; i++) { - transferFrom( - nestedAssetData[i], - from, - to, - amount.safeMul(nestedAmounts[i]) - ); - } - } -} diff --git a/contracts/extensions/contracts/src/MaximumGasPrice.sol b/contracts/extensions/contracts/src/MaximumGasPrice.sol deleted file mode 100644 index 027d9e5d2a..0000000000 --- a/contracts/extensions/contracts/src/MaximumGasPrice.sol +++ /dev/null @@ -1,50 +0,0 @@ -/* - - Copyright 2019 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.5.16; - - -contract MaximumGasPrice { - // 20 Gwei - uint256 constant private DEFAULT_MAX_GAS_PRICE = 20 * (10 ** 9); - - /// @dev Checks that the current transaction's gas price is less than - /// the default maximum value of 20 Gwei. - function checkGasPrice() - external - view - { - require( - tx.gasprice <= DEFAULT_MAX_GAS_PRICE, - "MaximumGasPrice/GAS_PRICE_EXCEEDS_20_GWEI" - ); - } - - /// @dev Checks that the current transaction's gas price is less than - /// the specified maximum value. - /// @param maxGasPrice The maximum gas price allowed for the current transaction. - function checkGasPrice(uint256 maxGasPrice) - external - view - { - require( - tx.gasprice <= maxGasPrice, - "MaximumGasPrice/GAS_PRICE_EXCEEDS_MAXIMUM" - ); - } -} diff --git a/contracts/extensions/contracts/src/MixinWethUtils.sol b/contracts/extensions/contracts/src/MixinWethUtils.sol deleted file mode 100644 index 26d2ae95a0..0000000000 --- a/contracts/extensions/contracts/src/MixinWethUtils.sol +++ /dev/null @@ -1,135 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./rich-errors/LibWethUtilsRichErrors.sol"; - - -contract MixinWethUtils { - - uint256 constant internal MAX_UINT256 = uint256(-1); - - // solhint-disable var-name-mixedcase - IEtherToken internal WETH; - bytes internal WETH_ASSET_DATA; - // solhint-enable var-name-mixedcase - - using LibSafeMath for uint256; - - constructor ( - address exchange, - address weth - ) - public - { - WETH = IEtherToken(weth); - WETH_ASSET_DATA = abi.encodeWithSelector( - IAssetData(address(0)).ERC20Token.selector, - weth - ); - - address proxyAddress = IExchange(exchange).getAssetProxy(IAssetData(address(0)).ERC20Token.selector); - if (proxyAddress == address(0)) { - LibRichErrors.rrevert(LibWethUtilsRichErrors.UnregisteredAssetProxyError()); - } - WETH.approve(proxyAddress, MAX_UINT256); - - address protocolFeeCollector = IExchange(exchange).protocolFeeCollector(); - if (protocolFeeCollector != address(0)) { - WETH.approve(protocolFeeCollector, MAX_UINT256); - } - } - - /// @dev Default payable function, this allows us to withdraw WETH - function () - external - payable - { - if (msg.sender != address(WETH)) { - LibRichErrors.rrevert(LibWethUtilsRichErrors.DefaultFunctionWethContractOnlyError( - msg.sender - )); - } - } - - /// @dev Transfers ETH denominated fees to all feeRecipient addresses - /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. - /// @param feeRecipients Addresses that will receive ETH when orders are filled. - /// @return ethRemaining msg.value minus the amount of ETH spent on affiliate fees. - function _transferEthFeesAndWrapRemaining( - uint256[] memory ethFeeAmounts, - address payable[] memory feeRecipients - ) - internal - returns (uint256 ethRemaining) - { - uint256 feesLen = ethFeeAmounts.length; - // ethFeeAmounts len must equal feeRecipients len - if (feesLen != feeRecipients.length) { - LibRichErrors.rrevert(LibWethUtilsRichErrors.EthFeeLengthMismatchError( - feesLen, - feeRecipients.length - )); - } - - // This function is always called before any other function, so we assume that - // the ETH remaining is the entire msg.value. - ethRemaining = msg.value; - - for (uint256 i = 0; i != feesLen; i++) { - uint256 ethFeeAmount = ethFeeAmounts[i]; - // Ensure there is enough ETH to pay the fee - if (ethRemaining < ethFeeAmount) { - LibRichErrors.rrevert(LibWethUtilsRichErrors.InsufficientEthForFeeError( - ethFeeAmount, - ethRemaining - )); - } - // Decrease ethRemaining and transfer fee to corresponding feeRecipient - ethRemaining = ethRemaining.safeSub(ethFeeAmount); - feeRecipients[i].transfer(ethFeeAmount); - } - - // Convert remaining ETH to WETH. - WETH.deposit.value(ethRemaining)(); - - return ethRemaining; - } - - /// @dev Unwraps WETH and transfers ETH to msg.sender. - /// @param transferAmount Amount of WETH balance to unwrap and transfer. - function _unwrapAndTransferEth( - uint256 transferAmount - ) - internal - { - // Do nothing if amount is zero - if (transferAmount > 0) { - // Convert WETH to ETH - WETH.withdraw(transferAmount); - // Transfer ETH to sender - msg.sender.transfer(transferAmount); - } - } -} diff --git a/contracts/extensions/contracts/src/rich-errors/LibAssetDataTransferRichErrors.sol b/contracts/extensions/contracts/src/rich-errors/LibAssetDataTransferRichErrors.sol deleted file mode 100644 index 61bea82ffd..0000000000 --- a/contracts/extensions/contracts/src/rich-errors/LibAssetDataTransferRichErrors.sol +++ /dev/null @@ -1,58 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -library LibAssetDataTransferRichErrors { - - // bytes4(keccak256("UnsupportedAssetProxyError(bytes4)")) - bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR = - 0x7996a271; - - // bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)")) - bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR = - 0xbaffa474; - - // solhint-disable func-name-mixedcase - function UnsupportedAssetProxyError( - bytes4 proxyId - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR, - proxyId - ); - } - - function Erc721AmountMustEqualOneError( - uint256 amount - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR, - amount - ); - } -} diff --git a/contracts/extensions/contracts/src/rich-errors/LibWethUtilsRichErrors.sol b/contracts/extensions/contracts/src/rich-errors/LibWethUtilsRichErrors.sol deleted file mode 100644 index c1b1e3369a..0000000000 --- a/contracts/extensions/contracts/src/rich-errors/LibWethUtilsRichErrors.sol +++ /dev/null @@ -1,91 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -library LibWethUtilsRichErrors { - - // bytes4(keccak256("UnregisteredAssetProxyError()")) - bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR = - 0xf3b96b8d; - - // bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)")) - bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR = - 0xecf40fd9; - - // bytes4(keccak256("DefaultFunctionWethContractOnlyError(address)")) - bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR = - 0x08b18698; - - // bytes4(keccak256("EthFeeLengthMismatchError(uint256,uint256)")) - bytes4 internal constant ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR = - 0x3ecb6ceb; - - // solhint-disable func-name-mixedcase - function UnregisteredAssetProxyError() - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR); - } - - function InsufficientEthForFeeError( - uint256 ethFeeRequired, - uint256 ethAvailable - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR, - ethFeeRequired, - ethAvailable - ); - } - - function DefaultFunctionWethContractOnlyError( - address senderAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR, - senderAddress - ); - } - - function EthFeeLengthMismatchError( - uint256 ethFeesLength, - uint256 feeRecipientsLength - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR, - ethFeesLength, - feeRecipientsLength - ); - } -} diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json deleted file mode 100644 index 0e5e43e6e3..0000000000 --- a/contracts/extensions/package.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "name": "@0x/contracts-extensions", - "version": "6.2.32", - "engines": { - "node": ">=6.12" - }, - "description": "Smart contract extensions of 0x protocol", - "main": "lib/src/index.js", - "directories": { - "test": "test" - }, - "scripts": { - "build": "yarn pre_build && tsc -b", - "build:ts": "tsc -b", - "build:ci": "yarn build", - "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "abis": "./test/generated-artifacts/@(LibAssetDataTransfer|LibAssetDataTransferRichErrors|LibWethUtilsRichErrors|MaximumGasPrice|MixinWethUtils).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-dev-utils": "^1.3.36", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-erc721": "^3.1.37", - "@0x/contracts-exchange": "^3.2.38", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/order-utils": "^10.4.28", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "ethereumjs-abi": "0.6.5", - "ethereumjs-util": "^7.0.10", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/typescript-typings": "^5.2.0", - "ethereum-types": "^3.5.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/extensions/src/artifacts.ts b/contracts/extensions/src/artifacts.ts deleted file mode 100644 index 9dd9816cca..0000000000 --- a/contracts/extensions/src/artifacts.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as LibAssetDataTransfer from '../generated-artifacts/LibAssetDataTransfer.json'; -import * as LibAssetDataTransferRichErrors from '../generated-artifacts/LibAssetDataTransferRichErrors.json'; -import * as LibWethUtilsRichErrors from '../generated-artifacts/LibWethUtilsRichErrors.json'; -import * as MaximumGasPrice from '../generated-artifacts/MaximumGasPrice.json'; -import * as MixinWethUtils from '../generated-artifacts/MixinWethUtils.json'; -export const artifacts = { - LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact, - MaximumGasPrice: MaximumGasPrice as ContractArtifact, - MixinWethUtils: MixinWethUtils as ContractArtifact, - LibAssetDataTransferRichErrors: LibAssetDataTransferRichErrors as ContractArtifact, - LibWethUtilsRichErrors: LibWethUtilsRichErrors as ContractArtifact, -}; diff --git a/contracts/extensions/src/index.ts b/contracts/extensions/src/index.ts deleted file mode 100644 index 1e8731cfd1..0000000000 --- a/contracts/extensions/src/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -export { artifacts } from './artifacts'; -export { LibAssetDataTransferRevertErrors, MixinWethUtilsRevertErrors } from '@0x/utils'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; -export * from './max_gas_price_utils'; diff --git a/contracts/extensions/src/max_gas_price_utils.ts b/contracts/extensions/src/max_gas_price_utils.ts deleted file mode 100644 index 7816423933..0000000000 --- a/contracts/extensions/src/max_gas_price_utils.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { constants } from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { StaticCallAssetData } from '@0x/types'; -import { AbiEncoder, BigNumber } from '@0x/utils'; - -const customGasPriceEncoder = AbiEncoder.createMethod('checkGasPrice', [{ name: 'maxGasPrice', type: 'uint256' }]); -const defaultGasPriceEncoder = AbiEncoder.createMethod('checkGasPrice', []); - -const ONE_GWEI = new BigNumber(10 ** 9); -export const TWENTY_GWEI = ONE_GWEI.times(20); - -/** - * Encodes the given stop limit data parameters into StaticCall asset data so that it can be used - * in a 0x order. - */ -export function encodeMaxGasPriceStaticCallData(maxGasPriceContractAddress: string, maxGasPrice?: BigNumber): string { - const staticCallData = - maxGasPrice === undefined ? defaultGasPriceEncoder.encode({}) : customGasPriceEncoder.encode({ maxGasPrice }); - return assetDataUtils.encodeStaticCallAssetData( - maxGasPriceContractAddress, - staticCallData, - constants.KECCAK256_NULL, - ); -} - -/** - * Decodes the maxGasPrice StaticCall asset data. - */ -export function decodeMaxGasPriceStaticCallData(assetData: string): BigNumber { - // tslint:disable-next-line:no-unnecessary-type-assertion - const { staticCallData } = assetDataUtils.decodeAssetDataOrThrow(assetData) as StaticCallAssetData; - try { - return customGasPriceEncoder.strictDecode(staticCallData); - } catch (e) { - defaultGasPriceEncoder.strictDecode(staticCallData); - return TWENTY_GWEI; - } -} diff --git a/contracts/extensions/src/wrappers.ts b/contracts/extensions/src/wrappers.ts deleted file mode 100644 index b08177589c..0000000000 --- a/contracts/extensions/src/wrappers.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/lib_asset_data_transfer'; -export * from '../generated-wrappers/lib_asset_data_transfer_rich_errors'; -export * from '../generated-wrappers/lib_weth_utils_rich_errors'; -export * from '../generated-wrappers/maximum_gas_price'; -export * from '../generated-wrappers/mixin_weth_utils'; diff --git a/contracts/extensions/test/artifacts.ts b/contracts/extensions/test/artifacts.ts deleted file mode 100644 index d7c29b0ff3..0000000000 --- a/contracts/extensions/test/artifacts.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as LibAssetDataTransfer from '../test/generated-artifacts/LibAssetDataTransfer.json'; -import * as LibAssetDataTransferRichErrors from '../test/generated-artifacts/LibAssetDataTransferRichErrors.json'; -import * as LibWethUtilsRichErrors from '../test/generated-artifacts/LibWethUtilsRichErrors.json'; -import * as MaximumGasPrice from '../test/generated-artifacts/MaximumGasPrice.json'; -import * as MixinWethUtils from '../test/generated-artifacts/MixinWethUtils.json'; -export const artifacts = { - LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact, - MaximumGasPrice: MaximumGasPrice as ContractArtifact, - MixinWethUtils: MixinWethUtils as ContractArtifact, - LibAssetDataTransferRichErrors: LibAssetDataTransferRichErrors as ContractArtifact, - LibWethUtilsRichErrors: LibWethUtilsRichErrors as ContractArtifact, -}; diff --git a/contracts/extensions/test/max_gas_price_test.ts b/contracts/extensions/test/max_gas_price_test.ts deleted file mode 100644 index 76ac63b7cf..0000000000 --- a/contracts/extensions/test/max_gas_price_test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { artifacts as assetProxyArtifacts, StaticCallProxyContract } from '@0x/contracts-asset-proxy'; -import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; - -import { - decodeMaxGasPriceStaticCallData, - encodeMaxGasPriceStaticCallData, - TWENTY_GWEI, -} from '../src/max_gas_price_utils'; - -import { artifacts } from './artifacts'; -import { MaximumGasPriceContract } from './wrappers'; - -blockchainTests.resets('MaximumGasPrice unit tests', env => { - let maxGasPriceContract: MaximumGasPriceContract; - let staticCallProxy: StaticCallProxyContract; - - let defaultMaxAssetData: string; - - before(async () => { - maxGasPriceContract = await MaximumGasPriceContract.deployFrom0xArtifactAsync( - artifacts.MaximumGasPrice, - env.provider, - env.txDefaults, - artifacts, - ); - staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.StaticCallProxy, - env.provider, - env.txDefaults, - assetProxyArtifacts, - ); - - defaultMaxAssetData = encodeMaxGasPriceStaticCallData(maxGasPriceContract.address); - }); - - describe('Data encoding/decoding tools', () => { - it('correctly decodes default maximum gas price', async () => { - const decoded = decodeMaxGasPriceStaticCallData(defaultMaxAssetData); - expect(decoded).to.bignumber.equal(TWENTY_GWEI); - }); - it('correctly decodes custom maximum gas price', async () => { - const customMaxGasPrice = getRandomInteger(0, constants.MAX_UINT256); - const customMaxAssetData = encodeMaxGasPriceStaticCallData(maxGasPriceContract.address, customMaxGasPrice); - const decoded = decodeMaxGasPriceStaticCallData(customMaxAssetData); - expect(decoded).to.bignumber.equal(customMaxGasPrice); - }); - }); - - describe('Contract functionality', () => { - it('does not revert if tx.gasprice < default maximum', async () => { - await staticCallProxy - .transferFrom(defaultMaxAssetData, randomAddress(), randomAddress(), constants.ZERO_AMOUNT) - .callAsync({ gasPrice: TWENTY_GWEI.minus(1) }); - }); - it('does not revert if tx.gasprice = default maximum', async () => { - await staticCallProxy - .transferFrom(defaultMaxAssetData, randomAddress(), randomAddress(), constants.ZERO_AMOUNT) - .callAsync({ gasPrice: TWENTY_GWEI }); - }); - it('reverts if tx.gasPrice > default maximum', async () => { - const tx = staticCallProxy - .transferFrom(defaultMaxAssetData, randomAddress(), randomAddress(), constants.ZERO_AMOUNT) - .callAsync({ gasPrice: TWENTY_GWEI.plus(1) }); - return expect(tx).to.revertWith('MaximumGasPrice/GAS_PRICE_EXCEEDS_20_GWEI'); - }); - it('does not revert if tx.gasprice < custom maximum', async () => { - const maxGasPrice = getRandomInteger(0, TWENTY_GWEI.times(2)); - const customMaxAssetData = encodeMaxGasPriceStaticCallData(maxGasPriceContract.address, maxGasPrice); - await staticCallProxy - .transferFrom(customMaxAssetData, randomAddress(), randomAddress(), constants.ZERO_AMOUNT) - .callAsync({ gasPrice: maxGasPrice.minus(1) }); - }); - it('does not revert if tx.gasprice = custom maximum', async () => { - const maxGasPrice = getRandomInteger(0, TWENTY_GWEI.times(2)); - const customMaxAssetData = encodeMaxGasPriceStaticCallData(maxGasPriceContract.address, maxGasPrice); - await staticCallProxy - .transferFrom(customMaxAssetData, randomAddress(), randomAddress(), constants.ZERO_AMOUNT) - .callAsync({ gasPrice: maxGasPrice }); - }); - it('reverts if tx.gasPrice > custom maximum', async () => { - const maxGasPrice = getRandomInteger(0, TWENTY_GWEI.times(2)); - const customMaxAssetData = encodeMaxGasPriceStaticCallData(maxGasPriceContract.address, maxGasPrice); - const tx = staticCallProxy - .transferFrom(customMaxAssetData, randomAddress(), randomAddress(), constants.ZERO_AMOUNT) - .callAsync({ gasPrice: maxGasPrice.plus(1) }); - return expect(tx).to.revertWith('MaximumGasPrice/GAS_PRICE_EXCEEDS_MAXIMUM'); - }); - }); -}); diff --git a/contracts/extensions/test/wrappers.ts b/contracts/extensions/test/wrappers.ts deleted file mode 100644 index fffb69973f..0000000000 --- a/contracts/extensions/test/wrappers.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/lib_asset_data_transfer'; -export * from '../test/generated-wrappers/lib_asset_data_transfer_rich_errors'; -export * from '../test/generated-wrappers/lib_weth_utils_rich_errors'; -export * from '../test/generated-wrappers/maximum_gas_price'; -export * from '../test/generated-wrappers/mixin_weth_utils'; diff --git a/contracts/extensions/truffle-config.js b/contracts/extensions/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/extensions/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/extensions/tsconfig.json b/contracts/extensions/tsconfig.json deleted file mode 100644 index 76c8c725b3..0000000000 --- a/contracts/extensions/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/LibAssetDataTransfer.json", - "generated-artifacts/LibAssetDataTransferRichErrors.json", - "generated-artifacts/LibWethUtilsRichErrors.json", - "generated-artifacts/MaximumGasPrice.json", - "generated-artifacts/MixinWethUtils.json", - "test/generated-artifacts/LibAssetDataTransfer.json", - "test/generated-artifacts/LibAssetDataTransferRichErrors.json", - "test/generated-artifacts/LibWethUtilsRichErrors.json", - "test/generated-artifacts/MaximumGasPrice.json", - "test/generated-artifacts/MixinWethUtils.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/extensions/tslint.json b/contracts/extensions/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/extensions/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/extensions/typedoc-tsconfig.json b/contracts/extensions/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/extensions/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/integrations/.npmignore b/contracts/integrations/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/integrations/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/integrations/CHANGELOG.json b/contracts/integrations/CHANGELOG.json deleted file mode 100644 index dd80d30e1b..0000000000 --- a/contracts/integrations/CHANGELOG.json +++ /dev/null @@ -1,348 +0,0 @@ -[ - { - "timestamp": 1605763885, - "version": "2.7.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605320370, - "version": "2.7.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "2.7.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604620645, - "version": "2.7.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "2.7.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "2.7.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "2.7.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "2.7.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "2.7.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603487270, - "version": "2.7.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.7.0", - "changes": [ - { - "note": "Update curveBridge tests", - "pr": 2633 - }, - { - "note": "Add EP RFQT + MTX tests", - "pr": 2692 - } - ], - "timestamp": 1603265572 - }, - { - "version": "2.6.0", - "changes": [ - { - "note": "Add `BalancerBridge` mainnet tests", - "pr": 2613 - } - ], - "timestamp": 1594788383 - }, - { - "version": "2.5.2", - "changes": [ - { - "note": "Update `ERC20BridgeSampler` tests", - "pr": 2531 - } - ], - "timestamp": 1592969527 - }, - { - "timestamp": 1583220306, - "version": "2.5.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.5.0", - "changes": [ - { - "note": "Add `ChaiBridge` and `DydxBridge` gas benchmark tests.", - "pr": 2478 - } - ], - "timestamp": 1582837861 - }, - { - "timestamp": 1582677073, - "version": "2.4.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "2.4.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.4.0", - "changes": [ - { - "note": "Added ChainlinkStopLimit contract and tests", - "pr": 2473 - }, - { - "note": "Fixed the mainnet dYdX Bridge tests.", - "pr": 2479 - }, - { - "note": "Addded decoders for stop-limit data", - "pr": 2484 - }, - { - "note": "Added ERC20Sampler and Curve Mainnet test", - "pr": 2483 - } - ], - "timestamp": 1581748629 - }, - { - "version": "2.3.0", - "changes": [ - { - "note": "Remove dependency on `DevUtils` for asset data encoding/decoding", - "pr": 2462 - }, - { - "note": "Update tests for refactored `DevUtils`", - "pr": 2464 - }, - { - "note": "Add DydxBridge validation", - "pr": 2466 - }, - { - "note": "Add DevUtils DydxBridge validation mainnet tests", - "pr": 2466 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "2.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "2.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579744659, - "version": "2.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.2.0", - "changes": [ - { - "note": "Add mainnet contract wrapper `callAsync()` revert behavior tests.", - "pr": 2433 - }, - { - "note": "Fuzz tests for `matchOrders` and `matchOrdersWithMaximalFill`.", - "pr": 2437 - }, - { - "note": "Add various negative assertions for fuzz tests", - "pr": 2431 - } - ], - "timestamp": 1579682890 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Integration tests for DydxBridge with (i) Exchange v3 and (ii) Mainnet dYdX SoloMargin contract.", - "pr": 2401 - }, - { - "note": "Add aggregator mainnet tests.", - "pr": 2407 - }, - { - "note": "Add fuzz tests for Exchange signature validation.", - "pr": 2425 - } - ], - "timestamp": 1578272714 - }, - { - "timestamp": 1576540892, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Forwader <> ERC20Bridge integration tests", - "pr": 2356 - } - ], - "timestamp": 1575296764 - }, - { - "version": "1.0.3-beta.2", - "changes": [ - { - "note": "Forwader <> ERC20Bridge integration tests", - "pr": 2356 - } - ], - "timestamp": 1575290197 - }, - { - "version": "1.0.3-beta.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "timestamp": 1574030254, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1573159180, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Created package", - "pr": "2240" - }, - { - "note": "Added the deployment manager class", - "pr": "2240" - } - ] - } -] diff --git a/contracts/integrations/CHANGELOG.md b/contracts/integrations/CHANGELOG.md deleted file mode 100644 index 37c3e27d28..0000000000 --- a/contracts/integrations/CHANGELOG.md +++ /dev/null @@ -1,146 +0,0 @@ - - -CHANGELOG - -## v2.7.10 - _November 19, 2020_ - - * Dependencies updated - -## v2.7.9 - _November 14, 2020_ - - * Dependencies updated - -## v2.7.8 - _November 13, 2020_ - - * Dependencies updated - -## v2.7.7 - _November 5, 2020_ - - * Dependencies updated - -## v2.7.6 - _November 3, 2020_ - - * Dependencies updated - -## v2.7.5 - _November 3, 2020_ - - * Dependencies updated - -## v2.7.4 - _November 2, 2020_ - - * Dependencies updated - -## v2.7.3 - _October 28, 2020_ - - * Dependencies updated - -## v2.7.2 - _October 27, 2020_ - - * Dependencies updated - -## v2.7.1 - _October 23, 2020_ - - * Dependencies updated - -## v2.7.0 - _October 21, 2020_ - - * Update curveBridge tests (#2633) - * Add EP RFQT + MTX tests (#2692) - -## v2.6.0 - _July 15, 2020_ - - * Add `BalancerBridge` mainnet tests (#2613) - -## v2.5.2 - _June 24, 2020_ - - * Update `ERC20BridgeSampler` tests (#2531) - -## v2.5.1 - _March 3, 2020_ - - * Dependencies updated - -## v2.5.0 - _February 27, 2020_ - - * Add `ChaiBridge` and `DydxBridge` gas benchmark tests. (#2478) - -## v2.4.2 - _February 26, 2020_ - - * Dependencies updated - -## v2.4.1 - _February 25, 2020_ - - * Dependencies updated - -## v2.4.0 - _February 15, 2020_ - - * Added ChainlinkStopLimit contract and tests (#2473) - * Fixed the mainnet dYdX Bridge tests. (#2479) - * Addded decoders for stop-limit data (#2484) - * Added ERC20Sampler and Curve Mainnet test (#2483) - -## v2.3.0 - _February 8, 2020_ - - * Remove dependency on `DevUtils` for asset data encoding/decoding (#2462) - * Update tests for refactored `DevUtils` (#2464) - * Add DydxBridge validation (#2466) - * Add DevUtils DydxBridge validation mainnet tests (#2466) - -## v2.2.3 - _February 6, 2020_ - - * Dependencies updated - -## v2.2.2 - _February 4, 2020_ - - * Dependencies updated - -## v2.2.1 - _January 23, 2020_ - - * Dependencies updated - -## v2.2.0 - _January 22, 2020_ - - * Add mainnet contract wrapper `callAsync()` revert behavior tests. (#2433) - * Fuzz tests for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437) - * Add various negative assertions for fuzz tests (#2431) - -## v2.1.0 - _January 6, 2020_ - - * Integration tests for DydxBridge with (i) Exchange v3 and (ii) Mainnet dYdX SoloMargin contract. (#2401) - * Add aggregator mainnet tests. (#2407) - * Add fuzz tests for Exchange signature validation. (#2425) - -## v2.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v2.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v2.0.0 - _December 2, 2019_ - - * Forwader <> ERC20Bridge integration tests (#2356) - -## v1.0.3-beta.2 - _December 2, 2019_ - - * Forwader <> ERC20Bridge integration tests (#2356) - -## v1.0.3-beta.1 - _November 20, 2019_ - - * Dependencies updated - -## v1.0.2 - _November 17, 2019_ - - * Dependencies updated - -## v1.0.1 - _November 7, 2019_ - - * Dependencies updated - -## v1.0.0 - _Invalid date_ - - * Created package (#2240) - * Added the deployment manager class (#2240) diff --git a/contracts/integrations/README.md b/contracts/integrations/README.md deleted file mode 100644 index 5a1d2be163..0000000000 --- a/contracts/integrations/README.md +++ /dev/null @@ -1,65 +0,0 @@ -## Integration Tests - -This package implements integration tests against 0x's smart contracts and will provide a location for external contracts to be tested alongside the 0x smart contracts. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-integrations --save -``` - -## 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=@0x/contracts-integrations yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-integrations yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` diff --git a/contracts/integrations/compiler.json b/contracts/integrations/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/integrations/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/integrations/contracts/src/ChainlinkStopLimit.sol b/contracts/integrations/contracts/src/ChainlinkStopLimit.sol deleted file mode 100644 index 397e139148..0000000000 --- a/contracts/integrations/contracts/src/ChainlinkStopLimit.sol +++ /dev/null @@ -1,50 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./interfaces/IChainlinkAggregator.sol"; - - -contract ChainlinkStopLimit { - - /// @dev Checks that the price returned by the encoded Chainlink reference contract is - /// within the encoded price range. - /// @param stopLimitData Encodes the address of the Chainlink reference contract and the - /// valid price range. - function checkStopLimit(bytes calldata stopLimitData) - external - view - { - ( - address oracle, - int256 minPrice, - int256 maxPrice - ) = abi.decode( - stopLimitData, - (address, int256, int256) - ); - - int256 latestPrice = IChainlinkAggregator(oracle).latestAnswer(); - require( - latestPrice >= minPrice && latestPrice <= maxPrice, - "ChainlinkStopLimit/OUT_OF_PRICE_RANGE" - ); - } -} diff --git a/contracts/integrations/contracts/src/interfaces/IChainlinkAggregator.sol b/contracts/integrations/contracts/src/interfaces/IChainlinkAggregator.sol deleted file mode 100644 index 08cf6af408..0000000000 --- a/contracts/integrations/contracts/src/interfaces/IChainlinkAggregator.sol +++ /dev/null @@ -1,30 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -// A subset of https://github.com/smartcontractkit/chainlink/blob/master/evm/contracts/interfaces/AggregatorInterface.sol -interface IChainlinkAggregator { - - /// @dev Returns the latest data value recorded by the contract. - /// @return answer The latest data value recorded. For a price oracle aggregator, this will be - /// the price of the given asset in USD, multipled by 10^8 - function latestAnswer() external view returns (int256 answer); -} diff --git a/contracts/integrations/contracts/test/TestChainlinkAggregator.sol b/contracts/integrations/contracts/test/TestChainlinkAggregator.sol deleted file mode 100644 index 4626e20dad..0000000000 --- a/contracts/integrations/contracts/test/TestChainlinkAggregator.sol +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IChainlinkAggregator.sol"; - - -contract TestChainlinkAggregator is - IChainlinkAggregator -{ - int256 internal _price; - - function setPrice(int256 price_) - external - { - _price = price_; - } - - function latestAnswer() - external - view - returns (int256) - { - return _price; - } -} diff --git a/contracts/integrations/contracts/test/TestContractWrapper.sol b/contracts/integrations/contracts/test/TestContractWrapper.sol deleted file mode 100644 index 6472327120..0000000000 --- a/contracts/integrations/contracts/test/TestContractWrapper.sol +++ /dev/null @@ -1,60 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -// solhint-disable no-empty-blocks -contract TestContractWrapper { - - uint256 constant public VALID_RETURN_VALUE = 0xf984f922a56ea9a20a32a32f0f60f2d216ff0c0a0d16c986a97a7f1897a6613b; - - function throwStringRevert() external returns (uint256) { - revert("ERROR"); - } - - function throwEmptyRevert() external returns (uint256) { - revert(); - } - - function throwInvalidOpcode() external returns (uint256) { - assembly { - invalid() - } - } - - function returnForcedEmpty() external returns (uint256) { - assembly { - return(0x60, 0) - } - } - - function returnTruncated() external returns (uint256) { - uint256 v = VALID_RETURN_VALUE; - assembly { - mstore(0x0, v) - return(0x0, 16) - } - } - - function returnEmpty() external { } - - function returnValid() external returns (uint256) { - return VALID_RETURN_VALUE; - } -} diff --git a/contracts/integrations/contracts/test/TestDydxUser.sol b/contracts/integrations/contracts/test/TestDydxUser.sol deleted file mode 100644 index f57e85c6d2..0000000000 --- a/contracts/integrations/contracts/test/TestDydxUser.sol +++ /dev/null @@ -1,207 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -/// @dev THIS IS A SELF-CONTAINED CONVENIENCE CONTRACT FOR TESTING THE DYDX BRIDGE ON MAINNET. -/// Currently deployed at 0xeb58c2caa96f39626dcceb74fdbb7a9a8b54ec18. -/// Steps: -/// 1. Deploy to mainnet (can copy-paste this into Remix and deploy). -/// 2. Send some DAI to the contract. -/// 3. Call `init()` to configure. -interface IERC20Token { - - /// @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 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); -} - - -/// @dev TestDydxUser uses this interface to interact with dydx. -interface IDydx { - - /// @dev Respresents an operator's privileges. - struct OperatorArg { - address operator; - bool trusted; - } - - /// @dev Represents the unique key that specifies an account - struct AccountInfo { - address owner; // The address that owns the account - uint256 number; // A nonce that allows a single address to control many accounts - } - - enum ActionType { - Deposit, // supply tokens - Withdraw, // borrow tokens - Transfer, // transfer balance between accounts - Buy, // buy an amount of some token (externally) - Sell, // sell an amount of some token (externally) - Trade, // trade tokens against another account - Liquidate, // liquidate an undercollateralized or expiring account - Vaporize, // use excess tokens to zero-out a completely negative account - Call // send arbitrary data to an address - } - - /// @dev Arguments that are passed to Solo in an ordered list as part of a single operation. - /// Each ActionArgs has an actionType which specifies which action struct that this data will be - /// parsed into before being processed. - struct ActionArgs { - ActionType actionType; - uint256 accountId; - AssetAmount amount; - uint256 primaryMarketId; - uint256 secondaryMarketId; - address otherAddress; - uint256 otherAccountId; - bytes data; - } - - enum AssetDenomination { - Wei, // the amount is denominated in wei - Par // the amount is denominated in par - } - - enum AssetReference { - Delta, // the amount is given as a delta from the current value - Target // the amount is given as an exact number to end up at - } - - struct AssetAmount { - bool sign; // true if positive - AssetDenomination denomination; - AssetReference ref; - uint256 value; - } - - /// @dev The main entry-point to Solo that allows users and contracts to manage accounts. - /// Take one or more actions on one or more accounts. The msg.sender must be the owner or - /// operator of all accounts except for those being liquidated, vaporized, or traded with. - /// One call to operate() is considered a singular "operation". Account collateralization is - /// ensured only after the completion of the entire operation. - /// @param accounts A list of all accounts that will be used in this operation. Cannot contain - /// duplicates. In each action, the relevant account will be referred-to by its - /// index in the list. - /// @param actions An ordered list of all actions that will be taken in this operation. The - /// actions will be processed in order. - function operate( - AccountInfo[] calldata accounts, - ActionArgs[] calldata actions - ) - external; - - /// @dev Sets operators of dydx account. - /// @param operators to give/remove access. - function setOperators(OperatorArg[] calldata operators) - external; -} - - -/// @dev Deploy this contract and call `init` to run the mainnet DydxBridge integration tests. -contract TestDydxUser { - - address public constant DYDX_BRIDGE_ADDRESS = 0x55dC8f21D20D4c6ED3C82916A438A413ca68e335; - address public constant DYDX_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e; - address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F; - uint256 public constant DYDX_DAI_MARKET_ID = 3; - bytes4 public constant MAGIC_BYTES = bytes4(keccak256("init()")); - - function init() - public - returns (bytes4) - { - // 1. Assert that this account has DAI. - uint256 daiBalance = IERC20Token(DAI_ADDRESS).balanceOf(address(this)); - require( - daiBalance > 0, - "TestDydxUser/DAI_BALANCE_MUST_BE_NONZERO" - ); - - // 2. Set allowance for Dydx to transfer DAI. - require( - IERC20Token(DAI_ADDRESS).approve( - DYDX_ADDRESS, - daiBalance - ), - "TestDydxUser/FAILED_TO_SET_DAI_ALLOWANCE" - ); - - // 3. Add DydxBridge as operator on dydx. - // This will revert on failure. - IDydx.OperatorArg[] memory operatorArgs = new IDydx.OperatorArg[](1); - operatorArgs[0] = IDydx.OperatorArg({ - operator: DYDX_BRIDGE_ADDRESS, - trusted: true - }); - IDydx(DYDX_ADDRESS).setOperators(operatorArgs); - - // 4. Deposit 1/2 DAI balance into dydx. This allows us to test withdrawals. - // 4.i Create dydx account struct. - IDydx.AccountInfo[] memory accounts = new IDydx.AccountInfo[](1); - accounts[0] = IDydx.AccountInfo({ - owner: address(this), - number: 0 - }); - - // 4.ii Create dydx amount. - IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({ - sign: true, // true if positive. - denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account. - ref: IDydx.AssetReference.Delta, // Delta => a relative amount. - value: daiBalance / 2 // amount to deposit. - }); - - // 4.iii Create dydx deposit action. - IDydx.ActionArgs[] memory actions = new IDydx.ActionArgs[](1); - actions[0] = IDydx.ActionArgs({ - actionType: IDydx.ActionType.Deposit, // deposit tokens. - amount: dydxAmount, // amount to deposit. - accountId: 0, // index in the `accounts` when calling `operate`. - primaryMarketId: DYDX_DAI_MARKET_ID, // indicates which token to deposit. - otherAddress: address(this), // deposit from the account owner. - // unused parameters - secondaryMarketId: 0, - otherAccountId: 0, - data: hex'' - }); - - // 4.iv Deposit DAI into dydx. This will revert on failure. - IDydx(DYDX_ADDRESS).operate( - accounts, - actions - ); - - // Return magic bytes on success. - return MAGIC_BYTES; - } -} \ No newline at end of file diff --git a/contracts/integrations/contracts/test/TestEth2Dai.sol b/contracts/integrations/contracts/test/TestEth2Dai.sol deleted file mode 100644 index 011906472c..0000000000 --- a/contracts/integrations/contracts/test/TestEth2Dai.sol +++ /dev/null @@ -1,59 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IEth2Dai.sol"; -import "@0x/contracts-erc20/contracts/test/DummyERC20Token.sol"; - - -contract TestEth2Dai is - IEth2Dai -{ - uint256 private _excessBuyAmount; - - function setExcessBuyAmount(uint256 amount) - external - { - _excessBuyAmount = amount; - } - - function sellAllAmount( - address sellTokenAddress, - uint256 sellTokenAmount, - address buyTokenAddress, - uint256 minimumFillAmount - ) - external - returns (uint256 fillAmount) - { - DummyERC20Token(sellTokenAddress).transferFrom( - msg.sender, - address(this), - sellTokenAmount - ); - DummyERC20Token buyToken = DummyERC20Token(buyTokenAddress); - buyToken.mint(minimumFillAmount + _excessBuyAmount); - buyToken.transfer( - msg.sender, - minimumFillAmount + _excessBuyAmount - ); - return minimumFillAmount + _excessBuyAmount; - } -} diff --git a/contracts/integrations/contracts/test/TestEth2DaiBridge.sol b/contracts/integrations/contracts/test/TestEth2DaiBridge.sol deleted file mode 100644 index 80c0536762..0000000000 --- a/contracts/integrations/contracts/test/TestEth2DaiBridge.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol"; - - -contract TestEth2DaiBridge is - Eth2DaiBridge -{ - // solhint-disable var-name-mixedcase - address public TEST_ETH2DAI_ADDRESS; - - constructor (address testEth2Dai) - public - { - TEST_ETH2DAI_ADDRESS = testEth2Dai; - } - - function _getEth2DaiAddress() - internal - view - returns (address exchange) - { - return TEST_ETH2DAI_ADDRESS; - } -} diff --git a/contracts/integrations/contracts/test/TestFixinProtocolFeesIntegration.sol b/contracts/integrations/contracts/test/TestFixinProtocolFeesIntegration.sol deleted file mode 100644 index 6030a1cfb2..0000000000 --- a/contracts/integrations/contracts/test/TestFixinProtocolFeesIntegration.sol +++ /dev/null @@ -1,39 +0,0 @@ -/* - - Copyright 2020 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.6.5; - -import "@0x/contracts-zero-ex/contracts/test/TestFixinProtocolFees.sol"; -import "@0x/contracts-zero-ex/contracts/src/external/FeeCollectorController.sol"; - - -contract TestFixinProtocolFeesIntegration is TestFixinProtocolFees { - constructor( - IEtherTokenV06 weth, - IStaking staking, - uint32 protocolFeeMultiplier - ) - public - TestFixinProtocolFees( - weth, - staking, - new FeeCollectorController(weth, staking), - protocolFeeMultiplier - ) - {} -} diff --git a/contracts/integrations/contracts/test/TestFramework.sol b/contracts/integrations/contracts/test/TestFramework.sol deleted file mode 100644 index 6eb019e8fb..0000000000 --- a/contracts/integrations/contracts/test/TestFramework.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity ^0.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; - - -// This contract is intended to be used in the unit tests that test the typescript -// test framework found in `test/utils/` -contract TestFramework { - - event Event(string input); - - // bytes4(keccak256("RichRevertErrorSelector(string)")) - bytes4 internal constant RICH_REVERT_ERROR_SELECTOR = 0x49a7e246; - - function emitEvent(string calldata input) - external - { - emit Event(input); - } - - function emptyRevert() - external - pure - { - revert(); - } - - function stringRevert(string calldata message) - external - pure - { - revert(message); - } - - function doNothing() - external - pure - {} // solhint-disable-line no-empty-blocks - - function returnInteger(uint256 integer) - external - pure - returns (uint256) - { - return integer; - } -} diff --git a/contracts/integrations/contracts/test/TestMainnetAggregatorFills.sol b/contracts/integrations/contracts/test/TestMainnetAggregatorFills.sol deleted file mode 100644 index facd42997d..0000000000 --- a/contracts/integrations/contracts/test/TestMainnetAggregatorFills.sol +++ /dev/null @@ -1,180 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; -import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; -import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; - - -/// @dev A forwarder contract for filling 0x asset-swapper aggregated orders. -/// The forwarder is necessary to purchase taker assets and set up -/// approvals in one transaction. Only call the functions on this contract -/// in an `eth_call` context or you will lose money! -contract TestMainnetAggregatorFills is - DeploymentConstants -{ - using LibSafeMath for uint256; - - address constant internal EXCHANGE_ADDRESS = 0x61935CbDd02287B511119DDb11Aeb42F1593b7Ef; - bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)")); - - struct SimulatedMarketFillResults { - uint256 makerAssetBalanceBefore; - uint256 takerAssetBalanceBefore; - uint256 makerAssetBalanceAfter; - uint256 takerAssetBalanceAfter; - LibFillResults.FillResults fillResults; - } - - // solhint-disable-next-line no-empty-blocks - function() external payable {} - - /// @dev Buy taker assets with ETH from `takerOrders` and then perform a - /// market buy on `makerOrders`. - function marketBuy( - address makerTokenAddress, - address takerTokenAddress, - LibOrder.Order[] memory makerOrders, - LibOrder.Order[] memory takerOrders, - bytes[] memory makerOrderSignatures, - bytes[] memory takerOrderSignatures, - uint256 makerAssetBuyAmount - ) - public - payable - returns (SimulatedMarketFillResults memory results) - { - _prepareFunds(takerTokenAddress, makerOrders, takerOrders, takerOrderSignatures); - results.makerAssetBalanceBefore = IERC20Token(makerTokenAddress).balanceOf(address(this)); - results.takerAssetBalanceBefore = IERC20Token(takerTokenAddress).balanceOf(address(this)); - results.fillResults = IExchange(EXCHANGE_ADDRESS) - .marketBuyOrdersNoThrow - .value(address(this).balance)( - makerOrders, - makerAssetBuyAmount, - makerOrderSignatures - ); - results.makerAssetBalanceAfter = IERC20Token(makerTokenAddress).balanceOf(address(this)); - results.takerAssetBalanceAfter = IERC20Token(takerTokenAddress).balanceOf(address(this)); - } - - /// @dev Buy taker assets with ETH from `takerOrders` and then perform a - /// market sell on `makerOrders`. - function marketSell( - address makerTokenAddress, - address takerTokenAddress, - LibOrder.Order[] memory makerOrders, - LibOrder.Order[] memory takerOrders, - bytes[] memory makerOrderSignatures, - bytes[] memory takerOrderSignatures, - uint256 takerAssetSellAmount - ) - public - payable - returns (SimulatedMarketFillResults memory results) - { - _prepareFunds(takerTokenAddress, makerOrders, takerOrders, takerOrderSignatures); - results.makerAssetBalanceBefore = IERC20Token(makerTokenAddress).balanceOf(address(this)); - results.takerAssetBalanceBefore = IERC20Token(takerTokenAddress).balanceOf(address(this)); - results.fillResults = IExchange(EXCHANGE_ADDRESS) - .marketSellOrdersNoThrow - .value(address(this).balance)( - makerOrders, - takerAssetSellAmount, - makerOrderSignatures - ); - results.makerAssetBalanceAfter = IERC20Token(makerTokenAddress).balanceOf(address(this)); - results.takerAssetBalanceAfter = IERC20Token(takerTokenAddress).balanceOf(address(this)); - } - - /// @dev Like `marketSell`, but calls `fillOrder()` individually to detect - /// errors. - function fillOrders( - address makerTokenAddress, - address takerTokenAddress, - LibOrder.Order[] memory makerOrders, - LibOrder.Order[] memory takerOrders, - bytes[] memory makerOrderSignatures, - bytes[] memory takerOrderSignatures, - uint256 takerAssetSellAmount - ) - public - payable - returns (SimulatedMarketFillResults memory results) - { - _prepareFunds(takerTokenAddress, makerOrders, takerOrders, takerOrderSignatures); - results.makerAssetBalanceBefore = IERC20Token(makerTokenAddress).balanceOf(address(this)); - results.takerAssetBalanceBefore = IERC20Token(takerTokenAddress).balanceOf(address(this)); - for (uint256 i = 0; i < makerOrders.length; i++) { - if (takerAssetSellAmount == 0) { - break; - } - LibFillResults.FillResults memory fillResults = IExchange(EXCHANGE_ADDRESS) - .fillOrder - .value(address(this).balance)( - makerOrders[i], - takerAssetSellAmount, - makerOrderSignatures[i] - ); - results.fillResults = LibFillResults.addFillResults(results.fillResults, fillResults); - takerAssetSellAmount = takerAssetSellAmount.safeSub(fillResults.takerAssetFilledAmount); - } - results.makerAssetBalanceAfter = IERC20Token(makerTokenAddress).balanceOf(address(this)); - results.takerAssetBalanceAfter = IERC20Token(takerTokenAddress).balanceOf(address(this)); - } - - function _approveAssetProxy(address tokenAddress) private { - address assetProxyAddress = IExchange(EXCHANGE_ADDRESS).getAssetProxy(ERC20_PROXY_ID); - LibERC20Token.approve(tokenAddress, assetProxyAddress, uint256(-1)); - } - - /// @dev Buys as much of `takerOrders` as possible with the ETH transferred - /// to this contract, leaving enough ETH behind for protocol fees. - function _prepareFunds( - address takerTokenAddress, - LibOrder.Order[] memory makerOrders, - LibOrder.Order[] memory takerOrders, - bytes[] memory takerOrderSignatures - ) - private - { - _approveAssetProxy(_getWethAddress()); - uint256 protocolFee = IExchange(EXCHANGE_ADDRESS).protocolFeeMultiplier() * tx.gasprice; - uint256 maxProtocolFees = protocolFee * (takerOrders.length + makerOrders.length); - uint256 ethSellAmount = msg.value.safeSub(maxProtocolFees); - IEtherToken(_getWethAddress()).deposit.value(ethSellAmount)(); - if (takerTokenAddress != _getWethAddress()) { - IExchange(EXCHANGE_ADDRESS) - .marketSellOrdersNoThrow - .value(maxProtocolFees)( - takerOrders, - ethSellAmount, - takerOrderSignatures - ); - _approveAssetProxy(takerTokenAddress); - } - } -} diff --git a/contracts/integrations/contracts/test/TestSignatureValidationWallet.sol b/contracts/integrations/contracts/test/TestSignatureValidationWallet.sol deleted file mode 100644 index 3600c9a0ac..0000000000 --- a/contracts/integrations/contracts/test/TestSignatureValidationWallet.sol +++ /dev/null @@ -1,53 +0,0 @@ -/* - - Copyright 2019 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.5.5; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; - - -contract TestSignatureValidationWallet is - LibEIP1271 -{ - bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; - - // Callback used by `EIP1271Wallet` and `Validator` signature types. - function isValidSignature( - bytes memory, - bytes memory - ) - public - pure - returns (bytes4 magicValue) - { - return EIP1271_MAGIC_VALUE; - } - - // Callback used by `Wallet` signature type. - function isValidSignature( - bytes32, - bytes memory - ) - public - pure - returns (bytes4 magicValue) - { - return LEGACY_WALLET_MAGIC_VALUE; - } -} diff --git a/contracts/integrations/contracts/test/TestStaking.sol b/contracts/integrations/contracts/test/TestStaking.sol deleted file mode 100644 index 644e065384..0000000000 --- a/contracts/integrations/contracts/test/TestStaking.sol +++ /dev/null @@ -1,110 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-staking/contracts/src/Staking.sol"; - - -contract TestStaking is - Staking -{ - IEtherToken public testWeth; - - struct TestPool { - uint96 operatorStake; - uint96 membersStake; - } - - mapping(bytes32 => TestPool) private _testPools; - - constructor(address exchangeAddress, IEtherToken _testWeth) public { - testWeth = _testWeth; - - _addAuthorizedAddress(msg.sender); - init(); - validExchanges[exchangeAddress] = true; - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - function advanceEpoch() - external - { - currentEpoch += 1; - } - - /// @dev Create a test pool. - function createTestPool( - bytes32 poolId, - uint96 operatorStake, - uint96 membersStake - ) - external - { - TestPool storage pool = _testPools[poolId]; - pool.operatorStake = operatorStake; - pool.membersStake = membersStake; - } - - function getAggregatedStatsForCurrentEpoch() - external - view - returns (IStructs.AggregatedStats memory) - { - return aggregatedStatsByEpoch[currentEpoch]; - } - - /// @dev Overridden to use test pools. - function getTotalStakeDelegatedToPool(bytes32 poolId) - public - view - returns (IStructs.StoredBalance memory balance) - { - TestPool memory pool = _testPools[poolId]; - uint96 stake = pool.operatorStake + pool.membersStake; - return IStructs.StoredBalance({ - currentEpoch: currentEpoch.downcastToUint64(), - currentEpochBalance: stake, - nextEpochBalance: stake - }); - } - - /// @dev Overridden to use test pools. - function getStakeDelegatedToPoolByOwner(address, bytes32 poolId) - public - view - returns (IStructs.StoredBalance memory balance) - { - TestPool memory pool = _testPools[poolId]; - return IStructs.StoredBalance({ - currentEpoch: currentEpoch.downcastToUint64(), - currentEpochBalance: pool.operatorStake, - nextEpochBalance: pool.operatorStake - }); - } - - function getWethContract() - public - view - returns (IEtherToken wethContract) - { - return testWeth; - } -} - diff --git a/contracts/integrations/contracts/test/TestUniswapBridge.sol b/contracts/integrations/contracts/test/TestUniswapBridge.sol deleted file mode 100644 index 0686a2e6f8..0000000000 --- a/contracts/integrations/contracts/test/TestUniswapBridge.sol +++ /dev/null @@ -1,57 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/bridges/UniswapBridge.sol"; - - -contract TestUniswapBridge is - UniswapBridge -{ - // solhint-disable var-name-mixedcase - address public TEST_WETH_ADDRESS; - address public TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS; - - constructor ( - address testWeth, - address testUniswapExchangeFactory - ) - public - { - TEST_WETH_ADDRESS = testWeth; - TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS = testUniswapExchangeFactory; - } - - function _getWethAddress() - internal - view - returns (address token) - { - return TEST_WETH_ADDRESS; - } - - function _getUniswapExchangeFactoryAddress() - internal - view - returns (address factory) - { - return TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS; - } -} diff --git a/contracts/integrations/contracts/test/TestUniswapExchange.sol b/contracts/integrations/contracts/test/TestUniswapExchange.sol deleted file mode 100644 index 256d58a035..0000000000 --- a/contracts/integrations/contracts/test/TestUniswapExchange.sol +++ /dev/null @@ -1,109 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchange.sol"; -import "@0x/contracts-erc20/contracts/test/DummyERC20Token.sol"; - - -contract TestUniswapExchange is - IUniswapExchange -{ - DummyERC20Token public token; - uint256 private _excessBuyAmount; - - constructor(address _tokenAddress) public { - token = DummyERC20Token(_tokenAddress); - } - - // solhint-disable no-empty-blocks - /// @dev Used to receive ETH for testing. - function topUpEth() - external - payable - {} - - function setExcessBuyAmount(uint256 amount) - external - { - _excessBuyAmount = amount; - } - - function ethToTokenTransferInput( - uint256 minTokensBought, - uint256, /* deadline */ - address recipient - ) - external - payable - returns (uint256 tokensBought) - { - token.mint(minTokensBought + _excessBuyAmount); - token.transfer(recipient, minTokensBought + _excessBuyAmount); - return minTokensBought + _excessBuyAmount; - } - - function tokenToEthSwapInput( - uint256 tokensSold, - uint256 minEthBought, - uint256 /* deadline */ - ) - external - returns (uint256 ethBought) - { - token.transferFrom( - msg.sender, - address(this), - tokensSold - ); - msg.sender.transfer(minEthBought + _excessBuyAmount); - return minEthBought + _excessBuyAmount; - } - - function tokenToTokenTransferInput( - uint256 tokensSold, - uint256 minTokensBought, - uint256, /* minEthBought */ - uint256, /* deadline */ - address recipient, - address toTokenAddress - ) - external - returns (uint256 tokensBought) - { - token.transferFrom( - msg.sender, - address(this), - tokensSold - ); - DummyERC20Token toToken = DummyERC20Token(toTokenAddress); - toToken.mint(minTokensBought + _excessBuyAmount); - toToken.transfer(recipient, minTokensBought + _excessBuyAmount); - return minTokensBought + _excessBuyAmount; - } - - function toTokenAddress() - external - view - returns (address _tokenAddress) - { - return address(token); - } -} diff --git a/contracts/integrations/contracts/test/TestUniswapExchangeFactory.sol b/contracts/integrations/contracts/test/TestUniswapExchangeFactory.sol deleted file mode 100644 index 04f0654c02..0000000000 --- a/contracts/integrations/contracts/test/TestUniswapExchangeFactory.sol +++ /dev/null @@ -1,52 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/bridges/UniswapBridge.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol"; - - -contract TestUniswapExchangeFactory is - IUniswapExchangeFactory -{ - // Token address to UniswapExchange address. - mapping (address => address) private _testExchanges; - - /// @dev Create a token and exchange (if they don't exist) for a new token - /// and sets the exchange revert and fill behavior. - /// @param tokenAddress The token address. - function addExchange( - address tokenAddress, - address exchangeAddress - ) - external - { - _testExchanges[tokenAddress] = exchangeAddress; - } - - /// @dev `IUniswapExchangeFactory.getExchange` - function getExchange(address tokenAddress) - external - view - returns (address) - { - return _testExchanges[tokenAddress]; - } -} diff --git a/contracts/integrations/contracts/test/TestWethIntegration.sol b/contracts/integrations/contracts/test/TestWethIntegration.sol deleted file mode 100644 index 22d0a7f4ac..0000000000 --- a/contracts/integrations/contracts/test/TestWethIntegration.sol +++ /dev/null @@ -1,24 +0,0 @@ -/* - - Copyright 2020 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.6.5; - -import "@0x/contracts-zero-ex/contracts/test/TestWeth.sol"; - - -contract TestWethIntegration is TestWeth {} diff --git a/contracts/integrations/package.json b/contracts/integrations/package.json deleted file mode 100644 index 6e91aa35a4..0000000000 --- a/contracts/integrations/package.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "name": "@0x/contracts-integrations", - "version": "2.7.64", - "private": true, - "engines": { - "node": ">=6.12" - }, - "description": "Integrations with the 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 contracts:gen generate_contract_wrappers contracts:copy", - "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 1000000 --bail --exit", - "test:fuzz": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/fuzz_tests/*.js' --timeout 0 --bail --exit", - "compile": "sol-compiler", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile" - }, - "config": { - "publicInterfaceContracts": "TestFramework", - "abis": "./test/generated-artifacts/@(ChainlinkStopLimit|IChainlinkAggregator|TestChainlinkAggregator|TestContractWrapper|TestDydxUser|TestEth2Dai|TestEth2DaiBridge|TestFixinProtocolFeesIntegration|TestFramework|TestMainnetAggregatorFills|TestSignatureValidationWallet|TestStaking|TestUniswapBridge|TestUniswapExchange|TestUniswapExchangeFactory|TestWethIntegration).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contract-addresses": "^6.6.0", - "@0x/contract-wrappers": "^13.17.4", - "@0x/contracts-broker": "^1.1.37", - "@0x/contracts-coordinator": "^3.1.38", - "@0x/contracts-dev-utils": "^1.3.36", - "@0x/contracts-exchange-forwarder": "^4.2.38", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/contracts-extensions": "^6.2.32", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-utils": "^4.7.16", - "@0x/coordinator-server": "^1.0.5", - "@0x/dev-utils": "^4.2.7", - "@0x/migrations": "^8.1.1", - "@0x/order-utils": "^10.4.28", - "@0x/protocol-utils": "^1.8.2", - "@0x/sol-compiler": "^4.7.3", - "@0x/tslint-config": "^4.1.4", - "@0x/web3-wrapper": "^7.5.3", - "@azure/core-asynciterator-polyfill": "^1.0.0", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "@types/seedrandom": "^2.4.28", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "js-combinatorics": "^0.5.3", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "nock": "^10.0.6", - "npm-run-all": "^4.1.2", - "seedrandom": "^3.0.5", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/asset-swapper": "^16.25.0", - "@0x/base-contract": "^6.4.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-erc1155": "^2.1.37", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-erc721": "^3.1.37", - "@0x/contracts-exchange": "^3.2.38", - "@0x/contracts-multisig": "^4.1.38", - "@0x/contracts-staking": "^2.0.45", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-zero-ex": "^0.28.0", - "@0x/subproviders": "^6.5.3", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "ethereum-types": "^3.5.0", - "ethereumjs-util": "^7.0.10", - "lodash": "^4.17.11" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/integrations/src/artifacts.ts b/contracts/integrations/src/artifacts.ts deleted file mode 100644 index 6d4eb6b5f1..0000000000 --- a/contracts/integrations/src/artifacts.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as TestFramework from '../generated-artifacts/TestFramework.json'; -export const artifacts = { TestFramework: TestFramework as ContractArtifact }; diff --git a/contracts/integrations/src/chainlink_utils.ts b/contracts/integrations/src/chainlink_utils.ts deleted file mode 100644 index 9e45621f32..0000000000 --- a/contracts/integrations/src/chainlink_utils.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { constants } from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { StaticCallAssetData } from '@0x/types'; -import { AbiEncoder, BigNumber } from '@0x/utils'; - -export interface StopLimitParameters { - oracle: string; - minPrice: BigNumber; - maxPrice: BigNumber; -} - -const stopLimitDataEncoder = AbiEncoder.create([ - { name: 'oracle', type: 'address' }, - { name: 'minPrice', type: 'int256' }, - { name: 'maxPrice', type: 'int256' }, -]); - -const stopLimitMethodEncoder = AbiEncoder.createMethod('checkStopLimit', [{ name: 'stopLimitData', type: 'bytes' }]); - -/** - * Encodes the given stop limit data parameters into the bytes format expected by the - * ChainlinkStopLimit contract. - */ -export function encodeChainlinkStopLimitData(params: StopLimitParameters): string { - return stopLimitDataEncoder.encode(params); -} - -/** - * Encodes the given stop limit data parameters into StaticCall asset data so that it can be used - * in a 0x order. - */ -export function encodeStopLimitStaticCallData(chainlinkStopLimitAddress: string, params: StopLimitParameters): string { - const staticCallData = stopLimitMethodEncoder.encode({ - stopLimitData: encodeChainlinkStopLimitData(params), - }); - return assetDataUtils.encodeStaticCallAssetData( - chainlinkStopLimitAddress, - staticCallData, - constants.KECCAK256_NULL, - ); -} - -/** - * Decodes stop limit data parameters from the bytes format expected by the ChainlinkStopLimit contract. - */ -export function decodeChainlinkStopLimitData(stopLimitData: string): StopLimitParameters { - return stopLimitDataEncoder.decode(stopLimitData); -} - -/** - * Decodes stop limit data parameters from stop limit StaticCall asset data. - */ -export function decodeStopLimitStaticCallData(assetData: string): StopLimitParameters { - // tslint:disable-next-line:no-unnecessary-type-assertion - const { staticCallData } = assetDataUtils.decodeAssetDataOrThrow(assetData) as StaticCallAssetData; - const stopLimitData = stopLimitMethodEncoder.strictDecode(staticCallData); - return decodeChainlinkStopLimitData(stopLimitData); -} diff --git a/contracts/integrations/src/index.ts b/contracts/integrations/src/index.ts deleted file mode 100644 index e25fb51cdb..0000000000 --- a/contracts/integrations/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { artifacts } from './artifacts'; -export * from './wrappers'; -export * from './chainlink_utils'; diff --git a/contracts/integrations/src/wrappers.ts b/contracts/integrations/src/wrappers.ts deleted file mode 100644 index 1c09045bc5..0000000000 --- a/contracts/integrations/src/wrappers.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/test_framework'; diff --git a/contracts/integrations/test/artifacts.ts b/contracts/integrations/test/artifacts.ts deleted file mode 100644 index ec44e03bb6..0000000000 --- a/contracts/integrations/test/artifacts.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as ChainlinkStopLimit from '../test/generated-artifacts/ChainlinkStopLimit.json'; -import * as IChainlinkAggregator from '../test/generated-artifacts/IChainlinkAggregator.json'; -import * as TestChainlinkAggregator from '../test/generated-artifacts/TestChainlinkAggregator.json'; -import * as TestContractWrapper from '../test/generated-artifacts/TestContractWrapper.json'; -import * as TestDydxUser from '../test/generated-artifacts/TestDydxUser.json'; -import * as TestEth2Dai from '../test/generated-artifacts/TestEth2Dai.json'; -import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json'; -import * as TestFixinProtocolFeesIntegration from '../test/generated-artifacts/TestFixinProtocolFeesIntegration.json'; -import * as TestFramework from '../test/generated-artifacts/TestFramework.json'; -import * as TestMainnetAggregatorFills from '../test/generated-artifacts/TestMainnetAggregatorFills.json'; -import * as TestSignatureValidationWallet from '../test/generated-artifacts/TestSignatureValidationWallet.json'; -import * as TestStaking from '../test/generated-artifacts/TestStaking.json'; -import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json'; -import * as TestUniswapExchange from '../test/generated-artifacts/TestUniswapExchange.json'; -import * as TestUniswapExchangeFactory from '../test/generated-artifacts/TestUniswapExchangeFactory.json'; -import * as TestWethIntegration from '../test/generated-artifacts/TestWethIntegration.json'; -export const artifacts = { - ChainlinkStopLimit: ChainlinkStopLimit as ContractArtifact, - IChainlinkAggregator: IChainlinkAggregator as ContractArtifact, - TestChainlinkAggregator: TestChainlinkAggregator as ContractArtifact, - TestContractWrapper: TestContractWrapper as ContractArtifact, - TestDydxUser: TestDydxUser as ContractArtifact, - TestEth2Dai: TestEth2Dai as ContractArtifact, - TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, - TestFixinProtocolFeesIntegration: TestFixinProtocolFeesIntegration as ContractArtifact, - TestFramework: TestFramework as ContractArtifact, - TestMainnetAggregatorFills: TestMainnetAggregatorFills as ContractArtifact, - TestSignatureValidationWallet: TestSignatureValidationWallet as ContractArtifact, - TestStaking: TestStaking as ContractArtifact, - TestUniswapBridge: TestUniswapBridge as ContractArtifact, - TestUniswapExchange: TestUniswapExchange as ContractArtifact, - TestUniswapExchangeFactory: TestUniswapExchangeFactory as ContractArtifact, - TestWethIntegration: TestWethIntegration as ContractArtifact, -}; diff --git a/contracts/integrations/test/benchmarks/chai_bridge_test.ts b/contracts/integrations/test/benchmarks/chai_bridge_test.ts deleted file mode 100644 index 5c9ea2440b..0000000000 --- a/contracts/integrations/test/benchmarks/chai_bridge_test.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { encodeERC20AssetData, encodeERC20BridgeAssetData } from '@0x/contracts-asset-proxy'; -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { ExchangeContract } from '@0x/contracts-exchange'; -import { blockchainTests, constants, expect, FillEventArgs, getRandomInteger } from '@0x/contracts-test-utils'; -import { orderHashUtils } from '@0x/order-utils'; -import { Order } from '@0x/types'; -import { BigNumber, logUtils } from '@0x/utils'; -import { DecodedLogEntry } from 'ethereum-types'; - -import { contractAddresses } from '../mainnet_fork_utils'; - -const CHONKY_DAI_WALLET = '0xe235AAa27428E32cA14089b03F532c571C7ab3c8'; -const CHONKY_CHAI_WALLET = '0xfc64382c9ce89ba1c21692a68000366a35ff0336'; -const CHONKY_WETH_WALLET = '0x4abB24590606f5bf4645185e20C4E7B97596cA3B'; -blockchainTests.configure({ - fork: { - unlockedAccounts: [CHONKY_CHAI_WALLET, CHONKY_WETH_WALLET, CHONKY_DAI_WALLET], - }, -}); - -blockchainTests.fork.skip('ChaiBridge fill benchmarks', env => { - let exchange: ExchangeContract; - - before(async () => { - exchange = new ExchangeContract(contractAddresses.exchange, env.provider, env.txDefaults); - }); - - const DAI_ADDRESS = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; - const CHAI_ADDRESS = '0x06AF07097C9Eeb7fD685c692751D5C66dB49c215'; - const CHAI_BRIDGE_ASSET_DATA = encodeERC20BridgeAssetData( - DAI_ADDRESS, - contractAddresses.chaiBridge, - constants.NULL_BYTES, - ); - const DAI_ASSET_DATA = encodeERC20AssetData(DAI_ADDRESS); - const WETH_ASSET_DATA = encodeERC20AssetData(contractAddresses.etherToken); - const SIGNATURE_PRESIGN = '0x06'; - const PROTOCOL_FEE = 150e3; - const ONE_DAY = 60 * 60 * 24; - const ORDER_DEFAULTS: Order = { - chainId: 1, - exchangeAddress: contractAddresses.exchange, - expirationTimeSeconds: new BigNumber(Math.floor(Date.now() / 1e3) + ONE_DAY), - salt: getRandomInteger(0, constants.MAX_UINT256), - makerAddress: CHONKY_CHAI_WALLET, - feeRecipientAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - makerAssetAmount: new BigNumber(1e18), - takerAssetAmount: new BigNumber(1e18), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerAssetData: CHAI_BRIDGE_ASSET_DATA, - takerAssetData: WETH_ASSET_DATA, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - }; - - async function approveSpenderAsync( - ownerAddress: string, - spenderAddress: string, - tokenAddress: string, - ): Promise { - const token = new ERC20TokenContract(tokenAddress, env.provider, env.txDefaults); - await token.approve(spenderAddress, constants.MAX_UINT256).awaitTransactionSuccessAsync( - { - from: ownerAddress, - }, - { shouldValidate: false }, - ); - } - - describe('chai gas usage', () => { - before(async () => { - await approveSpenderAsync(CHONKY_CHAI_WALLET, contractAddresses.chaiBridge, CHAI_ADDRESS); - await approveSpenderAsync(CHONKY_WETH_WALLET, contractAddresses.erc20Proxy, contractAddresses.etherToken); - }); - - async function prepareOrderAsync(fields: Partial = {}): Promise { - const order = { - ...ORDER_DEFAULTS, - ...fields, - }; - const orderHash = orderHashUtils.getOrderHash(order); - await exchange.preSign(orderHash).awaitTransactionSuccessAsync( - { - from: order.makerAddress, - }, - { shouldValidate: false }, - ); - return order; - } - - // Last run: 282194 - it('filling one chai maker asset', async () => { - const order = await prepareOrderAsync(); - const receipt = await exchange - .fillOrder(order, order.takerAssetAmount, SIGNATURE_PRESIGN) - .awaitTransactionSuccessAsync( - { - from: CHONKY_WETH_WALLET, - value: PROTOCOL_FEE, - gasPrice: 1, - }, - { shouldValidate: false }, - ); - const fillEvent = (receipt.logs as Array>).find(log => log.event === 'Fill'); - expect(fillEvent).to.exist(''); - logUtils.log(`gas used: ${receipt.gasUsed}`); - }); - - // Last run: 292707 - it('filling one chai taker asset', async () => { - const order = await prepareOrderAsync({ - makerAddress: CHONKY_WETH_WALLET, - takerAssetData: CHAI_BRIDGE_ASSET_DATA, - makerAssetData: WETH_ASSET_DATA, - }); - const receipt = await exchange - .fillOrder(order, order.takerAssetAmount, SIGNATURE_PRESIGN) - .awaitTransactionSuccessAsync( - { - from: CHONKY_CHAI_WALLET, - value: PROTOCOL_FEE, - gasPrice: 1, - }, - { shouldValidate: false }, - ); - const fillEvent = (receipt.logs as Array>).find(log => log.event === 'Fill'); - expect(fillEvent).to.exist(''); - logUtils.log(`gas used: ${receipt.gasUsed}`); - }); - }); - - describe('dai gas usage', () => { - before(async () => { - await approveSpenderAsync(CHONKY_DAI_WALLET, contractAddresses.erc20Proxy, DAI_ADDRESS); - await approveSpenderAsync(CHONKY_WETH_WALLET, contractAddresses.erc20Proxy, contractAddresses.etherToken); - }); - - async function prepareOrderAsync(fields: Partial = {}): Promise { - const order = { - ...ORDER_DEFAULTS, - ...fields, - }; - const orderHash = orderHashUtils.getOrderHash(order); - await exchange.preSign(orderHash).awaitTransactionSuccessAsync( - { - from: order.makerAddress, - }, - { shouldValidate: false }, - ); - return order; - } - - // Last run: 124665 - it('filling one dai maker asset', async () => { - const order = await prepareOrderAsync({ - makerAddress: CHONKY_DAI_WALLET, - makerAssetData: DAI_ASSET_DATA, - }); - const receipt = await exchange - .fillOrder(order, order.takerAssetAmount, SIGNATURE_PRESIGN) - .awaitTransactionSuccessAsync( - { - from: CHONKY_WETH_WALLET, - value: PROTOCOL_FEE, - gasPrice: 1, - }, - { shouldValidate: false }, - ); - const fillEvent = (receipt.logs as Array>).find(log => log.event === 'Fill'); - expect(fillEvent).to.exist(''); - logUtils.log(`gas used: ${receipt.gasUsed}`); - }); - - // Last run: 124665 - it('filling one dai taker asset', async () => { - const order = await prepareOrderAsync({ - makerAddress: CHONKY_WETH_WALLET, - takerAssetData: DAI_ASSET_DATA, - makerAssetData: WETH_ASSET_DATA, - }); - const receipt = await exchange - .fillOrder(order, order.takerAssetAmount, SIGNATURE_PRESIGN) - .awaitTransactionSuccessAsync( - { - from: CHONKY_DAI_WALLET, - value: PROTOCOL_FEE, - gasPrice: 1, - }, - { shouldValidate: false }, - ); - const fillEvent = (receipt.logs as Array>).find(log => log.event === 'Fill'); - expect(fillEvent).to.exist(''); - logUtils.log(`gas used: ${receipt.gasUsed}`); - }); - }); -}); diff --git a/contracts/integrations/test/benchmarks/dydx_bridge_test.ts b/contracts/integrations/test/benchmarks/dydx_bridge_test.ts deleted file mode 100644 index 474b1de0ad..0000000000 --- a/contracts/integrations/test/benchmarks/dydx_bridge_test.ts +++ /dev/null @@ -1,267 +0,0 @@ -import { - DydxBridgeActionType, - DydxBridgeData, - dydxBridgeDataEncoder, - encodeERC20AssetData, - encodeERC20BridgeAssetData, - IDydxContract, -} from '@0x/contracts-asset-proxy'; -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { ExchangeContract } from '@0x/contracts-exchange'; -import { - blockchainTests, - constants, - expect, - FillEventArgs, - getRandomInteger, - Numberish, -} from '@0x/contracts-test-utils'; -import { orderHashUtils } from '@0x/order-utils'; -import { Order } from '@0x/types'; -import { BigNumber, fromTokenUnitAmount, logUtils } from '@0x/utils'; -import { DecodedLogEntry } from 'ethereum-types'; - -import { contractAddresses } from '../mainnet_fork_utils'; - -// A chonky dai wallet. -const MAKER_ADDRESS = '0xe235AAa27428E32cA14089b03F532c571C7ab3c8'; -// Also a chonky dai wallet. -const TAKER_ADDRESS = '0x66c57bf505a85a74609d2c83e94aabb26d691e1f'; -blockchainTests.configure({ - fork: { - unlockedAccounts: [TAKER_ADDRESS, MAKER_ADDRESS], - }, -}); - -blockchainTests.fork.skip('DydxBridge fill benchmarks', env => { - let exchange: ExchangeContract; - let dydx: IDydxContract; - - before(async () => { - exchange = new ExchangeContract(contractAddresses.exchange, env.provider, env.txDefaults); - dydx = new IDydxContract(DYDX_ADDRESS, env.provider, env.txDefaults); - // Initialize a dydx account with some Dai collateral and USDC borrowed. - await approveSpenderAsync(MAKER_ADDRESS, BRIDGE_ADDRESS, DAI_ADDRESS); - await approveSpenderAsync(MAKER_ADDRESS, DYDX_ADDRESS, DAI_ADDRESS); - await dydx - .setOperators([{ operator: BRIDGE_ADDRESS, trusted: true }]) - .awaitTransactionSuccessAsync({ from: MAKER_ADDRESS }, { shouldValidate: false }); - await depositAndWithdrawAsync(100, 1); - }); - - async function approveSpenderAsync( - ownerAddress: string, - spenderAddress: string, - tokenAddress: string, - ): Promise { - const token = new ERC20TokenContract(tokenAddress, env.provider, env.txDefaults); - await token.approve(spenderAddress, constants.MAX_UINT256).awaitTransactionSuccessAsync( - { - from: ownerAddress, - }, - { shouldValidate: false }, - ); - } - - const ZERO = constants.ZERO_AMOUNT; - const BRIDGE_ADDRESS = contractAddresses.dydxBridge; - const DYDX_ACCOUNT_ID = getRandomInteger(0, constants.MAX_UINT256); - const DYDX_ADDRESS = '0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e'; - const DAI_ADDRESS = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; - const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; - const TOKEN_INFO: { [addr: string]: { decimals: number; marketId: number } } = { - [DAI_ADDRESS]: { - decimals: 18, - marketId: 3, - }, - [USDC_ADDRESS]: { - decimals: 6, - marketId: 2, - }, - }; - - function encodeDydxBridgeAssetData(fromToken: string, toToken: string, depositRate: number = 1): string { - const fromTokenMarketId = new BigNumber(TOKEN_INFO[fromToken].marketId); - const toTokenMarketId = new BigNumber(TOKEN_INFO[toToken].marketId); - const bridgeData: DydxBridgeData = { - accountNumbers: [DYDX_ACCOUNT_ID], - actions: [ - ...(depositRate > 0 - ? [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: ZERO, - marketId: fromTokenMarketId, - ...createConversionFraction(toToken, fromToken, depositRate), - }, - ] - : []), - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: ZERO, - marketId: toTokenMarketId, - ...createConversionFraction(toToken, toToken, 1), - }, - ], - }; - return encodeERC20BridgeAssetData( - toToken, - contractAddresses.dydxBridge, - dydxBridgeDataEncoder.encode({ bridgeData }), - ); - } - - // Create fraction with default 18 decimal precision. - function createConversionFraction( - fromToken: string, - toToken: string, - rate: number, - ): { - conversionRateNumerator: BigNumber; - conversionRateDenominator: BigNumber; - } { - const fromDecimals = TOKEN_INFO[fromToken].decimals; - const toDecimals = TOKEN_INFO[toToken].decimals; - return { - conversionRateNumerator: fromTokenUnitAmount(rate, toDecimals), - conversionRateDenominator: fromTokenUnitAmount(1, fromDecimals), - }; - } - - enum DydxActionType { - Deposit = 0, - Withdraw = 1, - } - - enum DydxAssetDenomination { - Wei = 0, - Par = 1, - } - - enum DydxAssetReference { - Delta = 0, - Target = 1, - } - - async function depositAndWithdrawAsync(depositSize: Numberish, withdrawSize: Numberish): Promise { - const dai = TOKEN_INFO[DAI_ADDRESS]; - const usdc = TOKEN_INFO[USDC_ADDRESS]; - await dydx - .operate( - [{ owner: MAKER_ADDRESS, number: DYDX_ACCOUNT_ID }], - [ - { - actionType: DydxActionType.Deposit, - accountIdx: ZERO, - amount: { - sign: true, - denomination: DydxAssetDenomination.Wei, - ref: DydxAssetReference.Delta, - value: fromTokenUnitAmount(depositSize, dai.decimals), - }, - primaryMarketId: new BigNumber(dai.marketId), - secondaryMarketId: new BigNumber(constants.NULL_ADDRESS), - otherAddress: MAKER_ADDRESS, - otherAccountIdx: ZERO, - data: constants.NULL_BYTES, - }, - { - actionType: DydxActionType.Withdraw, - accountIdx: ZERO, - amount: { - sign: false, - denomination: DydxAssetDenomination.Wei, - ref: DydxAssetReference.Delta, - value: fromTokenUnitAmount(withdrawSize, usdc.decimals), - }, - primaryMarketId: new BigNumber(usdc.marketId), - secondaryMarketId: new BigNumber(constants.NULL_ADDRESS), - otherAddress: MAKER_ADDRESS, - otherAccountIdx: ZERO, - data: constants.NULL_BYTES, - }, - ], - ) - .awaitTransactionSuccessAsync({ from: MAKER_ADDRESS }, { shouldValidate: false }); - } - - const DYDX_ASSET_DATA = encodeDydxBridgeAssetData(DAI_ADDRESS, USDC_ADDRESS); - const DAI_ASSET_DATA = encodeERC20AssetData(DAI_ADDRESS); - const SIGNATURE_PRESIGN = '0x06'; - const PROTOCOL_FEE = 150e3; - const ONE_DAY = 60 * 60 * 24; - const ORDER_DEFAULTS: Order = { - chainId: 1, - exchangeAddress: contractAddresses.exchange, - expirationTimeSeconds: new BigNumber(Math.floor(Date.now() / 1e3) + ONE_DAY), - salt: getRandomInteger(0, constants.MAX_UINT256), - makerAddress: MAKER_ADDRESS, - feeRecipientAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - makerAssetAmount: fromTokenUnitAmount(50, TOKEN_INFO[USDC_ADDRESS].decimals), - takerAssetAmount: fromTokenUnitAmount(100, TOKEN_INFO[USDC_ADDRESS].decimals), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerAssetData: DYDX_ASSET_DATA, - takerAssetData: DAI_ASSET_DATA, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - }; - - describe('gas usage', () => { - async function prepareOrderAsync(fields: Partial = {}): Promise { - const order = { - ...ORDER_DEFAULTS, - ...fields, - }; - const orderHash = orderHashUtils.getOrderHash(order); - await exchange.preSign(orderHash).awaitTransactionSuccessAsync( - { - from: order.makerAddress, - }, - { shouldValidate: false }, - ); - await approveSpenderAsync(TAKER_ADDRESS, contractAddresses.erc20Proxy, DAI_ADDRESS); - return order; - } - - // Last run: 375066 - it('filling a DAI->USDC dydx order with a deposit action', async () => { - const order = await prepareOrderAsync(); - const receipt = await exchange - .fillOrder(order, order.takerAssetAmount, SIGNATURE_PRESIGN) - .awaitTransactionSuccessAsync( - { - from: TAKER_ADDRESS, - value: PROTOCOL_FEE, - gasPrice: 1, - }, - { shouldValidate: false }, - ); - const fillEvent = (receipt.logs as Array>).find(log => log.event === 'Fill'); - expect(fillEvent).to.exist(''); - logUtils.log(`gas used: ${receipt.gasUsed}`); - }); - - // Last run: 315896 - it('filling a DAI->USDC dydx order with no deposit action', async () => { - const order = await prepareOrderAsync({ - makerAssetData: encodeDydxBridgeAssetData(DAI_ADDRESS, USDC_ADDRESS, 0), - }); - const receipt = await exchange - .fillOrder(order, order.takerAssetAmount, SIGNATURE_PRESIGN) - .awaitTransactionSuccessAsync( - { - from: TAKER_ADDRESS, - value: PROTOCOL_FEE, - gasPrice: 1, - }, - { shouldValidate: false }, - ); - const fillEvent = (receipt.logs as Array>).find(log => log.event === 'Fill'); - expect(fillEvent).to.exist(''); - logUtils.log(`gas used: ${receipt.gasUsed}`); - }); - }); -}); diff --git a/contracts/integrations/test/bridges/abi/dydxEvents.ts b/contracts/integrations/test/bridges/abi/dydxEvents.ts deleted file mode 100644 index d41d24d27c..0000000000 --- a/contracts/integrations/test/bridges/abi/dydxEvents.ts +++ /dev/null @@ -1,1002 +0,0 @@ -// tslint:disable max-file-line-count -export const dydxEvents = { - contractName: 'Events', - abi: [ - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'market', - type: 'uint256', - }, - { - components: [ - { - name: 'borrow', - type: 'uint96', - }, - { - name: 'supply', - type: 'uint96', - }, - { - name: 'lastUpdate', - type: 'uint32', - }, - ], - indexed: false, - name: 'index', - type: 'tuple', - }, - ], - name: 'LogIndexUpdate', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - name: 'sender', - type: 'address', - }, - ], - name: 'LogOperation', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'accountOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'market', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'update', - type: 'tuple', - }, - { - indexed: false, - name: 'from', - type: 'address', - }, - ], - name: 'LogDeposit', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'accountOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'market', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'update', - type: 'tuple', - }, - { - indexed: false, - name: 'to', - type: 'address', - }, - ], - name: 'LogWithdraw', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'accountOneOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountOneNumber', - type: 'uint256', - }, - { - indexed: true, - name: 'accountTwoOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountTwoNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'market', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'updateOne', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'updateTwo', - type: 'tuple', - }, - ], - name: 'LogTransfer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'accountOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'takerMarket', - type: 'uint256', - }, - { - indexed: false, - name: 'makerMarket', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'takerUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'makerUpdate', - type: 'tuple', - }, - { - indexed: false, - name: 'exchangeWrapper', - type: 'address', - }, - ], - name: 'LogBuy', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'accountOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'takerMarket', - type: 'uint256', - }, - { - indexed: false, - name: 'makerMarket', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'takerUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'makerUpdate', - type: 'tuple', - }, - { - indexed: false, - name: 'exchangeWrapper', - type: 'address', - }, - ], - name: 'LogSell', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'takerAccountOwner', - type: 'address', - }, - { - indexed: false, - name: 'takerAccountNumber', - type: 'uint256', - }, - { - indexed: true, - name: 'makerAccountOwner', - type: 'address', - }, - { - indexed: false, - name: 'makerAccountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'inputMarket', - type: 'uint256', - }, - { - indexed: false, - name: 'outputMarket', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'takerInputUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'takerOutputUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'makerInputUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'makerOutputUpdate', - type: 'tuple', - }, - { - indexed: false, - name: 'autoTrader', - type: 'address', - }, - ], - name: 'LogTrade', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'accountOwner', - type: 'address', - }, - { - indexed: false, - name: 'accountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'callee', - type: 'address', - }, - ], - name: 'LogCall', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'solidAccountOwner', - type: 'address', - }, - { - indexed: false, - name: 'solidAccountNumber', - type: 'uint256', - }, - { - indexed: true, - name: 'liquidAccountOwner', - type: 'address', - }, - { - indexed: false, - name: 'liquidAccountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'heldMarket', - type: 'uint256', - }, - { - indexed: false, - name: 'owedMarket', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'solidHeldUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'solidOwedUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'liquidHeldUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'liquidOwedUpdate', - type: 'tuple', - }, - ], - name: 'LogLiquidate', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: 'solidAccountOwner', - type: 'address', - }, - { - indexed: false, - name: 'solidAccountNumber', - type: 'uint256', - }, - { - indexed: true, - name: 'vaporAccountOwner', - type: 'address', - }, - { - indexed: false, - name: 'vaporAccountNumber', - type: 'uint256', - }, - { - indexed: false, - name: 'heldMarket', - type: 'uint256', - }, - { - indexed: false, - name: 'owedMarket', - type: 'uint256', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'solidHeldUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'solidOwedUpdate', - type: 'tuple', - }, - { - components: [ - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint256', - }, - ], - name: 'deltaWei', - type: 'tuple', - }, - { - components: [ - { - name: 'sign', - type: 'bool', - }, - { - name: 'value', - type: 'uint128', - }, - ], - name: 'newPar', - type: 'tuple', - }, - ], - indexed: false, - name: 'vaporOwedUpdate', - type: 'tuple', - }, - ], - name: 'LogVaporize', - type: 'event', - }, - ], -}; diff --git a/contracts/integrations/test/bridges/balancer_bridge_mainnet_test.ts b/contracts/integrations/test/bridges/balancer_bridge_mainnet_test.ts deleted file mode 100644 index 270062624f..0000000000 --- a/contracts/integrations/test/bridges/balancer_bridge_mainnet_test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { artifacts as assetProxyArtifacts } from '@0x/contracts-asset-proxy'; -import { BalancerBridgeContract } from '@0x/contracts-asset-proxy/lib/src/wrappers'; -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, expect, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { AbiEncoder } from '@0x/utils'; - -const CHONKY_DAI_WALLET = '0x1e0447b19bb6ecfdae1e4ae1694b0c3659614e4e'; // dydx solo margin -const CHONKY_WETH_WALLET = '0x2f0b23f53734252bda2277357e97e1517d6b042a'; // MCD wETH vault -const CHONKY_USDC_WALLET = '0x39aa39c021dfbae8fac545936693ac917d5e7563'; // Compound -blockchainTests.configure({ - fork: { - unlockedAccounts: [CHONKY_USDC_WALLET, CHONKY_WETH_WALLET, CHONKY_DAI_WALLET], - }, -}); - -blockchainTests.fork('Mainnet Balancer bridge tests', env => { - let testContract: BalancerBridgeContract; - let weth: ERC20TokenContract; - let usdc: ERC20TokenContract; - const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308'; - const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; - const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; - const wethUsdcBalancerAddress = '0x2471de1547296aadb02cc1af84afe369b6f67c87'; - const wethUsdcDaiBalancerAddress = '0x9b208194acc0a8ccb2a8dcafeacfbb7dcc093f81'; - const bridgeDataEncoder = AbiEncoder.create([ - { name: 'takerToken', type: 'address' }, - { name: 'poolAddress', type: 'address' }, - ]); - - before(async () => { - testContract = await BalancerBridgeContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.BalancerBridge, - env.provider, - { ...env.txDefaults, from: CHONKY_DAI_WALLET, gasPrice: 0 }, - {}, - ); - weth = new ERC20TokenContract(wethAddress, env.provider, env.txDefaults); - usdc = new ERC20TokenContract(usdcAddress, env.provider, env.txDefaults); - }); - - blockchainTests.resets('Can trade with two-asset pool', () => { - it('successfully exchanges WETH for USDC', async () => { - const bridgeData = bridgeDataEncoder.encode([wethAddress, wethUsdcBalancerAddress]); - // Fund the Bridge - await weth - .transfer(testContract.address, toBaseUnitAmount(1)) - .awaitTransactionSuccessAsync({ from: CHONKY_WETH_WALLET, gasPrice: 0 }, { shouldValidate: false }); - const usdcBalanceBefore = await usdc.balanceOf(receiver).callAsync(); - // Exchange via Balancer - await testContract - .bridgeTransferFrom(usdcAddress, constants.NULL_ADDRESS, receiver, constants.ZERO_AMOUNT, bridgeData) - .awaitTransactionSuccessAsync({ from: CHONKY_WETH_WALLET, gasPrice: 0 }, { shouldValidate: false }); - // Check that USDC balance increased - const usdcBalanceAfter = await usdc.balanceOf(receiver).callAsync(); - expect(usdcBalanceAfter).to.be.bignumber.greaterThan(usdcBalanceBefore); - }); - it('successfully exchanges USDC for WETH', async () => { - const bridgeData = bridgeDataEncoder.encode([usdcAddress, wethUsdcBalancerAddress]); - // Fund the Bridge - await usdc - .transfer(testContract.address, toBaseUnitAmount(1, 6)) - .awaitTransactionSuccessAsync({ from: CHONKY_USDC_WALLET, gasPrice: 0 }, { shouldValidate: false }); - const wethBalanceBefore = await weth.balanceOf(receiver).callAsync(); - // Exchange via Balancer - await testContract - .bridgeTransferFrom(wethAddress, constants.NULL_ADDRESS, receiver, constants.ZERO_AMOUNT, bridgeData) - .awaitTransactionSuccessAsync({ from: CHONKY_USDC_WALLET, gasPrice: 0 }, { shouldValidate: false }); - const wethBalanceAfter = await weth.balanceOf(receiver).callAsync(); - expect(wethBalanceAfter).to.be.bignumber.greaterThan(wethBalanceBefore); - }); - }); - blockchainTests.resets('Can trade with three-asset pool', () => { - it('successfully exchanges WETH for USDC', async () => { - const bridgeData = bridgeDataEncoder.encode([wethAddress, wethUsdcDaiBalancerAddress]); - // Fund the Bridge - await weth - .transfer(testContract.address, toBaseUnitAmount(1)) - .awaitTransactionSuccessAsync({ from: CHONKY_WETH_WALLET, gasPrice: 0 }, { shouldValidate: false }); - const usdcBalanceBefore = await usdc.balanceOf(receiver).callAsync(); - // Exchange via Balancer - await testContract - .bridgeTransferFrom(usdcAddress, constants.NULL_ADDRESS, receiver, constants.ZERO_AMOUNT, bridgeData) - .awaitTransactionSuccessAsync({ from: CHONKY_WETH_WALLET, gasPrice: 0 }, { shouldValidate: false }); - // Check that USDC balance increased - const usdcBalanceAfter = await usdc.balanceOf(receiver).callAsync(); - expect(usdcBalanceAfter).to.be.bignumber.greaterThan(usdcBalanceBefore); - }); - it('successfully exchanges USDC for WETH', async () => { - const bridgeData = bridgeDataEncoder.encode([usdcAddress, wethUsdcDaiBalancerAddress]); - // Fund the Bridge - await usdc - .transfer(testContract.address, toBaseUnitAmount(1, 6)) - .awaitTransactionSuccessAsync({ from: CHONKY_USDC_WALLET, gasPrice: 0 }, { shouldValidate: false }); - const wethBalanceBefore = await weth.balanceOf(receiver).callAsync(); - // Exchange via Balancer - await testContract - .bridgeTransferFrom(wethAddress, constants.NULL_ADDRESS, receiver, constants.ZERO_AMOUNT, bridgeData) - .awaitTransactionSuccessAsync({ from: CHONKY_USDC_WALLET, gasPrice: 0 }, { shouldValidate: false }); - const wethBalanceAfter = await weth.balanceOf(receiver).callAsync(); - expect(wethBalanceAfter).to.be.bignumber.greaterThan(wethBalanceBefore); - }); - }); -}); diff --git a/contracts/integrations/test/bridges/curve_bridge_mainnet_test.ts b/contracts/integrations/test/bridges/curve_bridge_mainnet_test.ts deleted file mode 100644 index da65662648..0000000000 --- a/contracts/integrations/test/bridges/curve_bridge_mainnet_test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { artifacts as assetProxyArtifacts } from '@0x/contracts-asset-proxy'; -import { CurveBridgeContract } from '@0x/contracts-asset-proxy/lib/src/wrappers'; -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, describe, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { AbiEncoder } from '@0x/utils'; - -const USDC_WALLET = '0x3dfd23a6c5e8bbcfc9581d2e864a68feb6a076d3'; -const DAI_WALLET = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b'; -const WBTC_WALLET = '0x56178a0d5F301bAf6CF3e1Cd53d9863437345Bf9'; -blockchainTests.configure({ - fork: { - unlockedAccounts: [USDC_WALLET, DAI_WALLET, WBTC_WALLET], - }, -}); - -blockchainTests.fork('Mainnet curve bridge tests', env => { - let testContract: CurveBridgeContract; - const RECEIVER = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308'; - const bridgeDataEncoder = AbiEncoder.create([ - { name: 'curveAddress', type: 'address' }, - { name: 'exchangeFunctionSelector', type: 'bytes4' }, - { name: 'fromTokenAddress', type: 'address' }, - { name: 'fromTokenIdx', type: 'int128' }, - { name: 'toTokenIdx', type: 'int128' }, - ]); - before(async () => { - testContract = await CurveBridgeContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.CurveBridge, - env.provider, - { ...env.txDefaults }, - {}, - ); - }); - - describe('bridgeTransferFrom()', () => { - describe('exchange_underlying()', () => { - const USDC_ADDRESS = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; - const DAI_ADDRESS = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; - const DAI_TOKEN_IDX = 0; - const USDC_TOKEN_IDX = 1; - const EXCHANGE_UNDERLYING_SELECTOR = '0xa6417ed6'; - const CURVE_ADDRESS = '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56'; - it('succeeds exchanges DAI for USDC', async () => { - const bridgeData = bridgeDataEncoder.encode([ - CURVE_ADDRESS, - EXCHANGE_UNDERLYING_SELECTOR, - DAI_ADDRESS, - DAI_TOKEN_IDX, - USDC_TOKEN_IDX, - ]); - // Fund the Bridge - const dai = new ERC20TokenContract(DAI_ADDRESS, env.provider, { ...env.txDefaults, from: DAI_WALLET }); - await dai - .transfer(testContract.address, toBaseUnitAmount(1)) - .awaitTransactionSuccessAsync({}, { shouldValidate: false }); - // Exchange via Curve - await testContract - .bridgeTransferFrom( - USDC_ADDRESS, - constants.NULL_ADDRESS, - RECEIVER, - constants.ZERO_AMOUNT, - bridgeData, - ) - .awaitTransactionSuccessAsync({}, { shouldValidate: false }); - }); - it('succeeds exchanges USDC for DAI', async () => { - const bridgeData = bridgeDataEncoder.encode([ - CURVE_ADDRESS, - EXCHANGE_UNDERLYING_SELECTOR, - USDC_ADDRESS, - USDC_TOKEN_IDX, - DAI_TOKEN_IDX, - ]); - // Fund the Bridge - const usdc = new ERC20TokenContract(USDC_ADDRESS, env.provider, { - ...env.txDefaults, - from: USDC_WALLET, - }); - await usdc - .transfer(testContract.address, toBaseUnitAmount(1, 6)) - .awaitTransactionSuccessAsync({}, { shouldValidate: false }); - // Exchange via Curve - await testContract - .bridgeTransferFrom( - DAI_ADDRESS, - constants.NULL_ADDRESS, - RECEIVER, - constants.ZERO_AMOUNT, - bridgeData, - ) - .awaitTransactionSuccessAsync({}, { shouldValidate: false }); - }); - }); - - describe('exchange()', () => { - const WBTC_ADDRESS = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599'; - const RENBTC_ADDRESS = '0xeb4c2781e4eba804ce9a9803c67d0893436bb27d'; - const RENBTC_TOKEN_IDX = 0; - const WBTC_TOKEN_IDX = 1; - const EXCHANGE_SELECTOR = '0x3df02124'; - const CURVE_ADDRESS = '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714'; - it('succeeds exchanges WBTC for renBTC', async () => { - const bridgeData = bridgeDataEncoder.encode([ - CURVE_ADDRESS, - EXCHANGE_SELECTOR, - WBTC_ADDRESS, - WBTC_TOKEN_IDX, - RENBTC_TOKEN_IDX, - ]); - // Fund the Bridge - const wbtc = new ERC20TokenContract(WBTC_ADDRESS, env.provider, { - ...env.txDefaults, - from: WBTC_WALLET, - }); - await wbtc - .transfer(testContract.address, toBaseUnitAmount(1, 8)) - .awaitTransactionSuccessAsync({}, { shouldValidate: false }); - // Exchange via Curve - await testContract - .bridgeTransferFrom( - RENBTC_ADDRESS, - constants.NULL_ADDRESS, - RECEIVER, - constants.ZERO_AMOUNT, - bridgeData, - ) - .awaitTransactionSuccessAsync({ gas: 6e6 }, { shouldValidate: false }); - }); - }); - }); -}); diff --git a/contracts/integrations/test/bridges/deploy_dydx_bridge.ts b/contracts/integrations/test/bridges/deploy_dydx_bridge.ts deleted file mode 100644 index f456772d51..0000000000 --- a/contracts/integrations/test/bridges/deploy_dydx_bridge.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { artifacts as assetProxyArtifacts, TestDydxBridgeContract } from '@0x/contracts-asset-proxy'; -import { BlockchainTestsEnvironment } from '@0x/contracts-test-utils'; - -import { DeploymentManager } from '../framework/deployment_manager'; - -/** - * Deploys test DydxBridge contract configured to work alongside the provided `deployment`. - */ -export async function deployDydxBridgeAsync( - deployment: DeploymentManager, - environment: BlockchainTestsEnvironment, -): Promise { - const tokenHolders = deployment.accounts; - const dydxBridge = await TestDydxBridgeContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.TestDydxBridge, - environment.provider, - deployment.txDefaults, - assetProxyArtifacts, - tokenHolders, - ); - return dydxBridge; -} diff --git a/contracts/integrations/test/bridges/deploy_eth2dai_bridge.ts b/contracts/integrations/test/bridges/deploy_eth2dai_bridge.ts deleted file mode 100644 index 6fb1693594..0000000000 --- a/contracts/integrations/test/bridges/deploy_eth2dai_bridge.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { artifacts as ERC20Artifacts } from '@0x/contracts-erc20'; -import { BlockchainTestsEnvironment } from '@0x/contracts-test-utils'; - -import { artifacts } from '../artifacts'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { TestEth2DaiBridgeContract, TestEth2DaiContract } from '../wrappers'; - -/** - * Deploys test Eth2Dai exchange and bridge contracts configured to work alongside the provided `deployment`. - */ -export async function deployEth2DaiBridgeAsync( - deployment: DeploymentManager, - environment: BlockchainTestsEnvironment, -): Promise<[TestEth2DaiBridgeContract, TestEth2DaiContract]> { - const eth2Dai = await TestEth2DaiContract.deployFrom0xArtifactAsync( - artifacts.TestEth2Dai, - environment.provider, - deployment.txDefaults, - artifacts, - ); - - const eth2DaiBridge = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestEth2DaiBridge, - environment.provider, - deployment.txDefaults, - { ...ERC20Artifacts, ...artifacts }, - eth2Dai.address, - ); - - return [eth2DaiBridge, eth2Dai]; -} diff --git a/contracts/integrations/test/bridges/deploy_uniswap_bridge.ts b/contracts/integrations/test/bridges/deploy_uniswap_bridge.ts deleted file mode 100644 index fb1e9b2647..0000000000 --- a/contracts/integrations/test/bridges/deploy_uniswap_bridge.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { artifacts as ERC20Artifacts } from '@0x/contracts-erc20'; -import { BlockchainTestsEnvironment } from '@0x/contracts-test-utils'; - -import { artifacts } from '../artifacts'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { - TestUniswapBridgeContract, - TestUniswapExchangeContract, - TestUniswapExchangeFactoryContract, -} from '../wrappers'; - -/** - * Deploys test Uniswap exchanges for the given tokens, a test UniswapExchangeFactory, and a test - * bridge contract configured to work alongside the provided `deployment`. - */ -export async function deployUniswapBridgeAsync( - deployment: DeploymentManager, - environment: BlockchainTestsEnvironment, - tokenAddresses: string[], -): Promise<[TestUniswapBridgeContract, TestUniswapExchangeContract[], TestUniswapExchangeFactoryContract]> { - const uniswapExchangeFactory = await TestUniswapExchangeFactoryContract.deployFrom0xArtifactAsync( - artifacts.TestUniswapExchangeFactory, - environment.provider, - deployment.txDefaults, - artifacts, - ); - - const uniswapExchanges = []; - for (const tokenAddress of tokenAddresses) { - const uniswapExchange = await TestUniswapExchangeContract.deployFrom0xArtifactAsync( - artifacts.TestUniswapExchange, - environment.provider, - deployment.txDefaults, - artifacts, - tokenAddress, - ); - await uniswapExchangeFactory.addExchange(tokenAddress, uniswapExchange.address).awaitTransactionSuccessAsync(); - uniswapExchanges.push(uniswapExchange); - } - - const uniswapBridge = await TestUniswapBridgeContract.deployFrom0xArtifactAsync( - artifacts.TestUniswapBridge, - environment.provider, - deployment.txDefaults, - { ...ERC20Artifacts, ...artifacts }, - deployment.tokens.weth.address, - uniswapExchangeFactory.address, - ); - - return [uniswapBridge, uniswapExchanges, uniswapExchangeFactory]; -} diff --git a/contracts/integrations/test/bridges/dydx_bridge_mainnet_test.ts b/contracts/integrations/test/bridges/dydx_bridge_mainnet_test.ts deleted file mode 100644 index f4992117c7..0000000000 --- a/contracts/integrations/test/bridges/dydx_bridge_mainnet_test.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { - artifacts as assetProxyArtifacts, - DydxBridgeActionType, - DydxBridgeContract, - DydxBridgeData, - dydxBridgeDataEncoder, -} from '@0x/contracts-asset-proxy'; -import { artifacts as erc20Artifacts } from '@0x/contracts-erc20'; -import { blockchainTests, constants, describe, expect, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types'; - -import { contractAddresses, dydxAccountOwner } from '../mainnet_fork_utils'; - -import { dydxEvents } from './abi/dydxEvents'; - -blockchainTests.fork.resets('Mainnet dydx bridge tests', env => { - let testContract: DydxBridgeContract; - // random account to receive tokens from dydx - const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308'; - const defaultAccountNumber = new BigNumber(0); - const daiMarketId = new BigNumber(3); - const defaultAmount = toBaseUnitAmount(0.01); - const defaultDepositAction = { - actionType: DydxBridgeActionType.Deposit as number, - accountIdx: constants.ZERO_AMOUNT, - marketId: daiMarketId, - conversionRateNumerator: constants.ZERO_AMOUNT, - conversionRateDenominator: constants.ZERO_AMOUNT, - }; - const defaultWithdrawAction = { - actionType: DydxBridgeActionType.Withdraw as number, - accountIdx: constants.ZERO_AMOUNT, - marketId: daiMarketId, - // This ratio must be less than the `1` to account - // for interest in dydx balances because the test - // account has an initial dydx balance of zero. - conversionRateNumerator: new BigNumber(1), - conversionRateDenominator: new BigNumber(2), - }; - before(async () => { - testContract = new DydxBridgeContract(contractAddresses.dydxBridge, env.provider, env.txDefaults, { - DydxBridge: assetProxyArtifacts.DydxBridge.compilerOutput.abi, - ERC20: erc20Artifacts.ERC20Token.compilerOutput.abi, - Dydx: dydxEvents.abi, - }); - }); - - describe('bridgeTransferFrom()', () => { - const callAndVerifyDydxEvents = async (bridgeData: DydxBridgeData): Promise => { - const txReceipt = await testContract - .bridgeTransferFrom( - constants.NULL_ADDRESS, - dydxAccountOwner, - receiver, - defaultAmount, - dydxBridgeDataEncoder.encode({ bridgeData }), - ) - .awaitTransactionSuccessAsync({ from: contractAddresses.erc20BridgeProxy, gasPrice: 0 }); - - // Construct expected events - const expectedDepositEvents = []; - const expectedWithdrawEvents = []; - for (const action of bridgeData.actions) { - const scaledAmount = action.conversionRateDenominator.gt(0) - ? defaultAmount - .times(action.conversionRateNumerator) - .dividedToIntegerBy(action.conversionRateDenominator) - : defaultAmount; - switch (action.actionType) { - case DydxBridgeActionType.Deposit: - expectedDepositEvents.push({ - accountOwner: dydxAccountOwner, - accountNumber: bridgeData.accountNumbers[action.accountIdx.toNumber()], - market: action.marketId, - update: { deltaWei: { sign: true, value: scaledAmount } }, - from: dydxAccountOwner, - }); - break; - - case DydxBridgeActionType.Withdraw: - expectedWithdrawEvents.push({ - accountOwner: dydxAccountOwner, - accountNumber: bridgeData.accountNumbers[action.accountIdx.toNumber()], - market: action.marketId, - update: { deltaWei: { sign: false, value: scaledAmount } }, - to: receiver, - }); - break; - - default: - throw new Error(`Unrecognized Action: ${action.actionType}`); - } - } - - // Verify events - let nextExpectedDepositEventIdx = 0; - let nextExpectedWithdrawEventIdx = 0; - for (const rawLog of txReceipt.logs) { - // tslint:disable-next-line no-unnecessary-type-assertion - const log = rawLog as LogWithDecodedArgs; - if (log.event !== 'LogDeposit' && log.event !== 'LogWithdraw') { - continue; - } - const expectedEvent = - log.event === 'LogDeposit' - ? expectedDepositEvents[nextExpectedDepositEventIdx++] - : expectedWithdrawEvents[nextExpectedWithdrawEventIdx++]; - expect(log.args.accountOwner, 'accountOwner').to.equal(expectedEvent.accountOwner); - expect(log.args.accountNumber, 'accountNumber').to.bignumber.equal(expectedEvent.accountNumber); - expect(log.args.market, 'market').to.bignumber.equal(expectedEvent.market); - expect(log.args.from, 'from').to.equal(expectedEvent.from); - // We only check the first update field because it's the delta balance (amount deposited). - // The next field is the new total, which depends on interest rates at the time of execution. - expect(log.args.update.deltaWei.sign, 'update sign').to.equal(expectedEvent.update.deltaWei.sign); - expect(log.args.update.deltaWei.value, 'update value').to.bignumber.equal( - expectedEvent.update.deltaWei.value, - ); - } - }; - - it('succeeds when calling `operate` with the `deposit` action and a single account', async () => { - await callAndVerifyDydxEvents({ - accountNumbers: [defaultAccountNumber], - actions: [defaultDepositAction], - }); - }); - it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { - await callAndVerifyDydxEvents({ - accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], - actions: [defaultDepositAction], - }); - }); - it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => { - await callAndVerifyDydxEvents({ - accountNumbers: [defaultAccountNumber], - actions: [defaultWithdrawAction], - }); - }); - it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => { - await callAndVerifyDydxEvents({ - accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], - actions: [defaultWithdrawAction], - }); - }); - it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => { - await callAndVerifyDydxEvents({ - accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)], - actions: [defaultWithdrawAction, defaultDepositAction], - }); - }); - it('succeeds when calling `operate` with multiple actions under a single account', async () => { - await callAndVerifyDydxEvents({ - accountNumbers: [defaultAccountNumber], - actions: [defaultWithdrawAction, defaultDepositAction], - }); - }); - }); -}); diff --git a/contracts/integrations/test/broker/broker_test.ts b/contracts/integrations/test/broker/broker_test.ts deleted file mode 100644 index 7252c12f1d..0000000000 --- a/contracts/integrations/test/broker/broker_test.ts +++ /dev/null @@ -1,741 +0,0 @@ -import { - artifacts as BrokerArtifacts, - BrokerContract, - decodeBrokerAssetData, - decodePropertyData, - encodeBrokerAssetData, - encodePropertyData, - GodsUnchainedValidatorContract, - TestGodsUnchainedContract, -} from '@0x/contracts-broker'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { ExchangeFunctionName, ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -blockchainTests.resets('Broker <> Gods Unchained integration tests', env => { - let deployment: DeploymentManager; - let balanceStore: BlockchainBalanceStore; - let initialBalances: LocalBalanceStore; - - let maker: Maker; - let taker: Taker; - let affiliate: Actor; - - let broker: BrokerContract; - let godsUnchained: TestGodsUnchainedContract; - let validator: GodsUnchainedValidatorContract; - - let godsUnchainedTokenIds: BigNumber[]; - const makerSpecifiedProto = new BigNumber(1337); - const makerSpecifiedQuality = new BigNumber(25); - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 1, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const [makerToken] = deployment.tokens.erc20; - - godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync( - BrokerArtifacts.TestGodsUnchained, - env.provider, - env.txDefaults, - BrokerArtifacts, - 'Gods Unchained Cards', - 'GU', - ); - - validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync( - BrokerArtifacts.GodsUnchainedValidator, - env.provider, - env.txDefaults, - BrokerArtifacts, - godsUnchained.address, - ); - - broker = await BrokerContract.deployFrom0xArtifactAsync( - BrokerArtifacts.Broker, - env.provider, - env.txDefaults, - BrokerArtifacts, - deployment.exchange.address, - deployment.tokens.weth.address, - ); - - const takerAssetData = encodeBrokerAssetData(broker.address, godsUnchained.address, validator.address, { - proto: makerSpecifiedProto, - quality: makerSpecifiedQuality, - }); - - const orderConfig = { - feeRecipientAddress: constants.NULL_ADDRESS, - makerAssetData: assetDataUtils.encodeERC20AssetData(makerToken.address), - takerAssetData, - takerAssetAmount: new BigNumber(2), // buy 2 cards - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }; - - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig, - }); - taker = new Taker({ name: 'Taker', deployment }); - affiliate = new Actor({ name: 'Affiliate', deployment }); - - // Set balances and allowances - await maker.configureERC20TokenAsync(makerToken); - godsUnchainedTokenIds = await taker.configureERC721TokenAsync( - new DummyERC721TokenContract(godsUnchained.address, env.provider), - broker.address, - 5, - ); - await maker.configureERC20TokenAsync(deployment.tokens.weth); - - const tokenOwners = { - Maker: maker.address, - Taker: taker.address, - Affiliate: affiliate.address, - Broker: broker.address, - StakingProxy: deployment.staking.stakingProxy.address, - }; - const tokenContracts = { - erc20: { makerToken, WETH: deployment.tokens.weth }, - erc721: { GodsUnchained: new DummyERC721TokenContract(godsUnchained.address, env.provider) }, - }; - const tokenIds = { - erc721: { [godsUnchained.address]: godsUnchainedTokenIds }, - }; - balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts, tokenIds); - await balanceStore.updateBalancesAsync(); - initialBalances = LocalBalanceStore.create(balanceStore); - }); - - after(async () => { - Actor.reset(); - }); - - function simulateBrokerFills( - brokeredAssets: BigNumber[], - orders: SignedOrder[], - takerAssetFillAmounts: BigNumber[], - receipt: TransactionReceiptWithDecodedLogs, - ): LocalBalanceStore { - const expectedBalances = LocalBalanceStore.create(initialBalances); - // Transaction gas cost - expectedBalances.burnGas(receipt.from, DeploymentManager.gasPrice.times(receipt.gasUsed)); - // Taker -> Maker - for (const brokeredAsset of brokeredAssets) { - const erc721AssetData = assetDataUtils.encodeERC721AssetData(godsUnchained.address, brokeredAsset); - expectedBalances.transferAsset(taker.address, maker.address, new BigNumber(1), erc721AssetData); - } - // Maker -> Taker - for (const [i, order] of orders.entries()) { - const amount = ReferenceFunctions.safeGetPartialAmountFloor( - takerAssetFillAmounts[i], - order.takerAssetAmount, - order.makerAssetAmount, - ); - expectedBalances.transferAsset(maker.address, taker.address, amount, order.makerAssetData); - } - // Protocol fee - expectedBalances.sendEth( - receipt.from, - deployment.staking.stakingProxy.address, - DeploymentManager.protocolFee.times(orders.length), - ); - expectedBalances.wrapEth( - deployment.staking.stakingProxy.address, - deployment.tokens.weth.address, - DeploymentManager.protocolFee.times(orders.length), - ); - return expectedBalances; - } - - describe('brokerTrade', () => { - let order: SignedOrder; - - before(async () => { - // The first two cards will satisfy the maker-specified proto and quality - await godsUnchained - .setTokenProperties(godsUnchainedTokenIds[0], makerSpecifiedProto, makerSpecifiedQuality) - .awaitTransactionSuccessAsync(); - await godsUnchained - .setTokenProperties(godsUnchainedTokenIds[1], makerSpecifiedProto, makerSpecifiedQuality) - .awaitTransactionSuccessAsync(); - - order = await maker.signOrderAsync(); - }); - - for (const fnName of constants.SINGLE_FILL_FN_NAMES) { - it(`${fnName} with one valid asset`, async () => { - const receipt = await broker - .brokerTrade( - [godsUnchainedTokenIds[0]], - order, - new BigNumber(1), - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0]], - [order], - [new BigNumber(1)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`${fnName} with two valid assets`, async () => { - const receipt = await broker - .brokerTrade( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[1]], - order, - new BigNumber(2), - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[1]], - [order], - [new BigNumber(2)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`${fnName} with one invalid asset`, async () => { - const tx = broker - .brokerTrade( - [godsUnchainedTokenIds[2]], - order, - new BigNumber(1), - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.AssetProxyTransferError()); - }); - it(`${fnName} with one valid asset, one invalid asset`, async () => { - const tx = broker - .brokerTrade( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[2]], // valid, invalid - order, - new BigNumber(2), - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.AssetProxyTransferError()); - }); - it(`${fnName} with too few assets`, async () => { - const tx = broker - .brokerTrade( - [godsUnchainedTokenIds[0]], // One asset provided - order, - new BigNumber(2), // But two are required for the fill - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.AssetProxyTransferError()); - }); - it(`${fnName} with same asset twice`, async () => { - const tx = broker - .brokerTrade( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[0]], - order, - new BigNumber(2), - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.AssetProxyTransferError()); - }); - it(`${fnName} with excess assets`, async () => { - const receipt = await broker - .brokerTrade( - godsUnchainedTokenIds, - order, - new BigNumber(2), - order.signature, - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[1]], // 3rd card isn't transferred - [order], - [new BigNumber(2)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - } - describe('ETH/WETH behavior', () => { - it(`Reverts if insufficient ETH is provided`, async () => { - const tx = broker - .brokerTrade( - [godsUnchainedTokenIds[0]], - order, - new BigNumber(1), - order.signature, - deployment.exchange.getSelector(ExchangeFunctionName.FillOrder), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.minus(1), - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.PayProtocolFeeError()); - }); - it(`Refunds sender if excess ETH is provided`, async () => { - const receipt = await broker - .brokerTrade( - [godsUnchainedTokenIds[0]], - order, - new BigNumber(1), - order.signature, - deployment.exchange.getSelector(ExchangeFunctionName.FillOrder), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.plus(1), // 1 wei gets refunded - gasPrice: DeploymentManager.gasPrice, - }); - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0]], - [order], - [new BigNumber(1)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`Pays a single ETH affiliate fee and refunds excess ETH`, async () => { - const affiliateFee = new BigNumber(100); - const receipt = await broker - .brokerTrade( - [godsUnchainedTokenIds[0]], - order, - new BigNumber(1), - order.signature, - deployment.exchange.getSelector(ExchangeFunctionName.FillOrder), - [affiliateFee], - [affiliate.address], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.plus(affiliateFee).plus(1), - gasPrice: DeploymentManager.gasPrice, - }); - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0]], - [order], - [new BigNumber(1)], - receipt, - ); - expectedBalances.sendEth(receipt.from, affiliate.address, affiliateFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`Pays a multiple ETH affiliate fees and refunds excess ETH`, async () => { - const affiliateFee = new BigNumber(100); - const receipt = await broker - .brokerTrade( - [godsUnchainedTokenIds[0]], - order, - new BigNumber(1), - order.signature, - deployment.exchange.getSelector(ExchangeFunctionName.FillOrder), - [affiliateFee, affiliateFee], - [affiliate.address, maker.address], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.plus(affiliateFee.times(2)).plus(1), - gasPrice: DeploymentManager.gasPrice, - }); - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0]], - [order], - [new BigNumber(1)], - receipt, - ); - expectedBalances.sendEth(receipt.from, affiliate.address, affiliateFee); - expectedBalances.sendEth(receipt.from, maker.address, affiliateFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`Taker can fill an order with a WETH takerFee`, async () => { - const wethAssetData = assetDataUtils.encodeERC20AssetData(deployment.tokens.weth.address); - const takerFee = new BigNumber(100); - const takerFeeOrder = await maker.signOrderAsync({ - feeRecipientAddress: affiliate.address, - takerFeeAssetData: wethAssetData, - takerFee, - }); - const receipt = await broker - .brokerTrade( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[1]], - takerFeeOrder, - new BigNumber(2), - takerFeeOrder.signature, - deployment.exchange.getSelector(ExchangeFunctionName.FillOrder), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: takerFee.plus(DeploymentManager.protocolFee), - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[1]], - [takerFeeOrder], - [new BigNumber(2)], - receipt, - ); - expectedBalances.wrapEth(taker.address, deployment.tokens.weth.address, takerFee); - expectedBalances.transferAsset(taker.address, affiliate.address, takerFee, wethAssetData); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`Taker can fill a vanilla (not property-based) order through the Broker if takerAssetData = WETH`, async () => { - const wethAssetData = assetDataUtils.encodeERC20AssetData(deployment.tokens.weth.address); - const takerAssetAmount = constants.ONE_ETHER.dividedToIntegerBy(2); - const wethOrder = await maker.signOrderAsync({ - takerAssetData: wethAssetData, - takerAssetAmount, - }); - const receipt = await broker - .brokerTrade( - [], - wethOrder, - takerAssetAmount, - wethOrder.signature, - deployment.exchange.getSelector(ExchangeFunctionName.FillOrder), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: takerAssetAmount.plus(DeploymentManager.protocolFee), - gasPrice: DeploymentManager.gasPrice, - }); - const expectedBalances = LocalBalanceStore.create(initialBalances); - expectedBalances.wrapEth( - taker.address, - deployment.tokens.weth.address, - takerAssetAmount.plus(DeploymentManager.protocolFee), - ); - expectedBalances.simulateFills([wethOrder], taker.address, receipt, deployment); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - }); - }); - - describe('batchBrokerTrade', () => { - let orders: SignedOrder[]; - - before(async () => { - // Two orders specifying different protos/qualities - const firstOrderProto = makerSpecifiedProto; - const firstOrderQuality = makerSpecifiedQuality; - const secondOrderProto = new BigNumber(42); - const secondOrderQuality = new BigNumber(7); - - // First two cards satisfy the proto/quality of the first order - await godsUnchained - .setTokenProperties(godsUnchainedTokenIds[0], firstOrderProto, firstOrderQuality) - .awaitTransactionSuccessAsync(); - await godsUnchained - .setTokenProperties(godsUnchainedTokenIds[1], firstOrderProto, firstOrderQuality) - .awaitTransactionSuccessAsync(); - // Next two cards satisfy the proto/quality of the second order - await godsUnchained - .setTokenProperties(godsUnchainedTokenIds[2], secondOrderProto, secondOrderQuality) - .awaitTransactionSuccessAsync(); - await godsUnchained - .setTokenProperties(godsUnchainedTokenIds[3], secondOrderProto, secondOrderQuality) - .awaitTransactionSuccessAsync(); - - orders = [ - await maker.signOrderAsync({ - takerAssetData: encodeBrokerAssetData(broker.address, godsUnchained.address, validator.address, { - proto: firstOrderProto, - quality: firstOrderQuality, - }), - }), - await maker.signOrderAsync({ - takerAssetData: encodeBrokerAssetData(broker.address, godsUnchained.address, validator.address, { - proto: secondOrderProto, - quality: secondOrderQuality, - }), - }), - ]; - }); - - for (const fnName of constants.BATCH_FILL_FN_NAMES) { - it(`${fnName} with one order, one valid asset`, async () => { - const receipt = await broker - .batchBrokerTrade( - [godsUnchainedTokenIds[0]], - [orders[0]], - [new BigNumber(1)], - [orders[0].signature], - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee, - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0]], - [orders[0]], - [new BigNumber(1)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`${fnName} with two orders, one valid asset each`, async () => { - const receipt = await broker - .batchBrokerTrade( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[2]], // valid for 1st order, valid for 2nd - orders, - [new BigNumber(1), new BigNumber(1)], - [orders[0].signature, orders[1].signature], - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(2), - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - [godsUnchainedTokenIds[0], godsUnchainedTokenIds[2]], - orders, - [new BigNumber(1), new BigNumber(1)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`${fnName} with two orders, two valid assets each`, async () => { - const receipt = await broker - .batchBrokerTrade( - godsUnchainedTokenIds.slice(0, 4), - orders, - [new BigNumber(2), new BigNumber(2)], - [orders[0].signature, orders[1].signature], - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(2), - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - godsUnchainedTokenIds.slice(0, 4), - orders, - [new BigNumber(2), new BigNumber(2)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it(`${fnName} with two orders, two valid assets each + excess asset`, async () => { - const receipt = await broker - .batchBrokerTrade( - godsUnchainedTokenIds, - orders, - [new BigNumber(2), new BigNumber(2)], - [orders[0].signature, orders[1].signature], - deployment.exchange.getSelector(fnName), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(2), - gasPrice: DeploymentManager.gasPrice, - }); - - const expectedBalances = simulateBrokerFills( - godsUnchainedTokenIds.slice(0, 4), // 5th card isn't transferred - orders, - [new BigNumber(2), new BigNumber(2)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - } - it(`batchFillOrders reverts on invalid asset`, async () => { - const tx = broker - .batchBrokerTrade( - [...godsUnchainedTokenIds.slice(0, 3), godsUnchainedTokenIds[4]], // Last card isn't valid for 2nd order - orders, - [new BigNumber(2), new BigNumber(2)], - [orders[0].signature, orders[1].signature], - deployment.exchange.getSelector(ExchangeFunctionName.BatchFillOrders), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(2), - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.AssetProxyTransferError()); - }); - it(`batchFillOrKillOrders reverts on invalid asset`, async () => { - const tx = broker - .batchBrokerTrade( - [...godsUnchainedTokenIds.slice(0, 3), godsUnchainedTokenIds[4]], // Last card isn't valid for 2nd order - orders, - [new BigNumber(2), new BigNumber(2)], - [orders[0].signature, orders[1].signature], - deployment.exchange.getSelector(ExchangeFunctionName.BatchFillOrKillOrders), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(2), - gasPrice: DeploymentManager.gasPrice, - }); - return expect(tx).to.revertWith(new ExchangeRevertErrors.AssetProxyTransferError()); - }); - it(`batchFillOrdersNoThrow catches revert on invalid asset`, async () => { - const receipt = await broker - .batchBrokerTrade( - [...godsUnchainedTokenIds.slice(0, 3), godsUnchainedTokenIds[4]], // Last card isn't valid for 2nd order - orders, - [new BigNumber(2), new BigNumber(2)], - [orders[0].signature, orders[1].signature], - deployment.exchange.getSelector(ExchangeFunctionName.BatchFillOrdersNoThrow), - [], - [], - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(2), - gasPrice: DeploymentManager.gasPrice, - }); - const expectedBalances = simulateBrokerFills( - godsUnchainedTokenIds.slice(0, 2), // First order gets filled - [orders[0]], - [new BigNumber(2)], - receipt, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - }); - - describe('Data encoding/decoding tools', () => { - const MAX_UINT8 = 2 ** 8 - 1; - const MAX_UINT16 = 2 ** 16 - 1; - - it('correctly decodes property data', async () => { - const properties = { - proto: getRandomInteger(0, MAX_UINT16), - quality: getRandomInteger(0, MAX_UINT8), - }; - const encoded = encodePropertyData(properties); - const decoded = decodePropertyData(encoded); - expect(decoded.proto).to.bignumber.equal(properties.proto); - expect(decoded.quality).to.bignumber.equal(properties.quality); - }); - it('correctly decodes broker asset data', async () => { - const properties = { - proto: getRandomInteger(0, MAX_UINT16), - quality: getRandomInteger(0, MAX_UINT8), - }; - const encoded = encodeBrokerAssetData(randomAddress(), randomAddress(), randomAddress(), properties); - const decoded = decodeBrokerAssetData(encoded); - expect(decoded.proto).to.bignumber.equal(properties.proto); - expect(decoded.quality).to.bignumber.equal(properties.quality); - }); - }); -}); // tslint:disable-line:max-file-line-count diff --git a/contracts/integrations/test/coordinator/client_test.ts b/contracts/integrations/test/coordinator/client_test.ts deleted file mode 100644 index 53563ae0b3..0000000000 --- a/contracts/integrations/test/coordinator/client_test.ts +++ /dev/null @@ -1,648 +0,0 @@ -import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { ExchangeContract } from '@0x/contracts-exchange'; -import { blockchainTests, constants, expect, OrderFactory } from '@0x/contracts-test-utils'; -import { defaultOrmConfig, getAppAsync } from '@0x/coordinator-server'; -import { devConstants, tokenUtils } from '@0x/dev-utils'; -import { runMigrationsOnceAsync } from '@0x/migrations'; -import { SignedOrder } from '@0x/types'; -import { BigNumber, fetchAsync, logUtils } from '@0x/utils'; -import * as nock from 'nock'; - -import { CoordinatorClient, CoordinatorRegistryContract, CoordinatorServerErrorMsg } from '@0x/contracts-coordinator'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; - -const coordinatorPort = '3000'; -const anotherCoordinatorPort = '4000'; -const coordinatorEndpoint = 'http://localhost:'; - -const DEFAULT_PROTOCOL_FEE_MULTIPLIER = new BigNumber(150000); - -// tslint:disable:custom-no-magic-numbers -blockchainTests.skip('Coordinator Client', env => { - const takerTokenFillAmount = new BigNumber(0); - const chainId = 1337; - - let contractAddresses: ContractAddresses; - let coordinatorRegistry: CoordinatorRegistryContract; - let coordinatorClient: CoordinatorClient; - let orderFactory: OrderFactory; - let userAddresses: string[]; - let makerAddress: string; - let takerAddress: string; - let feeRecipientAddressOne: string; - let feeRecipientAddressTwo: string; - let feeRecipientAddressThree: string; - let feeRecipientAddressFour: string; - let makerAssetData: string; - let takerAssetData: string; - let feeAssetData: string; - - let makerToken: DummyERC20TokenContract; - let takerToken: DummyERC20TokenContract; - let txHash: string; - let signedOrder: SignedOrder; - let anotherSignedOrder: SignedOrder; - let signedOrderWithDifferentFeeRecipient: SignedOrder; - let signedOrderWithDifferentCoordinatorOperator: SignedOrder; - - // for testing server error responses - let serverValidationError: any; - - before(async () => { - contractAddresses = await runMigrationsOnceAsync(env.provider, { - gas: devConstants.GAS_LIMIT, - from: devConstants.TESTRPC_FIRST_ADDRESS, - }); - - coordinatorClient = new CoordinatorClient( - contractAddresses.coordinator, - env.provider, - chainId, - {}, // txDefaults - contractAddresses.exchange, - contractAddresses.coordinatorRegistry, - ); - coordinatorRegistry = new CoordinatorRegistryContract(contractAddresses.coordinatorRegistry, env.provider); - userAddresses = await env.web3Wrapper.getAvailableAddressesAsync(); - [ - , - makerAddress, - takerAddress, - feeRecipientAddressOne, - feeRecipientAddressTwo, - feeRecipientAddressThree, - feeRecipientAddressFour, - ] = userAddresses.slice(0, 7); - - // declare encoded asset data - const [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - const feeTokenAddress = contractAddresses.zrxToken; - [makerAssetData, takerAssetData, feeAssetData] = [ - encodeERC20AssetData(makerTokenAddress), - encodeERC20AssetData(takerTokenAddress), - encodeERC20AssetData(feeTokenAddress), - ]; - - // set initial balances - makerToken = new DummyERC20TokenContract(makerTokenAddress, env.provider); - takerToken = new DummyERC20TokenContract(takerTokenAddress, env.provider); - - // Configure order defaults - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress, - feeRecipientAddress: feeRecipientAddressOne, - makerAssetData, - takerAssetData, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - senderAddress: contractAddresses.coordinator, - exchangeAddress: contractAddresses.exchange, - chainId, - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - - // configure mock coordinator servers - const coordinatorServerConfigs = { - HTTP_PORT: 3000, // Only used in default instantiation in 0x-coordinator-server/server.js; not used here - CHAIN_ID_TO_SETTINGS: { - // TODO: change to CHAIN_ID_TO_SETTINGS when @0x/coordinator-server is ready - [chainId]: { - FEE_RECIPIENTS: [feeRecipientAddressOne, feeRecipientAddressTwo, feeRecipientAddressThree].map( - address => { - return { - ADDRESS: address, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(address)].toString( - 'hex', - ), - }; - }, - ), - // Ethereum RPC url, only used in the default instantiation in 0x-coordinator-server/server.js - // Not used here when instantiating with the imported app - RPC_URL: 'http://ignore', - }, - }, - NETWORK_ID_TO_CONTRACT_ADDRESSES: { - // TODO: change to CHAIN_ID_TO_CONTRACT_ADDRESSES when @0x/coordinator-server is ready - [chainId]: getContractAddressesForChainOrThrow(chainId), - }, - // Optional selective delay on fill requests - SELECTIVE_DELAY_MS: 0, - EXPIRATION_DURATION_SECONDS: 60, // 1 minute - }; - - // start coordinator servers - const serverScenarios: Array<[string, string]> = [ - ['coord_server_1', coordinatorPort], - ['coord_server_2', anotherCoordinatorPort], - ]; - await Promise.all( - serverScenarios.map(async ([name, port]) => { - const app = await getAppAsync( - { - [chainId]: env.provider, - }, - coordinatorServerConfigs, - { - name, - type: 'sqlite', - database: ':memory:', - entities: defaultOrmConfig.entities, - cli: defaultOrmConfig.cli, - logging: defaultOrmConfig.logging, - synchronize: defaultOrmConfig.synchronize, - }, - ); - app.listen(port, () => { - logUtils.log(`Coordinator SERVER API (HTTP) listening on port ${port}!`); - }); - return app; - }), - ); - - // register coordinator servers - [ - [feeRecipientAddressOne, coordinatorPort], - [feeRecipientAddressTwo, coordinatorPort], - [feeRecipientAddressThree, anotherCoordinatorPort], - ].forEach(async ([address, port]) => { - await coordinatorRegistry - .setCoordinatorEndpoint(`${coordinatorEndpoint}${port}`) - .awaitTransactionSuccessAsync( - { from: address }, - { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS }, - ); - }); - }); - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - anotherSignedOrder = await orderFactory.newSignedOrderAsync(); - signedOrderWithDifferentFeeRecipient = await orderFactory.newSignedOrderAsync({ - feeRecipientAddress: feeRecipientAddressTwo, - }); - signedOrderWithDifferentCoordinatorOperator = await orderFactory.newSignedOrderAsync({ - feeRecipientAddress: feeRecipientAddressThree, - }); - makerToken.setBalance(makerAddress, constants.INITIAL_ERC20_BALANCE); - takerToken.setBalance(takerAddress, constants.INITIAL_ERC20_BALANCE); - }); - describe('test setup', () => { - it('should have coordinator registry which returns an endpoint', async () => { - const setCoordinatorEndpoint = await coordinatorRegistry - .getCoordinatorEndpoint(feeRecipientAddressOne) - .callAsync(); - const anotherSetCoordinatorEndpoint = await coordinatorRegistry - .getCoordinatorEndpoint(feeRecipientAddressThree) - .callAsync(); - expect(setCoordinatorEndpoint).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - expect(anotherSetCoordinatorEndpoint).to.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); - }); - it('should have coordinator server endpoints which respond to pings', async () => { - let result = await fetchAsync(`${coordinatorEndpoint}${coordinatorPort}/v2/ping`); - expect(result.status).to.equal(200); - expect(await result.text()).to.equal('pong'); - - result = await fetchAsync(`${coordinatorEndpoint}${anotherCoordinatorPort}/v2/ping`); - expect(result.status).to.equal(200); - expect(await result.text()).to.equal('pong'); - }); - }); - // fill handling is the same for all fill methods so we can test them all through the fillOrder and batchFillOrders interfaces - describe('#fillOrderAsync', () => { - it('should fill a valid order', async () => { - txHash = await coordinatorClient.fillOrderAsync( - signedOrder, - takerTokenFillAmount, - signedOrder.signature, - { from: takerAddress }, - { shouldValidate: true }, - ); - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); - describe('#batchFillOrdersAsync', () => { - it('should fill a batch of valid orders', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmounts = Array(2).fill(takerTokenFillAmount); - txHash = await coordinatorClient.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { from: takerAddress, value: DEFAULT_PROTOCOL_FEE_MULTIPLIER.times(signedOrders.length) }, - ); - - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - it('should fill a batch of orders with different feeRecipientAddresses with the same coordinator server', async () => { - const signedOrders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; - const takerAssetFillAmounts = Array(3).fill(takerTokenFillAmount); - txHash = await coordinatorClient.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { from: takerAddress, value: DEFAULT_PROTOCOL_FEE_MULTIPLIER.times(signedOrders.length) }, - ); - - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - // coordinator-server, as currently implemented, shares a singleton database connection across - // all instantiations. Making the request to two different mocked server endpoints still hits the - // same database and fails because of the uniqueness constraint on transactions in the database. - it.skip('should fill a batch of orders with different feeRecipientAddresses with different coordinator servers', async () => { - const signedOrders = [ - signedOrder, - anotherSignedOrder, - signedOrderWithDifferentFeeRecipient, - signedOrderWithDifferentCoordinatorOperator, - ]; - const takerAssetFillAmounts = Array(4).fill(takerTokenFillAmount); - txHash = await coordinatorClient.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { from: takerAddress }, - ); - - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - - it('should fill a batch of mixed coordinator and non-coordinator orders', async () => { - const nonCoordinatorOrder = await orderFactory.newSignedOrderAsync({ - senderAddress: constants.NULL_ADDRESS, - }); - const signedOrders = [signedOrder, nonCoordinatorOrder]; - const takerAssetFillAmounts = Array(2).fill(takerTokenFillAmount); - txHash = await coordinatorClient.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { from: takerAddress, value: DEFAULT_PROTOCOL_FEE_MULTIPLIER.multipliedBy(signedOrders.length) }, - ); - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); - describe('#softCancelAsync, #batchSoftCancelAsync', () => { - it('should soft cancel a valid order', async () => { - const response = await coordinatorClient.softCancelAsync(signedOrder); - expect(response.outstandingFillSignatures).to.have.lengthOf(0); - expect(response.cancellationSignatures).to.have.lengthOf(1); - }); - - it('should soft cancel a batch of valid orders', async () => { - const orders = [signedOrder, anotherSignedOrder]; - const response = await coordinatorClient.batchSoftCancelAsync(orders); - expect(response).to.have.lengthOf(1); - expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(response[0].cancellationSignatures).to.have.lengthOf(1); - }); - it('should soft cancel a batch of orders with different feeRecipientAddresses', async () => { - const orders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; - const response = await coordinatorClient.batchSoftCancelAsync(orders); - expect(response).to.have.lengthOf(1); - expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(response[0].cancellationSignatures).to.have.lengthOf(2); - }); - it('should soft cancel a batch of orders with different coordinatorOperator and concatenate responses', async () => { - const orders = [ - signedOrder, - anotherSignedOrder, - signedOrderWithDifferentFeeRecipient, - signedOrderWithDifferentCoordinatorOperator, - ]; - const response = await coordinatorClient.batchSoftCancelAsync(orders); - expect(response).to.have.lengthOf(2); - expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(response[0].cancellationSignatures).to.have.lengthOf(3); - expect(response[1].cancellationSignatures).to.have.lengthOf(3); // both coordinator servers support the same feeRecipients - }); - }); - describe('#hardCancelOrderAsync, #batchHardCancelOrdersAsync, #cancelOrdersUpToAsync', () => { - it('should hard cancel a valid order', async () => { - txHash = await coordinatorClient.hardCancelOrderAsync(signedOrder, { from: makerAddress }); - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - - it('should hard cancel a batch of valid orders', async () => { - const orders = [signedOrder, anotherSignedOrder]; - txHash = await coordinatorClient.batchHardCancelOrdersAsync(orders, { from: makerAddress }); - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - it('should hard cancel orders up to target order epoch', async () => { - const targetOrderEpoch = new BigNumber(42); - txHash = await coordinatorClient.hardCancelOrdersUpToAsync(targetOrderEpoch, { from: makerAddress }); - - await env.web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - - const exchange = new ExchangeContract(contractAddresses.exchange, env.provider); - const orderEpoch = await exchange.orderEpoch(makerAddress, contractAddresses.coordinator).callAsync(); - expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1)); - }); - }); - describe('coordinator edge cases', () => { - let badOrder: SignedOrder; - beforeEach('setup order with non-registered feeRecipient', async () => { - badOrder = await orderFactory.newSignedOrderAsync({ - feeRecipientAddress: feeRecipientAddressFour, - }); - }); - it('should throw error when feeRecipientAddress is not in registry', async () => { - await expect( - coordinatorClient.fillOrderAsync(badOrder, takerTokenFillAmount, badOrder.signature, { - from: takerAddress, - }), - ).to.eventually.be.rejected(); - }); - it('should throw informative error when coordinator endpoint does not work', async () => { - await env.web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorRegistry.setCoordinatorEndpoint('http://badUri.com').sendTransactionAsync({ - from: feeRecipientAddressFour, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await expect( - coordinatorClient.fillOrderAsync(badOrder, takerTokenFillAmount, badOrder.signature, { - from: takerAddress, - }), - ).to.eventually.be.rejectedWith(CoordinatorServerErrorMsg.FillFailed); - }); - }); - describe('coordinator server errors', () => { - serverValidationError = { - code: 1004, - reason: '', - validationErrors: [ - { - field: 'signedTransaction', - code: 1004, - reason: - 'A transaction can only be approved once. To request approval to perform the same actions, generate and sign an identical transaction with a different salt value.', - }, - ], - }; - beforeEach(async () => { - nock(`${coordinatorEndpoint}${coordinatorPort}`) - .post('/v2/request_transaction', () => true) - .query({ - chainId: 1337, - }) - .reply(400, serverValidationError); - }); - afterEach(async () => { - nock.cleanAll(); - }); - it('should throw error when softCancel fails', async () => { - await coordinatorClient - .softCancelAsync(signedOrder) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - }); - }); - - it('should throw error when batch soft cancel totally fails with single coordinator operator', async () => { - const orders = [signedOrder, signedOrderWithDifferentFeeRecipient]; - await coordinatorClient - .batchSoftCancelAsync(orders) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal(orders); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - }); - }); - it('should throw consolidated error when batch soft cancel partially fails with different coordinator operators', async () => { - const serverCancellationSuccess = { - outstandingFillSignatures: [ - { - orderHash: '0xd1dc61f3e7e5f41d72beae7863487beea108971de678ca00d903756f842ef3ce', - approvalSignatures: [ - '0x1c7383ca8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a8a535671303', - ], - expirationTimeSeconds: 1552390380, - takerAssetFillAmount: 100000000000000000000, - }, - ], - cancellationSignatures: [ - '0x2ea3117a8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a855b5a7b401', - ], - }; - nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) - .post('/v2/request_transaction', () => true) - .query({ - chainId: 1337, - }) - .reply(200, serverCancellationSuccess); - - const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; - await coordinatorClient - .batchSoftCancelAsync(signedOrders) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.deep.equal([serverCancellationSuccess]); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - }); - }); - it('should throw consolidated error when batch soft cancel totally fails with different coordinator operators', async () => { - nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) - .post('/v2/request_transaction', () => true) - .query({ - chainId: 1337, - }) - .reply(400, serverValidationError); - - const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; - await coordinatorClient - .batchSoftCancelAsync(signedOrders) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - - const anotherErrorBody = err.errors[1]; - expect(anotherErrorBody.isError).to.be.true(); - expect(anotherErrorBody.status).to.equal(400); - expect(anotherErrorBody.error).to.deep.equal(serverValidationError); - expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); - expect(anotherErrorBody.coordinatorOperator).to.equal( - `${coordinatorEndpoint}${anotherCoordinatorPort}`, - ); - }); - }); - it('should throw error when a fill fails', async () => { - await coordinatorClient - .fillOrderAsync(signedOrder, takerTokenFillAmount, signedOrder.signature, { from: takerAddress }) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - }); - }); - it('should throw error when batch fill fails with single coordinator operator', async () => { - const signedOrders = [signedOrder, signedOrderWithDifferentFeeRecipient]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; - await coordinatorClient - .batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { - from: takerAddress, - }, - ) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal(signedOrders); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - }); - }); - it('should throw consolidated error when batch fill partially fails with different coordinator operators', async () => { - const serverApprovalSuccess = { - signatures: [ - '0x1cc07d7ae39679690a91418d46491520f058e4fb14debdf2e98f2376b3970de8512ace44af0be6d1c65617f7aae8c2364ff63f241515ee1559c3eeecb0f671d9e903', - ], - expirationTimeSeconds: 1552390014, - }; - nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) - .post('/v2/request_transaction', () => true) - .query({ - chainId: 1337, - }) - .reply(200, serverApprovalSuccess); - - const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; - await coordinatorClient - .batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { - from: takerAddress, - }, - ) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - }); - }); - it('should throw consolidated error when batch fill totally fails with different coordinator operators', async () => { - nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) - .post('/v2/request_transaction', () => true) - .query({ - chainId: 1337, - }) - .reply(400, serverValidationError); - - const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; - await coordinatorClient - .batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(o => o.signature), - { - from: takerAddress, - }, - ) - .then(res => { - expect(res).to.be.undefined(); - }) - .catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - - const anotherErrorBody = err.errors[1]; - expect(anotherErrorBody.isError).to.be.true(); - expect(anotherErrorBody.status).to.equal(400); - expect(anotherErrorBody.error).to.deep.equal(serverValidationError); - expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); - expect(anotherErrorBody.coordinatorOperator).to.equal( - `${coordinatorEndpoint}${anotherCoordinatorPort}`, - ); - }); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/coordinator/coordinator_test.ts b/contracts/integrations/test/coordinator/coordinator_test.ts deleted file mode 100644 index 2fa37e25f7..0000000000 --- a/contracts/integrations/test/coordinator/coordinator_test.ts +++ /dev/null @@ -1,399 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { CoordinatorContract, CoordinatorRevertErrors, SignedCoordinatorApproval } from '@0x/contracts-coordinator'; -import { - ExchangeCancelEventArgs, - ExchangeCancelUpToEventArgs, - exchangeDataEncoder, - ExchangeEvents, - ExchangeFillEventArgs, -} from '@0x/contracts-exchange'; -import { - blockchainTests, - constants, - ExchangeFunctionName, - expect, - orderHashUtils, - transactionHashUtils, - verifyEvents, -} from '@0x/contracts-test-utils'; -import { SignedOrder, SignedZeroExTransaction } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { FeeRecipient } from '../framework/actors/fee_recipient'; -import { Maker } from '../framework/actors/maker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -import { deployCoordinatorAsync } from './deploy_coordinator'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Coordinator integration tests', env => { - let deployment: DeploymentManager; - let coordinator: CoordinatorContract; - let balanceStore: BlockchainBalanceStore; - - let maker: Maker; - let taker: Actor; - let feeRecipient: FeeRecipient; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 4, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - coordinator = await deployCoordinatorAsync(deployment, env); - - const [makerToken, takerToken, makerFeeToken, takerFeeToken] = deployment.tokens.erc20; - - taker = new Actor({ name: 'Taker', deployment }); - feeRecipient = new FeeRecipient({ - name: 'Fee recipient', - deployment, - verifyingContract: coordinator, - }); - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig: { - senderAddress: coordinator.address, - feeRecipientAddress: feeRecipient.address, - makerAssetData: encodeERC20AssetData(makerToken.address), - takerAssetData: encodeERC20AssetData(takerToken.address), - makerFeeAssetData: encodeERC20AssetData(makerFeeToken.address), - takerFeeAssetData: encodeERC20AssetData(takerFeeToken.address), - }, - }); - - await taker.configureERC20TokenAsync(takerToken); - await taker.configureERC20TokenAsync(takerFeeToken); - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - await maker.configureERC20TokenAsync(makerToken); - await maker.configureERC20TokenAsync(makerFeeToken); - - balanceStore = new BlockchainBalanceStore( - { - ...actorAddressesByName([maker, taker, feeRecipient]), - Coordinator: coordinator.address, - StakingProxy: deployment.staking.stakingProxy.address, - }, - { erc20: { makerToken, takerToken, makerFeeToken, takerFeeToken, wETH: deployment.tokens.weth } }, - {}, - ); - }); - - after(async () => { - Actor.reset(); - }); - - function expectedFillEvent(order: SignedOrder): ExchangeFillEventArgs { - return { - makerAddress: order.makerAddress, - takerAddress: taker.address, - senderAddress: order.senderAddress, - feeRecipientAddress: order.feeRecipientAddress, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData, - makerFeeAssetData: order.makerFeeAssetData, - takerFeeAssetData: order.takerFeeAssetData, - makerAssetFilledAmount: order.makerAssetAmount, - takerAssetFilledAmount: order.takerAssetAmount, - makerFeePaid: order.makerFee, - takerFeePaid: order.takerFee, - protocolFeePaid: DeploymentManager.protocolFee, - orderHash: orderHashUtils.getOrderHashHex(order), - }; - } - - describe('single order fills', () => { - let order: SignedOrder; - let data: string; - let transaction: SignedZeroExTransaction; - let approval: SignedCoordinatorApproval; - - for (const fnName of constants.SINGLE_FILL_FN_NAMES) { - before(async () => { - order = await maker.signOrderAsync(); - data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - transaction = await taker.signTransactionAsync({ data }); - approval = feeRecipient.signCoordinatorApproval(transaction, taker.address); - }); - - it(`${fnName} should fill the order with a signed approval`, async () => { - await balanceStore.updateBalancesAsync(); - const txReceipt = await coordinator - .executeTransaction(transaction, taker.address, transaction.signature, [approval.signature]) - .awaitTransactionSuccessAsync({ from: taker.address, value: DeploymentManager.protocolFee }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills( - [order], - taker.address, - txReceipt, - deployment, - DeploymentManager.protocolFee, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill); - }); - it(`${fnName} should fill the order if called by approver (eth protocol fee, no refund)`, async () => { - await balanceStore.updateBalancesAsync(); - const txReceipt = await coordinator - .executeTransaction(transaction, feeRecipient.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: feeRecipient.address, value: DeploymentManager.protocolFee }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills( - [order], - taker.address, - txReceipt, - deployment, - DeploymentManager.protocolFee, - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill); - }); - it(`${fnName} should fill the order if called by approver (eth protocol fee, refund)`, async () => { - await balanceStore.updateBalancesAsync(); - const txReceipt = await coordinator - .executeTransaction(transaction, feeRecipient.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ - from: feeRecipient.address, - value: DeploymentManager.protocolFee.plus(1), - }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills( - [order], - taker.address, - txReceipt, - deployment, - DeploymentManager.protocolFee.plus(1), - ); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill); - }); - it(`${fnName} should fill the order if called by approver (weth protocol fee, no refund)`, async () => { - await balanceStore.updateBalancesAsync(); - const txReceipt = await coordinator - .executeTransaction(transaction, feeRecipient.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: feeRecipient.address }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills([order], taker.address, txReceipt, deployment); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill); - }); - it(`${fnName} should fill the order if called by approver (weth protocol fee, refund)`, async () => { - await balanceStore.updateBalancesAsync(); - const txReceipt = await coordinator - .executeTransaction(transaction, feeRecipient.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: feeRecipient.address, value: new BigNumber(1) }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills([order], taker.address, txReceipt, deployment, new BigNumber(1)); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill); - }); - it(`${fnName} should revert with no approval signature`, async () => { - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const tx = coordinator - .executeTransaction(transaction, taker.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: taker.address, value: DeploymentManager.protocolFee }); - - const expectedError = new CoordinatorRevertErrors.InvalidApprovalSignatureError( - transactionHash, - feeRecipient.address, - ); - return expect(tx).to.revertWith(expectedError); - }); - it(`${fnName} should revert with an invalid approval signature`, async () => { - const approvalSignature = hexUtils.concat( - hexUtils.slice(approval.signature, 0, 2), - '0xFFFFFFFF', - hexUtils.slice(approval.signature, 6), - ); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const tx = coordinator - .executeTransaction(transaction, taker.address, transaction.signature, [approvalSignature]) - .awaitTransactionSuccessAsync({ from: taker.address, value: DeploymentManager.protocolFee }); - - const expectedError = new CoordinatorRevertErrors.InvalidApprovalSignatureError( - transactionHash, - feeRecipient.address, - ); - return expect(tx).to.revertWith(expectedError); - }); - it(`${fnName} should revert if not called by tx signer or approver`, async () => { - const tx = coordinator - .executeTransaction(transaction, taker.address, transaction.signature, [approval.signature]) - .awaitTransactionSuccessAsync({ from: maker.address, value: DeploymentManager.protocolFee }); - - const expectedError = new CoordinatorRevertErrors.InvalidOriginError(taker.address); - return expect(tx).to.revertWith(expectedError); - }); - } - }); - describe('batch order fills', () => { - let orders: SignedOrder[]; - let data: string; - let transaction: SignedZeroExTransaction; - let approval: SignedCoordinatorApproval; - - for (const fnName of [...constants.MARKET_FILL_FN_NAMES, ...constants.BATCH_FILL_FN_NAMES]) { - before(async () => { - orders = [await maker.signOrderAsync(), await maker.signOrderAsync()]; - data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); - transaction = await taker.signTransactionAsync({ data }); - approval = feeRecipient.signCoordinatorApproval(transaction, taker.address); - }); - - it(`${fnName} should fill the orders with a signed approval`, async () => { - await balanceStore.updateBalancesAsync(); - const value = DeploymentManager.protocolFee.times(orders.length); - const txReceipt = await coordinator - .executeTransaction(transaction, taker.address, transaction.signature, [approval.signature]) - .awaitTransactionSuccessAsync({ from: taker.address, value }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents( - txReceipt, - orders.map(order => expectedFillEvent(order)), - ExchangeEvents.Fill, - ); - }); - it(`${fnName} should fill the orders if called by approver (eth fee, no refund)`, async () => { - await balanceStore.updateBalancesAsync(); - const value = DeploymentManager.protocolFee.times(orders.length); - const txReceipt = await coordinator - .executeTransaction(transaction, feeRecipient.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: feeRecipient.address, value }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents( - txReceipt, - orders.map(order => expectedFillEvent(order)), - ExchangeEvents.Fill, - ); - }); - it(`${fnName} should fill the orders if called by approver (mixed fees, refund)`, async () => { - await balanceStore.updateBalancesAsync(); - const value = DeploymentManager.protocolFee.plus(1); - const txReceipt = await coordinator - .executeTransaction(transaction, feeRecipient.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: feeRecipient.address, value }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - verifyEvents( - txReceipt, - orders.map(order => expectedFillEvent(order)), - ExchangeEvents.Fill, - ); - }); - it(`${fnName} should revert with an invalid approval signature`, async () => { - const approvalSignature = hexUtils.concat( - hexUtils.slice(approval.signature, 0, 2), - '0xFFFFFFFF', - hexUtils.slice(approval.signature, 6), - ); - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const tx = coordinator - .executeTransaction(transaction, taker.address, transaction.signature, [approvalSignature]) - .awaitTransactionSuccessAsync({ - from: taker.address, - value: DeploymentManager.protocolFee.times(orders.length), - }); - const expectedError = new CoordinatorRevertErrors.InvalidApprovalSignatureError( - transactionHash, - feeRecipient.address, - ); - return expect(tx).to.revertWith(expectedError); - }); - it(`${fnName} should revert if not called by tx signer or approver`, async () => { - const tx = coordinator - .executeTransaction(transaction, taker.address, transaction.signature, [approval.signature]) - .awaitTransactionSuccessAsync({ - from: maker.address, - value: DeploymentManager.protocolFee.times(orders.length), - }); - const expectedError = new CoordinatorRevertErrors.InvalidOriginError(taker.address); - return expect(tx).to.revertWith(expectedError); - }); - } - }); - describe('cancels', () => { - function expectedCancelEvent(order: SignedOrder): ExchangeCancelEventArgs { - return { - makerAddress: order.makerAddress, - senderAddress: order.senderAddress, - feeRecipientAddress: order.feeRecipientAddress, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData, - orderHash: orderHashUtils.getOrderHashHex(order), - }; - } - - it('cancelOrder call should be successful without an approval', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]); - const transaction = await maker.signTransactionAsync({ - data, - }); - const txReceipt = await coordinator - .executeTransaction(transaction, maker.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: maker.address }); - - verifyEvents(txReceipt, [expectedCancelEvent(order)], ExchangeEvents.Cancel); - }); - it('batchCancelOrders call should be successful without an approval', async () => { - const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); - const transaction = await maker.signTransactionAsync({ - data, - }); - const txReceipt = await coordinator - .executeTransaction(transaction, maker.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: maker.address }); - - verifyEvents( - txReceipt, - orders.map(order => expectedCancelEvent(order)), - ExchangeEvents.Cancel, - ); - }); - it('cancelOrdersUpTo call should be successful without an approval', async () => { - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo, []); - const transaction = await maker.signTransactionAsync({ - data, - }); - const txReceipt = await coordinator - .executeTransaction(transaction, maker.address, transaction.signature, []) - .awaitTransactionSuccessAsync({ from: maker.address }); - - const expectedEvent: ExchangeCancelUpToEventArgs = { - makerAddress: maker.address, - orderSenderAddress: coordinator.address, - orderEpoch: new BigNumber(1), - }; - verifyEvents(txReceipt, [expectedEvent], ExchangeEvents.CancelUpTo); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/coordinator/deploy_coordinator.ts b/contracts/integrations/test/coordinator/deploy_coordinator.ts deleted file mode 100644 index b393c962c0..0000000000 --- a/contracts/integrations/test/coordinator/deploy_coordinator.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { artifacts, CoordinatorContract } from '@0x/contracts-coordinator'; -import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange'; -import { BlockchainTestsEnvironment } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { DeploymentManager } from '../framework/deployment_manager'; - -/** - * Deploys a Coordinator contract configured to work alongside the provided `deployment`. - */ -export async function deployCoordinatorAsync( - deployment: DeploymentManager, - environment: BlockchainTestsEnvironment, -): Promise { - return CoordinatorContract.deployFrom0xArtifactAsync( - artifacts.Coordinator, - environment.provider, - deployment.txDefaults, - { ...exchangeArtifacts, ...artifacts }, - deployment.exchange.address, - new BigNumber(deployment.chainId), - ); -} diff --git a/contracts/integrations/test/deployment_test.ts b/contracts/integrations/test/deployment_test.ts deleted file mode 100644 index 497f49ec3c..0000000000 --- a/contracts/integrations/test/deployment_test.ts +++ /dev/null @@ -1,412 +0,0 @@ -import { - artifacts as assetProxyArtifacts, - ERC1155ProxyContract, - ERC20ProxyContract, - ERC721ProxyContract, - MultiAssetProxyContract, - StaticCallProxyContract, -} from '@0x/contracts-asset-proxy'; -import { - artifacts as exchangeArtifacts, - ExchangeAssetProxyRegisteredEventArgs, - ExchangeContract, - ExchangeEvents, - ExchangeProtocolFeeCollectorAddressEventArgs, - ExchangeProtocolFeeMultiplierEventArgs, -} from '@0x/contracts-exchange'; -import { artifacts as multisigArtifacts, ZeroExGovernorContract } from '@0x/contracts-multisig'; -import { - artifacts as stakingArtifacts, - constants as stakingConstants, - StakingContract, - StakingEvents, - StakingExchangeAddedEventArgs, - StakingProxyContract, -} from '@0x/contracts-staking'; -import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { - AuthorizableAuthorizedAddressAddedEventArgs, - AuthorizableAuthorizedAddressRemovedEventArgs, - AuthorizableEvents, -} from '@0x/contracts-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TxData } from 'ethereum-types'; - -import { AssetProxyDispatcher, Authorizable, Ownable } from './framework/utils/wrapper_interfaces'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests('Deployment and Configuration End to End Tests', env => { - // Available Addresses - let owner: string; - - // Contract Instances - let governor: ZeroExGovernorContract; - let erc20Proxy: ERC20ProxyContract; - let erc721Proxy: ERC721ProxyContract; - let erc1155Proxy: ERC1155ProxyContract; - let exchange: ExchangeContract; - let multiAssetProxy: MultiAssetProxyContract; - let staking: StakingContract; - let staticCallProxy: StaticCallProxyContract; - let stakingProxy: StakingProxyContract; - let stakingWrapper: StakingContract; - - // TxDefaults - let txDefaults: Partial; - - // ChainId of the Exchange - let chainId: number; - - // Protocol Fees - const protocolFeeMultiplier = new BigNumber(150000); - - before(async () => { - // Get the chain ID. - chainId = await env.getChainIdAsync(); - - // Create accounts and tx defaults - [owner] = await env.getAccountAddressesAsync(); - txDefaults = { - ...env.txDefaults, - from: owner, - }; - - // Deploy ZeroExGovernor. For the purposes of this test, we will assume that - // the ZeroExGovernor does not know what destinations will be needed during - // construction. - governor = await ZeroExGovernorContract.deployFrom0xArtifactAsync( - multisigArtifacts.ZeroExGovernor, - env.provider, - txDefaults, - multisigArtifacts, - [], - [], - [], - [owner], - new BigNumber(1), - constants.ZERO_AMOUNT, - ); - - // Deploy Exchange. - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.Exchange, - env.provider, - txDefaults, - exchangeArtifacts, - new BigNumber(chainId), - ); - - // Deploy Staking. - staking = await StakingContract.deployFrom0xArtifactAsync( - stakingArtifacts.Staking, - env.provider, - txDefaults, - stakingArtifacts, - ); - - // Deploy the staking proxy. - stakingProxy = await StakingProxyContract.deployFrom0xArtifactAsync( - stakingArtifacts.StakingProxy, - env.provider, - txDefaults, - stakingArtifacts, - staking.address, - ); - - // Authorize owner in the staking proxy. - await stakingProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync(); - - // Deploy the asset proxy contracts. - erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC20Proxy, - env.provider, - txDefaults, - assetProxyArtifacts, - ); - erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC721Proxy, - env.provider, - txDefaults, - assetProxyArtifacts, - ); - erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC1155Proxy, - env.provider, - txDefaults, - assetProxyArtifacts, - ); - multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.MultiAssetProxy, - env.provider, - txDefaults, - assetProxyArtifacts, - ); - staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.StaticCallProxy, - env.provider, - txDefaults, - assetProxyArtifacts, - ); - - // Set up the staking wrapper so that the entire staking interface can be accessed - // easily through the proxy. - stakingWrapper = new StakingContract(stakingProxy.address, env.provider); - }); - - describe('deployment and configuration', () => { - describe('exchange specific', () => { - // Registers an asset proxy in the exchange contract and ensure that the correct state changes occurred. - async function registerAssetProxyAndAssertSuccessAsync( - registrationContract: AssetProxyDispatcher, - assetProxyAddress: string, - assetProxyId: string, - ): Promise { - // Register the asset proxy. - const receipt = await registrationContract - .registerAssetProxy(assetProxyAddress) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // Ensure that the correct event was logged. - const logs = filterLogsToArguments( - receipt.logs, - ExchangeEvents.AssetProxyRegistered, - ); - expect(logs).to.be.deep.eq([{ id: assetProxyId, assetProxy: assetProxyAddress }]); - - // Ensure that the asset proxy was actually registered. - const proxyAddress = await registrationContract.getAssetProxy(assetProxyId).callAsync(); - expect(proxyAddress).to.be.eq(assetProxyAddress); - } - - // Authorizes an address for a given asset proxy using the owner address. - async function authorizeAddressAndAssertSuccessAsync( - authorizable: Authorizable, - newAuthorityAddress: string, - ): Promise { - // Authorize the address. - const receipt = await authorizable - .addAuthorizedAddress(newAuthorityAddress) - .awaitTransactionSuccessAsync({ from: owner }); - - // Ensure that the correct log was emitted. - const logs = filterLogsToArguments( - receipt.logs, - AuthorizableEvents.AuthorizedAddressAdded, - ); - expect(logs).to.be.deep.eq([{ target: newAuthorityAddress, caller: owner }]); - - // Ensure that the address was actually authorized. - const wasAuthorized = await authorizable.authorized(newAuthorityAddress).callAsync(); - expect(wasAuthorized).to.be.true(); - } - - it('should successfully register the asset proxies in the exchange', async () => { - // Register the asset proxies in the exchange. - await registerAssetProxyAndAssertSuccessAsync(exchange, erc20Proxy.address, AssetProxyId.ERC20); - await registerAssetProxyAndAssertSuccessAsync(exchange, erc721Proxy.address, AssetProxyId.ERC721); - await registerAssetProxyAndAssertSuccessAsync(exchange, erc1155Proxy.address, AssetProxyId.ERC1155); - await registerAssetProxyAndAssertSuccessAsync( - exchange, - multiAssetProxy.address, - AssetProxyId.MultiAsset, - ); - await registerAssetProxyAndAssertSuccessAsync( - exchange, - staticCallProxy.address, - AssetProxyId.StaticCall, - ); - }); - - it('should successfully register the asset proxies in the multi-asset proxy', async () => { - // Register the asset proxies in the multi-asset proxy. - await registerAssetProxyAndAssertSuccessAsync(multiAssetProxy, erc20Proxy.address, AssetProxyId.ERC20); - await registerAssetProxyAndAssertSuccessAsync( - multiAssetProxy, - erc721Proxy.address, - AssetProxyId.ERC721, - ); - await registerAssetProxyAndAssertSuccessAsync( - multiAssetProxy, - erc1155Proxy.address, - AssetProxyId.ERC1155, - ); - await registerAssetProxyAndAssertSuccessAsync( - multiAssetProxy, - staticCallProxy.address, - AssetProxyId.StaticCall, - ); - }); - - it('should successfully add the exchange as an authority in the appropriate asset proxies', async () => { - // Authorize the exchange in all of the asset proxies, except for the static call proxy. - await authorizeAddressAndAssertSuccessAsync(erc20Proxy, exchange.address); - await authorizeAddressAndAssertSuccessAsync(erc721Proxy, exchange.address); - await authorizeAddressAndAssertSuccessAsync(erc1155Proxy, exchange.address); - await authorizeAddressAndAssertSuccessAsync(multiAssetProxy, exchange.address); - }); - - it('should successfully add the multi asset proxy as an authority in the appropriate asset proxies', async () => { - // Authorize the multi-asset proxy in the token asset proxies. - await authorizeAddressAndAssertSuccessAsync(erc20Proxy, multiAssetProxy.address); - await authorizeAddressAndAssertSuccessAsync(erc721Proxy, multiAssetProxy.address); - await authorizeAddressAndAssertSuccessAsync(erc1155Proxy, multiAssetProxy.address); - }); - }); - - describe('staking specific', () => { - it('should have properly configured the staking proxy with the logic contract', async () => { - // Ensure that the registered staking contract is correct. - const stakingAddress = await stakingProxy.stakingContract().callAsync(); - expect(stakingAddress).to.be.eq(staking.address); - }); - - it('should have initialized the correct parameters in the staking proxy', async () => { - // Ensure that the correct parameters were set. - const params = await stakingWrapper.getParams().callAsync(); - expect(params).to.be.deep.eq([ - stakingConstants.DEFAULT_PARAMS.epochDurationInSeconds, - stakingConstants.DEFAULT_PARAMS.rewardDelegatedStakeWeight, - stakingConstants.DEFAULT_PARAMS.minimumPoolStake, - stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaNumerator, - stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaDenominator, - ]); - }); - }); - - describe('exchange and staking integration', () => { - it('should successfully register the exchange in the staking contract', async () => { - // Register the exchange. - const receipt = await stakingWrapper.addExchangeAddress(exchange.address).awaitTransactionSuccessAsync({ - from: owner, - }); - - // Ensure that the correct events were logged. - const logs = filterLogsToArguments( - receipt.logs, - StakingEvents.ExchangeAdded, - ); - expect(logs).to.be.deep.eq([{ exchangeAddress: exchange.address }]); - - // Ensure that the exchange was registered. - const wasRegistered = await stakingWrapper.validExchanges(exchange.address).callAsync(); - expect(wasRegistered).to.be.true(); - }); - - it('should successfully register the staking contract in the exchange', async () => { - // Register the staking contract. - const receipt = await exchange - .setProtocolFeeCollectorAddress(stakingProxy.address) - .awaitTransactionSuccessAsync({ - from: owner, - }); - - // Ensure that the correct events were logged. - const logs = filterLogsToArguments( - receipt.logs, - ExchangeEvents.ProtocolFeeCollectorAddress, - ); - expect(logs).to.be.deep.eq([ - { - oldProtocolFeeCollector: constants.NULL_ADDRESS, - updatedProtocolFeeCollector: stakingProxy.address, - }, - ]); - - // Ensure that the staking contract was registered. - const feeCollector = await exchange.protocolFeeCollector().callAsync(); - expect(feeCollector).to.be.eq(stakingProxy.address); - }); - - it('should successfully update the protocol fee multiplier in the staking contract', async () => { - // Update the protocol fee multiplier. - const receipt = await exchange - .setProtocolFeeMultiplier(protocolFeeMultiplier) - .awaitTransactionSuccessAsync(); - - // Ensure that the correct events were logged. - const logs = filterLogsToArguments( - receipt.logs, - ExchangeEvents.ProtocolFeeMultiplier, - ); - expect(logs).to.be.deep.eq([ - { - oldProtocolFeeMultiplier: constants.ZERO_AMOUNT, - updatedProtocolFeeMultiplier: protocolFeeMultiplier, - }, - ]); - - // Ensure that the protocol fee multiplier was set correctly. - const multiplier = await exchange.protocolFeeMultiplier().callAsync(); - expect(multiplier).bignumber.to.be.eq(protocolFeeMultiplier); - }); - }); - }); - - describe('transferring ownership', () => { - // Removes authorization of the "externally owned address" owner and transfers the authorization - // to the asset proxy owner. - async function transferAuthorizationAndAssertSuccessAsync(contract: Authorizable): Promise { - // Remove authorization from the old owner. - let receipt = await contract.removeAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner }); - - // Ensure that the correct log was recorded. - let logs = filterLogsToArguments( - receipt.logs, - AuthorizableEvents.AuthorizedAddressRemoved, - ); - expect(logs).to.be.deep.eq([{ target: owner, caller: owner }]); - - // Ensure that the owner was actually removed. - let isAuthorized = await contract.authorized(owner).callAsync(); - expect(isAuthorized).to.be.false(); - - // Authorize the asset-proxy owner. - receipt = await contract.addAuthorizedAddress(governor.address).awaitTransactionSuccessAsync({ - from: owner, - }); - - // Ensure that the correct log was recorded. - logs = filterLogsToArguments( - receipt.logs, - AuthorizableEvents.AuthorizedAddressAdded, - ); - expect(logs).to.be.deep.eq([{ target: governor.address, caller: owner }]); - - // Ensure that the asset-proxy owner was actually authorized. - isAuthorized = await contract.authorized(governor.address).callAsync(); - expect(isAuthorized).to.be.true(); - } - - // Transfers ownership of a contract to the asset-proxy owner, and ensures that the change was actually made. - async function transferOwnershipAndAssertSuccessAsync(contract: Ownable): Promise { - // Transfer ownership to the new owner. - await contract.transferOwnership(governor.address).awaitTransactionSuccessAsync({ from: owner }); - - // Ensure that the owner address has been updated. - const ownerAddress = await contract.owner().callAsync(); - expect(ownerAddress).to.be.eq(governor.address); - } - - it('should transfer authorization of the owner to the asset-proxy owner in the staking contracts', async () => { - // Transfer authorization of the staking system. We intentionally neglect - // to add the asset-proxy owner as an authorized address in the asset proxies - // as a security precaution. - await transferAuthorizationAndAssertSuccessAsync(stakingProxy); - }); - - it('should transfer ownership of all appropriate contracts to the asset-proxy owner', async () => { - // Transfer ownership of most contracts (we exclude contracts that are not ownable). - await transferOwnershipAndAssertSuccessAsync(exchange); - await transferOwnershipAndAssertSuccessAsync(staking); - await transferOwnershipAndAssertSuccessAsync(stakingProxy); - await transferOwnershipAndAssertSuccessAsync(erc20Proxy); - await transferOwnershipAndAssertSuccessAsync(erc721Proxy); - await transferOwnershipAndAssertSuccessAsync(erc1155Proxy); - await transferOwnershipAndAssertSuccessAsync(multiAssetProxy); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/integrations/test/dev-utils/dev_utils_mainnet_test.ts b/contracts/integrations/test/dev-utils/dev_utils_mainnet_test.ts deleted file mode 100644 index db00762350..0000000000 --- a/contracts/integrations/test/dev-utils/dev_utils_mainnet_test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { IChaiContract } from '@0x/contracts-asset-proxy'; -import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -import { contractAddresses } from '../mainnet_fork_utils'; - -blockchainTests.fork.resets('DevUtils mainnet tests', env => { - const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f'; - const chaiAddress = '0x06af07097c9eeb7fd685c692751d5c66db49c215'; - const daiHolder = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b'; - let noDaiAddress: string; - - const assetData = assetDataUtils.encodeERC20BridgeAssetData( - daiAddress, - contractAddresses.chaiBridge, - constants.NULL_BYTES, - ); - - const dai = new ERC20TokenContract(daiAddress, env.provider, env.txDefaults); - const chai = new IChaiContract(chaiAddress, env.provider, env.txDefaults); - let devUtils: DevUtilsContract; - const daiDepositAmount = Web3Wrapper.toBaseUnitAmount(1000, 18); - - before(async () => { - [noDaiAddress] = await env.getAccountAddressesAsync(); - devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - devUtilsArtifacts.DevUtils, - devUtilsArtifacts, - env.provider, - env.txDefaults, - devUtilsArtifacts, - contractAddresses.exchange, - contractAddresses.chaiBridge, - contractAddresses.dydxBridge, - ); - await dai.approve(chai.address, constants.MAX_UINT256).awaitTransactionSuccessAsync({ from: daiHolder }); - await chai.join(daiHolder, daiDepositAmount).awaitTransactionSuccessAsync({ from: daiHolder }); - }); - - describe('LibAssetData', () => { - describe('ChaiBridge getBalance', () => { - it('should return the correct non-zero Dai balance for a Chai holder', async () => { - const expectedDaiBalance = await chai.dai(daiHolder).callAsync(); - const daiBalance = await devUtils.getBalance(daiHolder, assetData).callAsync(); - expect(daiBalance).bignumber.eq(expectedDaiBalance); - }); - it('should return a balance of 0 when Chai balance is 0', async () => { - const daiBalance = await devUtils.getBalance(noDaiAddress, assetData).callAsync(); - expect(daiBalance).bignumber.eq(constants.ZERO_AMOUNT); - }); - }); - describe('ChaiBridge getProxyAllowance', () => { - it('should return the correct non-zero non-unlimited allowance', async () => { - const chaiBalance = await chai.balanceOf(daiHolder).callAsync(); - await chai - .approve(contractAddresses.chaiBridge, chaiBalance) - .awaitTransactionSuccessAsync({ from: daiHolder }); - const daiBalance = await chai.dai(daiHolder).callAsync(); - const allowance = await devUtils.getAssetProxyAllowance(daiHolder, assetData).callAsync(); - expect(allowance).to.bignumber.eq(daiBalance); - }); - it('should return an unlimited allowance of Dai when Chai allowance is also unlimited', async () => { - await chai - .approve(contractAddresses.chaiBridge, constants.MAX_UINT256) - .awaitTransactionSuccessAsync({ from: daiHolder }); - const allowance = await devUtils.getAssetProxyAllowance(daiHolder, assetData).callAsync(); - expect(allowance).to.bignumber.eq(constants.MAX_UINT256); - }); - it('should return an allowance of 0 when Chai allowance is 0', async () => { - const allowance = await devUtils.getAssetProxyAllowance(noDaiAddress, assetData).callAsync(); - expect(allowance).to.bignumber.eq(constants.ZERO_AMOUNT); - }); - }); - }); -}); diff --git a/contracts/integrations/test/dev-utils/dydx_order_validation_test.ts b/contracts/integrations/test/dev-utils/dydx_order_validation_test.ts deleted file mode 100644 index 3951e716d4..0000000000 --- a/contracts/integrations/test/dev-utils/dydx_order_validation_test.ts +++ /dev/null @@ -1,452 +0,0 @@ -import { - artifacts as assetProxyArtifacts, - DydxBridgeActionType, - DydxBridgeContract, - DydxBridgeData, - dydxBridgeDataEncoder, - encodeERC20AssetData, - encodeERC20BridgeAssetData, - IDydxContract, -} from '@0x/contracts-asset-proxy'; -import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; -import { ERC20TokenContract } from '@0x/contracts-erc20'; -import { blockchainTests, constants, expect, Numberish } from '@0x/contracts-test-utils'; -import { Order } from '@0x/types'; -import { BigNumber, fromTokenUnitAmount, hexUtils, toTokenUnitAmount } from '@0x/utils'; - -import { contractAddresses } from '../mainnet_fork_utils'; - -enum DydxActionType { - Deposit = 0, - Withdraw = 1, -} - -enum DydxAssetDenomination { - Wei = 0, - Par = 1, -} - -enum DydxAssetReference { - Delta = 0, - Target = 1, -} - -const CHONKY_DAI_WALLET = '0x3a9F7C8cA36C42d7035E87C3304eE5cBd353a532'; -const CHONKY_USDC_WALLET = '0x1EDA7056fF11C9817038E0020C3a6F1d6A8Ec32e'; - -blockchainTests.configure({ - fork: { - unlockedAccounts: [CHONKY_DAI_WALLET, CHONKY_USDC_WALLET], - }, -}); - -blockchainTests.fork('DevUtils dydx order validation tests', env => { - const { ZERO_AMOUNT: ZERO } = constants; - const SIGNATURE = '0x01'; // Invalid signature. Doesn't matter. - const DAI_ADDRESS = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; - const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; - const DYDX_ADDRESS = '0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e'; - const TOKEN_INFO: { [addr: string]: { decimals: number; marketId: number } } = { - [DAI_ADDRESS]: { - decimals: 18, - marketId: 3, - }, - [USDC_ADDRESS]: { - decimals: 6, - marketId: 2, - }, - }; - const DAI_DECIMALS = TOKEN_INFO[DAI_ADDRESS].decimals; - const USDC_DECIMALS = TOKEN_INFO[USDC_ADDRESS].decimals; - let bridge: DydxBridgeContract; - let dydx: IDydxContract; - let dai: ERC20TokenContract; - let usdc: ERC20TokenContract; - let devUtils: DevUtilsContract; - let minMarginRatio: number; - - before(async () => { - dydx = new IDydxContract(DYDX_ADDRESS, env.provider, env.txDefaults); - dai = new ERC20TokenContract(DAI_ADDRESS, env.provider, env.txDefaults); - usdc = new ERC20TokenContract(USDC_ADDRESS, env.provider, env.txDefaults); - bridge = await DydxBridgeContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.DydxBridge, - env.provider, - env.txDefaults, - {}, - ); - devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - devUtilsArtifacts.DevUtils, - devUtilsArtifacts, - env.provider, - env.txDefaults, - devUtilsArtifacts, - contractAddresses.exchange, - contractAddresses.chaiBridge, - bridge.address, - ); - minMarginRatio = toTokenUnitAmount((await dydx.getRiskParams().callAsync()).marginRatio.value) - .plus(1) - .toNumber(); - // Set approvals and operators. - await dai - .approve(DYDX_ADDRESS, constants.MAX_UINT256) - .awaitTransactionSuccessAsync({ from: CHONKY_DAI_WALLET }); - await usdc - .approve(DYDX_ADDRESS, constants.MAX_UINT256) - .awaitTransactionSuccessAsync({ from: CHONKY_USDC_WALLET }); - await dydx - .setOperators([{ operator: bridge.address, trusted: true }]) - .awaitTransactionSuccessAsync({ from: CHONKY_DAI_WALLET }); - await dydx - .setOperators([{ operator: bridge.address, trusted: true }]) - .awaitTransactionSuccessAsync({ from: CHONKY_USDC_WALLET }); - }); - - async function depositAndWithdrawAsync( - makerAddress: string, - accountId: BigNumber, - depositSize: Numberish = 0, - withdrawSize: Numberish = 0, - ): Promise { - const fromToken = makerAddress === CHONKY_DAI_WALLET ? DAI_ADDRESS : USDC_ADDRESS; - const toToken = fromToken === DAI_ADDRESS ? USDC_ADDRESS : DAI_ADDRESS; - const fromDecimals = TOKEN_INFO[fromToken].decimals; - const fromMarketId = TOKEN_INFO[fromToken].marketId; - const toDecimals = TOKEN_INFO[toToken].decimals; - const toMarketId = TOKEN_INFO[toToken].marketId; - await dydx - .operate( - [{ owner: makerAddress, number: accountId }], - [ - ...(depositSize > 0 - ? [ - { - actionType: DydxActionType.Deposit, - accountIdx: ZERO, - amount: { - sign: true, - denomination: DydxAssetDenomination.Wei, - ref: DydxAssetReference.Delta, - value: fromTokenUnitAmount(depositSize, fromDecimals), - }, - primaryMarketId: new BigNumber(fromMarketId), - secondaryMarketId: new BigNumber(constants.NULL_ADDRESS), - otherAddress: makerAddress, - otherAccountIdx: ZERO, - data: constants.NULL_BYTES, - }, - ] - : []), - ...(withdrawSize > 0 - ? [ - { - actionType: DydxActionType.Withdraw, - accountIdx: ZERO, - amount: { - sign: false, - denomination: DydxAssetDenomination.Wei, - ref: DydxAssetReference.Delta, - value: fromTokenUnitAmount(withdrawSize, toDecimals), - }, - primaryMarketId: new BigNumber(toMarketId), - secondaryMarketId: new BigNumber(constants.NULL_ADDRESS), - otherAddress: makerAddress, - otherAccountIdx: ZERO, - data: constants.NULL_BYTES, - }, - ] - : []), - ], - ) - .awaitTransactionSuccessAsync({ from: makerAddress }); - } - - const SECONDS_IN_ONE_YEAR = 365 * 24 * 60 * 60; - - function createOrder(fields: Partial = {}): Order { - return { - chainId: 1, - exchangeAddress: contractAddresses.exchange, - expirationTimeSeconds: new BigNumber(Math.floor(Date.now() / 1000 + SECONDS_IN_ONE_YEAR)), - makerAddress: CHONKY_DAI_WALLET, - takerAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - feeRecipientAddress: constants.NULL_ADDRESS, - salt: new BigNumber(hexUtils.random()), - makerAssetAmount: fromTokenUnitAmount(100, USDC_DECIMALS), - takerAssetAmount: fromTokenUnitAmount(200, DAI_DECIMALS), - makerFee: ZERO, - takerFee: ZERO, - makerAssetData: encodeDydxBridgeAssetData(), - takerAssetData: encodeERC20AssetData(DAI_ADDRESS), - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - ...fields, - }; - } - - function encodeDydxBridgeAssetData( - fields: Partial<{ - fromToken: string; - toToken: string; - depositRate: number; - withdrawRate: number; - accountId: BigNumber; - }> = {}, - ): string { - const { fromToken, toToken, depositRate, withdrawRate, accountId } = { - fromToken: DAI_ADDRESS, - toToken: USDC_ADDRESS, - depositRate: 1, - withdrawRate: 1, - accountId: ZERO, - ...fields, - }; - const fromTokenMarketId = new BigNumber(TOKEN_INFO[fromToken].marketId); - const toTokenMarketId = new BigNumber(TOKEN_INFO[toToken].marketId); - const bridgeData: DydxBridgeData = { - accountNumbers: [accountId], - actions: [ - ...(depositRate > 0 - ? [ - { - actionType: DydxBridgeActionType.Deposit, - accountIdx: ZERO, - marketId: fromTokenMarketId, - ...createConversionFraction(toToken, fromToken, depositRate), - }, - ] - : []), - ...(withdrawRate > 0 - ? [ - { - actionType: DydxBridgeActionType.Withdraw, - accountIdx: ZERO, - marketId: toTokenMarketId, - ...createConversionFraction(toToken, toToken, withdrawRate), - }, - ] - : []), - ], - }; - return encodeERC20BridgeAssetData(toToken, bridge.address, dydxBridgeDataEncoder.encode({ bridgeData })); - } - - // Create fraction with default 18 decimal precision. - function createConversionFraction( - fromToken: string, - toToken: string, - rate: number, - ): { - conversionRateNumerator: BigNumber; - conversionRateDenominator: BigNumber; - } { - const fromDecimals = TOKEN_INFO[fromToken].decimals; - const toDecimals = TOKEN_INFO[toToken].decimals; - return { - conversionRateNumerator: fromTokenUnitAmount(rate, toDecimals), - conversionRateDenominator: fromTokenUnitAmount(1, fromDecimals), - }; - } - - function randomAccountId(): BigNumber { - return new BigNumber(hexUtils.random()); - } - - describe('DAI -> USDC', () => { - const makerAddress = CHONKY_DAI_WALLET; - function _createOrder(fields: Partial = {}): Order { - return createOrder(fields); - } - - it('validates a fully solvent order', async () => { - // This account is collateralized enough to fill the order with just - // withdraws. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 200, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: 0, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.eq(order.takerAssetAmount); - }); - - it('validates a perpetually solvent order', async () => { - // This account is not very well collateralized, but the deposit rate - // will keep the collateralization ratio the same or better. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: minMarginRatio, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.eq(order.takerAssetAmount); - }); - - it('validates a partially solvent order with an inadequate deposit', async () => { - // This account is not very well collateralized and the deposit rate is - // also too low to sustain the collateralization ratio for the full order. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: minMarginRatio * 0.95, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.gt(0); - expect(fillableTakerAssetAmount).to.bignumber.lt(order.takerAssetAmount); - }); - - it('validates a partially solvent order with no deposit', async () => { - // This account is not very well collateralized and there is no deposit - // to keep the collateralization ratio up. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: 0, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.gt(0); - expect(fillableTakerAssetAmount).to.bignumber.lt(order.takerAssetAmount); - }); - - // TODO(dorothy-zbornak): We can't actually create an account that's below - // the margin ratio without replacing the price oracles. - it('invalidates a virtually insolvent order', async () => { - // This account has a collateralization ratio JUST above the - // minimum margin ratio, so it can only withdraw nearly zero maker tokens. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 1 / (minMarginRatio + 3e-4)); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: 0, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - // Price fluctuations will cause this to be a little above zero, so we - // don't compare to zero. - expect(fillableTakerAssetAmount).to.bignumber.lt(fromTokenUnitAmount(1e-3, DAI_DECIMALS)); - }); - }); - - describe('USDC -> DAI', () => { - const makerAddress = CHONKY_USDC_WALLET; - function _createOrder(fields: Partial = {}): Order { - return createOrder({ - makerAddress, - takerAssetData: encodeERC20AssetData(USDC_ADDRESS), - makerAssetData: encodeDydxBridgeAssetData({ - fromToken: USDC_ADDRESS, - toToken: DAI_ADDRESS, - }), - makerAssetAmount: fromTokenUnitAmount(100, DAI_DECIMALS), - takerAssetAmount: fromTokenUnitAmount(100, USDC_DECIMALS), - ...fields, - }); - } - - it('validates a fully solvent order', async () => { - // This account is collateralized enough to fill the order with just - // withdraws. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 200, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: 0, - fromToken: USDC_ADDRESS, - toToken: DAI_ADDRESS, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.eq(order.takerAssetAmount); - }); - - it('validates a perpetually solvent order', async () => { - // This account is not very well collateralized, but the deposit rate - // will keep the collateralization ratio the same or better. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: minMarginRatio, - fromToken: USDC_ADDRESS, - toToken: DAI_ADDRESS, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.eq(order.takerAssetAmount); - }); - - it('validates a partially solvent order with an inadequate deposit', async () => { - // This account is not very well collateralized and the deposit rate is - // also too low to sustain the collateralization ratio for the full order. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: minMarginRatio * 0.95, - fromToken: USDC_ADDRESS, - toToken: DAI_ADDRESS, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.gt(0); - expect(fillableTakerAssetAmount).to.bignumber.lt(order.takerAssetAmount); - }); - - it('validates a partially solvent order with no deposit', async () => { - // This account is not very well collateralized and there is no deposit - // to keep the collateralization ratio up. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 0); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: 0, - fromToken: USDC_ADDRESS, - toToken: DAI_ADDRESS, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.gt(0); - expect(fillableTakerAssetAmount).to.bignumber.lt(order.takerAssetAmount); - }); - - // TODO(dorothy-zbornak): We can't actually create an account that's below - // the margin ratio without replacing the price oracles. - it('invalidates a virtually insolvent order', async () => { - // This account has a collateralization ratio JUST above the - // minimum margin ratio, so it can only withdraw nearly zero maker tokens. - const accountId = randomAccountId(); - await depositAndWithdrawAsync(makerAddress, accountId, 1, 1 / (minMarginRatio + 3e-4)); - const order = _createOrder({ - makerAssetData: encodeDydxBridgeAssetData({ - accountId, - depositRate: 0, - fromToken: USDC_ADDRESS, - toToken: DAI_ADDRESS, - }), - }); - const [, fillableTakerAssetAmount] = await devUtils.getOrderRelevantState(order, SIGNATURE).callAsync(); - // Price fluctuations will cause this to be a little above zero, so we - // don't compare to zero. - expect(fillableTakerAssetAmount).to.bignumber.lt(fromTokenUnitAmount(1e-3, USDC_DECIMALS)); - }); - }); -}); diff --git a/contracts/integrations/test/dev-utils/get_order_hash.ts b/contracts/integrations/test/dev-utils/get_order_hash.ts deleted file mode 100644 index ca8e53430b..0000000000 --- a/contracts/integrations/test/dev-utils/get_order_hash.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { artifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; -import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange'; -import { blockchainTests, constants, expect, orderHashUtils } from '@0x/contracts-test-utils'; -import { Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -blockchainTests('DevUtils.getOrderHash', env => { - let devUtils: DevUtilsContract; - let exchange: ExchangeContract; - let chainId: number; - - before(async () => { - chainId = await env.getChainIdAsync(); - - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.Exchange, - env.provider, - env.txDefaults, - exchangeArtifacts, - new BigNumber(chainId), - ); - devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - artifacts.DevUtils, - artifacts, - env.provider, - env.txDefaults, - artifacts, - exchange.address, - constants.NULL_ADDRESS, - constants.NULL_ADDRESS, - ); - }); - - it('should return the order hash', async () => { - const order: Order = { - makerAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - feeRecipientAddress: constants.NULL_ADDRESS, - makerAssetData: constants.NULL_ADDRESS, - takerAssetData: constants.NULL_ADDRESS, - makerFeeAssetData: constants.NULL_ADDRESS, - takerFeeAssetData: constants.NULL_ADDRESS, - salt: new BigNumber(0), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - makerAssetAmount: new BigNumber(0), - takerAssetAmount: new BigNumber(0), - expirationTimeSeconds: new BigNumber(0), - exchangeAddress: exchange.address, - chainId, - }; - expect(await devUtils.getOrderHash(order, new BigNumber(chainId), exchange.address).callAsync()).to.be.equal( - orderHashUtils.getOrderHashHex(order), - ); - }); -}); diff --git a/contracts/integrations/test/dev-utils/global_hooks.ts b/contracts/integrations/test/dev-utils/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/integrations/test/dev-utils/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/integrations/test/dev-utils/lib_asset_data.ts b/contracts/integrations/test/dev-utils/lib_asset_data.ts deleted file mode 100644 index 152f8db98f..0000000000 --- a/contracts/integrations/test/dev-utils/lib_asset_data.ts +++ /dev/null @@ -1,554 +0,0 @@ -import * as crypto from 'crypto'; - -import { artifacts as proxyArtifacts, TestStaticCallTargetContract } from '@0x/contracts-asset-proxy'; -import { artifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; -import { ERC1155MintableContract } from '@0x/contracts-erc1155'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber, hexUtils, LibBytesRevertErrors } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { DeploymentManager } from '../framework/deployment_manager'; - -const KNOWN_ERC20_ENCODING = { - address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', - assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48', -}; -const KNOWN_ERC721_ENCODING = { - address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', - tokenId: new BigNumber(1), - assetData: - '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', -}; -const KNOWN_ERC1155_ENCODING = { - tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', - tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)], - tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)], - callbackData: - '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', - assetData: - '0xa7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', -}; -const KNOWN_MULTI_ASSET_ENCODING = { - amounts: [new BigNumber(70), new BigNumber(1), new BigNumber(18)], - nestedAssetData: [ - KNOWN_ERC20_ENCODING.assetData, - KNOWN_ERC721_ENCODING.assetData, - KNOWN_ERC1155_ENCODING.assetData, - ], - assetData: - '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', -}; -const KNOWN_STATIC_CALL_ENCODING = { - staticCallTargetAddress: '0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f', - staticCallData: '0xed2cfc9c0000000000000000000000000000000000000000000000000000000000000001', - expectedReturnDataHash: '0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6', - assetData: - '0xc339d10a0000000000000000000000006dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f0000000000000000000000000000000000000000000000000000000000000060b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60000000000000000000000000000000000000000000000000000000000000024ed2cfc9c000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', -}; - -// TODO(jalextowle): This file could really be cleaned up by using the DeploymentManager tool. -blockchainTests.resets('LibAssetData', env => { - let deployment: DeploymentManager; - let staticCallTarget: TestStaticCallTargetContract; - let devUtils: DevUtilsContract; - - let tokenOwner: Actor; - - let erc20Token: DummyERC20TokenContract; - let secondErc20Token: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let erc1155Token: ERC1155MintableContract; - - let erc721TokenId: BigNumber; - let erc1155TokenId: BigNumber; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 2, - numErc721TokensToDeploy: 1, - numErc1155TokensToDeploy: 1, - }); - tokenOwner = new Actor({ name: 'Token Owner', deployment }); - - devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - artifacts.DevUtils, - artifacts, - env.provider, - env.txDefaults, - artifacts, - deployment.exchange.address, - constants.NULL_ADDRESS, - constants.NULL_ADDRESS, - ); - - staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( - proxyArtifacts.TestStaticCallTarget, - env.provider, - env.txDefaults, - artifacts, - ); - - [erc20Token, secondErc20Token] = deployment.tokens.erc20; - [erc721Token] = deployment.tokens.erc721; - [erc1155Token] = deployment.tokens.erc1155; - - // mint tokens - await tokenOwner.configureERC20TokenAsync(erc20Token); - [erc721TokenId] = await tokenOwner.configureERC721TokenAsync(erc721Token); - erc1155TokenId = await tokenOwner.configureERC1155TokenAsync( - erc1155Token, - deployment.assetProxies.erc1155Proxy.address, - new BigNumber(1), - ); - }); - - it('should have a deployed-to address', () => { - expect(devUtils.address.slice(0, 2)).to.equal('0x'); - }); - - describe('encoding and decoding', () => { - it('should decode any asset proxy ID', async () => { - const assetDataScenarios = [ - [KNOWN_ERC20_ENCODING.assetData, AssetProxyId.ERC20], - [KNOWN_ERC721_ENCODING.assetData, AssetProxyId.ERC721], - [KNOWN_ERC1155_ENCODING.assetData, AssetProxyId.ERC1155], - [KNOWN_MULTI_ASSET_ENCODING.assetData, AssetProxyId.MultiAsset], - ]; - - for (const [assetData, proxyId] of assetDataScenarios) { - expect(await devUtils.decodeAssetProxyId(assetData).callAsync()).to.equal(proxyId); - } - }); - it('should encode ERC20 asset data', async () => { - expect(await devUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address).callAsync()).to.equal( - KNOWN_ERC20_ENCODING.assetData, - ); - }); - - it('should decode ERC20 asset data', async () => { - expect(await devUtils.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData).callAsync()).to.deep.equal([ - AssetProxyId.ERC20, - KNOWN_ERC20_ENCODING.address, - ]); - }); - - it('should encode ERC721 asset data', async () => { - expect( - await devUtils - .encodeERC721AssetData(KNOWN_ERC721_ENCODING.address, KNOWN_ERC721_ENCODING.tokenId) - .callAsync(), - ).to.equal(KNOWN_ERC721_ENCODING.assetData); - }); - - it('should decode ERC721 asset data', async () => { - expect(await devUtils.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData).callAsync()).to.deep.equal([ - AssetProxyId.ERC721, - KNOWN_ERC721_ENCODING.address, - KNOWN_ERC721_ENCODING.tokenId, - ]); - }); - - it('should encode ERC1155 asset data', async () => { - expect( - await devUtils - .encodeERC1155AssetData( - KNOWN_ERC1155_ENCODING.tokenAddress, - KNOWN_ERC1155_ENCODING.tokenIds, - KNOWN_ERC1155_ENCODING.tokenValues, - KNOWN_ERC1155_ENCODING.callbackData, - ) - .callAsync(), - ).to.equal(KNOWN_ERC1155_ENCODING.assetData); - }); - - it('should decode ERC1155 asset data', async () => { - expect(await devUtils.decodeERC1155AssetData(KNOWN_ERC1155_ENCODING.assetData).callAsync()).to.deep.equal([ - AssetProxyId.ERC1155, - KNOWN_ERC1155_ENCODING.tokenAddress, - KNOWN_ERC1155_ENCODING.tokenIds, - KNOWN_ERC1155_ENCODING.tokenValues, - KNOWN_ERC1155_ENCODING.callbackData, - ]); - }); - - it('should encode multiasset data', async () => { - expect( - await devUtils - .encodeMultiAssetData( - KNOWN_MULTI_ASSET_ENCODING.amounts, - KNOWN_MULTI_ASSET_ENCODING.nestedAssetData, - ) - .callAsync(), - ).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData); - }); - - it('should decode multiasset data', async () => { - expect( - await devUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync(), - ).to.deep.equal([ - AssetProxyId.MultiAsset, - KNOWN_MULTI_ASSET_ENCODING.amounts, - KNOWN_MULTI_ASSET_ENCODING.nestedAssetData, - ]); - }); - - it('should encode StaticCall data', async () => { - expect( - await devUtils - .encodeStaticCallAssetData( - KNOWN_STATIC_CALL_ENCODING.staticCallTargetAddress, - KNOWN_STATIC_CALL_ENCODING.staticCallData, - KNOWN_STATIC_CALL_ENCODING.expectedReturnDataHash, - ) - .callAsync(), - ).to.equal(KNOWN_STATIC_CALL_ENCODING.assetData); - }); - - it('should decode StaticCall data', async () => { - expect( - await devUtils.decodeStaticCallAssetData(KNOWN_STATIC_CALL_ENCODING.assetData).callAsync(), - ).to.deep.equal([ - AssetProxyId.StaticCall, - KNOWN_STATIC_CALL_ENCODING.staticCallTargetAddress, - KNOWN_STATIC_CALL_ENCODING.staticCallData, - KNOWN_STATIC_CALL_ENCODING.expectedReturnDataHash, - ]); - }); - }); - describe('revertIfInvalidAssetData', async () => { - it('should succeed for any valid asset data', async () => { - const assetData = [ - KNOWN_ERC20_ENCODING.assetData, - KNOWN_ERC721_ENCODING.assetData, - KNOWN_ERC1155_ENCODING.assetData, - KNOWN_MULTI_ASSET_ENCODING.assetData, - KNOWN_STATIC_CALL_ENCODING.assetData, - ]; - - for (const data of assetData) { - await devUtils.revertIfInvalidAssetData(data).callAsync(); - } - return; - }); - - it('should revert for invalid assetProxyId', async () => { - const badAssetData = `0x${crypto.randomBytes(4).toString('hex')}${constants.NULL_ADDRESS}`; - await expect(devUtils.revertIfInvalidAssetData(badAssetData).callAsync()).to.revertWith('WRONG_PROXY_ID'); - }); - - it('should revert for invalid assetData with valid assetProxyId', async () => { - // the other encodings are always valid if the assetProxyId is valid - const assetData = [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData]; - - for (const data of assetData) { - const badData = data.substring(0, data.length - 2); // drop one byte but retain assetProxyId - await expect(devUtils.revertIfInvalidAssetData(badData).callAsync()).to.revertWith( - new LibBytesRevertErrors.InvalidByteOperationError(), - ); - } - }); - }); - - describe('getBalance', () => { - it('should query ERC20 balance by asset data', async () => { - const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(); - expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.INITIAL_ERC20_BALANCE, - ); - }); - - it('should return 0 if ERC20 token does not exist', async () => { - const assetData = await devUtils.encodeERC20AssetData(constants.NULL_ADDRESS).callAsync(); - const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync(); - expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - - it('should query ERC721 balance by asset data', async () => { - const assetData = await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(); - expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1); - }); - - it('should return 0 if ERC721 token does not exist', async () => { - const assetData = await devUtils.encodeERC721AssetData(constants.NULL_ADDRESS, erc721TokenId).callAsync(); - const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync(); - expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - - it('should query ERC1155 balances by asset data', async () => { - const assetData = await devUtils - .encodeERC1155AssetData( - erc1155Token.address, - [erc1155TokenId], - [new BigNumber(1)], - constants.NULL_BYTES, - ) - .callAsync(); - expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1); - }); - - it('should return 0 if ERC1155 token does not exist', async () => { - const assetData = await devUtils - .encodeERC1155AssetData( - constants.NULL_ADDRESS, - [erc1155TokenId], - [new BigNumber(1)], - constants.NULL_BYTES, - ) - .callAsync(); - const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync(); - expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - - it('should query multi-asset batch balance by asset data', async () => { - const assetData = await devUtils - .encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [ - await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(), - await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(), - ], - ) - .callAsync(); - expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1); - }); - - it('should query multi-asset batch balance by asset data, skipping over a nested asset if its amount == 0', async () => { - const assetData = await devUtils - .encodeMultiAssetData( - [constants.ZERO_AMOUNT, new BigNumber(1)], - [ - await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(), - await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(), - ], - ) - .callAsync(); - expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1); - }); - - it('should return a balance of 0 if the balance for a nested asset is 0', async () => { - const assetData = await devUtils - .encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [ - await devUtils.encodeERC20AssetData(secondErc20Token.address).callAsync(), - await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(), - ], - ) - .callAsync(); - expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.ZERO_AMOUNT, - ); - }); - - it('should return a balance of 0 if the assetData does not correspond to an AssetProxy contract', async () => { - const fakeAssetData = '0x01020304'; - const balance = await devUtils.getBalance(tokenOwner.address, fakeAssetData).callAsync(); - expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - - it('should return a balance of MAX_UINT256 if the the StaticCallProxy assetData contains data for a successful staticcall', async () => { - const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData(); - const expectedResultHash = hexUtils.hash(hexUtils.leftPad(1)); - const assetData = await devUtils - .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) - .callAsync(); - const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync(); - expect(balance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - }); - - it('should return a balance of 0 if the the StaticCallProxy assetData contains data for an unsuccessful staticcall', async () => { - const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData(); - const expectedResultHash = hexUtils.hash(hexUtils.leftPad(1)); - const assetData = await devUtils - .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash) - .callAsync(); - const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync(); - expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - - describe('getAssetProxyAllowance', () => { - it('should query ERC20 allowances by asset data', async () => { - const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.MAX_UINT256, - ); - }); - - it('should query ERC721 approval by asset data', async () => { - // Temporarily remove approval for all - await erc721Token - .setApprovalForAll(deployment.assetProxies.erc721Proxy.address, false) - .awaitTransactionSuccessAsync({ from: tokenOwner.address }); - await erc721Token - .approve(deployment.assetProxies.erc721Proxy.address, erc721TokenId) - .awaitTransactionSuccessAsync({ - from: tokenOwner.address, - }); - const assetData = await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - 1, - ); - }); - - it('should query ERC721 approvalForAll by assetData', async () => { - const assetData = await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - }); - - it('should query ERC1155 allowances by asset data', async () => { - const assetData = await devUtils - .encodeERC1155AssetData( - erc1155Token.address, - [erc1155TokenId], - [new BigNumber(1)], - constants.NULL_BYTES, - ) - .callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - }); - - it('should query multi-asset allowances by asset data', async () => { - const allowance = new BigNumber(1); - await erc20Token - .approve(deployment.assetProxies.erc20Proxy.address, allowance) - .awaitTransactionSuccessAsync({ - from: tokenOwner.address, - }); - const assetData = await devUtils - .encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [ - await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(), - await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(), - ], - ) - .callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - 1, - ); - return; - }); - - it('should query multi-asset allowances by asset data, skipping over a nested asset if its amount == 0', async () => { - const allowance = new BigNumber(1); - await erc20Token - .approve(deployment.assetProxies.erc20Proxy.address, allowance) - .awaitTransactionSuccessAsync({ - from: tokenOwner.address, - }); - const assetData = await devUtils - .encodeMultiAssetData( - [constants.ZERO_AMOUNT, new BigNumber(1)], - [ - await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(), - await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(), - ], - ) - .callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - return; - }); - - it('should return an allowance of 0 if the allowance for a nested asset is 0', async () => { - const assetData = await devUtils - .encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [ - await devUtils.encodeERC20AssetData(secondErc20Token.address).callAsync(), - await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(), - ], - ) - .callAsync(); - expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal( - constants.ZERO_AMOUNT, - ); - }); - - it('should return an allowance of 0 if the assetData does not correspond to an AssetProxy contract', async () => { - const fakeAssetData = '0x01020304'; - const allowance = await devUtils.getAssetProxyAllowance(tokenOwner.address, fakeAssetData).callAsync(); - expect(allowance).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - - it('should return an allowance of MAX_UINT256 for any staticCallAssetData', async () => { - const staticCallData = AssetProxyId.StaticCall; - const assetData = await devUtils - .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, constants.KECCAK256_NULL) - .callAsync(); - const allowance = await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(); - expect(allowance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - }); - }); - - describe('getBatchBalances', () => { - it('should query balances for a batch of asset data strings', async () => { - const erc20AssetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(); - const erc721AssetData = await devUtils - .encodeERC721AssetData(erc721Token.address, erc721TokenId) - .callAsync(); - expect( - await devUtils.getBatchBalances(tokenOwner.address, [erc20AssetData, erc721AssetData]).callAsync(), - ).to.deep.equal([new BigNumber(constants.INITIAL_ERC20_BALANCE), new BigNumber(1)]); - }); - }); - - describe('getBalanceAndAllowance', () => { - it('should query balance and allowance together, from asset data', async () => { - const allowance = new BigNumber(1); - await erc20Token - .approve(deployment.assetProxies.erc20Proxy.address, allowance) - .awaitTransactionSuccessAsync({ - from: tokenOwner.address, - }); - const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(); - expect( - await devUtils.getBalanceAndAssetProxyAllowance(tokenOwner.address, assetData).callAsync(), - ).to.deep.equal([new BigNumber(constants.INITIAL_ERC20_BALANCE), allowance]); - }); - }); - describe('getBatchBalancesAndAllowances', () => { - it('should query balances and allowances together, from an asset data array', async () => { - const allowance = new BigNumber(1); - await erc20Token - .approve(deployment.assetProxies.erc20Proxy.address, allowance) - .awaitTransactionSuccessAsync({ - from: tokenOwner.address, - }); - const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(); - expect( - await devUtils.getBatchBalancesAndAssetProxyAllowances(tokenOwner.address, [assetData]).callAsync(), - ).to.deep.equal([[new BigNumber(constants.INITIAL_ERC20_BALANCE)], [allowance]]); - }); - }); - - describe('getBatchAssetProxyAllowances', () => { - it('should query allowances for a batch of asset data strings', async () => { - const allowance = new BigNumber(1); - await erc20Token - .approve(deployment.assetProxies.erc20Proxy.address, allowance) - .awaitTransactionSuccessAsync({ - from: tokenOwner.address, - }); - const erc20AssetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(); - const erc721AssetData = await devUtils - .encodeERC721AssetData(erc721Token.address, erc721TokenId) - .callAsync(); - expect( - await devUtils - .getBatchAssetProxyAllowances(tokenOwner.address, [erc20AssetData, erc721AssetData]) - .callAsync(), - ).to.deep.equal([allowance, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS]); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/dev-utils/lib_transaction_decoder.ts b/contracts/integrations/test/dev-utils/lib_transaction_decoder.ts deleted file mode 100644 index 7b3cb76a5b..0000000000 --- a/contracts/integrations/test/dev-utils/lib_transaction_decoder.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange'; -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { artifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; - -const order = { - makerAddress: '0xe36ea790bc9d7ab70c55260c66d52b1eca985f84', - takerAddress: '0x0000000000000000000000000000000000000000', - feeRecipientAddress: '0x78dc5d2d739606d31509c31d654056a45185ecb6', - senderAddress: '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb', - makerAssetAmount: new BigNumber('100000000000000000000'), - takerAssetAmount: new BigNumber('200000000000000000000'), - makerFee: new BigNumber('1000000000000000000'), - takerFee: new BigNumber('1000000000000000000'), - expirationTimeSeconds: new BigNumber('1552396423'), - salt: new BigNumber('66097384406870180066678463045003379626790660770396923976862707230261946348951'), - makerAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064', - takerAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3', - makerFeeAssetData: '0xf47261b000000000000000000000000034d402f14d58e001d8efbe6585051bf9706aa064', - takerFeeAssetData: '0xf47261b000000000000000000000000025b8fe1de9daf8ba351890744ff28cf7dfa8f5e3', -}; -const takerAssetFillAmount = new BigNumber('100000000000000000000'); -const signature = - '0x1ce8e3c600d933423172b5021158a6be2e818613ff8e762d70ef490c752fd98a626a215f09f169668990414de75a53da221c294a3002f796d004827258b641876e03'; - -blockchainTests('LibTransactionDecoder', env => { - let devUtils: DevUtilsContract; - const exchangeInterface = new ExchangeContract(constants.NULL_ADDRESS, { isEIP1193: true } as any); - before(async () => { - const exchange = await ExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.Exchange, - env.provider, - env.txDefaults, - exchangeArtifacts, - new BigNumber(1), - ); - devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - artifacts.DevUtils, - artifacts, - env.provider, - env.txDefaults, - artifacts, - exchange.address, - constants.NULL_ADDRESS, - constants.NULL_ADDRESS, - ); - }); - - it('should decode an Exchange.batchCancelOrders() transaction', async () => { - const input = exchangeInterface.batchCancelOrders([order, order]).getABIEncodedTransactionData(); - expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([ - 'batchCancelOrders', - [order, order], - [], - [], - ]); - }); - - for (const func of ['batchFillOrders', 'batchFillOrdersNoThrow', 'batchFillOrKillOrders']) { - const input = (exchangeInterface as any) - [func]([order, order], [takerAssetFillAmount, takerAssetFillAmount], [signature, signature]) - .getABIEncodedTransactionData(); - it(`should decode an Exchange.${func}() transaction`, async () => { - expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([ - func, - [order, order], - [takerAssetFillAmount, takerAssetFillAmount], - [signature, signature], - ]); - }); - } - - it('should decode an Exchange.cancelOrder() transaction', async () => { - const input = exchangeInterface.cancelOrder(order).getABIEncodedTransactionData(); - expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([ - 'cancelOrder', - [order], - [], - [], - ]); - }); - - for (const func of ['fillOrder', 'fillOrKillOrder']) { - const input = (exchangeInterface as any) - [func](order, takerAssetFillAmount, signature) - .getABIEncodedTransactionData(); - it(`should decode an Exchange.${func}() transaction`, async () => { - expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([ - func, - [order], - [takerAssetFillAmount], - [signature], - ]); - }); - } - - for (const func of [ - 'marketBuyOrdersNoThrow', - 'marketSellOrdersNoThrow', - 'marketBuyOrdersFillOrKill', - 'marketSellOrdersFillOrKill', - ]) { - const input = (exchangeInterface as any) - [func]([order, order], takerAssetFillAmount, [signature, signature]) - .getABIEncodedTransactionData(); - it(`should decode an Exchange.${func}() transaction`, async () => { - expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([ - func, - [order, order], - [takerAssetFillAmount], - [signature, signature], - ]); - }); - } - - it('should decode an Exchange.matchOrders() transaction', async () => { - const complementaryOrder = { - ...order, - makerAddress: order.takerAddress, - takerAddress: order.makerAddress, - makerAssetData: order.takerAssetData, - takerAssetData: order.makerAssetData, - makerAssetAmount: order.takerAssetAmount, - takerAssetAmount: order.makerAssetAmount, - makerFee: order.takerFee, - takerFee: order.makerFee, - makerFeeAssetData: order.takerFeeAssetData, - takerFeeAssetData: order.makerFeeAssetData, - }; - const input = exchangeInterface - .matchOrders(order, complementaryOrder, signature, signature) - .getABIEncodedTransactionData(); - expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([ - 'matchOrders', - [order, complementaryOrder], - [order.takerAssetAmount, complementaryOrder.takerAssetAmount], - [signature, signature], - ]); - }); -}); diff --git a/contracts/integrations/test/dev-utils/order_validation_utils.ts b/contracts/integrations/test/dev-utils/order_validation_utils.ts deleted file mode 100644 index a9b0497135..0000000000 --- a/contracts/integrations/test/dev-utils/order_validation_utils.ts +++ /dev/null @@ -1,655 +0,0 @@ -import { ERC20ProxyContract } from '@0x/contracts-asset-proxy'; -import { DevUtilsContract } from '@0x/contracts-dev-utils'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { ExchangeContract } from '@0x/contracts-exchange'; -import { blockchainTests, constants, expect, orderHashUtils, OrderStatus } from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { OrderTransferResults, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { DeploymentManager } from '../framework/deployment_manager'; - -// TODO(jalextowle): This can be cleaned up by using the actors more. -blockchainTests.resets('OrderValidationUtils/OrderTransferSimulatorUtils', env => { - let owner: string; - - let maker: Maker; - let taker: Taker; - let devUtils: DevUtilsContract; - let erc20Token: DummyERC20TokenContract; - let erc20Token2: DummyERC20TokenContract; - let feeErc20Token: DummyERC20TokenContract; - let erc20Proxy: ERC20ProxyContract; - let exchange: ExchangeContract; - let deployment: DeploymentManager; - - let erc20AssetData: string; - let erc20AssetData2: string; - let feeAssetData: string; - let erc721AssetData: string; - - let signedOrder: SignedOrder; - - before(async () => { - [owner] = await env.getAccountAddressesAsync(); - - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 3, - numErc721TokensToDeploy: 1, - owner, - }); - erc20Token = deployment.tokens.erc20[0]; - erc20Token2 = deployment.tokens.erc20[1]; - feeErc20Token = deployment.tokens.erc20[2]; - erc20Proxy = deployment.assetProxies.erc20Proxy; - devUtils = deployment.devUtils; - exchange = deployment.exchange; - - erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address); - erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20Token2.address); - feeAssetData = assetDataUtils.encodeERC20AssetData(feeErc20Token.address); - - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig: { - makerAssetData: erc20AssetData, - takerAssetData: erc20AssetData2, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: constants.NULL_ADDRESS, - }, - }); - taker = new Taker({ - name: 'Taker', - deployment, - }); - - const [tokenID] = await maker.configureERC721TokenAsync(deployment.tokens.erc721[0]); - erc721AssetData = assetDataUtils.encodeERC721AssetData(deployment.tokens.erc721[0].address, tokenID); - }); - - describe('getTransferableAssetAmount', () => { - it('should return the balance when balance < allowance', async () => { - const balance = new BigNumber(123); - const allowance = new BigNumber(456); - await erc20Token.setBalance(maker.address, balance).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, allowance).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const transferableAmount = await devUtils - .getTransferableAssetAmount(maker.address, erc20AssetData) - .callAsync(); - expect(transferableAmount).to.bignumber.equal(balance); - }); - it('should return the allowance when allowance < balance', async () => { - const balance = new BigNumber(456); - const allowance = new BigNumber(123); - await erc20Token.setBalance(maker.address, balance).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, allowance).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const transferableAmount = await devUtils - .getTransferableAssetAmount(maker.address, erc20AssetData) - .callAsync(); - expect(transferableAmount).to.bignumber.equal(allowance); - }); - it('should return the correct transferable amount for multiAssetData', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc20AssetData, erc20AssetData2]) - .callAsync(); - const transferableAmount1 = new BigNumber(10); - const transferableAmount2 = new BigNumber(5); - await erc20Token.setBalance(maker.address, transferableAmount1).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, transferableAmount1).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await erc20Token2.setBalance(maker.address, transferableAmount2).awaitTransactionSuccessAsync(); - await erc20Token2.approve(erc20Proxy.address, transferableAmount2).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const transferableAmount = await devUtils - .getTransferableAssetAmount(maker.address, multiAssetData) - .callAsync(); - expect(transferableAmount).to.bignumber.equal(transferableAmount2); - }); - }); - describe('getOrderRelevantState', () => { - beforeEach(async () => { - signedOrder = await maker.signOrderAsync({}); - }); - it('should return the correct orderInfo when the order is valid', async () => { - const [orderInfo] = await devUtils.getOrderRelevantState(signedOrder, signedOrder.signature).callAsync(); - expect(orderInfo.orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder)); - expect(orderInfo.orderStatus).to.equal(OrderStatus.Fillable); - expect(orderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return isValidSignature=true when the signature is valid', async () => { - const [, , isValidSignature] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(isValidSignature).to.equal(true); - }); - it('should return isValidSignature=false when the signature is invalid', async () => { - const invalidSignature = '0x01'; - const [, , isValidSignature] = await devUtils - .getOrderRelevantState(signedOrder, invalidSignature) - .callAsync(); - expect(isValidSignature).to.equal(false); - }); - it('should return a fillableTakerAssetAmount of 0 when balances or allowances are insufficient', async () => { - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when fee balances/allowances are insufficient', async () => { - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should correctly validate fillable order', async () => { - signedOrder = await maker.signOrderAsync({ - makerAssetData: erc721AssetData, - makerAssetAmount: new BigNumber(1), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - await taker.configureERC20TokenAsync(erc20Token2); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.greaterThan(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when balances/allowances of one asset within a multiAssetData are insufficient (ERC20)', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc20AssetData, erc20AssetData2]) - .callAsync(); - signedOrder = await maker.signOrderAsync({ makerAssetData: multiAssetData }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when balances/allowances of one asset within a multiAssetData are insufficient (ERC721)', async () => { - const [tokenID] = await taker.configureERC721TokenAsync(deployment.tokens.erc721[0]); - const takerOwnedErc721AssetData = assetDataUtils.encodeERC721AssetData( - deployment.tokens.erc721[0].address, - tokenID, - ); - - const multiAssetData = await devUtils - .encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [takerOwnedErc721AssetData, erc721AssetData], - ) - .callAsync(); - signedOrder = await maker.signOrderAsync({ makerAssetData: multiAssetData }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when an erc721 asset is duplicated in the maker side of a multi-asset proxy order', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc721AssetData, erc721AssetData]) - .callAsync(); - signedOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - makerAssetAmount: new BigNumber(1), - takerAssetData: erc721AssetData, - takerAssetAmount: new BigNumber(1), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when an erc721 asset is duplicated in the taker side of a multi-asset proxy order', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc721AssetData, erc721AssetData]) - .callAsync(); - signedOrder = await maker.signOrderAsync({ - makerAssetData: erc721AssetData, - makerAssetAmount: new BigNumber(1), - takerAssetData: multiAssetData, - takerAssetAmount: new BigNumber(1), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when an erc721 asset is duplicated in the maker fee side of a multi-asset proxy order', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc721AssetData, erc721AssetData]) - .callAsync(); - signedOrder = await maker.signOrderAsync({ - makerFeeAssetData: multiAssetData, - makerFee: new BigNumber(1), - takerFee: constants.ZERO_AMOUNT, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount of 0 when an erc721 asset is duplicated in the taker fee side of a multi-asset proxy order', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc721AssetData, erc721AssetData]) - .callAsync(); - signedOrder = await maker.signOrderAsync({ - makerFee: constants.ZERO_AMOUNT, - takerFeeAssetData: multiAssetData, - takerFee: new BigNumber(1), - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return the correct fillableTakerAssetAmount when fee balances/allowances are partially sufficient', async () => { - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const divisor = 4; - await feeErc20Token - .setBalance(maker.address, signedOrder.makerFee.dividedToIntegerBy(divisor)) - .awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal( - signedOrder.takerAssetAmount.dividedToIntegerBy(divisor), - ); - }); - it('should return the correct fillableTakerAssetAmount when non-fee balances/allowances are partially sufficient', async () => { - const divisor = 4; - await erc20Token - .setBalance(maker.address, signedOrder.makerAssetAmount.dividedToIntegerBy(divisor)) - .awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal( - signedOrder.takerAssetAmount.dividedToIntegerBy(divisor), - ); - }); - it('should return the correct fillableTakerAssetAmount when balances/allowances of one asset within a multiAssetData are partially sufficient', async () => { - const multiAssetData = await devUtils - .encodeMultiAssetData([new BigNumber(1), new BigNumber(1)], [erc20AssetData, erc20AssetData2]) - .callAsync(); - signedOrder = await maker.signOrderAsync({ makerAssetData: multiAssetData }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const divisor = 4; - await erc20Token2 - .setBalance(maker.address, signedOrder.makerAssetAmount.dividedToIntegerBy(divisor)) - .awaitTransactionSuccessAsync(); - await erc20Token2 - .approve(erc20Proxy.address, signedOrder.makerAssetAmount.dividedToIntegerBy(divisor)) - .awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal( - signedOrder.takerAssetAmount.dividedToIntegerBy(divisor), - ); - }); - it('should return a fillableTakerAssetAmount of 0 when non-fee balances/allowances are insufficient', async () => { - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return a fillableTakerAssetAmount equal to the takerAssetAmount when the order is unfilled and balances/allowances are sufficient', async () => { - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount); - }); - it('should return the correct fillableTakerAssetAmount when balances/allowances are partially sufficient and makerAsset=makerFeeAsset', async () => { - signedOrder = await maker.signOrderAsync({ - makerAssetData: feeAssetData, - makerAssetAmount: new BigNumber(10), - takerAssetAmount: new BigNumber(20), - makerFee: new BigNumber(40), - }); - const transferableMakerAssetAmount = new BigNumber(10); - await feeErc20Token.setBalance(maker.address, transferableMakerAssetAmount).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, transferableMakerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const expectedFillableTakerAssetAmount = transferableMakerAssetAmount - .times(signedOrder.takerAssetAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount.plus(signedOrder.makerFee)); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(expectedFillableTakerAssetAmount); - }); - it('should return the correct fillabeTakerassetAmount when makerAsset balances/allowances are sufficient and there are no maker fees', async () => { - signedOrder = await maker.signOrderAsync({ makerFee: constants.ZERO_AMOUNT }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount); - }); - it('should return a fillableTakerAssetAmount when the remaining takerAssetAmount is less than the transferable amount', async () => { - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await feeErc20Token.setBalance(taker.address, signedOrder.takerFee).awaitTransactionSuccessAsync(); - - await feeErc20Token.approve(erc20Proxy.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: taker.address, - }); - const takerAssetFillAmount = signedOrder.takerAssetAmount.dividedToIntegerBy(4); - await exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: taker.address, value: DeploymentManager.protocolFee }); - const [, fillableTakerAssetAmount] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(fillableTakerAssetAmount).to.bignumber.equal( - signedOrder.takerAssetAmount.minus(takerAssetFillAmount), - ); - }); - it('should return correct info even when there are no fees specified', async () => { - signedOrder = await maker.signOrderAsync({ - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - makerFeeAssetData: '0x', - takerFeeAssetData: '0x', - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [orderInfo, fillableTakerAssetAmount, isValidSignature] = await devUtils - .getOrderRelevantState(signedOrder, signedOrder.signature) - .callAsync(); - expect(orderInfo.orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder)); - expect(orderInfo.orderStatus).to.equal(OrderStatus.Fillable); - expect(orderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount); - expect(isValidSignature).to.equal(true); - }); - it('should not revert when rounding errors occur', async () => { - signedOrder = await maker.signOrderAsync({ - makerAssetAmount: new BigNumber('2040250070'), - takerAssetAmount: new BigNumber('2040250070000000000000'), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - await taker.fillOrderAsync(signedOrder, new BigNumber('2040250069999999999990')); - await devUtils.getOrderRelevantState(signedOrder, signedOrder.signature).callAsync(); - }); - }); - describe('getOrderRelevantStates', async () => { - it('should return the correct information for multiple orders', async () => { - signedOrder = await maker.signOrderAsync(); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync(); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync(); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const signedOrder2 = await maker.signOrderAsync({ - makerAssetData: erc721AssetData, - makerAssetAmount: new BigNumber(1), - }); - const invalidSignature = '0x01'; - await exchange.cancelOrder(signedOrder2).awaitTransactionSuccessAsync({ from: maker.address }); - const [ordersInfo, fillableTakerAssetAmounts, isValidSignature] = await devUtils - .getOrderRelevantStates([signedOrder, signedOrder2], [signedOrder.signature, invalidSignature]) - .callAsync(); - expect(ordersInfo[0].orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder)); - expect(ordersInfo[1].orderHash).to.equal(orderHashUtils.getOrderHashHex(signedOrder2)); - expect(ordersInfo[0].orderStatus).to.equal(OrderStatus.Fillable); - expect(ordersInfo[1].orderStatus).to.equal(OrderStatus.Cancelled); - expect(ordersInfo[0].orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - expect(ordersInfo[1].orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - expect(fillableTakerAssetAmounts[0]).to.bignumber.equal(signedOrder.takerAssetAmount); - expect(fillableTakerAssetAmounts[1]).to.bignumber.equal(constants.ZERO_AMOUNT); - expect(isValidSignature[0]).to.equal(true); - expect(isValidSignature[1]).to.equal(false); - }); - }); - describe('getSimulatedOrderTransferResults', () => { - beforeEach(async () => { - signedOrder = await maker.signOrderAsync(); - }); - it('should return TakerAssetDataFailed if the takerAsset transfer fails', async () => { - const orderTransferResults = await devUtils - .getSimulatedOrderTransferResults(signedOrder, taker.address, signedOrder.takerAssetAmount) - .callAsync(); - expect(orderTransferResults).to.equal(OrderTransferResults.TakerAssetDataFailed); - }); - it('should return MakerAssetDataFailed if the makerAsset transfer fails', async () => { - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - const orderTransferResults = await devUtils - .getSimulatedOrderTransferResults(signedOrder, taker.address, signedOrder.takerAssetAmount) - .callAsync(); - expect(orderTransferResults).to.equal(OrderTransferResults.MakerAssetDataFailed); - }); - it('should return TakerFeeAssetDataFailed if the takerFeeAsset transfer fails', async () => { - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const orderTransferResults = await devUtils - .getSimulatedOrderTransferResults(signedOrder, taker.address, signedOrder.takerAssetAmount) - .callAsync(); - expect(orderTransferResults).to.equal(OrderTransferResults.TakerFeeAssetDataFailed); - }); - it('should return MakerFeeAssetDataFailed if the makerFeeAsset transfer fails', async () => { - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(taker.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: taker.address, - }); - const orderTransferResults = await devUtils - .getSimulatedOrderTransferResults(signedOrder, taker.address, signedOrder.takerAssetAmount) - .callAsync(); - expect(orderTransferResults).to.equal(OrderTransferResults.MakerFeeAssetDataFailed); - }); - it('should return TransfersSuccessful if all transfers succeed', async () => { - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(taker.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const orderTransferResults = await devUtils - .getSimulatedOrderTransferResults(signedOrder, taker.address, signedOrder.takerAssetAmount) - .callAsync(); - expect(orderTransferResults).to.equal(OrderTransferResults.TransfersSuccessful); - }); - it('should return TransfersSuccessful for a partial fill when taker has ample assets for the fill but not for the whole order', async () => { - await erc20Token2 - .setBalance(taker.address, signedOrder.takerAssetAmount.dividedBy(2)) - .awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(taker.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const orderTransferResults = await devUtils - .getSimulatedOrderTransferResults(signedOrder, taker.address, signedOrder.takerAssetAmount.dividedBy(2)) - .callAsync(); - expect(orderTransferResults).to.equal(OrderTransferResults.TransfersSuccessful); - }); - }); - describe('getSimulatedOrdersTransferResults', async () => { - it('should simulate the transfers of each order independently from one another', async () => { - // Set balances and allowances to exactly enough to fill a single order - await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: owner, - }); - await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({ - from: maker.address, - }); - await feeErc20Token.setBalance(taker.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.takerFee).awaitTransactionSuccessAsync({ - from: taker.address, - }); - await feeErc20Token.setBalance(maker.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: owner, - }); - await feeErc20Token.approve(erc20Proxy.address, signedOrder.makerFee).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const [orderTransferResults1, orderTransferResults2] = await devUtils - .getSimulatedOrdersTransferResults( - [signedOrder, signedOrder], - [taker.address, taker.address], - [signedOrder.takerAssetAmount, signedOrder.takerAssetAmount], - ) - .callAsync(); - expect(orderTransferResults1).to.equal(OrderTransferResults.TransfersSuccessful); - expect(orderTransferResults2).to.equal(OrderTransferResults.TransfersSuccessful); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/exchange/batch_match_orders_test.ts b/contracts/integrations/test/exchange/batch_match_orders_test.ts deleted file mode 100644 index 08158cf22e..0000000000 --- a/contracts/integrations/test/exchange/batch_match_orders_test.ts +++ /dev/null @@ -1,880 +0,0 @@ -import { encodeERC1155AssetData, encodeERC20AssetData, encodeERC721AssetData } from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { blockchainTests, constants, expect, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { Order, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { TokenIds } from '../framework/balances/types'; -import { DeploymentManager } from '../framework/deployment_manager'; - -import { MatchOrderTester, MatchTransferAmounts } from './match_order_tester'; - -blockchainTests.resets('matchOrders integration tests', env => { - // The fee recipient addresses. - let feeRecipientLeft: Actor; - let feeRecipientRight: Actor; - - // The address that should be responsible for matching orders. - let matcher: Actor; - - // Market makers who have opposite maker and taker assets. - let makerLeft: Maker; - let makerRight: Maker; - - // The addresses of important assets for testing. - let makerAssetLeft: DummyERC20TokenContract; - let makerAssetRight: DummyERC20TokenContract; - let feeAsset: DummyERC20TokenContract; - - let makerAssetDataLeft: string; - let makerAssetDataRight: string; - let feeAssetData: string; - - let deployment: DeploymentManager; - let matchOrderTester: MatchOrderTester; - let leftId: BigNumber; - let rightId: BigNumber; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 3, - numErc721TokensToDeploy: 1, - numErc1155TokensToDeploy: 1, - }); - - makerAssetLeft = deployment.tokens.erc20[0]; - makerAssetRight = deployment.tokens.erc20[1]; - feeAsset = deployment.tokens.erc20[2]; - - // Create the fee recipient actors. - feeRecipientLeft = new Actor({ - name: 'left fee recipient', - deployment, - }); - feeRecipientRight = new Actor({ - name: 'right fee recipient', - deployment, - }); - - // Encode the asset data. - makerAssetDataLeft = encodeERC20AssetData(makerAssetLeft.address); - makerAssetDataRight = encodeERC20AssetData(makerAssetRight.address); - feeAssetData = encodeERC20AssetData(feeAsset.address); - - // Create two market makers with compatible orders for matching. - makerLeft = new Maker({ - name: 'left maker', - deployment, - orderConfig: { - makerAssetData: makerAssetDataLeft, - takerAssetData: makerAssetDataRight, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: feeRecipientLeft.address, - }, - }); - makerRight = new Maker({ - name: 'right maker', - deployment, - orderConfig: { - makerAssetData: makerAssetDataRight, - takerAssetData: makerAssetDataLeft, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: feeRecipientRight.address, - }, - }); - - // Create a matcher. - matcher = new Actor({ - name: 'matcher', - deployment, - }); - - // Configure the appropriate actors with initial balances. - await Promise.all([ - ...deployment.tokens.erc20.map(async token => makerLeft.configureERC20TokenAsync(token)), - ...deployment.tokens.erc20.map(async token => makerRight.configureERC20TokenAsync(token)), - makerLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - makerRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - matcher.configureERC20TokenAsync(feeAsset), - matcher.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - feeRecipientLeft.configureERC20TokenAsync(feeAsset), - feeRecipientLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - feeRecipientRight.configureERC20TokenAsync(feeAsset), - feeRecipientRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - ]); - - leftId = await makerLeft.configureERC1155TokenAsync(deployment.tokens.erc1155[0]); - [rightId] = await makerRight.configureERC721TokenAsync(deployment.tokens.erc721[0]); - - const tokenIds: TokenIds = { erc721: {}, erc1155: {} }; - tokenIds.erc1155[deployment.tokens.erc1155[0].address] = { fungible: [leftId], nonFungible: [] }; - tokenIds.erc721[deployment.tokens.erc721[0].address] = [rightId]; - - const blockchainBalanceStore = new BlockchainBalanceStore( - { - ...actorAddressesByName([feeRecipientLeft, feeRecipientRight, makerLeft, makerRight, matcher]), - stakingProxy: deployment.staking.stakingProxy.address, - }, - { - erc20: { - makerTokenLeft: deployment.tokens.erc20[0], - makerTokenRight: deployment.tokens.erc20[1], - feeToken: deployment.tokens.erc20[2], - weth: deployment.tokens.weth, - }, - erc721: { - nft: deployment.tokens.erc721[0], - }, - erc1155: { - fungible: deployment.tokens.erc1155[0], - }, - }, - tokenIds, - ); - - matchOrderTester = new MatchOrderTester(deployment, blockchainBalanceStore); - }); - - after(async () => { - Actor.reset(); - }); - - describe('batchMatchOrders and batchMatchOrdersWithMaximalFill rich errors', async () => { - it('should fail if there are zero leftOrders with the ZeroLeftOrders rich error reason', async () => { - const leftOrders: SignedOrder[] = []; - const rightOrders = [ - await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - ]; - const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError( - ExchangeRevertErrors.BatchMatchOrdersErrorCodes.ZeroLeftOrders, - ); - let tx = deployment.exchange - .batchMatchOrders( - leftOrders, - rightOrders, - leftOrders.map(order => order.signature), - rightOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - await expect(tx).to.revertWith(expectedError); - tx = deployment.exchange - .batchMatchOrdersWithMaximalFill( - leftOrders, - rightOrders, - leftOrders.map(order => order.signature), - rightOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should fail if there are zero rightOrders', async () => { - const leftOrders = [ - await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - ]; - const rightOrders: SignedOrder[] = []; - const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError( - ExchangeRevertErrors.BatchMatchOrdersErrorCodes.ZeroRightOrders, - ); - let tx = deployment.exchange - .batchMatchOrders( - leftOrders, - rightOrders, - leftOrders.map(order => order.signature), - rightOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - await expect(tx).to.revertWith(expectedError); - tx = deployment.exchange - .batchMatchOrdersWithMaximalFill( - leftOrders, - rightOrders, - leftOrders.map(order => order.signature), - rightOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should fail if there are a different number of left orders and signatures', async () => { - const leftOrders = [ - await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }), - await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - ]; - const rightOrders = [ - await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - ]; - const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError( - ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthLeftSignatures, - ); - let tx = deployment.exchange - .batchMatchOrders( - leftOrders, - rightOrders, - [leftOrders[0].signature], - rightOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - await expect(tx).to.revertWith(expectedError); - tx = deployment.exchange - .batchMatchOrdersWithMaximalFill( - leftOrders, - rightOrders, - [leftOrders[0].signature], - rightOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should fail if there are a different number of right orders and signatures', async () => { - const leftOrders = [ - await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }), - await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }), - ]; - const rightOrders = [ - await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }), - ]; - const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError( - ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthRightSignatures, - ); - let tx = deployment.exchange - .batchMatchOrders( - leftOrders, - rightOrders, - leftOrders.map(order => order.signature), - [rightOrders[0].signature], - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - await expect(tx).to.revertWith(expectedError); - tx = deployment.exchange - .batchMatchOrdersWithMaximalFill( - leftOrders, - rightOrders, - leftOrders.map(order => order.signature), - [rightOrders[0].signature], - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - }); - - interface TestBatchMatchOrdersArgs { - leftOrders: Array>; - rightOrders: Array>; - expectedTransferAmounts: Array>; - leftOrdersTakerAssetFilledAmounts: BigNumber[]; - rightOrdersTakerAssetFilledAmounts: BigNumber[]; - matchIndices: Array<[number, number]>; - shouldMaximallyFill: boolean; - matcherAddress?: string; - } - - /** - * Tests a batch order matching scenario with both eth and weth protocol fees. - */ - async function testBatchMatchOrdersAsync(args: TestBatchMatchOrdersArgs): Promise { - const signedLeftOrders = await Promise.all(args.leftOrders.map(async order => makerLeft.signOrderAsync(order))); - const signedRightOrders = await Promise.all( - args.rightOrders.map(async order => makerRight.signOrderAsync(order)), - ); - - await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync( - { - leftOrders: signedLeftOrders, - rightOrders: signedRightOrders, - leftOrdersTakerAssetFilledAmounts: args.leftOrdersTakerAssetFilledAmounts, - rightOrdersTakerAssetFilledAmounts: args.rightOrdersTakerAssetFilledAmounts, - }, - args.matcherAddress || matcher.address, - DeploymentManager.protocolFee.times(args.matchIndices.length).times(2), - args.matchIndices, - args.expectedTransferAmounts.map(transferAmounts => { - return { - ...transferAmounts, - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - leftProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT, - rightProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT, - }; - }), - args.shouldMaximallyFill, - ); - - await env.blockchainLifecycle.revertAsync(); - await env.blockchainLifecycle.startAsync(); - - await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync( - { - leftOrders: signedLeftOrders, - rightOrders: signedRightOrders, - leftOrdersTakerAssetFilledAmounts: args.leftOrdersTakerAssetFilledAmounts, - rightOrdersTakerAssetFilledAmounts: args.rightOrdersTakerAssetFilledAmounts, - }, - args.matcherAddress || matcher.address, - constants.ZERO_AMOUNT, - args.matchIndices, - args.expectedTransferAmounts.map(transferAmounts => { - return { - ...transferAmounts, - leftProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT, - rightProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT, - leftProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee, - }; - }), - args.shouldMaximallyFill, - ); - } - - describe('batchMatchOrders', () => { - it('should correctly match two opposite orders', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - matchIndices: [[0, 0]], - shouldMaximallyFill: false, - }); - }); - - it('should correctly match a partial fill', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(4), - takerAssetAmount: new BigNumber(2), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - matchIndices: [[0, 0]], - shouldMaximallyFill: false, - }); - }); - - it('should correctly match two left orders to one complementary right order', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(4), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(2), - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - }, - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 50% - // Right Maker - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(2), - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - matchIndices: [ - [0, 0], - [1, 0], - ], - shouldMaximallyFill: false, - }); - }); - - it('should correctly match one left order to two complementary right orders', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(4), - takerAssetAmount: new BigNumber(2), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - matchIndices: [ - [0, 0], - [0, 1], - ], - shouldMaximallyFill: false, - }); - }); - - it('should correctly match one left order to two right orders, where the last should not be touched', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - matchIndices: [[0, 0]], - shouldMaximallyFill: false, - }); - }); - - it('should have three order matchings with only two left orders and two right orders', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(4), - takerAssetAmount: new BigNumber(2), - }, - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(4), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - }, - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - matchIndices: [ - [0, 0], - [0, 1], - [1, 1], - ], - shouldMaximallyFill: false, - }); - }); - }); - - describe('batchMatchOrdersWithMaximalFill', () => { - it('should fully fill the the right order and pay the profit denominated in the left maker asset', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(17), - takerAssetAmount: new BigNumber(98), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(75), - takerAssetAmount: new BigNumber(13), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(13), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('76.4705882352941176', 16), // 76.47% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(75), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('76.5306122448979591', 16), // 76.53% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - matchIndices: [[0, 0]], - shouldMaximallyFill: true, - }); - }); - - it('should transfer correct amounts when left order is fully filled', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(15), - takerAssetAmount: new BigNumber(90), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(196), - takerAssetAmount: new BigNumber(28), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(15), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(90), - // Right Maker - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(15), - rightMakerAssetSoldByRightMakerAmount: new BigNumber(105), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('53.5714285714285714', 16), // 53.57% - // Taker - rightMakerAssetReceivedByTakerAmount: new BigNumber(15), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('53.5714285714285714', 16), // 53.57% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - matchIndices: [[0, 0]], - shouldMaximallyFill: true, - }); - }); - - it('should correctly match one left order to two right orders, where the last should not be touched', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - { - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(2), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - matchIndices: [[0, 0]], - shouldMaximallyFill: true, - }); - }); - - it('should correctly fill all four orders in three matches', async () => { - await testBatchMatchOrdersAsync({ - leftOrders: [ - { - makerAssetAmount: new BigNumber(2), - takerAssetAmount: new BigNumber(1), - }, - { - makerAssetAmount: new BigNumber(72), - takerAssetAmount: new BigNumber(36), - }, - ], - rightOrders: [ - { - makerAssetAmount: new BigNumber(15), - takerAssetAmount: new BigNumber(30), - }, - { - makerAssetAmount: new BigNumber(22), - takerAssetAmount: new BigNumber(44), - }, - ], - expectedTransferAmounts: [ - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('6.6666666666666666', 16), // 6.66% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('6.6666666666666666', 16), // 6.66% - }, - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(28), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('38.8888888888888888', 16), // 38.88% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(14), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('93.3333333333333333', 16), // 93.33% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('38.8888888888888888', 16), // 38.88% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('93.3333333333333333', 16), // 93.33% - }, - { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(44), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('61.1111111111111111', 16), // 61.11% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(22), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('61.1111111111111111', 16), // 61.11% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - ], - leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], - matchIndices: [ - [0, 0], - [1, 0], - [1, 1], - ], - shouldMaximallyFill: true, - }); - }); - }); - - describe('token sanity checks', () => { - it('should be able to match ERC721 tokens with ERC1155 tokens', async () => { - const leftMakerAssetData = encodeERC1155AssetData( - deployment.tokens.erc1155[0].address, - [leftId], - [new BigNumber(1)], - '0x', - ); - const rightMakerAssetData = encodeERC721AssetData(deployment.tokens.erc721[0].address, rightId); - - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(4), - takerAssetAmount: new BigNumber(1), - makerAssetData: leftMakerAssetData, - takerAssetData: rightMakerAssetData, - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - takerAssetAmount: new BigNumber(4), - makerAssetData: rightMakerAssetData, - takerAssetData: leftMakerAssetData, - }); - - const expectedTransferAmounts = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(4), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/integrations/test/exchange/core_test.ts b/contracts/integrations/test/exchange/core_test.ts deleted file mode 100644 index 5bdfa76ec7..0000000000 --- a/contracts/integrations/test/exchange/core_test.ts +++ /dev/null @@ -1,1154 +0,0 @@ -import { - artifacts as proxyArtifacts, - encodeERC1155AssetData, - encodeERC20AssetData, - encodeERC721AssetData, - encodeMultiAssetData, - encodeStaticCallAssetData, - ERC1155ProxyContract, - ERC1155ProxyWrapper, - ERC20ProxyContract, - ERC20Wrapper, - ERC721ProxyContract, - ERC721Wrapper, - MultiAssetProxyContract, - StaticCallProxyContract, - TestStaticCallTargetContract, -} from '@0x/contracts-asset-proxy'; -import { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; -import { - artifacts as erc20Artifacts, - DummyERC20TokenContract, - DummyNoReturnERC20TokenContract, -} from '@0x/contracts-erc20'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { artifacts, ExchangeCancelEventArgs, ExchangeContract, ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { LibMathRevertErrors } from '@0x/contracts-exchange-libs'; -import { - blockchainTests, - constants, - describe, - ERC20BalancesByOwner, - expect, - getLatestBlockTimestampAsync, - increaseTimeAndMineBlockAsync, - OrderFactory, - orderHashUtils, - OrderStatus, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber, providerUtils, StringRevertError } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { FillOrderWrapper } from './fill_order_wrapper'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Exchange core', () => { - let chainId: number; - let makerAddress: string; - let owner: string; - let takerAddress: string; - let feeRecipientAddress: string; - - let erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: DummyERC20TokenContract; - let feeToken: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let noReturnErc20Token: DummyNoReturnERC20TokenContract; - let exchange: ExchangeContract; - let erc20Proxy: ERC20ProxyContract; - let erc721Proxy: ERC721ProxyContract; - let erc1155Proxy: ERC1155ProxyContract; - let multiAssetProxy: MultiAssetProxyContract; - let erc1155Contract: ERC1155MintableContract; - let staticCallProxy: StaticCallProxyContract; - let staticCallTarget: TestStaticCallTargetContract; - - let signedOrder: SignedOrder; - let erc20Balances: ERC20BalancesByOwner; - let erc20Wrapper: ERC20Wrapper; - let erc721Wrapper: ERC721Wrapper; - let erc1155Wrapper: Erc1155Wrapper; - let erc1155ProxyWrapper: ERC1155ProxyWrapper; - let orderFactory: OrderFactory; - - let erc721MakerAssetIds: BigNumber[]; - let erc721TakerAssetIds: BigNumber[]; - let erc1155FungibleTokens: BigNumber[]; - let erc1155NonFungibleTokensOwnedByMaker: BigNumber[]; - let erc1155NonFungibleTokensOwnedByTaker: BigNumber[]; - - let defaultMakerAssetAddress: string; - let defaultTakerAssetAddress: string; - let defaultFeeAssetAddress: string; - - let fillOrderWrapper: FillOrderWrapper; - - before(async () => { - chainId = await providerUtils.getChainIdAsync(provider); - 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); - erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); - - // Deploy AssetProxies, Exchange, tokens, and malicious contracts - erc20Proxy = await erc20Wrapper.deployProxyAsync(); - erc721Proxy = await erc721Wrapper.deployProxyAsync(); - multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( - proxyArtifacts.MultiAssetProxy, - provider, - txDefaults, - {}, - ); - staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( - proxyArtifacts.StaticCallProxy, - provider, - txDefaults, - {}, - ); - const numDummyErc20ToDeploy = 3; - [erc20TokenA, erc20TokenB, feeToken] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - noReturnErc20Token = await DummyNoReturnERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyNoReturnERC20Token, - provider, - txDefaults, - {}, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - erc20Wrapper.addDummyTokenContract((noReturnErc20Token as any) as DummyERC20TokenContract); - [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); - erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); - [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); - erc1155Contract = erc1155Wrapper.getContract(); - exchange = await ExchangeContract.deployFrom0xArtifactAsync( - artifacts.Exchange, - provider, - txDefaults, - {}, - new BigNumber(chainId), - ); - // Configure ERC20Proxy - await erc20Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner }); - await erc20Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure ERC721Proxy - await erc721Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner }); - await erc721Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure ERC1155Proxy - await erc1155Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner }); - await erc1155Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure MultiAssetProxy - await multiAssetProxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner }); - await multiAssetProxy.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - await multiAssetProxy.registerAssetProxy(erc721Proxy.address).awaitTransactionSuccessAsync({ from: owner }); - await multiAssetProxy.registerAssetProxy(staticCallProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - // Configure Exchange - for (const proxy of [erc20Proxy, erc721Proxy, erc1155Proxy, multiAssetProxy, staticCallProxy]) { - await exchange.registerAssetProxy(proxy.address).awaitTransactionSuccessAsync({ from: owner }); - } - - // Configure ERC20 tokens - await erc20Wrapper.setBalancesAndAllowancesAsync(); - - // Configure ERC721 tokens - await erc721Wrapper.setBalancesAndAllowancesAsync(); - const erc721Balances = await erc721Wrapper.getBalancesAsync(); - erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address]; - erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address]; - - // Configure ERC1155 tokens - await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); - erc1155FungibleTokens = erc1155ProxyWrapper.getFungibleTokenIds(); - const nonFungibleTokens = erc1155ProxyWrapper.getNonFungibleTokenIds(); - const tokenBalances = await erc1155ProxyWrapper.getBalancesAsync(); - erc1155NonFungibleTokensOwnedByMaker = []; - erc1155NonFungibleTokensOwnedByTaker = []; - _.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => { - const nonFungibleTokenAsString = nonFungibleToken.toString(); - const nonFungibleTokenHeldByMaker = - tokenBalances.nonFungible[makerAddress][erc1155Contract.address][nonFungibleTokenAsString][0]; - erc1155NonFungibleTokensOwnedByMaker.push(nonFungibleTokenHeldByMaker); - const nonFungibleTokenHeldByTaker = - tokenBalances.nonFungible[takerAddress][erc1155Contract.address][nonFungibleTokenAsString][0]; - erc1155NonFungibleTokensOwnedByTaker.push(nonFungibleTokenHeldByTaker); - }); - - // Configure order defaults - defaultMakerAssetAddress = erc20TokenA.address; - defaultTakerAssetAddress = erc20TokenB.address; - defaultFeeAssetAddress = feeToken.address; - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress, - feeRecipientAddress, - makerAssetData: encodeERC20AssetData(defaultMakerAssetAddress), - takerAssetData: encodeERC20AssetData(defaultTakerAssetAddress), - makerFeeAssetData: encodeERC20AssetData(defaultFeeAssetAddress), - takerFeeAssetData: encodeERC20AssetData(defaultFeeAssetAddress), - exchangeAddress: exchange.address, - chainId, - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - - const tokenContracts = { - erc20: { erc20TokenA, erc20TokenB, feeToken, noReturnErc20Token }, - erc721: { erc721Token }, - erc1155: { erc1155Contract }, - }; - const tokenIds = { - erc721: { [erc721Token.address]: [...erc721MakerAssetIds, ...erc721TakerAssetIds] }, - erc1155: { - [erc1155Contract.address]: { - fungible: erc1155FungibleTokens, - nonFungible: [...erc1155NonFungibleTokensOwnedByMaker, ...erc1155NonFungibleTokensOwnedByTaker], - }, - }, - }; - fillOrderWrapper = new FillOrderWrapper( - exchange, - { makerAddress, takerAddress, feeRecipientAddress }, - tokenContracts, - tokenIds, - ); - }); - describe('fillOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - signedOrder = await orderFactory.newSignedOrderAsync(); - }); - - it('should revert if fully filled', async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - await exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHex, OrderStatus.FullyFilled); - const tx = exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should noop transfer but return nonzero FillResults for fills where from == to', async () => { - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, makerAddress); - }); - - it('should revert if order is expired', async () => { - const currentTimestamp = await getLatestBlockTimestampAsync(); - signedOrder = await orderFactory.newSignedOrderAsync({ - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Expired); - const tx = exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - 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 exchange - .fillOrder(signedOrder, fillTakerAssetAmount1, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - - const fillTakerAssetAmount2 = new BigNumber(1); - const expectedError = new LibMathRevertErrors.RoundingError( - fillTakerAssetAmount2, - new BigNumber(3), - new BigNumber(1001), - ); - const tx = exchange - .fillOrder(signedOrder, fillTakerAssetAmount2, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('Fill transfer ordering', () => { - it('should allow the maker to exchange assets received by the taker', async () => { - // Set maker/taker assetData to the same asset - const takerAssetData = encodeERC20AssetData(erc20TokenA.address); - const takerAssetAmount = new BigNumber(1); - const makerAssetData = encodeMultiAssetData([takerAssetAmount], [takerAssetData]); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount: takerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - // Set maker balance to 0 so that the asset must be received by the taker in order for the fill to succeed - await erc20TokenA.setBalance(makerAddress, constants.ZERO_AMOUNT).awaitTransactionSuccessAsync({ - from: owner, - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should allow the taker to pay fees with an asset that received by the maker', async () => { - const makerAssetData = encodeERC20AssetData(erc20TokenA.address); - signedOrder = await orderFactory.newSignedOrderAsync({ - takerFeeAssetData: makerAssetData, - makerFee: constants.ZERO_AMOUNT, - takerFee: new BigNumber(1), - }); - // Set taker balance to 0 so that the asset must be received by the maker in order for the fill to succeed - await erc20TokenA.setBalance(takerAddress, constants.ZERO_AMOUNT).awaitTransactionSuccessAsync({ - from: owner, - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should allow the maker to pay fees with an asset that received by the taker', async () => { - const takerAssetData = encodeERC20AssetData(erc20TokenB.address); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerFeeAssetData: takerAssetData, - makerFee: new BigNumber(1), - takerFee: constants.ZERO_AMOUNT, - }); - // Set maker balance to 0 so that the asset must be received by the taker in order for the fill to succeed - await erc20TokenB.setBalance(makerAddress, constants.ZERO_AMOUNT).awaitTransactionSuccessAsync({ - from: owner, - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - }); - describe('Testing exchange of ERC20 tokens with no return values', () => { - before(async () => { - await noReturnErc20Token - .setBalance(makerAddress, constants.INITIAL_ERC20_BALANCE) - .awaitTransactionSuccessAsync(); - await noReturnErc20Token - .approve(erc20Proxy.address, constants.INITIAL_ERC20_ALLOWANCE) - .awaitTransactionSuccessAsync({ from: makerAddress }); - }); - it('should transfer the correct amounts when makerAssetAmount === takerAssetAmount', async () => { - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData: encodeERC20AssetData(noReturnErc20Token.address), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => { - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData: encodeERC20AssetData(noReturnErc20Token.address), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => { - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData: encodeERC20AssetData(noReturnErc20Token.address), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - }); - - describe('cancelOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - signedOrder = await orderFactory.newSignedOrderAsync(); - }); - - it('should revert if not sent by maker', async () => { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.ExchangeInvalidContextError( - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker, - orderHash, - takerAddress, - ); - const tx = exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should noop if makerAssetAmount is 0', async () => { - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: new BigNumber(0), - }); - const tx = await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - expect(tx.logs.length).to.equal(0); - }); - - it('should noop if takerAssetAmount is 0', async () => { - signedOrder = await orderFactory.newSignedOrderAsync({ - takerAssetAmount: new BigNumber(0), - }); - const tx = await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - expect(tx.logs.length).to.equal(0); - }); - - it('should be able to cancel an order', async () => { - await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Cancelled); - const tx = exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount.div(2), signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should log 1 event with correct arguments if cancelled successfully', async () => { - const res = await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - expect(res.logs).to.have.length(1); - - const log = res.logs[0] as LogWithDecodedArgs; - 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 noop if already cancelled', async () => { - await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - const tx = await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - expect(tx.logs.length).to.equal(0); - }); - - it('should noop if order is expired', async () => { - const currentTimestamp = await getLatestBlockTimestampAsync(); - signedOrder = await orderFactory.newSignedOrderAsync({ - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const tx = await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - expect(tx.logs.length).to.equal(0); - }); - }); - - describe('cancelOrdersUpTo', () => { - it('should fail to set orderEpoch less than current orderEpoch', async () => { - const orderEpoch = new BigNumber(1); - await exchange.cancelOrdersUpTo(orderEpoch).awaitTransactionSuccessAsync({ from: makerAddress }); - const lesserOrderEpoch = new BigNumber(0); - const expectedError = new ExchangeRevertErrors.OrderEpochError( - makerAddress, - constants.NULL_ADDRESS, - orderEpoch.plus(1), - ); - const tx = exchange.cancelOrdersUpTo(lesserOrderEpoch).awaitTransactionSuccessAsync({ from: makerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should fail to set orderEpoch equal to existing orderEpoch', async () => { - const orderEpoch = new BigNumber(1); - await exchange.cancelOrdersUpTo(orderEpoch).awaitTransactionSuccessAsync({ from: makerAddress }); - const expectedError = new ExchangeRevertErrors.OrderEpochError( - makerAddress, - constants.NULL_ADDRESS, - orderEpoch.plus(1), - ); - const tx = exchange.cancelOrdersUpTo(orderEpoch).awaitTransactionSuccessAsync({ from: makerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should cancel only orders with a orderEpoch less than existing orderEpoch', async () => { - // Cancel all transactions with a orderEpoch less than 2 - const orderEpoch = new BigNumber(1); - await exchange.cancelOrdersUpTo(orderEpoch).awaitTransactionSuccessAsync({ from: makerAddress }); - - // Create 4 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 exchange - .batchFillOrdersNoThrow( - signedOrders, - signedOrders.map(order => order.takerAssetAmount), - signedOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ from: takerAddress }); - const newBalances = await erc20Wrapper.getBalancesAsync(); - const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.plus(signedOrders[3].makerAssetAmount); - const fillTakerAssetAmount = signedOrders[2].takerAssetAmount.plus(signedOrders[3].takerAssetAmount); - const makerFee = signedOrders[2].makerFee.plus(signedOrders[3].makerFee); - const takerFee = signedOrders[2].takerFee.plus(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].plus(fillTakerAssetAmount), - ); - expect(newBalances[makerAddress][feeToken.address]).to.be.bignumber.equal( - erc20Balances[makerAddress][feeToken.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].plus(fillMakerAssetAmount), - ); - expect(newBalances[takerAddress][feeToken.address]).to.be.bignumber.equal( - erc20Balances[takerAddress][feeToken.address].minus(takerFee), - ); - expect(newBalances[feeRecipientAddress][feeToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][feeToken.address].plus(makerFee.plus(takerFee)), - ); - }); - }); - - describe('Testing Exchange of ERC721 Tokens', () => { - it('should revert 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: encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: encodeERC721AssetData(erc721Token.address, takerAssetId), - }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Verify pre-conditions - const initialOwnerMakerAsset = await erc721Token.ownerOf(makerAssetId).callAsync(); - expect(initialOwnerMakerAsset).to.be.bignumber.not.equal(makerAddress); - const initialOwnerTakerAsset = await erc721Token.ownerOf(takerAssetId).callAsync(); - expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); - // Call Exchange - const takerAssetFillAmount = signedOrder.takerAssetAmount; - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashHex, - signedOrder.makerAssetData, - new StringRevertError(RevertReason.TransferFailed).encode(), - ); - const tx = exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert 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: encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: encodeERC721AssetData(erc721Token.address, takerAssetId), - }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Verify pre-conditions - const initialOwnerMakerAsset = await erc721Token.ownerOf(makerAssetId).callAsync(); - expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress); - const initialOwnerTakerAsset = await erc721Token.ownerOf(takerAssetId).callAsync(); - expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress); - // Call Exchange - const takerAssetFillAmount = signedOrder.takerAssetAmount; - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashHex, - signedOrder.takerAssetData, - new StringRevertError(RevertReason.TransferFailed).encode(), - ); - const tx = exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert 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: encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: encodeERC721AssetData(erc721Token.address, takerAssetId), - }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Verify pre-conditions - const initialOwnerMakerAsset = await erc721Token.ownerOf(makerAssetId).callAsync(); - expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress); - const initialOwnerTakerAsset = await erc721Token.ownerOf(takerAssetId).callAsync(); - expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); - // Call Exchange - const takerAssetFillAmount = signedOrder.takerAssetAmount; - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashHex, - signedOrder.makerAssetData, - new StringRevertError(RevertReason.InvalidAmount).encode(), - ); - const tx = exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert 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: encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: encodeERC721AssetData(erc721Token.address, takerAssetId), - }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - // Verify pre-conditions - const initialOwnerMakerAsset = await erc721Token.ownerOf(makerAssetId).callAsync(); - expect(initialOwnerMakerAsset).to.be.bignumber.equal(makerAddress); - const initialOwnerTakerAsset = await erc721Token.ownerOf(takerAssetId).callAsync(); - expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress); - // Call Exchange - const takerAssetFillAmount = signedOrder.takerAssetAmount; - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashHex, - signedOrder.takerAssetData, - new StringRevertError(RevertReason.InvalidAmount).encode(), - ); - const tx = exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert 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: encodeERC721AssetData(erc721Token.address, makerAssetId), - takerAssetData: encodeERC20AssetData(defaultTakerAssetAddress), - }); - // Call Exchange - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - const expectedError = new LibMathRevertErrors.RoundingError( - takerAssetFillAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - const tx = exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('Testing exchange of multiple assets', () => { - it('should allow multiple assets to be exchanged for a single asset', async () => { - const makerAmounts = [new BigNumber(10), new BigNumber(20)]; - const makerNestedAssetData = [ - encodeERC20AssetData(erc20TokenA.address), - encodeERC20AssetData(erc20TokenB.address), - ]; - const makerAssetData = encodeMultiAssetData(makerAmounts, makerNestedAssetData); - const makerAssetAmount = new BigNumber(1); - const takerAssetData = encodeERC20AssetData(feeToken.address); - const takerAssetAmount = new BigNumber(10); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should allow multiple assets to be exchanged for multiple assets', async () => { - const makerAmounts = [new BigNumber(10), new BigNumber(20)]; - const makerNestedAssetData = [ - encodeERC20AssetData(erc20TokenA.address), - encodeERC20AssetData(erc20TokenB.address), - ]; - const makerAssetData = encodeMultiAssetData(makerAmounts, makerNestedAssetData); - const makerAssetAmount = new BigNumber(1); - const takerAmounts = [new BigNumber(10), new BigNumber(1)]; - const takerAssetId = erc721TakerAssetIds[0]; - const takerNestedAssetData = [ - encodeERC20AssetData(feeToken.address), - encodeERC721AssetData(erc721Token.address, takerAssetId), - ]; - const takerAssetData = encodeMultiAssetData(takerAmounts, takerNestedAssetData); - const takerAssetAmount = new BigNumber(1); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should allow an order selling multiple assets to be partially filled', async () => { - const makerAmounts = [new BigNumber(10), new BigNumber(20)]; - const makerNestedAssetData = [ - encodeERC20AssetData(erc20TokenA.address), - encodeERC20AssetData(erc20TokenB.address), - ]; - const makerAssetData = encodeMultiAssetData(makerAmounts, makerNestedAssetData); - const makerAssetAmount = new BigNumber(30); - const takerAssetData = encodeERC20AssetData(feeToken.address); - const takerAssetAmount = new BigNumber(10); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - - const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - }); - it('should allow an order buying multiple assets to be partially filled', async () => { - const takerAmounts = [new BigNumber(10), new BigNumber(20)]; - const takerNestedAssetData = [ - encodeERC20AssetData(erc20TokenA.address), - encodeERC20AssetData(erc20TokenB.address), - ]; - const takerAssetData = encodeMultiAssetData(takerAmounts, takerNestedAssetData); - const takerAssetAmount = new BigNumber(30); - const makerAssetData = encodeERC20AssetData(feeToken.address); - const makerAssetAmount = new BigNumber(10); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const takerAssetFillAmount = takerAssetAmount.dividedToIntegerBy(2); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { - takerAssetFillAmount, - }); - }); - }); - describe('Testing exchange of erc1155 assets', () => { - it('should allow a single fungible erc1155 asset to be exchanged for another', async () => { - // setup test parameters - const makerAssetsToTransfer = erc1155FungibleTokens.slice(0, 1); - const takerAssetsToTransfer = erc1155FungibleTokens.slice(1, 2); - const makerValuesToTransfer = [new BigNumber(500)]; - const takerValuesToTransfer = [new BigNumber(200)]; - const makerAssetAmount = new BigNumber(1); - const takerAssetAmount = new BigNumber(1); - const receiverCallbackData = '0x'; - const makerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - makerAssetsToTransfer, - makerValuesToTransfer, - receiverCallbackData, - ); - const takerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - takerAssetsToTransfer, - takerValuesToTransfer, - receiverCallbackData, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const takerAssetFillAmount = new BigNumber(1); - // execute transfer - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { - takerAssetFillAmount, - }); - }); - it('should allow a single non-fungible erc1155 asset to be exchanged for another', async () => { - // setup test parameters - const makerAssetsToTransfer = erc1155NonFungibleTokensOwnedByMaker.slice(0, 1); - const takerAssetsToTransfer = erc1155NonFungibleTokensOwnedByTaker.slice(0, 1); - const makerValuesToTransfer = [new BigNumber(1)]; - const takerValuesToTransfer = [new BigNumber(1)]; - const makerAssetAmount = new BigNumber(1); - const takerAssetAmount = new BigNumber(1); - const receiverCallbackData = '0x'; - const makerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - makerAssetsToTransfer, - makerValuesToTransfer, - receiverCallbackData, - ); - const takerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - takerAssetsToTransfer, - takerValuesToTransfer, - receiverCallbackData, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const takerAssetFillAmount = new BigNumber(1); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { - takerAssetFillAmount, - }); - }); - it('should allow multiple erc1155 assets to be exchanged for a single asset', async () => { - // setup test parameters - const makerAssetsToTransfer = erc1155FungibleTokens.slice(0, 3); - const takerAssetsToTransfer = erc1155NonFungibleTokensOwnedByTaker.slice(0, 1); - const makerValuesToTransfer = [new BigNumber(500), new BigNumber(700), new BigNumber(900)]; - const takerValuesToTransfer = [new BigNumber(1)]; - const makerAssetAmount = new BigNumber(1); - const takerAssetAmount = new BigNumber(1); - const receiverCallbackData = '0x'; - const makerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - makerAssetsToTransfer, - makerValuesToTransfer, - receiverCallbackData, - ); - const takerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - takerAssetsToTransfer, - takerValuesToTransfer, - receiverCallbackData, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const takerAssetFillAmount = new BigNumber(1); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { - takerAssetFillAmount, - }); - }); - it('should allow multiple erc1155 assets to be exchanged for multiple erc1155 assets, mixed fungible/non-fungible', async () => { - // setup test parameters - // the maker is trading two fungibles & one non-fungible - // the taker is trading one fungible & two non-fungibles - const makerFungibleAssetsToTransfer = erc1155FungibleTokens.slice(0, 2); - const makerNonFungibleAssetsToTransfer = erc1155NonFungibleTokensOwnedByMaker.slice(0, 1); - const makerAssetsToTransfer = makerFungibleAssetsToTransfer.concat(makerNonFungibleAssetsToTransfer); - const takerFungibleAssetsToTransfer = erc1155FungibleTokens.slice(2, 3); - const takerNonFungibleAssetsToTransfer = erc1155NonFungibleTokensOwnedByTaker.slice(0, 2); - const takerAssetsToTransfer = takerFungibleAssetsToTransfer.concat(takerNonFungibleAssetsToTransfer); - const makerValuesToTransfer = [new BigNumber(500), new BigNumber(700), new BigNumber(1)]; - const takerValuesToTransfer = [new BigNumber(900), new BigNumber(1), new BigNumber(1)]; - const makerAssetAmount = new BigNumber(1); - const takerAssetAmount = new BigNumber(1); - const receiverCallbackData = '0x'; - const makerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - makerAssetsToTransfer, - makerValuesToTransfer, - receiverCallbackData, - ); - const takerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - takerAssetsToTransfer, - takerValuesToTransfer, - receiverCallbackData, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - const takerAssetFillAmount = new BigNumber(1); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { - takerAssetFillAmount, - }); - }); - it('should allow an order exchanging erc1155 assets to be partially filled', async () => { - // NOTICE: - // As-per the eip1155 standard, there is no way to distinguish between a fungible or non-fungible erc1155 assets. - // Hence we cannot force partial fills to fail if there is a non-fungible asset (which should be fill or kill). - // We considered encoding whether an asset is fungible/non-fungible in erc1155 assetData, but - // this is no more robust than a simple check by the client. Enforcing this at the smart contract level - // is something that could be done with the upcoming static call proxy. - // - // setup test parameters - // the maker is trading two fungibles and the taker is trading one fungible - // note that this will result in a partial fill because the `takerAssetAmount` - // less than the `takerAssetAmount` of the order. - const takerAssetFillAmount = new BigNumber(6); - const makerAssetsToTransfer = erc1155FungibleTokens.slice(0, 2); - const takerAssetsToTransfer = erc1155FungibleTokens.slice(2, 3); - const makerValuesToTransfer = [new BigNumber(500), new BigNumber(700)]; - const takerValuesToTransfer = [new BigNumber(900)]; - const makerAssetAmount = new BigNumber(10); - const takerAssetAmount = new BigNumber(20); - const receiverCallbackData = '0x'; - const makerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - makerAssetsToTransfer, - makerValuesToTransfer, - receiverCallbackData, - ); - const takerAssetData = encodeERC1155AssetData( - erc1155Contract.address, - takerAssetsToTransfer, - takerValuesToTransfer, - receiverCallbackData, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAssetData, - takerAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { - takerAssetFillAmount, - }); - }); - }); - - describe('Testing orders that utilize StaticCallProxy', () => { - before(async () => { - staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( - proxyArtifacts.TestStaticCallTarget, - provider, - txDefaults, - {}, - ); - }); - it('should revert if the staticcall is unsuccessful', async () => { - const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); - const assetData = encodeStaticCallAssetData( - staticCallTarget.address, - staticCallData, - constants.KECCAK256_NULL, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: assetData }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashHex, - assetData, - new StringRevertError(RevertReason.TargetNotEven).encode(), - ); - const tx = exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - it('should fill the order if the staticcall is successful', async () => { - const staticCallData = staticCallTarget - .assertEvenNumber(constants.ZERO_AMOUNT) - .getABIEncodedTransactionData(); - const assetData = encodeStaticCallAssetData( - staticCallTarget.address, - staticCallData, - constants.KECCAK256_NULL, - ); - signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: assetData }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should revert if the staticcall is unsuccessful using the MultiAssetProxy', async () => { - const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(); - const staticCallAssetData = encodeStaticCallAssetData( - staticCallTarget.address, - staticCallData, - constants.KECCAK256_NULL, - ); - const assetData = encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [encodeERC20AssetData(defaultMakerAssetAddress), staticCallAssetData], - ); - signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: assetData }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashHex, - assetData, - new StringRevertError(RevertReason.TargetNotEven).encode(), - ); - const tx = exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - return expect(tx).to.revertWith(expectedError); - }); - it('should fill the order is the staticcall is successful using the MultiAssetProxy', async () => { - const staticCallData = staticCallTarget - .assertEvenNumber(constants.ZERO_AMOUNT) - .getABIEncodedTransactionData(); - const staticCallAssetData = encodeStaticCallAssetData( - staticCallTarget.address, - staticCallData, - constants.KECCAK256_NULL, - ); - const assetData = encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [encodeERC20AssetData(defaultMakerAssetAddress), staticCallAssetData], - ); - signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetData: assetData }); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - }); - - describe('getOrderInfo', () => { - beforeEach(async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should return the correct orderInfo for an unfilled valid order', async () => { - const orderInfo = await exchange.getOrderInfo(signedOrder).callAsync(); - 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 fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress); - }); - it('should return the correct orderInfo for a partially filled order', async () => { - const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); - await fillOrderWrapper.fillOrderAndAssertEffectsAsync(signedOrder, takerAddress, { takerAssetFillAmount }); - }); - it('should return the correct orderInfo for a cancelled and unfilled order', async () => { - await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - const orderInfo = await exchange.getOrderInfo(signedOrder).callAsync(); - 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 exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - await exchange.cancelOrder(signedOrder).awaitTransactionSuccessAsync({ from: makerAddress }); - const orderInfo = await exchange.getOrderInfo(signedOrder).callAsync(); - 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 exchange.getOrderInfo(signedOrder).callAsync(); - 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 exchange - .fillOrder(signedOrder, takerAssetFillAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - const currentTimestamp = await getLatestBlockTimestampAsync(); - const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber(); - await increaseTimeAndMineBlockAsync(timeUntilExpiration); - const orderInfo = await exchange.getOrderInfo(signedOrder).callAsync(); - 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 exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ from: takerAddress }); - const currentTimestamp = await getLatestBlockTimestampAsync(); - const timeUntilExpiration = signedOrder.expirationTimeSeconds.minus(currentTimestamp).toNumber(); - await increaseTimeAndMineBlockAsync(timeUntilExpiration); - const orderInfo = await exchange.getOrderInfo(signedOrder).callAsync(); - const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder); - const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount; - // FULLY_FILLED takes precedence over EXPIRED - const expectedOrderStatus = OrderStatus.FullyFilled; - 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 exchange.getOrderInfo(signedOrder).callAsync(); - const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder); - const expectedTakerAssetFilledAmount = new BigNumber(0); - const expectedOrderStatus = OrderStatus.InvalidMakerAssetAmount; - 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 exchange.getOrderInfo(signedOrder).callAsync(); - const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder); - const expectedTakerAssetFilledAmount = new BigNumber(0); - const expectedOrderStatus = OrderStatus.InvalidTakerAssetAmount; - 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/contracts/integrations/test/exchange/exchange_wrapper_test.ts b/contracts/integrations/test/exchange/exchange_wrapper_test.ts deleted file mode 100644 index 80dd612ce9..0000000000 --- a/contracts/integrations/test/exchange/exchange_wrapper_test.ts +++ /dev/null @@ -1,1090 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract, ERC20TokenEvents, ERC20TokenTransferEventArgs } from '@0x/contracts-erc20'; -import { ExchangeRevertErrors, IExchangeEvents, IExchangeFillEventArgs } from '@0x/contracts-exchange'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - blockchainTests, - constants, - describe, - expect, - getLatestBlockTimestampAsync, - Numberish, - orderHashUtils, - toBaseUnitAmount, - verifyEvents, -} from '@0x/contracts-test-utils'; -import { FillResults, OrderStatus, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -const { addFillResults, safeGetPartialAmountFloor } = ReferenceFunctions; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Exchange wrappers', env => { - let maker: Maker; - let taker: Actor; - let feeRecipient: string; - - let makerToken: DummyERC20TokenContract; - let takerToken: DummyERC20TokenContract; - let feeToken: DummyERC20TokenContract; - - const nullFillResults: FillResults = { - makerAssetFilledAmount: constants.ZERO_AMOUNT, - takerAssetFilledAmount: constants.ZERO_AMOUNT, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: constants.ZERO_AMOUNT, - }; - - let deployment: DeploymentManager; - let blockchainBalances: BlockchainBalanceStore; - let initialLocalBalances: LocalBalanceStore; - let localBalances: LocalBalanceStore; - - let wethAssetData: string; - - before(async () => { - [feeRecipient] = await env.getAccountAddressesAsync(); - - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 3, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - - [makerToken, takerToken, feeToken] = deployment.tokens.erc20; - - maker = new Maker({ - name: 'market maker', - deployment, - orderConfig: { - makerAssetData: encodeERC20AssetData(makerToken.address), - takerAssetData: encodeERC20AssetData(takerToken.address), - makerFeeAssetData: encodeERC20AssetData(feeToken.address), - takerFeeAssetData: encodeERC20AssetData(feeToken.address), - feeRecipientAddress: feeRecipient, - }, - }); - - taker = new Actor({ - name: 'taker', - deployment, - }); - - await Promise.all([ - ...deployment.tokens.erc20.map(async token => maker.configureERC20TokenAsync(token)), - taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - ...deployment.tokens.erc20.map(async token => taker.configureERC20TokenAsync(token)), - ]); - - blockchainBalances = new BlockchainBalanceStore( - { - makerAddress: maker.address, - takerAddress: taker.address, - feeRecipientAddress: feeRecipient, - stakingProxy: deployment.staking.stakingProxy.address, - }, - { - erc20: { - makerToken, - takerToken, - feeToken, - weth: deployment.tokens.weth, - }, - }, - {}, - ); - - await blockchainBalances.updateBalancesAsync(); - - initialLocalBalances = LocalBalanceStore.create(blockchainBalances); - - wethAssetData = encodeERC20AssetData(deployment.tokens.weth.address); - }); - - beforeEach(async () => { - localBalances = LocalBalanceStore.create(initialLocalBalances); - }); - - after(async () => { - Actor.reset(); - }); - - interface SignedOrderWithValidity { - signedOrder: SignedOrder; - isValid: boolean; - } - - function simulateFill(signedOrder: SignedOrder, expectedFillResults: FillResults, shouldUseWeth: boolean): void { - // taker -> maker - localBalances.transferAsset( - taker.address, - maker.address, - expectedFillResults.takerAssetFilledAmount, - signedOrder.takerAssetData, - ); - - // maker -> taker - localBalances.transferAsset( - maker.address, - taker.address, - expectedFillResults.makerAssetFilledAmount, - signedOrder.makerAssetData, - ); - - // maker -> feeRecipient - localBalances.transferAsset( - maker.address, - feeRecipient, - expectedFillResults.makerFeePaid, - signedOrder.makerFeeAssetData, - ); - - // taker -> feeRecipient - localBalances.transferAsset( - taker.address, - feeRecipient, - expectedFillResults.takerFeePaid, - signedOrder.takerFeeAssetData, - ); - - // taker -> protocol fees - if (shouldUseWeth) { - localBalances.transferAsset( - taker.address, - deployment.staking.stakingProxy.address, - expectedFillResults.protocolFeePaid, - wethAssetData, - ); - } else { - localBalances.sendEth( - taker.address, - deployment.staking.stakingProxy.address, - expectedFillResults.protocolFeePaid, - ); - } - } - - interface FillTestInfo { - signedOrder: SignedOrder; - expectedFillResults: FillResults; - shouldPayWethFees: boolean; - } - - function verifyFillEvents(receipt: TransactionReceiptWithDecodedLogs, fillTestInfos: FillTestInfo[]): void { - const expectedFillEvents: IExchangeFillEventArgs[] = []; - - let expectedTransferEvents: ERC20TokenTransferEventArgs[] = []; - - for (const { signedOrder, expectedFillResults, shouldPayWethFees } of fillTestInfos) { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - - expectedFillEvents.push({ - makerAddress: maker.address, - feeRecipientAddress: feeRecipient, - makerAssetData: signedOrder.makerAssetData, - takerAssetData: signedOrder.takerAssetData, - makerFeeAssetData: signedOrder.makerFeeAssetData, - takerFeeAssetData: signedOrder.takerFeeAssetData, - orderHash, - takerAddress: taker.address, - senderAddress: taker.address, - makerAssetFilledAmount: expectedFillResults.makerAssetFilledAmount, - takerAssetFilledAmount: expectedFillResults.takerAssetFilledAmount, - makerFeePaid: expectedFillResults.makerFeePaid, - takerFeePaid: expectedFillResults.takerFeePaid, - protocolFeePaid: expectedFillResults.protocolFeePaid, - }); - - const transferEvents = [ - { - _from: taker.address, - _to: maker.address, - _value: expectedFillResults.takerAssetFilledAmount, - }, - { - _from: maker.address, - _to: taker.address, - _value: expectedFillResults.makerAssetFilledAmount, - }, - { - _from: taker.address, - _to: feeRecipient, - _value: expectedFillResults.takerFeePaid, - }, - { - _from: maker.address, - _to: feeRecipient, - _value: expectedFillResults.makerFeePaid, - }, - ]; - - if (shouldPayWethFees) { - transferEvents.push({ - _from: taker.address, - _to: deployment.staking.stakingProxy.address, - _value: expectedFillResults.protocolFeePaid, - }); - } - - expectedTransferEvents = expectedTransferEvents.concat(transferEvents); - } - verifyEvents(receipt, expectedFillEvents, IExchangeEvents.Fill); - verifyEvents(receipt, expectedTransferEvents, ERC20TokenEvents.Transfer); - } - - function calculateScaledFillResultsWithMaker(signedOrder: SignedOrder, fillAmount: BigNumber): FillResults { - if (fillAmount === signedOrder.makerAssetAmount) { - return { - makerAssetFilledAmount: signedOrder.makerAssetAmount, - takerAssetFilledAmount: signedOrder.takerAssetAmount, - makerFeePaid: signedOrder.makerFee, - takerFeePaid: signedOrder.takerFee, - protocolFeePaid: DeploymentManager.protocolFee, - }; - } else { - return { - makerAssetFilledAmount: fillAmount, - takerAssetFilledAmount: safeGetPartialAmountFloor( - fillAmount, - signedOrder.makerAssetAmount, - signedOrder.takerAssetAmount, - ), - makerFeePaid: safeGetPartialAmountFloor(fillAmount, signedOrder.makerAssetAmount, signedOrder.makerFee), - takerFeePaid: safeGetPartialAmountFloor(fillAmount, signedOrder.makerAssetAmount, signedOrder.takerFee), - protocolFeePaid: DeploymentManager.protocolFee, - }; - } - } - - function calculateScaledFillResultsWithTaker(signedOrder: SignedOrder, fillAmount: BigNumber): FillResults { - if (fillAmount === signedOrder.takerAssetAmount) { - return { - makerAssetFilledAmount: signedOrder.makerAssetAmount, - takerAssetFilledAmount: signedOrder.takerAssetAmount, - makerFeePaid: signedOrder.makerFee, - takerFeePaid: signedOrder.takerFee, - protocolFeePaid: DeploymentManager.protocolFee, - }; - } else { - return { - makerAssetFilledAmount: safeGetPartialAmountFloor( - fillAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ), - takerAssetFilledAmount: fillAmount, - makerFeePaid: safeGetPartialAmountFloor(fillAmount, signedOrder.takerAssetAmount, signedOrder.makerFee), - takerFeePaid: safeGetPartialAmountFloor(fillAmount, signedOrder.takerAssetAmount, signedOrder.takerFee), - protocolFeePaid: DeploymentManager.protocolFee, - }; - } - } - - async function assertResultsAsync( - receipt: TransactionReceiptWithDecodedLogs, - fillTestInfo: FillTestInfo[], - ): Promise { - // Burn the gas used by the taker to ensure that the expected results are accurate. - localBalances.burnGas(taker.address, DeploymentManager.gasPrice.times(receipt.gasUsed)); - - // Update the blockchain balances balance store. - await blockchainBalances.updateBalancesAsync(); - - // Ensure that the blockchain and the local balance stores are equal. - blockchainBalances.assertEquals(localBalances); - - // Verify that the correct fill and transfer events were emitted. - verifyFillEvents(receipt, fillTestInfo); - } - - describe('fillOrKillOrder', () => { - async function testFillOrKillOrderAsync(value: Numberish): Promise { - const signedOrder = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(new BigNumber(100)), - takerAssetAmount: toBaseUnitAmount(new BigNumber(200)), - }); - const takerAssetFilledAmount = signedOrder.takerAssetAmount.div(5); - - const contractFn = deployment.exchange.fillOrKillOrder( - signedOrder, - takerAssetFilledAmount, - signedOrder.signature, - ); - const callData = { from: taker.address, gasPrice: DeploymentManager.gasPrice, value }; - const fillResults = await contractFn.callAsync(callData); - const receipt = await contractFn.awaitTransactionSuccessAsync(callData); - - const expectedFillResults = calculateScaledFillResultsWithTaker(signedOrder, takerAssetFilledAmount); - - expect(fillResults).to.be.deep.eq(expectedFillResults); - - const shouldPayWethFees = DeploymentManager.protocolFee.gt(value); - - // Simulate filling the order - simulateFill(signedOrder, expectedFillResults, shouldPayWethFees); - - // Ensure that the correct logs were emitted and that the balances are accurate. - await assertResultsAsync(receipt, [{ signedOrder, expectedFillResults, shouldPayWethFees }]); - } - - it('should transfer the correct amounts and pay the protocol fee in eth', async () => { - await testFillOrKillOrderAsync(DeploymentManager.protocolFee); - }); - - it('should transfer the correct amounts, pay the protocol fee in eth, and refund for excess eth sent', async () => { - await testFillOrKillOrderAsync(DeploymentManager.protocolFee.times(2)); - }); - - it('should transfer the correct amounts and pay the protocol fee in weth', async () => { - await testFillOrKillOrderAsync(0); - }); - - it('should transfer the correct amounts, pay the protocol fee in weth, and refund for excess eth sent', async () => { - await testFillOrKillOrderAsync(DeploymentManager.protocolFee.div(2)); - }); - - it('should revert if a signedOrder is expired', async () => { - const currentTimestamp = await getLatestBlockTimestampAsync(); - const signedOrder = await maker.signOrderAsync({ - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHex, OrderStatus.Expired); - const tx = deployment.exchange - .fillOrKillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value: DeploymentManager.protocolFee, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if entire takerAssetFillAmount not filled', async () => { - const signedOrder = await maker.signOrderAsync(); - const takerAssetFillAmount = signedOrder.takerAssetAmount; - - await deployment.exchange - .fillOrder(signedOrder, signedOrder.takerAssetAmount.dividedToIntegerBy(2), signedOrder.signature) - .awaitTransactionSuccessAsync({ - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value: DeploymentManager.protocolFee, - }); - const expectedError = new ExchangeRevertErrors.IncompleteFillError( - ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteFillOrder, - takerAssetFillAmount, - takerAssetFillAmount.dividedToIntegerBy(2), - ); - const tx = deployment.exchange - .fillOrKillOrder(signedOrder, signedOrder.takerAssetAmount, signedOrder.signature) - .awaitTransactionSuccessAsync({ - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value: DeploymentManager.protocolFee, - }); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('batch functions', () => { - let signedOrders: SignedOrder[]; - - before(async () => { - signedOrders = [await maker.signOrderAsync(), await maker.signOrderAsync(), await maker.signOrderAsync()]; - }); - - describe('batchFillOrders', () => { - async function testBatchFillOrdersAsync(value: BigNumber): Promise { - const takerAssetFillAmounts: BigNumber[] = []; - const fillTestInfo: FillTestInfo[] = []; - const totalFillResults: FillResults[] = []; - - let valueLeft = value; - - for (const signedOrder of signedOrders) { - const takerAssetFilledAmount = signedOrder.takerAssetAmount.div(2); - - takerAssetFillAmounts.push(takerAssetFilledAmount); - - const expectedFillResults = calculateScaledFillResultsWithTaker( - signedOrder, - takerAssetFilledAmount, - ); - totalFillResults.push(expectedFillResults); - - let shouldPayWethFees; - if (DeploymentManager.protocolFee.lte(valueLeft)) { - shouldPayWethFees = false; - valueLeft = valueLeft.minus(DeploymentManager.protocolFee); - } else { - shouldPayWethFees = true; - } - - fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees }); - simulateFill(signedOrder, expectedFillResults, shouldPayWethFees); - } - - const contractFn = deployment.exchange.batchFillOrders( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(signedOrder => signedOrder.signature), - ); - const callData = { - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value, - }; - const fillResults = await contractFn.callAsync(callData); - const receipt = await contractFn.awaitTransactionSuccessAsync(callData); - - expect(totalFillResults).to.be.deep.eq(fillResults); - await assertResultsAsync(receipt, fillTestInfo); - } - - it('should transfer the correct amounts if all fees are paid in eth', async () => { - await testBatchFillOrdersAsync(DeploymentManager.protocolFee.times(signedOrders.length)); - }); - - it('should transfer the correct amounts if some fees are paid in eth and some in weth', async () => { - await testBatchFillOrdersAsync(DeploymentManager.protocolFee.times(signedOrders.length - 1)); - }); - - it('should transfer the correct amounts if all fees are paid in weth', async () => { - await testBatchFillOrdersAsync(constants.ZERO_AMOUNT); - }); - }); - - describe('batchFillOrKillOrders', () => { - async function testBatchFillOrKillOrdersAsync(value: BigNumber): Promise { - const takerAssetFillAmounts: BigNumber[] = []; - const fillTestInfo: FillTestInfo[] = []; - const totalFillResults: FillResults[] = []; - - let valueLeft = value; - - for (const signedOrder of signedOrders) { - const takerAssetFilledAmount = signedOrder.takerAssetAmount.div(2); - - takerAssetFillAmounts.push(takerAssetFilledAmount); - - const expectedFillResults = calculateScaledFillResultsWithTaker( - signedOrder, - takerAssetFilledAmount, - ); - totalFillResults.push(expectedFillResults); - - let shouldPayWethFees; - - if (valueLeft.gte(DeploymentManager.protocolFee)) { - shouldPayWethFees = false; - valueLeft = valueLeft.minus(DeploymentManager.protocolFee); - } else { - shouldPayWethFees = true; - } - - fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees }); - simulateFill(signedOrder, expectedFillResults, shouldPayWethFees); - } - - const contractFn = deployment.exchange.batchFillOrKillOrders( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(order => order.signature), - ); - const callData = { - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value, - }; - const fillResults = await contractFn.callAsync(callData); - const receipt = await contractFn.awaitTransactionSuccessAsync(callData); - - expect(totalFillResults).to.be.deep.eq(fillResults); - - await assertResultsAsync(receipt, fillTestInfo); - } - - it('should transfer the correct amounts if all fees are paid in eth', async () => { - await testBatchFillOrKillOrdersAsync(DeploymentManager.protocolFee.times(signedOrders.length)); - }); - - it('should transfer the correct amounts if some fees are paid in eth and some in weth', async () => { - await testBatchFillOrKillOrdersAsync(DeploymentManager.protocolFee.times(signedOrders.length - 1)); - }); - - it('should transfer the correct amounts if all fees are paid in weth', async () => { - await testBatchFillOrKillOrdersAsync(constants.ZERO_AMOUNT); - }); - - it('should revert if a single signedOrder does not fill the expected amount', async () => { - const takerAssetFillAmounts = signedOrders.map(signedOrder => signedOrder.takerAssetAmount.div(2)); - - await deployment.exchange - .fillOrKillOrder(signedOrders[0], signedOrders[0].takerAssetAmount, signedOrders[0].signature) - .awaitTransactionSuccessAsync({ - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value: DeploymentManager.protocolFee, - }); - - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrders[0]); - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHex, OrderStatus.FullyFilled); - const tx = deployment.exchange - .batchFillOrKillOrders( - signedOrders, - takerAssetFillAmounts, - signedOrders.map(order => order.signature), - ) - .awaitTransactionSuccessAsync({ - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value: DeploymentManager.protocolFee.times(signedOrders.length), - }); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('batchFillOrdersNoThrow', async () => { - async function testBatchFillOrdersNoThrowAsync( - signedOrdersWithValidity: SignedOrderWithValidity[], - value: BigNumber, - defaultTakerAssetFillAmounts?: BigNumber[], - ): Promise { - const takerAssetFillAmounts: BigNumber[] = defaultTakerAssetFillAmounts || []; - const fillTestInfo: FillTestInfo[] = []; - const totalFillResults: FillResults[] = []; - - let valueLeft = value; - - for (const { signedOrder, isValid } of signedOrdersWithValidity) { - if (isValid) { - const takerAssetFilledAmount = signedOrder.takerAssetAmount.div(2); - takerAssetFillAmounts.push(takerAssetFilledAmount); - const expectedFillResults = calculateScaledFillResultsWithTaker( - signedOrder, - takerAssetFilledAmount, - ); - - totalFillResults.push(expectedFillResults); - - let shouldPayWethFees; - - if (valueLeft.gte(DeploymentManager.protocolFee)) { - shouldPayWethFees = false; - valueLeft = valueLeft.minus(DeploymentManager.protocolFee); - } else { - shouldPayWethFees = true; - } - - fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees }); - simulateFill(signedOrder, expectedFillResults, shouldPayWethFees); - } else { - totalFillResults.push(nullFillResults); - } - } - - const contractFn = deployment.exchange.batchFillOrdersNoThrow( - signedOrdersWithValidity.map(signedOrderWithValidity => signedOrderWithValidity.signedOrder), - takerAssetFillAmounts, - signedOrdersWithValidity.map( - signedOrderWithValidity => signedOrderWithValidity.signedOrder.signature, - ), - ); - const callData = { - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value, - }; - const fillResults = await contractFn.callAsync(callData); - const receipt = await contractFn.awaitTransactionSuccessAsync(callData); - - expect(totalFillResults).to.be.deep.eq(fillResults); - - await assertResultsAsync(receipt, fillTestInfo); - } - - it('should transfer the correct amounts if all fees are paid in eth', async () => { - await testBatchFillOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - DeploymentManager.protocolFee.times(signedOrders.length), - ); - }); - - it('should transfer the correct amounts if some fees are paid in eth and some in weth', async () => { - await testBatchFillOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - DeploymentManager.protocolFee.times(signedOrders.length - 1), - ); - }); - - it('should transfer the correct amounts if all fees are paid in weth', async () => { - await testBatchFillOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - constants.ZERO_AMOUNT, - ); - }); - - it('should not revert if an order is invalid and fill the remaining orders', async () => { - const invalidOrder: SignedOrder = { - ...signedOrders[0], - signature: '0x00', - }; - - const validOrders = signedOrders.slice(1); - - const newOrders = [ - { signedOrder: invalidOrder, isValid: false }, - ...validOrders.map(validOrder => { - return { signedOrder: validOrder, isValid: true }; - }), - ]; - - const takerAssetFillAmounts: BigNumber[] = [invalidOrder.takerAssetAmount.div(2)]; - - await testBatchFillOrdersNoThrowAsync( - newOrders, - DeploymentManager.protocolFee.times(newOrders.length), - takerAssetFillAmounts, - ); - }); - }); - - describe('marketSellOrdersNoThrow', () => { - async function testMarketSellOrdersNoThrowAsync( - signedOrdersWithValidity: SignedOrderWithValidity[], - takerAssetFillAmount: BigNumber, - value: BigNumber, - ): Promise { - const fillTestInfo: FillTestInfo[] = []; - - let valueLeft = value; - let takerAssetFillAmountLeft = takerAssetFillAmount; - - let totalFillResults = { ...nullFillResults }; - - for (const { signedOrder, isValid } of signedOrdersWithValidity) { - if (isValid) { - let shouldPayWethFees; - - if (valueLeft.gte(DeploymentManager.protocolFee)) { - shouldPayWethFees = false; - valueLeft = valueLeft.minus(DeploymentManager.protocolFee); - } else { - shouldPayWethFees = true; - } - - if (!takerAssetFillAmountLeft.eq(0)) { - const takerFillAmount = takerAssetFillAmountLeft.gte(signedOrder.takerAssetAmount) - ? signedOrder.takerAssetAmount - : takerAssetFillAmountLeft; - - takerAssetFillAmountLeft = takerAssetFillAmountLeft.minus(takerFillAmount); - - const expectedFillResults = calculateScaledFillResultsWithTaker( - signedOrder, - takerFillAmount, - ); - - simulateFill(signedOrder, expectedFillResults, shouldPayWethFees); - fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees }); - - totalFillResults = addFillResults(totalFillResults, expectedFillResults); - } - } - } - - const contractFn = deployment.exchange.marketSellOrdersNoThrow( - signedOrdersWithValidity.map(orderWithValidity => orderWithValidity.signedOrder), - takerAssetFillAmount, - signedOrdersWithValidity.map(orderWithValidity => orderWithValidity.signedOrder.signature), - ); - const callData = { - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value, - }; - const fillResults = await contractFn.callAsync(callData); - const receipt = await contractFn.awaitTransactionSuccessAsync(callData); - expect(fillResults).to.deep.equal(totalFillResults); - - await assertResultsAsync(receipt, fillTestInfo); - } - - it('should stop when the entire takerAssetFillAmount is filled (eth protocol fee)', async () => { - const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus( - signedOrders[1].takerAssetAmount.div(2), - ); - - await testMarketSellOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - takerAssetFillAmount, - DeploymentManager.protocolFee.times(2), - ); - }); - - it('should stop when the entire takerAssetFillAmount is filled (weth protocol fee)', async () => { - const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus( - signedOrders[1].takerAssetAmount.div(2), - ); - - await testMarketSellOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - takerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - - it('should fill all signedOrders if cannot fill entire takerAssetFillAmount (eth protocol fee)', async () => { - const takerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketSellOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - takerAssetFillAmount, - DeploymentManager.protocolFee.times(signedOrders.length), - ); - }); - - it('should fill all signedOrders if cannot fill entire takerAssetFillAmount (weth protocol fee)', async () => { - const takerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketSellOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - takerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - - it('should fill a signedOrder that does not use the same takerAssetAddress (eth protocol fee)', async () => { - const differentTakerAssetData = encodeERC20AssetData(feeToken.address); - - signedOrders = [ - await maker.signOrderAsync(), - await maker.signOrderAsync(), - await maker.signOrderAsync({ - takerAssetData: differentTakerAssetData, - }), - ]; - const takerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketSellOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - takerAssetFillAmount, - DeploymentManager.protocolFee.times(signedOrders.length), - ); - }); - - it('should fill a signedOrder that does not use the same takerAssetAddress (weth protocol fee)', async () => { - const differentTakerAssetData = encodeERC20AssetData(feeToken.address); - - signedOrders = [ - await maker.signOrderAsync(), - await maker.signOrderAsync(), - await maker.signOrderAsync({ - takerAssetData: differentTakerAssetData, - }), - ]; - const takerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketSellOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - takerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - - it('should not revert if an invalid order is included (eth protocol fee)', async () => { - const takerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - const invalidOrder = { ...signedOrders[0], signature: '0x00' }; - const validOrders = signedOrders.slice(1); - - const newOrdersWithValidity = [ - { signedOrder: invalidOrder, isValid: false }, - ...validOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - ]; - - await testMarketSellOrdersNoThrowAsync( - newOrdersWithValidity, - takerAssetFillAmount, - DeploymentManager.protocolFee.times(validOrders.length), - ); - }); - - it('should not revert if an invalid order is included (weth protocol fee)', async () => { - const takerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - const invalidOrder = { ...signedOrders[0], signature: '0x00' }; - const validOrders = signedOrders.slice(1); - - const newOrdersWithValidity = [ - { signedOrder: invalidOrder, isValid: false }, - ...validOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - ]; - - await testMarketSellOrdersNoThrowAsync( - newOrdersWithValidity, - takerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - }); - - describe('marketBuyOrdersNoThrow', () => { - async function testMarketBuyOrdersNoThrowAsync( - signedOrdersWithValidity: SignedOrderWithValidity[], - makerAssetFillAmount: BigNumber, - value: BigNumber, - ): Promise { - const fillTestInfo: FillTestInfo[] = []; - - let valueLeft = value; - let totalFillResults = { ...nullFillResults }; - let makerAssetRemaining = makerAssetFillAmount; - for (const { signedOrder, isValid } of signedOrdersWithValidity) { - if (isValid) { - let shouldPayWethFees; - - if (valueLeft.gte(DeploymentManager.protocolFee)) { - shouldPayWethFees = false; - valueLeft = valueLeft.minus(DeploymentManager.protocolFee); - } else { - shouldPayWethFees = true; - } - - if (!makerAssetRemaining.eq(0)) { - const makerAssetBought = makerAssetRemaining.gte(signedOrder.makerAssetAmount) - ? signedOrder.makerAssetAmount - : makerAssetRemaining; - - makerAssetRemaining = makerAssetRemaining.minus(makerAssetBought); - - const expectedFillResults = calculateScaledFillResultsWithMaker( - signedOrder, - makerAssetBought, - ); - - simulateFill(signedOrder, expectedFillResults, shouldPayWethFees); - fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees }); - - totalFillResults = addFillResults(totalFillResults, expectedFillResults); - } - } - } - - const contractFn = deployment.exchange.marketBuyOrdersNoThrow( - signedOrdersWithValidity.map(orderWithValidity => orderWithValidity.signedOrder), - makerAssetFillAmount, - signedOrdersWithValidity.map(orderWithValidity => orderWithValidity.signedOrder.signature), - ); - const callData = { - from: taker.address, - gasPrice: DeploymentManager.gasPrice, - value, - }; - const fillResults = await contractFn.callAsync(callData); - const receipt = await contractFn.awaitTransactionSuccessAsync(callData); - expect(fillResults).to.deep.equal(totalFillResults); - - await assertResultsAsync(receipt, fillTestInfo); - } - - it('should stop when the entire makerAssetFillAmount is filled (eth protocol fee)', async () => { - const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus( - signedOrders[1].makerAssetAmount.div(2), - ); - - await testMarketBuyOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - makerAssetFillAmount, - DeploymentManager.protocolFee.times(signedOrders.length), - ); - }); - - it('should stop when the entire makerAssetFillAmount is filled (weth protocol fee)', async () => { - const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus( - signedOrders[1].makerAssetAmount.div(2), - ); - - await testMarketBuyOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - makerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - - it('should fill all signedOrders if cannot fill entire makerAssetFillAmount (eth protocol fee)', async () => { - const makerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketBuyOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - makerAssetFillAmount, - DeploymentManager.protocolFee.times(signedOrders.length), - ); - }); - - it('should fill all signedOrders if cannot fill entire makerAssetFillAmount (weth protocol fee)', async () => { - const makerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketBuyOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - makerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - - it('should fill a signedOrder that does not use the same makerAssetAddress (eth protocol fee)', async () => { - const differentMakerAssetData = encodeERC20AssetData(feeToken.address); - - signedOrders = [ - await maker.signOrderAsync(), - await maker.signOrderAsync(), - await maker.signOrderAsync({ - makerAssetData: differentMakerAssetData, - }), - ]; - - const makerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketBuyOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - makerAssetFillAmount, - DeploymentManager.protocolFee.times(signedOrders.length), - ); - }); - - it('should fill a signedOrder that does not use the same makerAssetAddress (weth protocol fee)', async () => { - const differentMakerAssetData = encodeERC20AssetData(feeToken.address); - - signedOrders = [ - await maker.signOrderAsync(), - await maker.signOrderAsync(), - await maker.signOrderAsync({ - makerAssetData: differentMakerAssetData, - }), - ]; - - const makerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - await testMarketBuyOrdersNoThrowAsync( - signedOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - makerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - - it('should not revert if an invalid order is included (eth protocol fee)', async () => { - const makerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - const invalidOrder = { ...signedOrders[0], signature: '0x00' }; - const validOrders = signedOrders.slice(1); - - const newOrdersWithValidity = [ - { signedOrder: invalidOrder, isValid: false }, - ...validOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - ]; - - await testMarketBuyOrdersNoThrowAsync( - newOrdersWithValidity, - makerAssetFillAmount, - DeploymentManager.protocolFee.times(validOrders.length), - ); - }); - - it('should not revert if an invalid order is included (weth protocol fee)', async () => { - const makerAssetFillAmount = toBaseUnitAmount(new BigNumber(100000)); - - const invalidOrder = { ...signedOrders[0], signature: '0x00' }; - const validOrders = signedOrders.slice(1); - - const newOrdersWithValidity = [ - { signedOrder: invalidOrder, isValid: false }, - ...validOrders.map(signedOrder => { - return { signedOrder, isValid: true }; - }), - ]; - - await testMarketBuyOrdersNoThrowAsync( - newOrdersWithValidity, - makerAssetFillAmount, - constants.ZERO_AMOUNT, - ); - }); - }); - - describe('batchCancelOrders', () => { - it('should be able to cancel multiple signedOrders', async () => { - const receipt = await deployment.exchange.batchCancelOrders(signedOrders).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const expectedOrderHashes = signedOrders.map(order => orderHashUtils.getOrderHashHex(order)); - expect(receipt.logs.length).to.equal(signedOrders.length); - receipt.logs.forEach((log, index) => { - expect((log as any).args.orderHash).to.equal(expectedOrderHashes[index]); - }); - }); - - it('should not revert if a single cancel noops', async () => { - await deployment.exchange.cancelOrder(signedOrders[1]).awaitTransactionSuccessAsync({ - from: maker.address, - }); - const expectedOrderHashes = [signedOrders[0], ...signedOrders.slice(2)].map(order => - orderHashUtils.getOrderHashHex(order), - ); - const receipt = await deployment.exchange.batchCancelOrders(signedOrders).awaitTransactionSuccessAsync({ - from: maker.address, - }); - - expect(receipt.logs.length).to.equal(signedOrders.length - 1); - receipt.logs.forEach((log, index) => { - expect((log as any).args.orderHash).to.equal(expectedOrderHashes[index]); - }); - }); - }); - }); -}); // tslint:disable-line:max-file-line-count diff --git a/contracts/integrations/test/exchange/fill_dydx_order_test.ts b/contracts/integrations/test/exchange/fill_dydx_order_test.ts deleted file mode 100644 index 3c5bdc2216..0000000000 --- a/contracts/integrations/test/exchange/fill_dydx_order_test.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { - DydxBridgeActionType, - dydxBridgeDataEncoder, - encodeERC20AssetData, - encodeERC20BridgeAssetData, - TestDydxBridgeContract, -} from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { LibMathRevertErrors } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, describe, expect, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { SignedOrder } from '@0x/order-utils'; -import { BigNumber, decodeThrownErrorAsRevertError, StringRevertError } from '@0x/utils'; -import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { deployDydxBridgeAsync } from '../bridges/deploy_dydx_bridge'; -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { DeploymentManager } from '../framework/deployment_manager'; - -blockchainTests.resets('Exchange fills dydx orders', env => { - let testContract: TestDydxBridgeContract; - let makerToken: DummyERC20TokenContract; - let takerToken: DummyERC20TokenContract; - const marketId = new BigNumber(3); - const dydxConversionRateNumerator = toBaseUnitAmount(6); - const dydxConversionRateDenominator = toBaseUnitAmount(1); - let maker: Maker; - let taker: Taker; - let orderConfig: Partial; - let dydxBridgeProxyAssetData: string; - let deployment: DeploymentManager; - let testTokenAddress: string; - const defaultDepositAction = { - actionType: DydxBridgeActionType.Deposit as number, - accountIdx: constants.ZERO_AMOUNT, - marketId, - conversionRateNumerator: dydxConversionRateNumerator, - conversionRateDenominator: dydxConversionRateDenominator, - }; - const defaultWithdrawAction = { - actionType: DydxBridgeActionType.Withdraw as number, - accountIdx: constants.ZERO_AMOUNT, - marketId, - conversionRateNumerator: constants.ZERO_AMOUNT, - conversionRateDenominator: constants.ZERO_AMOUNT, - }; - const bridgeData = { - accountNumbers: [new BigNumber(0)], - actions: [defaultDepositAction, defaultWithdrawAction], - }; - - before(async () => { - // Deploy contracts - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 2, - }); - testContract = await deployDydxBridgeAsync(deployment, env); - const encodedBridgeData = dydxBridgeDataEncoder.encode({ bridgeData }); - testTokenAddress = await testContract.getTestToken().callAsync(); - dydxBridgeProxyAssetData = encodeERC20BridgeAssetData( - testTokenAddress, - testContract.address, - encodedBridgeData, - ); - [makerToken, takerToken] = deployment.tokens.erc20; - - // Configure default order parameters. - orderConfig = { - makerAssetAmount: toBaseUnitAmount(1), - takerAssetAmount: toBaseUnitAmount(1), - makerAssetData: encodeERC20AssetData(makerToken.address), - takerAssetData: encodeERC20AssetData(takerToken.address), - // Not important for this test. - feeRecipientAddress: constants.NULL_ADDRESS, - makerFeeAssetData: encodeERC20AssetData(makerToken.address), - takerFeeAssetData: encodeERC20AssetData(takerToken.address), - makerFee: toBaseUnitAmount(1), - takerFee: toBaseUnitAmount(1), - }; - - // Configure maker. - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig, - }); - await maker.configureERC20TokenAsync(makerToken, deployment.assetProxies.erc20Proxy.address); - - // Configure taker. - taker = new Taker({ - name: 'Taker', - deployment, - }); - await taker.configureERC20TokenAsync(takerToken, deployment.assetProxies.erc20Proxy.address); - }); - - after(async () => { - Actor.reset(); - }); - - describe('fillOrder', () => { - interface DydxFillResults { - makerAssetFilledAmount: BigNumber; - takerAssetFilledAmount: BigNumber; - makerFeePaid: BigNumber; - takerFeePaid: BigNumber; - amountDepositedIntoDydx: BigNumber; - amountWithdrawnFromDydx: BigNumber; - } - const fillOrder = async ( - signedOrder: SignedOrder, - customTakerAssetFillAmount?: BigNumber, - ): Promise => { - // Fill order - const takerAssetFillAmount = - customTakerAssetFillAmount !== undefined ? customTakerAssetFillAmount : signedOrder.takerAssetAmount; - const tx = await taker.fillOrderAsync(signedOrder, takerAssetFillAmount); - - // Extract values from fill event. - // tslint:disable no-unnecessary-type-assertion - const fillEvent = _.find(tx.logs, log => { - return (log as any).event === 'Fill'; - }) as LogWithDecodedArgs; - - // Extract amount deposited into dydx from maker. - const dydxDepositEvent = _.find(tx.logs, log => { - return ( - (log as any).event === 'OperateAction' && - (log as any).args.actionType === DydxBridgeActionType.Deposit - ); - }) as LogWithDecodedArgs; - - // Extract amount withdrawn from dydx to taker. - const dydxWithdrawEvent = _.find(tx.logs, log => { - return ( - (log as any).event === 'OperateAction' && - (log as any).args.actionType === DydxBridgeActionType.Withdraw - ); - }) as LogWithDecodedArgs; - - // Return values of interest for assertions. - return { - makerAssetFilledAmount: fillEvent.args.makerAssetFilledAmount, - takerAssetFilledAmount: fillEvent.args.takerAssetFilledAmount, - makerFeePaid: fillEvent.args.makerFeePaid, - takerFeePaid: fillEvent.args.takerFeePaid, - amountDepositedIntoDydx: dydxDepositEvent.args.amountValue, - amountWithdrawnFromDydx: dydxWithdrawEvent.args.amountValue, - }; - }; - it('should successfully fill a dydx order (DydxBridge used in makerAssetData)', async () => { - const signedOrder = await maker.signOrderAsync({ - // Invert the dydx conversion rate when using the bridge in the makerAssetData. - makerAssetData: dydxBridgeProxyAssetData, - makerAssetAmount: dydxConversionRateDenominator, - takerAssetAmount: dydxConversionRateNumerator, - }); - const dydxFillResults = await fillOrder(signedOrder); - expect( - dydxFillResults.makerAssetFilledAmount, - 'makerAssetFilledAmount should equal amountWithdrawnFromDydx', - ).to.bignumber.equal(dydxFillResults.amountWithdrawnFromDydx); - expect( - dydxFillResults.takerAssetFilledAmount, - 'takerAssetFilledAmount should equal amountDepositedIntoDydx', - ).to.bignumber.equal(dydxFillResults.amountDepositedIntoDydx); - }); - it('should successfully fill a dydx order (DydxBridge used in takerAssetData)', async () => { - const signedOrder = await maker.signOrderAsync({ - // Match the dydx conversion rate when using the bridge in the takerAssetData. - takerAssetData: dydxBridgeProxyAssetData, - makerAssetAmount: dydxConversionRateNumerator, - takerAssetAmount: dydxConversionRateDenominator, - }); - const dydxFillResults = await fillOrder(signedOrder); - expect( - dydxFillResults.makerAssetFilledAmount, - 'makerAssetFilledAmount should equal amountDepositedIntoDydx', - ).to.bignumber.equal(dydxFillResults.amountDepositedIntoDydx); - expect( - dydxFillResults.takerAssetFilledAmount, - 'takerAssetFilledAmount should equal amountWithdrawnFromDydx', - ).to.bignumber.equal(dydxFillResults.amountWithdrawnFromDydx); - }); - it('should successfully fill a dydx order (DydxBridge used in makerFeeAssetData)', async () => { - const signedOrder = await maker.signOrderAsync({ - // Invert the dydx conversion rate when using the bridge in the makerFeeAssetData. - makerFeeAssetData: dydxBridgeProxyAssetData, - makerFee: dydxConversionRateDenominator, - takerFee: dydxConversionRateNumerator, - }); - const dydxFillResults = await fillOrder(signedOrder); - expect( - dydxFillResults.makerFeePaid, - 'makerFeePaid should equal amountWithdrawnFromDydx', - ).to.bignumber.equal(dydxFillResults.amountWithdrawnFromDydx); - expect( - dydxFillResults.takerFeePaid, - 'takerFeePaid should equal amountDepositedIntoDydx', - ).to.bignumber.equal(dydxFillResults.amountDepositedIntoDydx); - }); - it('should successfully fill a dydx order (DydxBridge used in takerFeeAssetData)', async () => { - const signedOrder = await maker.signOrderAsync({ - // Match the dydx conversion rate when using the bridge in the takerFeeAssetData. - takerFeeAssetData: dydxBridgeProxyAssetData, - makerFee: dydxConversionRateNumerator, - takerFee: dydxConversionRateDenominator, - }); - const dydxFillResults = await fillOrder(signedOrder); - expect( - dydxFillResults.makerFeePaid, - 'makerFeePaid should equal amountDepositedIntoDydx', - ).to.bignumber.equal(dydxFillResults.amountDepositedIntoDydx); - expect( - dydxFillResults.takerFeePaid, - 'takerFeePaid should equal amountWithdrawnFromDydx', - ).to.bignumber.equal(dydxFillResults.amountWithdrawnFromDydx); - }); - it('should partially fill a dydx order (DydxBridge used in makerAssetData)', async () => { - const signedOrder = await maker.signOrderAsync({ - // Invert the dydx conversion rate when using the bridge in the makerAssetData. - makerAssetData: dydxBridgeProxyAssetData, - makerAssetAmount: dydxConversionRateDenominator, - takerAssetAmount: dydxConversionRateNumerator, - }); - const dydxFillResults = await fillOrder(signedOrder, signedOrder.takerAssetAmount.div(2)); - expect( - dydxFillResults.makerAssetFilledAmount, - 'makerAssetFilledAmount should equal amountWithdrawnFromDydx', - ).to.bignumber.equal(dydxFillResults.amountWithdrawnFromDydx); - expect( - dydxFillResults.takerAssetFilledAmount, - 'takerAssetFilledAmount should equal amountDepositedIntoDydx', - ).to.bignumber.equal(dydxFillResults.amountDepositedIntoDydx); - }); - it('should revert in DydxBridge when there is a rounding error', async () => { - // This order will not trigger the rounding error in the Exchange, - // but will trigger one in the DydxBridge. - const badDepositAction = { - ...defaultDepositAction, - conversionRateNumerator: new BigNumber(5318), - conversionRateDenominator: new BigNumber(47958), - }; - const badBridgeData = { - accountNumbers: [new BigNumber(0)], - actions: [badDepositAction], - }; - const encodedBridgeData = dydxBridgeDataEncoder.encode({ bridgeData: badBridgeData }); - const badDydxBridgeProxyAssetData = encodeERC20BridgeAssetData( - testTokenAddress, - testContract.address, - encodedBridgeData, - ); - const signedOrder = await maker.signOrderAsync({ - makerAssetData: badDydxBridgeProxyAssetData, - makerAssetAmount: badDepositAction.conversionRateDenominator, - takerAssetAmount: badDepositAction.conversionRateNumerator, - }); - const takerAssetFillAmount = new BigNumber(998); - - // Compute expected error. - const target = takerAssetFillAmount - .multipliedBy(signedOrder.makerAssetAmount) - .dividedToIntegerBy(signedOrder.takerAssetAmount); - const expectedAssetProxyError = new LibMathRevertErrors.RoundingError( - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - target, - ); - - // Call fillOrder and assert the rounding error generated by the DydxBridge. - const txPromise = taker.fillOrderAsync(signedOrder, takerAssetFillAmount); - let assetProxyError; - try { - await txPromise.catch(); - } catch (e) { - assetProxyError = decodeThrownErrorAsRevertError(e).values.errorData; - } - expect(assetProxyError).to.deep.equal(new StringRevertError(expectedAssetProxyError.encode())); - }); - }); -}); diff --git a/contracts/integrations/test/exchange/fill_order_test.ts b/contracts/integrations/test/exchange/fill_order_test.ts deleted file mode 100644 index c847812923..0000000000 --- a/contracts/integrations/test/exchange/fill_order_test.ts +++ /dev/null @@ -1,360 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { ERC20TokenEvents, ERC20TokenTransferEventArgs } from '@0x/contracts-erc20'; -import { ExchangeEvents, ExchangeFillEventArgs } from '@0x/contracts-exchange'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - constants as stakingConstants, - IStakingEventsEpochEndedEventArgs, - IStakingEventsEpochFinalizedEventArgs, - IStakingEventsEvents, - IStakingEventsRewardsPaidEventArgs, - IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs, -} from '@0x/contracts-staking'; -import { - blockchainTests, - constants, - expect, - orderHashUtils, - toBaseUnitAmount, - verifyEvents, -} from '@0x/contracts-test-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { Actor } from '../framework/actors/base'; -import { FeeRecipient } from '../framework/actors/fee_recipient'; -import { OperatorStakerMaker, StakerKeeper } from '../framework/actors/hybrids'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -blockchainTests.resets('fillOrder integration tests', env => { - let deployment: DeploymentManager; - let balanceStore: BlockchainBalanceStore; - - let feeRecipient: FeeRecipient; - let operator: OperatorStakerMaker; - let maker: Maker; - let taker: Taker; - let delegator: StakerKeeper; - - let poolId: string; - let operatorShare: number; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 2, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const [makerToken, takerToken] = deployment.tokens.erc20; - - feeRecipient = new FeeRecipient({ - name: 'Fee recipient', - deployment, - }); - const orderConfig = { - feeRecipientAddress: feeRecipient.address, - makerAssetData: encodeERC20AssetData(makerToken.address), - takerAssetData: encodeERC20AssetData(takerToken.address), - makerFeeAssetData: encodeERC20AssetData(makerToken.address), - takerFeeAssetData: encodeERC20AssetData(takerToken.address), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }; - operator = new OperatorStakerMaker({ - name: 'Pool operator', - deployment, - orderConfig, - }); - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig, - }); - taker = new Taker({ name: 'Taker', deployment }); - delegator = new StakerKeeper({ name: 'Delegator', deployment }); - - await operator.configureERC20TokenAsync(makerToken); - await maker.configureERC20TokenAsync(makerToken); - await taker.configureERC20TokenAsync(takerToken); - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - - await operator.configureERC20TokenAsync(deployment.tokens.zrx); - await delegator.configureERC20TokenAsync(deployment.tokens.zrx); - - // Create a staking pool with the operator as a maker. - operatorShare = stakingConstants.PPM * 0.95; - poolId = await operator.createStakingPoolAsync(operatorShare, true); - // A vanilla maker joins the pool as well. - await maker.joinStakingPoolAsync(poolId); - - const tokenOwners = { - ...actorAddressesByName([feeRecipient, operator, maker, taker, delegator]), - StakingProxy: deployment.staking.stakingProxy.address, - ZrxVault: deployment.staking.zrxVault.address, - }; - const tokenContracts = { - erc20: { makerToken, takerToken, ZRX: deployment.tokens.zrx, WETH: deployment.tokens.weth }, - }; - balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts); - await balanceStore.updateBalancesAsync(); - }); - - after(async () => { - Actor.reset(); - }); - - function verifyFillEvents(order: SignedOrder, receipt: TransactionReceiptWithDecodedLogs): void { - // Ensure that the fill event was correct. - verifyEvents( - receipt, - [ - { - makerAddress: maker.address, - feeRecipientAddress: feeRecipient.address, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData, - makerFeeAssetData: order.makerFeeAssetData, - takerFeeAssetData: order.takerFeeAssetData, - orderHash: orderHashUtils.getOrderHashHex(order), - takerAddress: taker.address, - senderAddress: taker.address, - makerAssetFilledAmount: order.makerAssetAmount, - takerAssetFilledAmount: order.takerAssetAmount, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: DeploymentManager.protocolFee, - }, - ], - ExchangeEvents.Fill, - ); - - // Ensure that the transfer events were correctly emitted. - verifyEvents( - receipt, - [ - { - _from: taker.address, - _to: maker.address, - _value: order.takerAssetAmount, - }, - { - _from: maker.address, - _to: taker.address, - _value: order.makerAssetAmount, - }, - ], - ERC20TokenEvents.Transfer, - ); - } - - it('should fill an order', async () => { - // Create and fill the order - const order = await maker.signOrderAsync(); - const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount); - - // Check balances - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // There should have been a fill event and two transfer events. A - // 'StakingPoolEarnedRewardsInEpoch' event should not be expected because the only staking - // pool that was created does not have enough stake. - verifyFillEvents(order, receipt); - }); - it('should activate a staking pool if it has sufficient stake', async () => { - // Stake just enough to qualify the pool for rewards. - await delegator.stakeAsync(toBaseUnitAmount(100), poolId); - - // The delegator, functioning as a keeper, ends the epoch so that delegated stake (theirs - // and the operator's) becomes active. This puts the staking pool above the minimumPoolStake - // threshold, so it should be able to earn rewards in the new epoch. - // Finalizing the pool shouldn't settle rewards because it didn't earn rewards last epoch. - await delegator.endEpochAsync(); - await delegator.finalizePoolsAsync([poolId]); - await balanceStore.updateBalancesAsync(); - - // Create and fill the order - const order = await maker.signOrderAsync(); - const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount); - - // Check balances - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // In addition to the fill event and two transfer events emitted in the previous test, we - // now expect a `StakingPoolEarnedRewardsInEpoch` event to be emitted because the staking - // pool now has enough stake in the current epoch to earn rewards. - verifyFillEvents(order, receipt); - const currentEpoch = await deployment.staking.stakingWrapper.currentEpoch().callAsync(); - verifyEvents( - receipt, - [ - { - epoch: currentEpoch, - poolId, - }, - ], - IStakingEventsEvents.StakingPoolEarnedRewardsInEpoch, - ); - }); - it('should pay out rewards to operator and delegator', async () => { - // Operator and delegator each stake some ZRX; wait an epoch so that the stake is active. - await operator.stakeAsync(toBaseUnitAmount(100), poolId); - await delegator.stakeAsync(toBaseUnitAmount(50), poolId); - await delegator.endEpochAsync(); - - // Create and fill the order. One order's worth of protocol fees are now available as rewards. - const order = await maker.signOrderAsync(); - await taker.fillOrderAsync(order, order.takerAssetAmount); - const rewardsAvailable = DeploymentManager.protocolFee; - - // Fetch the current balances - await balanceStore.updateBalancesAsync(); - const expectedBalances = LocalBalanceStore.create(balanceStore); - - // End the epoch. This should wrap the staking proxy's ETH balance. - const endEpochReceipt = await delegator.endEpochAsync(); - const newEpoch = await deployment.staking.stakingWrapper.currentEpoch().callAsync(); - - // Check balances - expectedBalances.wrapEth( - deployment.staking.stakingProxy.address, - deployment.tokens.weth.address, - DeploymentManager.protocolFee, - ); - expectedBalances.burnGas(delegator.address, DeploymentManager.gasPrice.times(endEpochReceipt.gasUsed)); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // Check the EpochEnded event - const weightedDelegatorStake = toBaseUnitAmount(50).times(0.9); - verifyEvents( - endEpochReceipt, - [ - { - epoch: newEpoch.minus(1), - numPoolsToFinalize: new BigNumber(1), - rewardsAvailable, - totalFeesCollected: DeploymentManager.protocolFee, - totalWeightedStake: toBaseUnitAmount(100).plus(weightedDelegatorStake), - }, - ], - IStakingEventsEvents.EpochEnded, - ); - - // The rewards are split between the operator and delegator based on the pool's operatorShare - const operatorReward = ReferenceFunctions.getPartialAmountFloor( - new BigNumber(operatorShare), - new BigNumber(constants.PPM_DENOMINATOR), - rewardsAvailable, - ); - const delegatorReward = rewardsAvailable.minus(operatorReward); - - // Finalize the pool. This should automatically pay the operator in WETH. - const [finalizePoolReceipt] = await delegator.finalizePoolsAsync([poolId]); - - // Check balances - expectedBalances.transferAsset( - deployment.staking.stakingProxy.address, - operator.address, - operatorReward, - encodeERC20AssetData(deployment.tokens.weth.address), - ); - expectedBalances.burnGas(delegator.address, DeploymentManager.gasPrice.times(finalizePoolReceipt.gasUsed)); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // Check finalization events - verifyEvents( - finalizePoolReceipt, - [ - { - epoch: newEpoch, - poolId, - operatorReward, - membersReward: delegatorReward, - }, - ], - IStakingEventsEvents.RewardsPaid, - ); - verifyEvents( - finalizePoolReceipt, - [ - { - epoch: newEpoch.minus(1), - rewardsPaid: rewardsAvailable, - rewardsRemaining: constants.ZERO_AMOUNT, - }, - ], - IStakingEventsEvents.EpochFinalized, - ); - }); - it('should credit rewards from orders made by the operator to their pool', async () => { - // Stake just enough to qualify the pool for rewards. - await delegator.stakeAsync(toBaseUnitAmount(100), poolId); - await delegator.endEpochAsync(); - - // Create and fill the order - const order = await operator.signOrderAsync(); - await taker.fillOrderAsync(order, order.takerAssetAmount); - - // Check that the pool has collected fees from the above fill. - const poolStats = await deployment.staking.stakingWrapper.getStakingPoolStatsThisEpoch(poolId).callAsync(); - expect(poolStats.feesCollected).to.bignumber.equal(DeploymentManager.protocolFee); - }); - it('should collect WETH fees and pay out rewards', async () => { - // Operator and delegator each stake some ZRX; wait an epoch so that the stake is active. - await operator.stakeAsync(toBaseUnitAmount(100), poolId); - await delegator.stakeAsync(toBaseUnitAmount(50), poolId); - await delegator.endEpochAsync(); - - // Fetch the current balances - await balanceStore.updateBalancesAsync(); - - // Create and fill the order. One order's worth of protocol fees are now available as rewards. - const order = await maker.signOrderAsync(); - const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount, { value: constants.ZERO_AMOUNT }); - const rewardsAvailable = DeploymentManager.protocolFee; - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.simulateFills([order], taker.address, receipt, deployment); - - // End the epoch. This should wrap the staking proxy's ETH balance. - const endEpochReceipt = await delegator.endEpochAsync(); - - // Check balances - expectedBalances.burnGas(delegator.address, DeploymentManager.gasPrice.times(endEpochReceipt.gasUsed)); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // The rewards are split between the operator and delegator based on the pool's operatorShare - const operatorReward = ReferenceFunctions.getPartialAmountFloor( - new BigNumber(operatorShare), - new BigNumber(constants.PPM_DENOMINATOR), - rewardsAvailable, - ); - - // Finalize the pool. This should automatically pay the operator in WETH. - const [finalizePoolReceipt] = await delegator.finalizePoolsAsync([poolId]); - - // Check balances - expectedBalances.transferAsset( - deployment.staking.stakingProxy.address, - operator.address, - operatorReward, - encodeERC20AssetData(deployment.tokens.weth.address), - ); - expectedBalances.burnGas(delegator.address, DeploymentManager.gasPrice.times(finalizePoolReceipt.gasUsed)); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); -}); diff --git a/contracts/integrations/test/exchange/fill_order_wrapper.ts b/contracts/integrations/test/exchange/fill_order_wrapper.ts deleted file mode 100644 index 9f2b85cf98..0000000000 --- a/contracts/integrations/test/exchange/fill_order_wrapper.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { ExchangeContract } from '@0x/contracts-exchange'; -import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - constants, - expect, - FillEventArgs, - filterLogsToArguments, - orderHashUtils, - OrderStatus, - orderUtils, -} from '@0x/contracts-test-utils'; -import { FillResults, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { BalanceStore } from '../framework/balances/balance_store'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { TokenContractsByName, TokenIds, TokenOwnersByName } from '../framework/balances/types'; - -export class FillOrderWrapper { - private readonly _blockchainBalanceStore: BlockchainBalanceStore; - - /** - * Simulates the event emitted by the exchange contract when an order is filled. - */ - public static simulateFillEvent(order: SignedOrder, takerAddress: string, fillResults: FillResults): FillEventArgs { - // prettier-ignore - return { - orderHash: orderHashUtils.getOrderHashHex(order), - makerAddress: order.makerAddress, - takerAddress, - makerAssetFilledAmount: fillResults.makerAssetFilledAmount, - takerAssetFilledAmount: fillResults.takerAssetFilledAmount, - makerFeePaid: fillResults.makerFeePaid, - takerFeePaid: fillResults.takerFeePaid, - }; - } - - /** - * Extract the exchanges `Fill` event from a transaction receipt. - */ - private static _extractFillEventsfromReceipt(receipt: TransactionReceiptWithDecodedLogs): FillEventArgs[] { - const events = filterLogsToArguments(receipt.logs, 'Fill'); - const fieldsOfInterest = [ - 'orderHash', - 'makerAddress', - 'takerAddress', - 'makerAssetFilledAmount', - 'takerAssetFilledAmount', - 'makerFeePaid', - 'takerFeePaid', - ]; - return events.map(event => _.pick(event, fieldsOfInterest)) as FillEventArgs[]; - } - - /** - * Constructor. - * @param exchangeContract Instance of the deployed exchange contract. - * @param tokenOwnersByName The addresses of token owners to assert the balances of. - * @param tokenContractsByName The contracts of tokens to assert the balances of. - * @param tokenIds The tokenIds of ERC721 and ERC1155 assets to assert the balances of. - */ - public constructor( - private readonly _exchange: ExchangeContract, - tokenOwnersByName: TokenOwnersByName, - tokenContractsByName: Partial, - tokenIds: Partial, - ) { - this._blockchainBalanceStore = new BlockchainBalanceStore(tokenOwnersByName, tokenContractsByName, tokenIds); - } - - /** - * Returns the balance store used by this wrapper. - */ - public getBlockchainBalanceStore(): BlockchainBalanceStore { - return this._blockchainBalanceStore; - } - - /** - * Fills an order and asserts the effects. This includes - * 1. The order info (via `getOrderInfo`) - * 2. The fill results returned by making an `eth_call` to `exchange.fillOrder` - * 3. The events emitted by the exchange when the order is filled. - * 4. The balance changes as a result of filling the order. - */ - public async fillOrderAndAssertEffectsAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise { - // Get init state - await this._blockchainBalanceStore.updateBalancesAsync(); - const initTakerAssetFilledAmount = await this._exchange - .filled(orderHashUtils.getOrderHashHex(signedOrder)) - .callAsync(); - // Assert init state of exchange - await this._assertOrderStateAsync(signedOrder, initTakerAssetFilledAmount); - // Simulate and execute fill then assert outputs - const [fillResults, fillEvent, txReceipt] = await this._fillOrderAsync(signedOrder, from, opts); - const [simulatedFillResults, simulatedFillEvent, simulatedFinalBalanceStore] = simulateFillOrder( - txReceipt, - signedOrder, - from, - this._blockchainBalanceStore, - opts, - ); - // Assert state transition - expect(simulatedFillResults, 'Fill Results').to.be.deep.equal(fillResults); - expect(simulatedFillEvent, 'Fill Events').to.be.deep.equal(fillEvent); - - await this._blockchainBalanceStore.updateBalancesAsync(); - this._blockchainBalanceStore.assertEquals(simulatedFinalBalanceStore); - - // Assert end state of exchange - const finalTakerAssetFilledAmount = initTakerAssetFilledAmount.plus(fillResults.takerAssetFilledAmount); - await this._assertOrderStateAsync(signedOrder, finalTakerAssetFilledAmount); - } - - /** - * Fills an order on-chain. - */ - protected async _fillOrderAsync( - signedOrder: SignedOrder, - from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, - ): Promise<[FillResults, FillEventArgs, TransactionReceiptWithDecodedLogs]> { - const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const fillResults = await this._exchange - .fillOrder(params.order, params.takerAssetFillAmount, params.signature) - .callAsync({ from }); - const txReceipt = await this._exchange - .fillOrder(params.order, params.takerAssetFillAmount, params.signature) - .awaitTransactionSuccessAsync({ from }); - const fillEvent = FillOrderWrapper._extractFillEventsfromReceipt(txReceipt)[0]; - return [fillResults, fillEvent, txReceipt]; - } - - /** - * Asserts that the provided order's fill amount and order status - * are the expected values. - * @param order The order to verify for a correct state. - * @param expectedFilledAmount The amount that the order should have been filled. - */ - private async _assertOrderStateAsync( - order: SignedOrder, - expectedFilledAmount: BigNumber = new BigNumber(0), - ): Promise { - const orderInfo = await this._exchange.getOrderInfo(order).callAsync(); - // Check filled amount of order. - const actualFilledAmount = orderInfo.orderTakerAssetFilledAmount; - expect(actualFilledAmount, 'order filled amount').to.be.bignumber.equal(expectedFilledAmount); - // Check status of order. - const expectedStatus = expectedFilledAmount.isGreaterThanOrEqualTo(order.takerAssetAmount) - ? OrderStatus.FullyFilled - : OrderStatus.Fillable; - const actualStatus = orderInfo.orderStatus; - expect(actualStatus, 'order status').to.equal(expectedStatus); - } -} - -/** - * Locally simulates filling an order. - * @param txReceipt Transaction receipt from the actual fill, needed to update eth balance - * @param signedOrder The order being filled. - * @param takerAddress Address of taker (the address who matched the two orders) - * @param opts Optionally specifies the amount to fill. - * @param initBalanceStore Account balances prior to the fill. - * @return The expected account balances, fill results, and fill events. - */ -function simulateFillOrder( - txReceipt: TransactionReceiptWithDecodedLogs, - signedOrder: SignedOrder, - takerAddress: string, - initBalanceStore: BalanceStore, - opts: { takerAssetFillAmount?: BigNumber } = {}, -): [FillResults, FillEventArgs, BalanceStore] { - const balanceStore = LocalBalanceStore.create(initBalanceStore); - const takerAssetFillAmount = - opts.takerAssetFillAmount !== undefined ? opts.takerAssetFillAmount : signedOrder.takerAssetAmount; - // TODO(jalextowle): Change this if the integration tests take protocol fees into account. - const fillResults = LibReferenceFunctions.calculateFillResults( - signedOrder, - takerAssetFillAmount, - constants.ZERO_AMOUNT, - constants.ZERO_AMOUNT, - ); - const fillEvent = FillOrderWrapper.simulateFillEvent(signedOrder, takerAddress, fillResults); - // Taker -> Maker - balanceStore.transferAsset( - takerAddress, - signedOrder.makerAddress, - fillResults.takerAssetFilledAmount, - signedOrder.takerAssetData, - ); - // Maker -> Taker - balanceStore.transferAsset( - signedOrder.makerAddress, - takerAddress, - fillResults.makerAssetFilledAmount, - signedOrder.makerAssetData, - ); - // Taker -> Fee Recipient - balanceStore.transferAsset( - takerAddress, - signedOrder.feeRecipientAddress, - fillResults.takerFeePaid, - signedOrder.takerFeeAssetData, - ); - // Maker -> Fee Recipient - balanceStore.transferAsset( - signedOrder.makerAddress, - signedOrder.feeRecipientAddress, - fillResults.makerFeePaid, - signedOrder.makerFeeAssetData, - ); - balanceStore.burnGas(txReceipt.from, constants.DEFAULT_GAS_PRICE * txReceipt.gasUsed); - return [fillResults, fillEvent, balanceStore]; -} diff --git a/contracts/integrations/test/exchange/match_order_tester.ts b/contracts/integrations/test/exchange/match_order_tester.ts deleted file mode 100644 index d5d76237c7..0000000000 --- a/contracts/integrations/test/exchange/match_order_tester.ts +++ /dev/null @@ -1,1004 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { BlockchainTestsEnvironment, constants, expect, orderHashUtils, OrderStatus } from '@0x/contracts-test-utils'; -import { BatchMatchedFillResults, FillResults, MatchedFillResults, Order, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { Maker } from '../framework/actors/maker'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -export interface FillEventArgs { - orderHash: string; - makerAddress: string; - takerAddress: string; - makerAssetFilledAmount: BigNumber; - takerAssetFilledAmount: BigNumber; - makerFeePaid: BigNumber; - takerFeePaid: BigNumber; - protocolFeePaid: BigNumber; -} - -export interface MatchTransferAmounts { - // Assets being traded. - leftMakerAssetSoldByLeftMakerAmount: BigNumber; // leftMakerAssetBoughtByRightMakerAmount if omitted. - rightMakerAssetSoldByRightMakerAmount: BigNumber; // rightMakerAssetBoughtByLeftMakerAmount if omitted. - rightMakerAssetBoughtByLeftMakerAmount: BigNumber; // rightMakerAssetSoldByRightMakerAmount if omitted. - leftMakerAssetBoughtByRightMakerAmount: BigNumber; // leftMakerAssetSoldByLeftMakerAmount if omitted. - // Taker profit. - leftMakerAssetReceivedByTakerAmount: BigNumber; // 0 if omitted. - rightMakerAssetReceivedByTakerAmount: BigNumber; // 0 if omitted. - // Maker fees. - leftMakerFeeAssetPaidByLeftMakerAmount: BigNumber; // 0 if omitted. - rightMakerFeeAssetPaidByRightMakerAmount: BigNumber; // 0 if omitted. - // Taker fees. - leftTakerFeeAssetPaidByTakerAmount: BigNumber; // 0 if omitted. - rightTakerFeeAssetPaidByTakerAmount: BigNumber; // 0 if omitted. - // Protocol fees. - leftProtocolFeePaidByTakerInEthAmount: BigNumber; // 0 if omitted - leftProtocolFeePaidByTakerInWethAmount: BigNumber; // 0 if omitted - rightProtocolFeePaidByTakerInWethAmount: BigNumber; // 0 if omitted - rightProtocolFeePaidByTakerInEthAmount: BigNumber; // 0 if omitted -} - -export interface MatchResults { - orders: MatchedOrders; - fills: FillEventArgs[]; -} - -export interface BatchMatchResults { - matches: MatchResults[]; - filledAmounts: Array<[SignedOrder, BigNumber, string]>; - leftFilledResults: FillEventArgs[]; - rightFilledResults: FillEventArgs[]; -} - -export interface BatchMatchedOrders { - leftOrders: SignedOrder[]; - rightOrders: SignedOrder[]; - leftOrdersTakerAssetFilledAmounts: BigNumber[]; - rightOrdersTakerAssetFilledAmounts: BigNumber[]; -} - -export interface MatchedOrders { - leftOrder: SignedOrder; - rightOrder: SignedOrder; - leftOrderTakerAssetFilledAmount?: BigNumber; - rightOrderTakerAssetFilledAmount?: BigNumber; -} - -export interface TestMatchOrdersArgs { - env: BlockchainTestsEnvironment; - matchOrderTester: MatchOrderTester; - leftOrder: Partial; - rightOrder: Partial; - makerLeft: Maker; - makerRight: Maker; - expectedTransferAmounts: Partial; - withMaximalFill: boolean; - matcherAddress: string; -} - -/** - * Tests an order matching scenario with both eth and weth protocol fees. - */ -export async function testMatchOrdersAsync(args: TestMatchOrdersArgs): Promise { - // Create orders to match. - const signedOrderLeft = await args.makerLeft.signOrderAsync(args.leftOrder); - const signedOrderRight = await args.makerRight.signOrderAsync(args.rightOrder); - - await args.matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - { - ...args.expectedTransferAmounts, - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - leftProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT, - rightProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT, - }, - args.matcherAddress, - DeploymentManager.protocolFee.times(2), - args.withMaximalFill, - ); - - await args.env.blockchainLifecycle.revertAsync(); - await args.env.blockchainLifecycle.startAsync(); - - await args.matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - { - ...args.expectedTransferAmounts, - leftProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT, - rightProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT, - leftProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee, - }, - args.matcherAddress, - constants.ZERO_AMOUNT, - args.withMaximalFill, - ); -} - -export class MatchOrderTester { - /** - * Constructs new MatchOrderTester. - */ - constructor( - protected readonly _deployment: DeploymentManager, - protected readonly _blockchainBalanceStore: BlockchainBalanceStore, - ) {} - - /** - * Performs batch order matching on a set of complementary orders and asserts results. - * @param orders The list of orders and filled states - * @param takerAddress Address of taker (the address who matched the two orders) - * @param value The amount of value that should be sent in the contract call. - * @param matchPairs An array of left and right indices that will be used to perform - * the expected simulation. - * @param expectedTransferAmounts Expected amounts transferred as a result of each round of - * order matching. Omitted fields are either set to 0 or their - * complementary field. - * @param withMaximalFill A boolean that indicates whether the "maximal fill" order matching - * strategy should be used. - * @return Results of `batchMatchOrders()`. - */ - public async batchMatchOrdersAndAssertEffectsAsync( - orders: BatchMatchedOrders, - takerAddress: string, - value: BigNumber, - matchPairs: Array<[number, number]>, - expectedTransferAmounts: Array>, - withMaximalFill: boolean, - ): Promise { - // Ensure that the provided input is valid. - expect(matchPairs.length).to.be.eq(expectedTransferAmounts.length); - expect(orders.leftOrders.length).to.be.eq(orders.leftOrdersTakerAssetFilledAmounts.length); - expect(orders.rightOrders.length).to.be.eq(orders.rightOrdersTakerAssetFilledAmounts.length); - - // Ensure that the exchange is in the expected state. - await this._assertBatchOrderStatesAsync(orders); - - // Update the blockchain balance store and create a new local balance store - // with the same initial balances. - await this._blockchainBalanceStore.updateBalancesAsync(); - const localBalanceStore = LocalBalanceStore.create(this._blockchainBalanceStore); - - // Execute `batchMatchOrders()` - let actualBatchMatchResults; - let transactionReceipt; - if (withMaximalFill) { - const tx = this._deployment.exchange.batchMatchOrdersWithMaximalFill( - orders.leftOrders, - orders.rightOrders, - orders.leftOrders.map(order => order.signature), - orders.rightOrders.map(order => order.signature), - ); - actualBatchMatchResults = await tx.callAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - transactionReceipt = await tx.awaitTransactionSuccessAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - } else { - const tx = this._deployment.exchange.batchMatchOrders( - orders.leftOrders, - orders.rightOrders, - orders.leftOrders.map(order => order.signature), - orders.rightOrders.map(order => order.signature), - ); - actualBatchMatchResults = await tx.callAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - transactionReceipt = await tx.awaitTransactionSuccessAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - } - - // Burn the gas used to execute the transaction in the local balance store. - localBalanceStore.burnGas(takerAddress, DeploymentManager.gasPrice.times(transactionReceipt.gasUsed)); - - // Simulate the batch order match. - const expectedBatchMatchResults = await this._simulateBatchMatchOrdersAsync( - orders, - takerAddress, - matchPairs, - expectedTransferAmounts, - localBalanceStore, - ); - - const expectedResults = convertToBatchMatchResults(expectedBatchMatchResults); - expect(actualBatchMatchResults).to.be.eql(expectedResults); - - // Validate the simulation against reality. - await this._assertBatchMatchResultsAsync(expectedBatchMatchResults, transactionReceipt, localBalanceStore); - return expectedBatchMatchResults; - } - - /** - * Matches two complementary orders and asserts results. - * @param orders The matched orders and filled states. - * @param expectedTransferAmounts Expected amounts transferred as a result of order matching. - * Omitted fields are either set to 0 or their complementary - * field. - * @param takerAddress Address of taker (the address who matched the two orders) - * @param value The amount of value that should be sent in the contract call. - * @param withMaximalFill A boolean that indicates whether the "maximal fill" order matching - * strategy should be used. - * @return Results of `matchOrders()`. - */ - public async matchOrdersAndAssertEffectsAsync( - orders: MatchedOrders, - expectedTransferAmounts: Partial, - takerAddress: string, - value: BigNumber, - withMaximalFill: boolean, - ): Promise { - await this._assertInitialOrderStatesAsync(orders); - - // Update the blockchain balance store and create a new local balance store - // with the same initial balances. - await this._blockchainBalanceStore.updateBalancesAsync(); - const localBalanceStore = LocalBalanceStore.create(this._blockchainBalanceStore); - - // Execute `matchOrders()` - let actualMatchResults; - let transactionReceipt; - if (withMaximalFill) { - const tx = this._deployment.exchange.matchOrdersWithMaximalFill( - orders.leftOrder, - orders.rightOrder, - orders.leftOrder.signature, - orders.rightOrder.signature, - ); - actualMatchResults = await tx.callAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - transactionReceipt = await tx.awaitTransactionSuccessAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - } else { - const tx = this._deployment.exchange.matchOrders( - orders.leftOrder, - orders.rightOrder, - orders.leftOrder.signature, - orders.rightOrder.signature, - ); - actualMatchResults = await tx.callAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - transactionReceipt = await tx.awaitTransactionSuccessAsync({ - from: takerAddress, - gasPrice: DeploymentManager.gasPrice, - value, - }); - } - localBalanceStore.burnGas(takerAddress, DeploymentManager.gasPrice.times(transactionReceipt.gasUsed)); - - // Simulate the fill. - const expectedMatchResults = this._simulateMatchOrders( - orders, - takerAddress, - toFullMatchTransferAmounts(expectedTransferAmounts), - localBalanceStore, - ); - const expectedResults = convertToMatchResults(expectedMatchResults); - expect(actualMatchResults).to.be.eql(expectedResults); - - // Validate the simulation against reality. - await this._assertMatchResultsAsync(expectedMatchResults, transactionReceipt, localBalanceStore); - return expectedMatchResults; - } - - /** - * Simulates matching two orders by transferring amounts defined in - * `transferAmounts` and returns the results. - * @param orders The orders being matched and their filled states. - * @param takerAddress Address of taker (the address who matched the two orders) - * @param transferAmounts Amounts to transfer during the simulation. - * @param localBalanceStore The balance store to use for the simulation. - * @return The new account balances and fill events that occurred during the match. - */ - protected _simulateMatchOrders( - orders: MatchedOrders, - takerAddress: string, - transferAmounts: MatchTransferAmounts, - localBalanceStore: LocalBalanceStore, - ): MatchResults { - // prettier-ignore - const matchResults = { - orders: { - leftOrder: orders.leftOrder, - leftOrderTakerAssetFilledAmount: - (orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT).plus( - transferAmounts.rightMakerAssetBoughtByLeftMakerAmount, - ), - rightOrder: orders.rightOrder, - rightOrderTakerAssetFilledAmount: - (orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT).plus( - transferAmounts.leftMakerAssetBoughtByRightMakerAmount, - ), - }, - fills: simulateFillEvents(orders, takerAddress, transferAmounts), - }; - - // Right maker asset -> left maker - localBalanceStore.transferAsset( - orders.rightOrder.makerAddress, - orders.leftOrder.makerAddress, - transferAmounts.rightMakerAssetBoughtByLeftMakerAmount, - orders.rightOrder.makerAssetData, - ); - - if (orders.leftOrder.makerAddress !== orders.leftOrder.feeRecipientAddress) { - // Left maker fees - localBalanceStore.transferAsset( - orders.leftOrder.makerAddress, - orders.leftOrder.feeRecipientAddress, - transferAmounts.leftMakerFeeAssetPaidByLeftMakerAmount, - orders.leftOrder.makerFeeAssetData, - ); - } - - // Left maker asset -> right maker - localBalanceStore.transferAsset( - orders.leftOrder.makerAddress, - orders.rightOrder.makerAddress, - transferAmounts.leftMakerAssetBoughtByRightMakerAmount, - orders.leftOrder.makerAssetData, - ); - - if (orders.rightOrder.makerAddress !== orders.rightOrder.feeRecipientAddress) { - // Right maker fees - localBalanceStore.transferAsset( - orders.rightOrder.makerAddress, - orders.rightOrder.feeRecipientAddress, - transferAmounts.rightMakerFeeAssetPaidByRightMakerAmount, - orders.rightOrder.makerFeeAssetData, - ); - } - - // Left taker profit - localBalanceStore.transferAsset( - orders.leftOrder.makerAddress, - takerAddress, - transferAmounts.leftMakerAssetReceivedByTakerAmount, - orders.leftOrder.makerAssetData, - ); - - // Right taker profit - localBalanceStore.transferAsset( - orders.rightOrder.makerAddress, - takerAddress, - transferAmounts.rightMakerAssetReceivedByTakerAmount, - orders.rightOrder.makerAssetData, - ); - - // Left taker fees - localBalanceStore.transferAsset( - takerAddress, - orders.leftOrder.feeRecipientAddress, - transferAmounts.leftTakerFeeAssetPaidByTakerAmount, - orders.leftOrder.takerFeeAssetData, - ); - - // Right taker fees - localBalanceStore.transferAsset( - takerAddress, - orders.rightOrder.feeRecipientAddress, - transferAmounts.rightTakerFeeAssetPaidByTakerAmount, - orders.rightOrder.takerFeeAssetData, - ); - - // Protocol Fee - const wethAssetData = encodeERC20AssetData(this._deployment.tokens.weth.address); - localBalanceStore.sendEth( - takerAddress, - this._deployment.staking.stakingProxy.address, - transferAmounts.leftProtocolFeePaidByTakerInEthAmount, - ); - localBalanceStore.sendEth( - takerAddress, - this._deployment.staking.stakingProxy.address, - transferAmounts.rightProtocolFeePaidByTakerInEthAmount, - ); - localBalanceStore.transferAsset( - takerAddress, - this._deployment.staking.stakingProxy.address, - transferAmounts.leftProtocolFeePaidByTakerInWethAmount, - wethAssetData, - ); - localBalanceStore.transferAsset( - takerAddress, - this._deployment.staking.stakingProxy.address, - transferAmounts.rightProtocolFeePaidByTakerInWethAmount, - wethAssetData, - ); - - return matchResults; - } - - /** - * Simulates matching a batch of orders by transferring amounts defined in - * `transferAmounts` and returns the results. - * @param orders The orders being batch matched and their filled states. - * @param takerAddress Address of taker (the address who matched the two orders) - * @param matchPairs The pairs of orders that are expected to be matched. - * @param transferAmounts Amounts to transfer during the simulation. - * @param localBalanceStore The balance store to use for the simulation. - * @return The new account balances and fill events that occurred during the match. - */ - protected async _simulateBatchMatchOrdersAsync( - orders: BatchMatchedOrders, - takerAddress: string, - matchPairs: Array<[number, number]>, - transferAmounts: Array>, - localBalanceStore: LocalBalanceStore, - ): Promise { - // Initialize variables - let leftIdx = 0; - let rightIdx = 0; - let lastLeftIdx = -1; - let lastRightIdx = -1; - let matchedOrders: MatchedOrders; - const batchMatchResults: BatchMatchResults = { - matches: [], - filledAmounts: [], - leftFilledResults: [], - rightFilledResults: [], - }; - - // Loop over all of the matched pairs from the round - for (let i = 0; i < matchPairs.length; i++) { - leftIdx = matchPairs[i][0]; - rightIdx = matchPairs[i][1]; - - // Construct a matched order out of the current left and right orders - matchedOrders = { - leftOrder: orders.leftOrders[leftIdx], - rightOrder: orders.rightOrders[rightIdx], - leftOrderTakerAssetFilledAmount: orders.leftOrdersTakerAssetFilledAmounts[leftIdx], - rightOrderTakerAssetFilledAmount: orders.rightOrdersTakerAssetFilledAmounts[rightIdx], - }; - - // If there has been a match recorded and one or both of the side indices have not changed, - // replace the side's taker asset filled amount - if (batchMatchResults.matches.length > 0) { - if (lastLeftIdx === leftIdx) { - matchedOrders.leftOrderTakerAssetFilledAmount = getLastMatch( - batchMatchResults, - ).orders.leftOrderTakerAssetFilledAmount; - } else { - batchMatchResults.filledAmounts.push([ - orders.leftOrders[lastLeftIdx], - getLastMatch(batchMatchResults).orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT, - 'left', - ]); - } - if (lastRightIdx === rightIdx) { - matchedOrders.rightOrderTakerAssetFilledAmount = getLastMatch( - batchMatchResults, - ).orders.rightOrderTakerAssetFilledAmount; - } else { - batchMatchResults.filledAmounts.push([ - orders.rightOrders[lastRightIdx], - getLastMatch(batchMatchResults).orders.rightOrderTakerAssetFilledAmount || - constants.ZERO_AMOUNT, - 'right', - ]); - } - } - - // Add the latest match to the batch match results - batchMatchResults.matches.push( - this._simulateMatchOrders( - matchedOrders, - takerAddress, - toFullMatchTransferAmounts(transferAmounts[i]), - localBalanceStore, - ), - ); - - // Update the left and right fill results - if (lastLeftIdx === leftIdx) { - addFillResults(batchMatchResults.leftFilledResults[leftIdx], getLastMatch(batchMatchResults).fills[0]); - } else { - batchMatchResults.leftFilledResults.push({ ...getLastMatch(batchMatchResults).fills[0] }); - } - if (lastRightIdx === rightIdx) { - addFillResults( - batchMatchResults.rightFilledResults[rightIdx], - getLastMatch(batchMatchResults).fills[1], - ); - } else { - batchMatchResults.rightFilledResults.push({ ...getLastMatch(batchMatchResults).fills[1] }); - } - - lastLeftIdx = leftIdx; - lastRightIdx = rightIdx; - } - - for (let i = leftIdx + 1; i < orders.leftOrders.length; i++) { - batchMatchResults.leftFilledResults.push(emptyFillEventArgs()); - } - - for (let i = rightIdx + 1; i < orders.rightOrders.length; i++) { - batchMatchResults.rightFilledResults.push(emptyFillEventArgs()); - } - - // The two orders indexed by lastLeftIdx and lastRightIdx were potentially - // filled; however, the TakerAssetFilledAmounts that pertain to these orders - // will not have been added to batchMatchResults, so we need to write them - // here. - batchMatchResults.filledAmounts.push([ - orders.leftOrders[lastLeftIdx], - getLastMatch(batchMatchResults).orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT, - 'left', - ]); - batchMatchResults.filledAmounts.push([ - orders.rightOrders[lastRightIdx], - getLastMatch(batchMatchResults).orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT, - 'right', - ]); - - // Return the batch match results - return batchMatchResults; - } - /** - * Checks that the results of `simulateBatchMatchOrders()` agrees with reality. - * @param batchMatchResults The results of a `simulateBatchMatchOrders()`. - * @param transactionReceipt The transaction receipt of a call to `matchOrders()`. - * @param localBalanceStore The balance store to use during the simulation. - */ - protected async _assertBatchMatchResultsAsync( - batchMatchResults: BatchMatchResults, - transactionReceipt: TransactionReceiptWithDecodedLogs, - localBalanceStore: LocalBalanceStore, - ): Promise { - // Ensure that the batchMatchResults contain at least one match - expect(batchMatchResults.matches.length).to.be.gt(0); - - // Check the fill events. - assertFillEvents( - batchMatchResults.matches.map(match => match.fills).reduce((total, fills) => total.concat(fills)), - transactionReceipt, - ); - - // Update the blockchain balance store balances. - await this._blockchainBalanceStore.updateBalancesAsync(); - - // Ensure that the actual and expected token balances are equivalent. - localBalanceStore.assertEquals(this._blockchainBalanceStore); - - // Check the Exchange state. - await this._assertPostBatchExchangeStateAsync(batchMatchResults); - } - - /** - * Checks that the results of `simulateMatchOrders()` agrees with reality. - * @param matchResults The results of a `simulateMatchOrders()`. - * @param transactionReceipt The transaction receipt of a call to `matchOrders()`. - * @param localBalanceStore The balance store to use during the simulation. - */ - protected async _assertMatchResultsAsync( - matchResults: MatchResults, - transactionReceipt: TransactionReceiptWithDecodedLogs, - localBalanceStore: LocalBalanceStore, - ): Promise { - // Check the fill events. - assertFillEvents(matchResults.fills, transactionReceipt); - - // Update the blockchain balance store balances. - await this._blockchainBalanceStore.updateBalancesAsync(); - - // Check the token balances. - localBalanceStore.assertEquals(this._blockchainBalanceStore); - - // Check the Exchange state. - await this._assertPostExchangeStateAsync(matchResults); - } - - /** - * Asserts the initial exchange state for batch matched orders. - * @param orders Batch matched orders with intial filled amounts. - */ - private async _assertBatchOrderStatesAsync(orders: BatchMatchedOrders): Promise { - for (let i = 0; i < orders.leftOrders.length; i++) { - await this._assertOrderFilledAmountAsync( - orders.leftOrders[i], - orders.leftOrdersTakerAssetFilledAmounts[i], - 'left', - ); - } - for (let i = 0; i < orders.rightOrders.length; i++) { - await this._assertOrderFilledAmountAsync( - orders.rightOrders[i], - orders.rightOrdersTakerAssetFilledAmounts[i], - 'right', - ); - } - } - - /** - * Asserts the initial exchange state for matched orders. - * @param orders Matched orders with intial filled amounts. - */ - private async _assertInitialOrderStatesAsync(orders: MatchedOrders): Promise { - const pairs = [ - [orders.leftOrder, orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT], - [orders.rightOrder, orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT], - ] as Array<[SignedOrder, BigNumber]>; - await Promise.all( - pairs.map(async ([order, expectedFilledAmount]) => { - const side = order === orders.leftOrder ? 'left' : 'right'; - await this._assertOrderFilledAmountAsync(order, expectedFilledAmount, side); - }), - ); - } - - /** - * Asserts the exchange state after a call to `batchMatchOrders()`. - * @param batchMatchResults Results from a call to `simulateBatchMatchOrders()`. - */ - private async _assertPostBatchExchangeStateAsync(batchMatchResults: BatchMatchResults): Promise { - await this._assertTriplesExchangeStateAsync(batchMatchResults.filledAmounts); - } - - /** - * Asserts the exchange state after a call to `matchOrders()`. - * @param matchResults Results from a call to `simulateMatchOrders()`. - */ - private async _assertPostExchangeStateAsync(matchResults: MatchResults): Promise { - const triples = [ - [matchResults.orders.leftOrder, matchResults.orders.leftOrderTakerAssetFilledAmount, 'left'], - [matchResults.orders.rightOrder, matchResults.orders.rightOrderTakerAssetFilledAmount, 'right'], - ] as Array<[SignedOrder, BigNumber, string]>; - await this._assertTriplesExchangeStateAsync(triples); - } - - /** - * Asserts the exchange state represented by provided sequence of triples. - * @param triples The sequence of triples to verifiy. Each triple consists - * of an `order`, a `takerAssetFilledAmount`, and a `side`, - * which will be used to determine if the exchange's state - * is valid. - */ - private async _assertTriplesExchangeStateAsync(triples: Array<[SignedOrder, BigNumber, string]>): Promise { - await Promise.all( - triples.map(async ([order, expectedFilledAmount, side]) => { - expect(['left', 'right']).to.include(side); - await this._assertOrderFilledAmountAsync(order, expectedFilledAmount, side); - }), - ); - } - - /** - * Asserts that the provided order's fill amount and order status - * are the expected values. - * @param order The order to verify for a correct state. - * @param expectedFilledAmount The amount that the order should - * have been filled. - * @param side The side that the provided order should be matched on. - */ - private async _assertOrderFilledAmountAsync( - order: SignedOrder, - expectedFilledAmount: BigNumber, - side: string, - ): Promise { - const orderInfo = await this._deployment.exchange.getOrderInfo(order).callAsync(); - // Check filled amount of order. - const actualFilledAmount = orderInfo.orderTakerAssetFilledAmount; - expect(actualFilledAmount, `${side} order final filled amount`).to.be.bignumber.equal(expectedFilledAmount); - // Check status of order. - const expectedStatus = expectedFilledAmount.isGreaterThanOrEqualTo(order.takerAssetAmount) - ? OrderStatus.FullyFilled - : OrderStatus.Fillable; - const actualStatus = orderInfo.orderStatus; - expect(actualStatus, `${side} order final status`).to.equal(expectedStatus); - } -} - -/** - * Converts a `Partial` to a `MatchTransferAmounts` by - * filling in missing fields with zero. - */ -function toFullMatchTransferAmounts(partial: Partial): MatchTransferAmounts { - // prettier-ignore - return { - leftMakerAssetSoldByLeftMakerAmount: - partial.leftMakerAssetSoldByLeftMakerAmount || - partial.leftMakerAssetBoughtByRightMakerAmount || - constants.ZERO_AMOUNT, - rightMakerAssetSoldByRightMakerAmount: - partial.rightMakerAssetSoldByRightMakerAmount || - partial.rightMakerAssetBoughtByLeftMakerAmount || - constants.ZERO_AMOUNT, - rightMakerAssetBoughtByLeftMakerAmount: - partial.rightMakerAssetBoughtByLeftMakerAmount || - partial.rightMakerAssetSoldByRightMakerAmount || - constants.ZERO_AMOUNT, - leftMakerAssetBoughtByRightMakerAmount: partial.leftMakerAssetBoughtByRightMakerAmount || - partial.leftMakerAssetSoldByLeftMakerAmount || - constants.ZERO_AMOUNT, - leftMakerFeeAssetPaidByLeftMakerAmount: - partial.leftMakerFeeAssetPaidByLeftMakerAmount || constants.ZERO_AMOUNT, - rightMakerFeeAssetPaidByRightMakerAmount: - partial.rightMakerFeeAssetPaidByRightMakerAmount || constants.ZERO_AMOUNT, - leftMakerAssetReceivedByTakerAmount: - partial.leftMakerAssetReceivedByTakerAmount || constants.ZERO_AMOUNT, - rightMakerAssetReceivedByTakerAmount: - partial.rightMakerAssetReceivedByTakerAmount || constants.ZERO_AMOUNT, - leftTakerFeeAssetPaidByTakerAmount: - partial.leftTakerFeeAssetPaidByTakerAmount || constants.ZERO_AMOUNT, - rightTakerFeeAssetPaidByTakerAmount: - partial.rightTakerFeeAssetPaidByTakerAmount || constants.ZERO_AMOUNT, - leftProtocolFeePaidByTakerInEthAmount: - partial.leftProtocolFeePaidByTakerInEthAmount || constants.ZERO_AMOUNT, - leftProtocolFeePaidByTakerInWethAmount: - partial.leftProtocolFeePaidByTakerInWethAmount || constants.ZERO_AMOUNT, - rightProtocolFeePaidByTakerInEthAmount: - partial.rightProtocolFeePaidByTakerInEthAmount || constants.ZERO_AMOUNT, - rightProtocolFeePaidByTakerInWethAmount: - partial.rightProtocolFeePaidByTakerInWethAmount || constants.ZERO_AMOUNT, - }; -} - -/** - * Checks values from the logs produced by Exchange.matchOrders against - * the expected transfer amounts. - * @param orders The matched orders. - * @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders. - */ -function assertFillEvents(expectedFills: FillEventArgs[], transactionReceipt: TransactionReceiptWithDecodedLogs): void { - // Extract the actual `Fill` events. - const actualFills = extractFillEventsfromReceipt(transactionReceipt); - expect(actualFills.length, 'wrong number of Fill events').to.be.equal(expectedFills.length); - // Validate event arguments. - const fillPairs = _.zip(expectedFills, actualFills) as Array<[FillEventArgs, FillEventArgs]>; - for (const [expected, actual] of fillPairs) { - const side = expected === expectedFills[0] ? 'Left' : 'Right'; - expect(actual.orderHash, `${side} order Fill event orderHash`).to.equal(expected.orderHash); - expect(actual.makerAddress, `${side} order Fill event makerAddress`).to.equal(expected.makerAddress); - expect(actual.takerAddress, `${side} order Fill event takerAddress`).to.equal(expected.takerAddress); - expect(actual.makerAssetFilledAmount, `${side} order Fill event makerAssetFilledAmount`).to.bignumber.equal( - expected.makerAssetFilledAmount, - ); - expect(actual.takerAssetFilledAmount, `${side} order Fill event takerAssetFilledAmount`).to.bignumber.equal( - expected.takerAssetFilledAmount, - ); - expect(actual.makerFeePaid, `${side} order Fill event makerFeePaid`).to.bignumber.equal(expected.makerFeePaid); - expect(actual.takerFeePaid, `${side} order Fill event takerFeePaid`).to.bignumber.equal(expected.takerFeePaid); - } -} - -/** - * Create a pair of `Fill` events for a simulated `matchOrder()`. - */ -function simulateFillEvents( - orders: MatchedOrders, - takerAddress: string, - transferAmounts: MatchTransferAmounts, -): [FillEventArgs, FillEventArgs] { - // prettier-ignore - return [ - // Left order Fill - { - orderHash: orderHashUtils.getOrderHashHex(orders.leftOrder), - makerAddress: orders.leftOrder.makerAddress, - takerAddress, - makerAssetFilledAmount: transferAmounts.leftMakerAssetSoldByLeftMakerAmount, - takerAssetFilledAmount: transferAmounts.rightMakerAssetBoughtByLeftMakerAmount, - makerFeePaid: transferAmounts.leftMakerFeeAssetPaidByLeftMakerAmount, - takerFeePaid: transferAmounts.leftTakerFeeAssetPaidByTakerAmount, - protocolFeePaid: transferAmounts.leftProtocolFeePaidByTakerInEthAmount.plus( - transferAmounts.leftProtocolFeePaidByTakerInWethAmount, - ), - }, - // Right order Fill - { - orderHash: orderHashUtils.getOrderHashHex(orders.rightOrder), - makerAddress: orders.rightOrder.makerAddress, - takerAddress, - makerAssetFilledAmount: transferAmounts.rightMakerAssetSoldByRightMakerAmount, - takerAssetFilledAmount: transferAmounts.leftMakerAssetBoughtByRightMakerAmount, - makerFeePaid: transferAmounts.rightMakerFeeAssetPaidByRightMakerAmount, - takerFeePaid: transferAmounts.rightTakerFeeAssetPaidByTakerAmount, - protocolFeePaid: transferAmounts.rightProtocolFeePaidByTakerInEthAmount.plus( - transferAmounts.rightProtocolFeePaidByTakerInWethAmount, - ), - }, - ]; -} - -/** - * Extract `Fill` events from a transaction receipt. - */ -function extractFillEventsfromReceipt(receipt: TransactionReceiptWithDecodedLogs): FillEventArgs[] { - interface RawFillEventArgs { - orderHash: string; - makerAddress: string; - takerAddress: string; - makerAssetFilledAmount: string; - takerAssetFilledAmount: string; - makerFeePaid: string; - takerFeePaid: string; - protocolFeePaid: string; - } - const actualFills = (_.filter(receipt.logs, ['event', 'Fill']) as any) as Array< - LogWithDecodedArgs - >; - // Convert RawFillEventArgs to FillEventArgs. - return actualFills.map(fill => ({ - orderHash: fill.args.orderHash, - makerAddress: fill.args.makerAddress, - takerAddress: fill.args.takerAddress, - makerAssetFilledAmount: new BigNumber(fill.args.makerAssetFilledAmount), - takerAssetFilledAmount: new BigNumber(fill.args.takerAssetFilledAmount), - makerFeePaid: new BigNumber(fill.args.makerFeePaid), - takerFeePaid: new BigNumber(fill.args.takerFeePaid), - protocolFeePaid: new BigNumber(fill.args.protocolFeePaid), - })); -} - -/** - * Gets the last match in a BatchMatchResults object. - * @param batchMatchResults The BatchMatchResults object. - * @return The last match of the results. - */ -function getLastMatch(batchMatchResults: BatchMatchResults): MatchResults { - return batchMatchResults.matches[batchMatchResults.matches.length - 1]; -} - -/** - * Add a new fill results object to a total fill results object destructively. - * @param total The total fill results that should be updated. - * @param fill The new fill results that should be used to accumulate. - */ -function addFillResults(total: FillEventArgs, fill: FillEventArgs): void { - // Ensure that the total and fill are compatibe fill events - expect(total.orderHash).to.be.eq(fill.orderHash); - expect(total.makerAddress).to.be.eq(fill.makerAddress); - expect(total.takerAddress).to.be.eq(fill.takerAddress); - - // Add the fill results together - total.makerAssetFilledAmount = total.makerAssetFilledAmount.plus(fill.makerAssetFilledAmount); - total.takerAssetFilledAmount = total.takerAssetFilledAmount.plus(fill.takerAssetFilledAmount); - total.makerFeePaid = total.makerFeePaid.plus(fill.makerFeePaid); - total.takerFeePaid = total.takerFeePaid.plus(fill.takerFeePaid); - total.protocolFeePaid = total.protocolFeePaid.plus(fill.protocolFeePaid); -} - -/** - * Converts a BatchMatchResults object to the associated value that correspondes to a value that could be - * returned by `batchMatchOrders` or `batchMatchOrdersWithMaximalFill`. - * @param results The results object to convert - * @return The associated object that can be compared to the return value of `batchMatchOrders` - */ -function convertToBatchMatchResults(results: BatchMatchResults): BatchMatchedFillResults { - // Initialize the results object - const batchMatchedFillResults: BatchMatchedFillResults = { - left: [], - right: [], - profitInLeftMakerAsset: constants.ZERO_AMOUNT, - profitInRightMakerAsset: constants.ZERO_AMOUNT, - }; - for (const match of results.matches) { - const leftSpread = match.fills[0].makerAssetFilledAmount.minus(match.fills[1].takerAssetFilledAmount); - // If the left maker spread is positive for match, update the profitInLeftMakerAsset - if (leftSpread.isGreaterThan(constants.ZERO_AMOUNT)) { - batchMatchedFillResults.profitInLeftMakerAsset = batchMatchedFillResults.profitInLeftMakerAsset.plus( - leftSpread, - ); - } - const rightSpread = match.fills[1].makerAssetFilledAmount.minus(match.fills[0].takerAssetFilledAmount); - // If the right maker spread is positive for match, update the profitInRightMakerAsset - if (rightSpread.isGreaterThan(constants.ZERO_AMOUNT)) { - batchMatchedFillResults.profitInRightMakerAsset = batchMatchedFillResults.profitInRightMakerAsset.plus( - rightSpread, - ); - } - } - for (const fill of results.leftFilledResults) { - batchMatchedFillResults.left.push(convertToFillResults(fill)); - } - for (const fill of results.rightFilledResults) { - batchMatchedFillResults.right.push(convertToFillResults(fill)); - } - return batchMatchedFillResults; -} - -/** - * Converts a MatchResults object to the associated value that correspondes to a value that could be - * returned by `matchOrders` or `matchOrdersWithMaximalFill`. - * @param results The results object to convert - * @return The associated object that can be compared to the return value of `matchOrders` - */ -function convertToMatchResults(result: MatchResults): MatchedFillResults { - // If the left spread is negative, set it to zero - let profitInLeftMakerAsset = result.fills[0].makerAssetFilledAmount.minus(result.fills[1].takerAssetFilledAmount); - if (profitInLeftMakerAsset.isLessThanOrEqualTo(constants.ZERO_AMOUNT)) { - profitInLeftMakerAsset = constants.ZERO_AMOUNT; - } - - // If the right spread is negative, set it to zero - let profitInRightMakerAsset = result.fills[1].makerAssetFilledAmount.minus(result.fills[0].takerAssetFilledAmount); - if (profitInRightMakerAsset.isLessThanOrEqualTo(constants.ZERO_AMOUNT)) { - profitInRightMakerAsset = constants.ZERO_AMOUNT; - } - - const matchedFillResults: MatchedFillResults = { - left: { - makerAssetFilledAmount: result.fills[0].makerAssetFilledAmount, - takerAssetFilledAmount: result.fills[0].takerAssetFilledAmount, - makerFeePaid: result.fills[0].makerFeePaid, - takerFeePaid: result.fills[0].takerFeePaid, - protocolFeePaid: result.fills[0].protocolFeePaid, - }, - right: { - makerAssetFilledAmount: result.fills[1].makerAssetFilledAmount, - takerAssetFilledAmount: result.fills[1].takerAssetFilledAmount, - makerFeePaid: result.fills[1].makerFeePaid, - takerFeePaid: result.fills[1].takerFeePaid, - protocolFeePaid: result.fills[1].protocolFeePaid, - }, - profitInLeftMakerAsset, - profitInRightMakerAsset, - }; - return matchedFillResults; -} - -/** - * Converts a fill event args object to the associated FillResults object. - * @param result The result to be converted to a FillResults object. - * @return The converted value. - */ -function convertToFillResults(result: FillEventArgs): FillResults { - const fillResults: FillResults = { - makerAssetFilledAmount: result.makerAssetFilledAmount, - takerAssetFilledAmount: result.takerAssetFilledAmount, - makerFeePaid: result.makerFeePaid, - takerFeePaid: result.takerFeePaid, - protocolFeePaid: result.protocolFeePaid, - }; - return fillResults; -} - -/** - * Creates an empty FillEventArgs object. - * @return The empty FillEventArgs object. - */ -function emptyFillEventArgs(): FillEventArgs { - const empty: FillEventArgs = { - orderHash: '', - makerAddress: '', - takerAddress: '', - makerAssetFilledAmount: constants.ZERO_AMOUNT, - takerAssetFilledAmount: constants.ZERO_AMOUNT, - makerFeePaid: constants.ZERO_AMOUNT, - takerFeePaid: constants.ZERO_AMOUNT, - protocolFeePaid: constants.ZERO_AMOUNT, - }; - return empty; -} -// tslint:disable-line:max-file-line-count diff --git a/contracts/integrations/test/exchange/match_orders_maximal_fill_test.ts b/contracts/integrations/test/exchange/match_orders_maximal_fill_test.ts deleted file mode 100644 index f11887a621..0000000000 --- a/contracts/integrations/test/exchange/match_orders_maximal_fill_test.ts +++ /dev/null @@ -1,1076 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, expect, orderHashUtils, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { OrderStatus } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { TokenIds } from '../framework/balances/types'; -import { DeploymentManager } from '../framework/deployment_manager'; - -import { MatchOrderTester, TestMatchOrdersArgs, testMatchOrdersAsync } from './match_order_tester'; - -const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions; - -blockchainTests.resets('matchOrdersWithMaximalFill integration tests', env => { - // The fee recipient addresses. - let feeRecipientLeft: Actor; - let feeRecipientRight: Actor; - - // The address that should be responsible for matching orders. - let matcher: Actor; - - // Market makers who have opposite maker and taker assets. - let makerLeft: Maker; - let makerRight: Maker; - - // The addresses of important assets for testing. - let makerAssetLeft: DummyERC20TokenContract; - let makerAssetRight: DummyERC20TokenContract; - let feeAsset: DummyERC20TokenContract; - - let makerAssetDataLeft: string; - let makerAssetDataRight: string; - let feeAssetData: string; - - let deployment: DeploymentManager; - let matchOrderTester: MatchOrderTester; - let leftId: BigNumber; - let rightId: BigNumber; - - let defaultMatchOrdersArgs: TestMatchOrdersArgs; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 3, - numErc721TokensToDeploy: 1, - numErc1155TokensToDeploy: 1, - }); - - makerAssetLeft = deployment.tokens.erc20[0]; - makerAssetRight = deployment.tokens.erc20[1]; - feeAsset = deployment.tokens.erc20[2]; - - // Create the fee recipient actors. - feeRecipientLeft = new Actor({ - name: 'left fee recipient', - deployment, - }); - feeRecipientRight = new Actor({ - name: 'right fee recipient', - deployment, - }); - - // Encode the asset data. - makerAssetDataLeft = encodeERC20AssetData(makerAssetLeft.address); - makerAssetDataRight = encodeERC20AssetData(makerAssetRight.address); - feeAssetData = encodeERC20AssetData(feeAsset.address); - - // Create two market makers with compatible orders for matching. - makerLeft = new Maker({ - name: 'left maker', - deployment, - orderConfig: { - makerAssetData: makerAssetDataLeft, - takerAssetData: makerAssetDataRight, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: feeRecipientLeft.address, - }, - }); - makerRight = new Maker({ - name: 'right maker', - deployment, - orderConfig: { - makerAssetData: makerAssetDataRight, - takerAssetData: makerAssetDataLeft, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: feeRecipientRight.address, - }, - }); - - // Create a matcher. - matcher = new Actor({ - name: 'matcher', - deployment, - }); - - // Configure the appropriate actors with initial balances. - await Promise.all([ - ...deployment.tokens.erc20.map(async token => makerLeft.configureERC20TokenAsync(token)), - ...deployment.tokens.erc20.map(async token => makerRight.configureERC20TokenAsync(token)), - makerLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - makerRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - matcher.configureERC20TokenAsync(feeAsset), - matcher.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - feeRecipientLeft.configureERC20TokenAsync(feeAsset), - feeRecipientLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - feeRecipientRight.configureERC20TokenAsync(feeAsset), - feeRecipientRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - ]); - - leftId = await makerLeft.configureERC1155TokenAsync(deployment.tokens.erc1155[0]); - [rightId] = await makerRight.configureERC721TokenAsync(deployment.tokens.erc721[0]); - - const tokenIds: TokenIds = { erc721: {}, erc1155: {} }; - tokenIds.erc1155[deployment.tokens.erc1155[0].address] = { fungible: [leftId], nonFungible: [] }; - tokenIds.erc721[deployment.tokens.erc721[0].address] = [rightId]; - - const blockchainBalanceStore = new BlockchainBalanceStore( - { - ...actorAddressesByName([feeRecipientLeft, feeRecipientRight, makerLeft, makerRight, matcher]), - stakingProxy: deployment.staking.stakingProxy.address, - }, - { - erc20: { - makerTokenLeft: deployment.tokens.erc20[0], - makerTokenRight: deployment.tokens.erc20[1], - feeToken: deployment.tokens.erc20[2], - weth: deployment.tokens.weth, - }, - erc721: { - nft: deployment.tokens.erc721[0], - }, - erc1155: { - fungible: deployment.tokens.erc1155[0], - }, - }, - tokenIds, - ); - - matchOrderTester = new MatchOrderTester(deployment, blockchainBalanceStore); - - defaultMatchOrdersArgs = { - env, - matchOrderTester, - makerLeft, - makerRight, - leftOrder: constants.STATIC_ORDER_PARAMS, - rightOrder: constants.STATIC_ORDER_PARAMS, - matcherAddress: matcher.address, - expectedTransferAmounts: {}, - withMaximalFill: true, - }; - }); - - after(async () => { - Actor.reset(); - }); - - describe('matchOrdersWithMaximalFill', () => { - // TODO: These tests should be converted to unit tests. - it('should transfer correct amounts when right order is fully filled and values pass isRoundingErrorCeil but fail isRoundingErrorFloor', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(17), - takerAssetAmount: new BigNumber(98), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(75), - takerAssetAmount: new BigNumber(13), - }); - // 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 = isRoundingErrorCeil(numerator, denominator, target); - expect(_isRoundingErrorCeil).to.be.true(); - const _isRoundingErrorFloor = isRoundingErrorFloor(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 - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(13), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('76.4705882352941176', 16), // 76.47% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(75), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('76.5306122448979591', 16), // 76.53% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - true, - ); - }); - - // TODO: These tests should be converted to unit tests. - it('should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil and isRoundingErrorFloor', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(15), - takerAssetAmount: new BigNumber(90), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(196), - takerAssetAmount: new BigNumber(28), - }); - - // Assert is rounding error floor - // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults - // The rounding error is derived computating how much the right maker will buy. - const numerator = signedOrderRight.makerAssetAmount; - const denominator = signedOrderRight.takerAssetAmount; - const target = signedOrderLeft.makerAssetAmount; - const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target); - expect(_isRoundingErrorCeil).to.be.false(); - const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target); - expect(_isRoundingErrorFloor).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 - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(15), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(90), - // Right Maker - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(15), - rightMakerAssetSoldByRightMakerAmount: new BigNumber(105), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('53.5714285714285714', 16), // 53.57% - // Taker - rightMakerAssetReceivedByTakerAmount: new BigNumber(15), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('53.5714285714285714', 16), // 53.57% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - true, - ); - }); - - it('should transfer correct amounts when left order is fully filled', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(16), - takerAssetAmount: new BigNumber(22), - }, - rightOrder: { - makerAssetAmount: new BigNumber(87), - takerAssetAmount: new BigNumber(48), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(16), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(22), - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(29), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(16), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('33.3333333333333333', 16), // 33.33% - // Taker - rightMakerAssetReceivedByTakerAmount: new BigNumber(7), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('33.3333333333333333', 16), // 33.33% - }, - }); - }); - - it('should fully fill both orders and pay out profit in both maker assets', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(7), - takerAssetAmount: new BigNumber(4), - }, - rightOrder: { - makerAssetAmount: new BigNumber(8), - takerAssetAmount: new BigNumber(6), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(7), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(4), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(8), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(6), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(1), - rightMakerAssetReceivedByTakerAmount: new BigNumber(4), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should give left maker a better sell price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(12), - takerAssetAmount: new BigNumber(97), - }, - rightOrder: { - makerAssetAmount: new BigNumber(89), - takerAssetAmount: new BigNumber(1), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(11), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('91.6666666666666666', 16), // 91.6% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(89), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(10), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('91.7525773195876288', 16), // 91.75% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should give right maker and right taker a favorable fee price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(16), - takerAssetAmount: new BigNumber(22), - }, - rightOrder: { - makerAssetAmount: new BigNumber(87), - takerAssetAmount: new BigNumber(48), - makerFee: new BigNumber(10000), - takerFee: new BigNumber(10000), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(16), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(22), - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(29), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(16), - rightMakerFeeAssetPaidByRightMakerAmount: new BigNumber(3333), // 3333.3 repeating rounded down to 3333 - // Taker - rightMakerAssetReceivedByTakerAmount: new BigNumber(7), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: new BigNumber(3333), // 3333.3 repeating rounded down to 3333 - }, - }); - }); - - it('should give left maker and left taker a favorable fee price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(12), - takerAssetAmount: new BigNumber(97), - makerFee: new BigNumber(10000), - takerFee: new BigNumber(10000), - }, - rightOrder: { - makerAssetAmount: new BigNumber(89), - takerAssetAmount: new BigNumber(1), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(11), - leftMakerFeeAssetPaidByLeftMakerAmount: new BigNumber(9166), // 9166.6 rounded down to 9166 - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(89), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(10), - leftTakerFeeAssetPaidByTakerAmount: new BigNumber(9175), // 9175.2 rounded down to 9175 - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should give left maker a better sell price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(12), - takerAssetAmount: new BigNumber(97), - }, - rightOrder: { - makerAssetAmount: new BigNumber(89), - takerAssetAmount: new BigNumber(1), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(11), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('91.6666666666666666', 16), // 91.6% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(89), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(10), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('91.7525773195876288', 16), // 91.75% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - 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 makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(50, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - - // Match orders - const expectedTransferAmounts = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(10, 16), // 10% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(10, 16), // 10% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - // prettier-ignore - const matchResults = await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - true, - ); - - // 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 makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(100, 18), - takerAssetAmount: toBaseUnitAmount(50, 18), - }); - - // Match the orders. - const expectedTransferAmounts2 = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(45, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(90, 16), // 90% (10% paid earlier) - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(90, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(90, 16), // 90% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(90, 16), // 90% (10% paid earlier) - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(90, 16), // 90% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight2, - leftOrderTakerAssetFilledAmount: matchResults.orders.leftOrderTakerAssetFilledAmount, - }, - expectedTransferAmounts2, - matcher.address, - DeploymentManager.protocolFee.times(2), - true, - ); - }); - - it('should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(1000), - takerAssetAmount: new BigNumber(1005), - }, - rightOrder: { - makerAssetAmount: new BigNumber(2126), - takerAssetAmount: new BigNumber(1063), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(1000), - rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(1005), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(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. - rightMakerAssetSoldByRightMakerAmount: new BigNumber(2000), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('94.0733772342427093', 16), // 94.07% - // Taker - rightMakerAssetReceivedByTakerAmount: new BigNumber(995), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('94.0733772342427093', 16), // 94.07% - }, - }); - }); - - it("should transfer the correct amounts when orders completely fill each other and taker doesn't take a profit", async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(5, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - 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 makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(50, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }); - - // Match orders - const expectedTransferAmounts = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(10, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - rightMakerAssetBoughtByLeftMakerAmount: toBaseUnitAmount(2, 18), - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(5, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(10, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(10, 16), // 10% - // Taker - rightMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(10, 16), // 10% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - const matchResults = await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - true, - ); - - // 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 makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(100, 18), - takerAssetAmount: toBaseUnitAmount(50, 18), - }); - - // Match signedOrderLeft2 with signedOrderRight - const expectedTransferAmounts2 = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(90, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(90, 16), // 90% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(45, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(90, 16), // 90% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(90, 16), // 96% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(90, 16), // 90% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft2, - rightOrder: signedOrderRight, - rightOrderTakerAssetFilledAmount: matchResults.orders.rightOrderTakerAssetFilledAmount, - }, - expectedTransferAmounts2, - matcher.address, - DeploymentManager.protocolFee.times(2), - true, - ); - }); - - it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - feeRecipientAddress: feeRecipientLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - feeRecipientAddress: feeRecipientLeft.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should transfer the correct amounts if taker == leftMaker', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: makerLeft.address, - }); - }); - - it('should transfer the correct amounts if taker == rightMaker', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: makerRight.address, - }); - }); - - it('should transfer the correct amounts if taker == leftFeeRecipient', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: feeRecipientLeft.address, - }); - }); - - it('should transfer the correct amounts if taker == rightFeeRecipient', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: feeRecipientRight.address, - }); - }); - - it('should transfer the correct amounts if leftMaker == leftFeeRecipient && rightMaker == rightFeeRecipient', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - feeRecipientAddress: makerLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - feeRecipientAddress: makerRight.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should transfer the correct amounts if leftMaker == leftFeeRecipient && leftMakerFeeAsset == leftTakerAsset', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - makerFeeAssetData: makerAssetDataRight, - feeRecipientAddress: makerLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should transfer the correct amounts if rightMaker == rightFeeRecipient && rightMakerFeeAsset == rightTakerAsset', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - makerFeeAssetData: makerAssetDataLeft, - feeRecipientAddress: makerRight.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer the correct amounts if rightMaker == rightFeeRecipient && rightTakerAsset == rightMakerFeeAsset - && leftMaker == leftFeeRecipient && leftTakerAsset == leftMakerFeeAsset`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - makerFeeAssetData: makerAssetDataRight, - feeRecipientAddress: makerLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - makerFeeAssetData: makerAssetDataRight, - feeRecipientAddress: makerRight.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should revert if left order is not fillable', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const orderHashHexLeft = orderHashUtils.getOrderHashHex(signedOrderLeft); - // Cancel left order - await makerLeft.cancelOrderAsync(signedOrderLeft); - - // Match orders - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHexLeft, OrderStatus.Cancelled); - const tx = deployment.exchange - .matchOrdersWithMaximalFill( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if right order is not fillable', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const orderHashHexRight = orderHashUtils.getOrderHashHex(signedOrderRight); - // Cancel right order - await makerRight.cancelOrderAsync(signedOrderRight); - - // Match orders - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHexRight, OrderStatus.Cancelled); - const tx = deployment.exchange - .matchOrdersWithMaximalFill( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if there is not a positive spread', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(1, 18), - takerAssetAmount: toBaseUnitAmount(200, 18), - }); - const orderHashHexLeft = orderHashUtils.getOrderHashHex(signedOrderLeft); - const orderHashHexRight = orderHashUtils.getOrderHashHex(signedOrderRight); - // Match orders - const expectedError = new ExchangeRevertErrors.NegativeSpreadError(orderHashHexLeft, orderHashHexRight); - const tx = deployment.exchange - .matchOrdersWithMaximalFill( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the left maker asset is not equal to the right taker asset ', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - takerAssetData: encodeERC20AssetData(makerAssetRight.address), - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - // 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 - const reconstructedOrderRight = { - ...signedOrderRight, - takerAssetData: signedOrderLeft.makerAssetData, - }; - const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrderRight.makerAddress, - signedOrderRight.signature, - ); - // Match orders - const tx = deployment.exchange - .matchOrdersWithMaximalFill( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the right maker asset is not equal to the left taker asset', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - takerAssetData: encodeERC20AssetData(makerAssetLeft.address), - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const reconstructedOrderRight = { - ...signedOrderRight, - makerAssetData: signedOrderLeft.takerAssetData, - }; - const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrderRight.makerAddress, - signedOrderRight.signature, - ); - // Match orders - const tx = deployment.exchange - .matchOrdersWithMaximalFill( - signedOrderLeft, - signedOrderRight, - signedOrderLeft.signature, - signedOrderRight.signature, - ) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/integrations/test/exchange/match_orders_test.ts b/contracts/integrations/test/exchange/match_orders_test.ts deleted file mode 100644 index c43a9b60cb..0000000000 --- a/contracts/integrations/test/exchange/match_orders_test.ts +++ /dev/null @@ -1,1083 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { blockchainTests, constants, expect, orderHashUtils, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { OrderStatus } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { TokenIds } from '../framework/balances/types'; -import { DeploymentManager } from '../framework/deployment_manager'; - -import { MatchOrderTester, TestMatchOrdersArgs, testMatchOrdersAsync } from './match_order_tester'; - -const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions; - -blockchainTests.resets('matchOrders integration tests', env => { - // The fee recipient addresses. - let feeRecipientLeft: Actor; - let feeRecipientRight: Actor; - - // The address that should be responsible for matching orders. - let matcher: Actor; - - // Market makers who have opposite maker and taker assets. - let makerLeft: Maker; - let makerRight: Maker; - - // The addresses of important assets for testing. - let makerAssetLeft: DummyERC20TokenContract; - let makerAssetRight: DummyERC20TokenContract; - let feeAsset: DummyERC20TokenContract; - - let makerAssetDataLeft: string; - let makerAssetDataRight: string; - let feeAssetData: string; - - let deployment: DeploymentManager; - let matchOrderTester: MatchOrderTester; - let leftId: BigNumber; - let rightId: BigNumber; - - let defaultMatchOrdersArgs: TestMatchOrdersArgs; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 3, - numErc721TokensToDeploy: 1, - numErc1155TokensToDeploy: 1, - }); - - makerAssetLeft = deployment.tokens.erc20[0]; - makerAssetRight = deployment.tokens.erc20[1]; - feeAsset = deployment.tokens.erc20[2]; - - // Create the fee recipient actors. - feeRecipientLeft = new Actor({ - name: 'left fee recipient', - deployment, - }); - feeRecipientRight = new Actor({ - name: 'right fee recipient', - deployment, - }); - - // Encode the asset data. - makerAssetDataLeft = encodeERC20AssetData(makerAssetLeft.address); - makerAssetDataRight = encodeERC20AssetData(makerAssetRight.address); - feeAssetData = encodeERC20AssetData(feeAsset.address); - - // Create two market makers with compatible orders for matching. - makerLeft = new Maker({ - name: 'left maker', - deployment, - orderConfig: { - makerAssetData: makerAssetDataLeft, - takerAssetData: makerAssetDataRight, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: feeRecipientLeft.address, - }, - }); - makerRight = new Maker({ - name: 'right maker', - deployment, - orderConfig: { - makerAssetData: makerAssetDataRight, - takerAssetData: makerAssetDataLeft, - makerFeeAssetData: feeAssetData, - takerFeeAssetData: feeAssetData, - feeRecipientAddress: feeRecipientRight.address, - }, - }); - - // Create a matcher. - matcher = new Actor({ - name: 'matcher', - deployment, - }); - - // Configure the appropriate actors with initial balances. - await Promise.all([ - ...deployment.tokens.erc20.map(async token => makerLeft.configureERC20TokenAsync(token)), - ...deployment.tokens.erc20.map(async token => makerRight.configureERC20TokenAsync(token)), - makerLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - makerRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - matcher.configureERC20TokenAsync(feeAsset), - matcher.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - feeRecipientLeft.configureERC20TokenAsync(feeAsset), - feeRecipientLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - feeRecipientRight.configureERC20TokenAsync(feeAsset), - feeRecipientRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address), - ]); - - leftId = await makerLeft.configureERC1155TokenAsync(deployment.tokens.erc1155[0]); - [rightId] = await makerRight.configureERC721TokenAsync(deployment.tokens.erc721[0]); - - const tokenIds: TokenIds = { erc721: {}, erc1155: {} }; - tokenIds.erc1155[deployment.tokens.erc1155[0].address] = { fungible: [leftId], nonFungible: [] }; - tokenIds.erc721[deployment.tokens.erc721[0].address] = [rightId]; - - const blockchainBalanceStore = new BlockchainBalanceStore( - { - ...actorAddressesByName([feeRecipientLeft, feeRecipientRight, makerLeft, makerRight, matcher]), - stakingProxy: deployment.staking.stakingProxy.address, - }, - { - erc20: { - makerTokenLeft: deployment.tokens.erc20[0], - makerTokenRight: deployment.tokens.erc20[1], - feeToken: deployment.tokens.erc20[2], - weth: deployment.tokens.weth, - }, - erc721: { - nft: deployment.tokens.erc721[0], - }, - erc1155: { - fungible: deployment.tokens.erc1155[0], - }, - }, - tokenIds, - ); - - matchOrderTester = new MatchOrderTester(deployment, blockchainBalanceStore); - - defaultMatchOrdersArgs = { - env, - matchOrderTester, - makerLeft, - makerRight, - leftOrder: constants.STATIC_ORDER_PARAMS, - rightOrder: constants.STATIC_ORDER_PARAMS, - matcherAddress: matcher.address, - expectedTransferAmounts: {}, - withMaximalFill: false, - }; - }); - - after(async () => { - Actor.reset(); - }); - - describe('matchOrders', () => { - // TODO: Should be refactored to use `testMatchOrdersAsync` or moved to unit tests - 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 makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(17), - takerAssetAmount: new BigNumber(98), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(75), - takerAssetAmount: new BigNumber(13), - }); - - // Assert is rounding error ceil & not rounding error floor - // These assertions are taken from MixinMatchOrders::calculateMatchedFillResults - // The rounding error is derived by computing how much the left maker will sell. - const numerator = signedOrderLeft.makerAssetAmount; - const denominator = signedOrderLeft.takerAssetAmount; - const target = signedOrderRight.makerAssetAmount; - const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target); - expect(_isRoundingErrorCeil).to.be.true(); - const _isRoundingErrorFloor = isRoundingErrorFloor(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 - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(13), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('76.4705882352941176', 16), // 76.47% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(75), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('76.5306122448979591', 16), // 76.53% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - }); - - // TODO: Should be refactored to use `testMatchOrdersAsync` or moved to unit tests - 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 makerLeft.signOrderAsync({ - makerAssetAmount: new BigNumber(15), - takerAssetAmount: new BigNumber(90), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: new BigNumber(97), - takerAssetAmount: new BigNumber(14), - }); - - // 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 = isRoundingErrorFloor(numerator, denominator, target); - expect(_isRoundingErrorFloor).to.be.true(); - const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target); - expect(_isRoundingErrorCeil).to.be.false(); - - // Match signedOrderLeft isRoundingErrorFloor 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 - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(15), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(13), - rightMakerAssetSoldByRightMakerAmount: new BigNumber(90), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('92.7835051546391752', 16), // 92.78% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(2), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('92.8571428571428571', 16), // 92.85% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - }); - - it('should give right maker a better buy price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(16), - takerAssetAmount: new BigNumber(22), - }, - rightOrder: { - makerAssetAmount: new BigNumber(83), - takerAssetAmount: new BigNumber(49), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(16), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(22), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(13), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('26.5060240963855421', 16), // 26.506% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(3), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('26.5306122448979591', 16), // 26.531% - }, - }); - }); - - it('should give left maker a better sell price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(12), - takerAssetAmount: new BigNumber(97), - }, - rightOrder: { - makerAssetAmount: new BigNumber(89), - takerAssetAmount: new BigNumber(1), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(11), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('91.6666666666666666', 16), // 91.6% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(89), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(10), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('91.7525773195876288', 16), // 91.75% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should give right maker and right taker a favorable fee price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(16), - takerAssetAmount: new BigNumber(22), - }, - rightOrder: { - makerAssetAmount: new BigNumber(83), - takerAssetAmount: new BigNumber(49), - makerFee: new BigNumber(10000), - takerFee: new BigNumber(10000), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(16), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(22), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(13), - rightMakerFeeAssetPaidByRightMakerAmount: new BigNumber(2650), // 2650.6 rounded down to 2650 - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(3), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: new BigNumber(2653), // 2653.1 rounded down to 2653 - }, - }); - }); - - it('should give left maker and left taker a favorable fee price when rounding', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(12), - takerAssetAmount: new BigNumber(97), - makerFee: new BigNumber(10000), - takerFee: new BigNumber(10000), - }, - rightOrder: { - makerAssetAmount: new BigNumber(89), - takerAssetAmount: new BigNumber(1), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(11), - leftMakerFeeAssetPaidByLeftMakerAmount: new BigNumber(9166), // 9166.6 rounded down to 9166 - // Right Maker - rightMakerAssetSoldByRightMakerAmount: new BigNumber(89), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(1), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(10), - leftTakerFeeAssetPaidByTakerAmount: new BigNumber(9175), // 9175.2 rounded down to 9175 - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer correct amounts when right order fill amount deviates - from amount derived by \`Exchange.fillOrder\``, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: new BigNumber(1000), - takerAssetAmount: new BigNumber(1005), - }, - rightOrder: { - makerAssetAmount: new BigNumber(2126), - takerAssetAmount: new BigNumber(1063), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: new BigNumber(1000), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(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. - rightMakerAssetSoldByRightMakerAmount: new BigNumber(1005), - leftMakerAssetBoughtByRightMakerAmount: new BigNumber(503), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('47.2718720602069614', 16), // 47.27% - // Taker - leftMakerAssetReceivedByTakerAmount: new BigNumber(497), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('47.3189087488240827', 16), // 47.31% - }, - }); - }); - - it('should transfer the correct amounts when orders completely fill each other', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer the correct amounts when orders completely fill each - other and taker doesn't take a profit`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(5, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer the correct amounts when left order is completely filled - and right order is partially filled`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(20, 18), - takerAssetAmount: toBaseUnitAmount(4, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% - }, - }); - }); - - it(`should transfer the correct amounts when right order is completely filled - and left order is partially filled`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(50, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(10, 16), // 10% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(10, 16), // 10% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - 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 makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(50, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - // Match orders - const expectedTransferAmounts = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(10, 16), // 10% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(10, 16), // 10% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - // prettier-ignore - const matchResults = await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - // 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 makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(100, 18), - takerAssetAmount: toBaseUnitAmount(50, 18), - }); - // Match signedOrderLeft with signedOrderRight2 - const expectedTransferAmounts2 = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(45, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(90, 16), // 90% (10% paid earlier) - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(90, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(90, 16), // 90% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(90, 16), // 90% (10% paid earlier) - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(90, 16), // 90% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight2, - leftOrderTakerAssetFilledAmount: matchResults.orders.leftOrderTakerAssetFilledAmount, - }, - expectedTransferAmounts2, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - }); - - 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 makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(50, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }); - - // Match orders - const expectedTransferAmounts = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(10, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(2, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(4, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(4, 16), // 4% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(6, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(4, 16), // 4% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - const matchResults = await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft, - rightOrder: signedOrderRight, - }, - expectedTransferAmounts, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - - // 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 makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(100, 18), - takerAssetAmount: toBaseUnitAmount(50, 18), - }); - - // Match signedOrderLeft2 with signedOrderRight - const expectedTransferAmounts2 = { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(96, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(96, 16), // 96% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(48, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(96, 16), // 96% - // Taker - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(96, 16), // 96% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(96, 16), // 96% - leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee, - }; - await matchOrderTester.matchOrdersAndAssertEffectsAsync( - { - leftOrder: signedOrderLeft2, - rightOrder: signedOrderRight, - rightOrderTakerAssetFilledAmount: matchResults.orders.rightOrderTakerAssetFilledAmount, - }, - expectedTransferAmounts2, - matcher.address, - DeploymentManager.protocolFee.times(2), - false, - ); - }); - - it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - feeRecipientAddress: feeRecipientLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - feeRecipientAddress: feeRecipientLeft.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should transfer the correct amounts if taker == leftMaker', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: makerLeft.address, - }); - }); - - it('should transfer the correct amounts if taker == rightMaker', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: makerRight.address, - }); - }); - - it('should transfer the correct amounts if taker == leftFeeRecipient', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: feeRecipientLeft.address, - }); - }); - - it('should transfer the correct amounts if taker == rightFeeRecipient', async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - matcherAddress: feeRecipientRight.address, - }); - }); - - it(`should transfer the correct amounts if leftMaker == leftFeeRecipient - && rightMaker == rightFeeRecipient`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - feeRecipientAddress: makerLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - feeRecipientAddress: makerRight.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer the correct amounts if leftMaker == leftFeeRecipient - && leftMakerFeeAsset == leftTakerAsset`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - makerFeeAssetData: makerAssetDataRight, - feeRecipientAddress: makerLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer the correct amounts if rightMaker == rightFeeRecipient - && rightMakerFeeAsset == rightTakerAsset`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - makerFeeAssetData: makerAssetDataLeft, - feeRecipientAddress: makerRight.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it(`should transfer the correct amounts if rightMaker == rightFeeRecipient && rightTakerAsset == rightMakerFeeAsset - && leftMaker == leftFeeRecipient && leftTakerAsset == leftMakerFeeAsset`, async () => { - await testMatchOrdersAsync({ - ...defaultMatchOrdersArgs, - leftOrder: { - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - makerFeeAssetData: makerAssetDataRight, - feeRecipientAddress: makerLeft.address, - }, - rightOrder: { - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - makerFeeAssetData: makerAssetDataRight, - feeRecipientAddress: makerRight.address, - }, - expectedTransferAmounts: { - // Left Maker - leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(5, 18), - leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Right Maker - rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(10, 18), - leftMakerAssetBoughtByRightMakerAmount: toBaseUnitAmount(2, 18), - rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% - // Taker - leftMakerAssetReceivedByTakerAmount: toBaseUnitAmount(3, 18), - leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% - }, - }); - }); - - it('should revert if left order is not fillable', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const orderHashHexLeft = orderHashUtils.getOrderHashHex(signedOrderLeft); - - // Cancel left order - await makerLeft.cancelOrderAsync(signedOrderLeft); - - // Match orders - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHexLeft, OrderStatus.Cancelled); - const tx = deployment.exchange - .matchOrders(signedOrderLeft, signedOrderRight, signedOrderLeft.signature, signedOrderRight.signature) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if right order is not fillable', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const orderHashHexRight = orderHashUtils.getOrderHashHex(signedOrderRight); - - // Cancel right order - await makerRight.cancelOrderAsync(signedOrderRight); - - // Match orders - const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHashHexRight, OrderStatus.Cancelled); - const tx = deployment.exchange - .matchOrders(signedOrderLeft, signedOrderRight, signedOrderLeft.signature, signedOrderRight.signature) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if there is not a positive spread', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(100, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(1, 18), - takerAssetAmount: toBaseUnitAmount(200, 18), - }); - const orderHashHexLeft = orderHashUtils.getOrderHashHex(signedOrderLeft); - const orderHashHexRight = orderHashUtils.getOrderHashHex(signedOrderRight); - - // Match orders - const expectedError = new ExchangeRevertErrors.NegativeSpreadError(orderHashHexLeft, orderHashHexRight); - const tx = deployment.exchange - .matchOrders(signedOrderLeft, signedOrderRight, signedOrderLeft.signature, signedOrderRight.signature) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the left maker asset is not equal to the right taker asset ', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - takerAssetData: encodeERC20AssetData(makerAssetRight.address), - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - - // 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 - const reconstructedOrderRight = { - ...signedOrderRight, - takerAssetData: signedOrderLeft.makerAssetData, - }; - const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrderRight.makerAddress, - signedOrderRight.signature, - ); - - // Match orders - const tx = deployment.exchange - .matchOrders(signedOrderLeft, signedOrderRight, signedOrderLeft.signature, signedOrderRight.signature) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if the right maker asset is not equal to the left taker asset', async () => { - // Create orders to match - const signedOrderLeft = await makerLeft.signOrderAsync({ - takerAssetData: encodeERC20AssetData(makerAssetLeft.address), - makerAssetAmount: toBaseUnitAmount(5, 18), - takerAssetAmount: toBaseUnitAmount(10, 18), - }); - const signedOrderRight = await makerRight.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(10, 18), - takerAssetAmount: toBaseUnitAmount(2, 18), - }); - const reconstructedOrderRight = { - ...signedOrderRight, - makerAssetData: signedOrderLeft.takerAssetData, - }; - const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrderRight); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadOrderSignature, - orderHashHex, - signedOrderRight.makerAddress, - signedOrderRight.signature, - ); - // Match orders - const tx = deployment.exchange - .matchOrders(signedOrderLeft, signedOrderRight, signedOrderLeft.signature, signedOrderRight.signature) - .awaitTransactionSuccessAsync({ from: matcher.address }); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); -// tslint:disable-line:max-file-line-count diff --git a/contracts/integrations/test/exchange/transaction_protocol_fee_test.ts b/contracts/integrations/test/exchange/transaction_protocol_fee_test.ts deleted file mode 100644 index 09c794a73e..0000000000 --- a/contracts/integrations/test/exchange/transaction_protocol_fee_test.ts +++ /dev/null @@ -1,499 +0,0 @@ -// tslint:disable: max-file-line-count -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { exchangeDataEncoder, ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { - blockchainTests, - constants, - describe, - ExchangeFunctionName, - expect, - orderHashUtils, - transactionHashUtils, -} from '@0x/contracts-test-utils'; -import { SignedOrder, SignedZeroExTransaction } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { FeeRecipient } from '../framework/actors/fee_recipient'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Transaction <> protocol fee integration tests', env => { - let deployment: DeploymentManager; - let balanceStore: BlockchainBalanceStore; - - let maker: Maker; - let feeRecipient: FeeRecipient; - let alice: Taker; - let bob: Taker; - let charlie: Taker; - let wethless: Taker; // Used to test revert scenarios - - let order: SignedOrder; // All orders will have the same fields, modulo salt and expiration time - let transactionA: SignedZeroExTransaction; // fillOrder transaction signed by Alice - let transactionB: SignedZeroExTransaction; // fillOrder transaction signed by Bob - let transactionC: SignedZeroExTransaction; // fillOrder transaction signed by Charlie - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 4, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const [makerToken, takerToken, makerFeeToken, takerFeeToken] = deployment.tokens.erc20; - - alice = new Taker({ name: 'Alice', deployment }); - bob = new Taker({ name: 'Bob', deployment }); - charlie = new Taker({ name: 'Charlie', deployment }); - wethless = new Taker({ name: 'wethless', deployment }); - feeRecipient = new FeeRecipient({ - name: 'Fee recipient', - deployment, - }); - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig: { - feeRecipientAddress: feeRecipient.address, - makerAssetData: encodeERC20AssetData(makerToken.address), - takerAssetData: encodeERC20AssetData(takerToken.address), - makerFeeAssetData: encodeERC20AssetData(makerFeeToken.address), - takerFeeAssetData: encodeERC20AssetData(takerFeeToken.address), - }, - }); - - for (const taker of [alice, bob, charlie]) { - await taker.configureERC20TokenAsync(takerToken); - await taker.configureERC20TokenAsync(takerFeeToken); - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - } - await wethless.configureERC20TokenAsync(takerToken); - await wethless.configureERC20TokenAsync(takerFeeToken); - await wethless.configureERC20TokenAsync( - deployment.tokens.weth, - deployment.staking.stakingProxy.address, - constants.ZERO_AMOUNT, // wethless taker has approved the proxy, but has no weth - ); - await maker.configureERC20TokenAsync(makerToken); - await maker.configureERC20TokenAsync(makerFeeToken); - - balanceStore = new BlockchainBalanceStore( - { - ...actorAddressesByName([alice, bob, charlie, maker, feeRecipient]), - StakingProxy: deployment.staking.stakingProxy.address, - }, - { erc20: { makerToken, takerToken, makerFeeToken, takerFeeToken, wETH: deployment.tokens.weth } }, - {}, - ); - await balanceStore.updateBalancesAsync(); - - order = await maker.signOrderAsync(); - let data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - transactionA = await alice.signTransactionAsync({ data }); - - order = await maker.signOrderAsync(); - data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - transactionB = await bob.signTransactionAsync({ data }); - - order = await maker.signOrderAsync(); - data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - transactionC = await charlie.signTransactionAsync({ data }); - }); - - after(async () => { - Actor.reset(); - }); - - const REFUND_AMOUNT = new BigNumber(1); - - function protocolFeeError( - failedOrder: SignedOrder, - failedTransaction: SignedZeroExTransaction, - ): ExchangeRevertErrors.TransactionExecutionError { - const nestedError = new ExchangeRevertErrors.PayProtocolFeeError( - orderHashUtils.getOrderHashHex(failedOrder), - DeploymentManager.protocolFee, - maker.address, - wethless.address, - '0x', - ).encode(); - return new ExchangeRevertErrors.TransactionExecutionError( - transactionHashUtils.getTransactionHashHex(failedTransaction), - nestedError, - ); - } - - describe('executeTransaction', () => { - const ETH_FEE_WITH_REFUND = DeploymentManager.protocolFee.plus(REFUND_AMOUNT); - - let expectedBalances: LocalBalanceStore; - beforeEach(async () => { - await balanceStore.updateBalancesAsync(); - expectedBalances = LocalBalanceStore.create(balanceStore); - }); - afterEach(async () => { - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - - describe('Simple', () => { - it('Alice executeTransaction => Alice fillOrder; protocol fee in ETH', async () => { - const txReceipt = await deployment.exchange - .executeTransaction(transactionA, transactionA.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND }); - expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, ETH_FEE_WITH_REFUND); - }); - it('Alice executeTransaction => Bob fillOrder; protocol fee in ETH', async () => { - const txReceipt = await deployment.exchange - .executeTransaction(transactionB, transactionB.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND }); - expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, ETH_FEE_WITH_REFUND); - }); - it('Alice executeTransaction => Alice fillOrder; protocol fee in wETH', async () => { - const txReceipt = await deployment.exchange - .executeTransaction(transactionA, transactionA.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, REFUND_AMOUNT); - }); - it('Alice executeTransaction => Bob fillOrder; protocol fee in wETH', async () => { - const txReceipt = await deployment.exchange - .executeTransaction(transactionB, transactionB.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, REFUND_AMOUNT); - }); - it('Alice executeTransaction => wETH-less taker fillOrder; reverts because protocol fee cannot be paid', async () => { - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const transaction = await wethless.signTransactionAsync({ data }); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - return expect(tx).to.revertWith(protocolFeeError(order, transaction)); - }); - it('Alice executeTransaction => Alice batchFillOrders; mixed protocol fees', async () => { - const orders = [order, await maker.signOrderAsync()]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData( - ExchangeFunctionName.BatchFillOrders, - orders, - ); - const batchFillTransaction = await alice.signTransactionAsync({ data }); - const txReceipt = await deployment.exchange - .executeTransaction(batchFillTransaction, batchFillTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND }); - expectedBalances.simulateFills(orders, alice.address, txReceipt, deployment, ETH_FEE_WITH_REFUND); - }); - it('Alice executeTransaction => Bob batchFillOrders; mixed protocol fees', async () => { - const orders = [order, await maker.signOrderAsync()]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData( - ExchangeFunctionName.BatchFillOrders, - orders, - ); - const batchFillTransaction = await bob.signTransactionAsync({ data }); - const txReceipt = await deployment.exchange - .executeTransaction(batchFillTransaction, batchFillTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND }); - expectedBalances.simulateFills(orders, bob.address, txReceipt, deployment, ETH_FEE_WITH_REFUND); - }); - }); - describe('Nested', () => { - it('Alice executeTransaction => Alice executeTransaction => Alice fillOrder; protocol fee in ETH', async () => { - const recursiveData = deployment.exchange - .executeTransaction(transactionA, transactionA.signature) - .getABIEncodedTransactionData(); - const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData }); - const txReceipt = await deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND }); - expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, ETH_FEE_WITH_REFUND); - }); - it('Alice executeTransaction => Alice executeTransaction => Bob fillOrder; protocol fee in ETH', async () => { - const recursiveData = deployment.exchange - .executeTransaction(transactionB, transactionB.signature) - .getABIEncodedTransactionData(); - const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData }); - const txReceipt = await deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND }); - expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, ETH_FEE_WITH_REFUND); - }); - it('Alice executeTransaction => Alice executeTransaction => Alice fillOrder; protocol fee in wETH', async () => { - const recursiveData = deployment.exchange - .executeTransaction(transactionA, transactionA.signature) - .getABIEncodedTransactionData(); - const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData }); - const txReceipt = await deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, REFUND_AMOUNT); - }); - it('Alice executeTransaction => Alice executeTransaction => Bob fillOrder; protocol fee in wETH', async () => { - const recursiveData = deployment.exchange - .executeTransaction(transactionB, transactionB.signature) - .getABIEncodedTransactionData(); - const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData }); - const txReceipt = await deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, REFUND_AMOUNT); - }); - it('Alice executeTransaction => Alice executeTransaction => wETH-less taker fillOrder; reverts because protocol fee cannot be paid', async () => { - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const transaction = await wethless.signTransactionAsync({ data }); - const recursiveData = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .getABIEncodedTransactionData(); - const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData }); - const tx = deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHashUtils.getTransactionHashHex(recursiveTransaction), - protocolFeeError(order, transaction).encode(), - ); - return expect(tx).to.revertWith(expectedError); - }); - }); - }); - describe('batchExecuteTransactions', () => { - let expectedBalances: LocalBalanceStore; - beforeEach(async () => { - await balanceStore.updateBalancesAsync(); - expectedBalances = LocalBalanceStore.create(balanceStore); - }); - afterEach(async () => { - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - - describe('Simple', () => { - // All orders' protocol fees paid in ETH by sender - const ETH_FEES_WITH_REFUND = DeploymentManager.protocolFee.times(3).plus(REFUND_AMOUNT); - // First order's protocol fee paid in ETH by sender, the other two paid in WETH by their respective takers - const MIXED_FEES_WITH_REFUND = DeploymentManager.protocolFee.times(1).plus(REFUND_AMOUNT); - - it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder; protocol fees in ETH', async () => { - const transactions = [transactionA, transactionB, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [alice.address, bob.address, charlie.address], - txReceipt, - deployment, - ETH_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Alice fillOrder, Charlie fillOrder; protocol fees in ETH', async () => { - const transactions = [transactionB, transactionA, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [bob.address, alice.address, charlie.address], - txReceipt, - deployment, - ETH_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, Alice fillOrder; protocol fees in ETH', async () => { - const transactions = [transactionB, transactionC, transactionA]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [bob.address, charlie.address, alice.address], - txReceipt, - deployment, - ETH_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder; protocol fees in wETH', async () => { - const transactions = [transactionA, transactionB, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills( - [order, order, order], - [alice.address, bob.address, charlie.address], - txReceipt, - deployment, - REFUND_AMOUNT, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Alice fillOrder, Charlie fillOrder; protocol fees in wETH', async () => { - const transactions = [transactionB, transactionA, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills( - [order, order, order], - [bob.address, alice.address, charlie.address], - txReceipt, - deployment, - REFUND_AMOUNT, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, Alice fillOrder; protocol fees in wETH', async () => { - const transactions = [transactionB, transactionC, transactionA]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT }); - expectedBalances.simulateFills( - [order, order, order], - [bob.address, charlie.address, alice.address], - txReceipt, - deployment, - REFUND_AMOUNT, - ); - }); - it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder; mixed protocol fees', async () => { - const transactions = [transactionA, transactionB, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [alice.address, bob.address, charlie.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Alice fillOrder, Charlie fillOrder; mixed protocol fees', async () => { - const transactions = [transactionB, transactionA, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [bob.address, alice.address, charlie.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, Alice fillOrder; mixed protocol fees', async () => { - const transactions = [transactionB, transactionC, transactionA]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [bob.address, charlie.address, alice.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, wETH-less taker fillOrder; reverts because protocol fee cannot be paid', async () => { - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const failTransaction = await wethless.signTransactionAsync({ data }); - const transactions = [transactionA, transactionB, failTransaction]; - const signatures = transactions.map(transaction => transaction.signature); - const tx = deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - return expect(tx).to.revertWith(protocolFeeError(order, failTransaction)); - }); - }); - describe('Nested', () => { - // First two orders' protocol fees paid in ETH by sender, the others paid in WETH by their respective takers - const MIXED_FEES_WITH_REFUND = DeploymentManager.protocolFee.times(2.5); - - // Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder - let nestedTransaction: SignedZeroExTransaction; - // Second fillOrder transaction signed by Bob - let transactionB2: SignedZeroExTransaction; - // Second fillOrder transaction signed by Charlie - let transactionC2: SignedZeroExTransaction; - - before(async () => { - let newOrder = await maker.signOrderAsync(); - let data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [newOrder]); - transactionB2 = await bob.signTransactionAsync({ data }); - - newOrder = await maker.signOrderAsync(); - data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [newOrder]); - transactionC2 = await charlie.signTransactionAsync({ data }); - - const transactions = [transactionA, transactionB, transactionC]; - const signatures = transactions.map(tx => tx.signature); - const recursiveData = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .getABIEncodedTransactionData(); - nestedTransaction = await alice.signTransactionAsync({ data: recursiveData }); - }); - - it('Alice executeTransaction => nested batchExecuteTransactions; mixed protocol fees', async () => { - const txReceipt = await deployment.exchange - .executeTransaction(nestedTransaction, nestedTransaction.signature) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order], - [alice.address, bob.address, charlie.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => nested batchExecuteTransactions, Bob fillOrder, Charlie fillOrder; mixed protocol fees', async () => { - const transactions = [nestedTransaction, transactionB2, transactionC2]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order, order, order], - [alice.address, bob.address, charlie.address, bob.address, charlie.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, nested batchExecuteTransactions, Charlie fillOrder; mixed protocol fees', async () => { - const transactions = [transactionB2, nestedTransaction, transactionC2]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order, order, order], - [bob.address, alice.address, bob.address, charlie.address, charlie.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, nested batchExecuteTransactions; mixed protocol fees', async () => { - const transactions = [transactionB2, transactionC2, nestedTransaction]; - const signatures = transactions.map(tx => tx.signature); - const txReceipt = await deployment.exchange - .batchExecuteTransactions(transactions, signatures) - .awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND }); - expectedBalances.simulateFills( - [order, order, order, order, order], - [bob.address, charlie.address, alice.address, bob.address, charlie.address], - txReceipt, - deployment, - MIXED_FEES_WITH_REFUND, - ); - }); - }); - }); -}); diff --git a/contracts/integrations/test/exchange/transaction_test.ts b/contracts/integrations/test/exchange/transaction_test.ts deleted file mode 100644 index 749ea812e3..0000000000 --- a/contracts/integrations/test/exchange/transaction_test.ts +++ /dev/null @@ -1,806 +0,0 @@ -// tslint:disable: max-file-line-count -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { - ExchangeCancelEventArgs, - ExchangeCancelUpToEventArgs, - exchangeDataEncoder, - ExchangeEvents, - ExchangeFillEventArgs, - ExchangeRevertErrors, - ExchangeSignatureValidatorApprovalEventArgs, - ExchangeTransactionExecutionEventArgs, -} from '@0x/contracts-exchange'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - blockchainTests, - constants, - describe, - ExchangeFunctionName, - expect, - getLatestBlockTimestampAsync, - orderHashUtils, - randomAddress, - transactionHashUtils, - verifyEventsFromLogs, -} from '@0x/contracts-test-utils'; -import { FillResults, OrderStatus, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; - -import { Actor } from '../framework/actors/base'; -import { FeeRecipient } from '../framework/actors/fee_recipient'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { DeploymentManager } from '../framework/deployment_manager'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Transaction integration tests', env => { - let deployment: DeploymentManager; - - let maker: Maker; - let takers: [Taker, Taker]; - let feeRecipient: FeeRecipient; - let sender: Actor; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 4, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const [makerToken, takerToken, makerFeeToken, takerFeeToken] = deployment.tokens.erc20; - - takers = [new Taker({ name: 'Taker 1', deployment }), new Taker({ name: 'Taker 2', deployment })]; - feeRecipient = new FeeRecipient({ - name: 'Fee recipient', - deployment, - }); - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig: { - feeRecipientAddress: feeRecipient.address, - makerAssetData: encodeERC20AssetData(makerToken.address), - takerAssetData: encodeERC20AssetData(takerToken.address), - makerFeeAssetData: encodeERC20AssetData(makerFeeToken.address), - takerFeeAssetData: encodeERC20AssetData(takerFeeToken.address), - }, - }); - sender = new Actor({ name: 'Transaction sender', deployment }); - - for (const taker of takers) { - await taker.configureERC20TokenAsync(takerToken); - await taker.configureERC20TokenAsync(takerFeeToken); - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - } - await maker.configureERC20TokenAsync(makerToken); - await maker.configureERC20TokenAsync(makerFeeToken); - }); - - after(async () => { - Actor.reset(); - }); - - function defaultFillEvent(order: SignedOrder): ExchangeFillEventArgs { - return { - makerAddress: maker.address, - feeRecipientAddress: feeRecipient.address, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData, - makerFeeAssetData: order.makerFeeAssetData, - takerFeeAssetData: order.takerFeeAssetData, - orderHash: orderHashUtils.getOrderHashHex(order), - takerAddress: takers[0].address, - senderAddress: sender.address, - makerAssetFilledAmount: order.makerAssetAmount, - takerAssetFilledAmount: order.takerAssetAmount, - makerFeePaid: order.makerFee, - takerFeePaid: order.takerFee, - protocolFeePaid: DeploymentManager.protocolFee, - }; - } - - function defaultCancelEvent(order: SignedOrder): ExchangeCancelEventArgs { - return { - makerAddress: maker.address, - feeRecipientAddress: feeRecipient.address, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData, - senderAddress: sender.address, - orderHash: orderHashUtils.getOrderHashHex(order), - }; - } - - describe('executeTransaction', () => { - describe('general functionality', () => { - it('should log the correct transactionHash if successfully executed', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction) }], - ExchangeEvents.TransactionExecution, - ); - }); - it('should revert if the transaction is expired', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const currentTimestamp = await getLatestBlockTimestampAsync(); - const transaction = await takers[0].signTransactionAsync({ - data, - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.Expired, - transactionHashHex, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if the actual gasPrice is greater than expected', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const actualGasPrice = transaction.gasPrice.plus(1); - const expectedError = new ExchangeRevertErrors.TransactionGasPriceError( - transactionHashHex, - actualGasPrice, - transaction.gasPrice, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ gasPrice: actualGasPrice, from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if the actual gasPrice is less than expected', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const actualGasPrice = transaction.gasPrice.minus(1); - const expectedError = new ExchangeRevertErrors.TransactionGasPriceError( - transactionHashHex, - actualGasPrice, - transaction.gasPrice, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ gasPrice: actualGasPrice, from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - }); - describe('fill methods', () => { - for (const fnName of [ - ...constants.SINGLE_FILL_FN_NAMES, - ...constants.BATCH_FILL_FN_NAMES, - ...constants.MARKET_FILL_FN_NAMES, - ]) { - it(`${fnName} should revert if signature is invalid and not called by signer`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - transaction.signature = hexUtils.concat(hexUtils.random(65), SignatureType.EthSign); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.BadTransactionSignature, - transactionHashHex, - transaction.signerAddress, - transaction.signature, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it(`${fnName} should be successful if signed by taker and called by sender`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [defaultFillEvent(order)], - ExchangeEvents.Fill, - ); - }); - it(`${fnName} should be successful if called by taker without a transaction signature`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, constants.NULL_BYTES) - .awaitTransactionSuccessAsync({ from: takers[0].address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [{ ...defaultFillEvent(order), senderAddress: takers[0].address }], - ExchangeEvents.Fill, - ); - }); - it(`${fnName} should return the correct data if successful`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const returnData = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .callAsync({ from: sender.address }); - - const decodedReturnData = deployment.exchange.getABIDecodedReturnData(fnName, returnData); - const fillResults = Array.isArray(decodedReturnData) ? decodedReturnData[0] : decodedReturnData; - - expect(fillResults).to.deep.equal( - ReferenceFunctions.calculateFillResults( - order, - order.takerAssetAmount, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - ), - ); - }); - it(`${fnName} should revert if transaction has already been executed`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted, - transactionHashHex, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it(`${fnName} should revert and rethrow error if executeTransaction is called recursively with a signature`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const recursiveData = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .getABIEncodedTransactionData(); - const recursiveTransaction = await takers[0].signTransactionAsync({ - data: recursiveData, - }); - const recursiveTransactionHashHex = transactionHashUtils.getTransactionHashHex( - recursiveTransaction, - ); - const noReentrancyError = new ExchangeRevertErrors.TransactionInvalidContextError( - transactionHashHex, - transaction.signerAddress, - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - recursiveTransactionHashHex, - noReentrancyError, - ); - const tx = deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it(`${fnName} should be successful if executeTransaction is called recursively by taker without a signature`, async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const recursiveData = deployment.exchange - .executeTransaction(transaction, constants.NULL_BYTES) - .getABIEncodedTransactionData(); - const recursiveTransaction = await takers[0].signTransactionAsync({ - data: recursiveData, - }); - const transactionReceipt = await deployment.exchange - .executeTransaction(recursiveTransaction, recursiveTransaction.signature) - .awaitTransactionSuccessAsync({ from: takers[0].address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [{ ...defaultFillEvent(order), senderAddress: takers[0].address }], - ExchangeEvents.Fill, - ); - }); - if ( - [ - ExchangeFunctionName.FillOrderNoThrow, - ExchangeFunctionName.BatchFillOrdersNoThrow, - ExchangeFunctionName.MarketBuyOrdersNoThrow, - ExchangeFunctionName.MarketSellOrdersNoThrow, - ExchangeFunctionName.MarketBuyOrdersFillOrKill, - ExchangeFunctionName.MarketSellOrdersFillOrKill, - ].indexOf(fnName) === -1 - ) { - it(`${fnName} should revert and rethrow error if the underlying function reverts`, async () => { - const order = await maker.signOrderAsync(); - order.signature = constants.NULL_BYTES; - const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const nestedError = new ExchangeRevertErrors.SignatureError( - ExchangeRevertErrors.SignatureErrorCode.InvalidLength, - orderHashUtils.getOrderHashHex(order), - order.makerAddress, - order.signature, - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHashHex, - nestedError, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - } - } - }); - describe('cancelOrder', () => { - it('should revert if not signed by or called by maker', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const nestedError = new ExchangeRevertErrors.ExchangeInvalidContextError( - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker, - orderHashUtils.getOrderHashHex(order), - takers[0].address, - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHashHex, - nestedError, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it('should be successful if signed by maker and called by sender', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]); - const transaction = await maker.signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [defaultCancelEvent(order)], - ExchangeEvents.Cancel, - ); - }); - it('should be successful if called by maker without a signature', async () => { - const order = await maker.signOrderAsync(); - const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]); - const transaction = await maker.signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, constants.NULL_BYTES) - .awaitTransactionSuccessAsync({ from: maker.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [{ ...defaultCancelEvent(order), senderAddress: maker.address }], - ExchangeEvents.Cancel, - ); - }); - }); - describe('batchCancelOrders', () => { - it('should revert if not signed by or called by maker', async () => { - const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData( - ExchangeFunctionName.BatchCancelOrders, - orders, - ); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction); - const nestedError = new ExchangeRevertErrors.ExchangeInvalidContextError( - ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker, - orderHashUtils.getOrderHashHex(orders[0]), - takers[0].address, - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHashHex, - nestedError, - ); - const tx = deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - return expect(tx).to.revertWith(expectedError); - }); - it('should be successful if signed by maker and called by sender', async () => { - const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData( - ExchangeFunctionName.BatchCancelOrders, - orders, - ); - const transaction = await maker.signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [defaultCancelEvent(orders[0]), defaultCancelEvent(orders[1])], - ExchangeEvents.Cancel, - ); - }); - it('should be successful if called by maker without a signature', async () => { - const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()]; - const data = exchangeDataEncoder.encodeOrdersToExchangeData( - ExchangeFunctionName.BatchCancelOrders, - orders, - ); - const transaction = await maker.signTransactionAsync({ data }); - transaction.signature = constants.NULL_BYTES; - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: maker.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { ...defaultCancelEvent(orders[0]), senderAddress: maker.address }, - { ...defaultCancelEvent(orders[1]), senderAddress: maker.address }, - ], - ExchangeEvents.Cancel, - ); - }); - }); - describe('cancelOrdersUpTo', () => { - it('should be successful if signed by maker and called by sender', async () => { - const targetEpoch = constants.ZERO_AMOUNT; - const data = deployment.exchange.cancelOrdersUpTo(targetEpoch).getABIEncodedTransactionData(); - const transaction = await maker.signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { - makerAddress: maker.address, - orderSenderAddress: sender.address, - orderEpoch: targetEpoch.plus(1), - }, - ], - ExchangeEvents.CancelUpTo, - ); - }); - it('should be successful if called by maker without a signature', async () => { - const targetEpoch = constants.ZERO_AMOUNT; - const data = deployment.exchange.cancelOrdersUpTo(targetEpoch).getABIEncodedTransactionData(); - const transaction = await maker.signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, constants.NULL_BYTES) - .awaitTransactionSuccessAsync({ from: maker.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { - makerAddress: maker.address, - orderSenderAddress: constants.NULL_ADDRESS, - orderEpoch: targetEpoch.plus(1), - }, - ], - ExchangeEvents.CancelUpTo, - ); - }); - }); - describe('preSign', () => { - it('should preSign a hash for the signer', async () => { - const order = await maker.signOrderAsync(); - const orderHash = orderHashUtils.getOrderHashHex(order); - const data = deployment.exchange.preSign(orderHash).getABIEncodedTransactionData(); - const transaction = await takers[0].signTransactionAsync({ data }); - let isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync(); - expect(isPreSigned).to.be.eq(false); - await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync(); - expect(isPreSigned).to.be.eq(true); - }); - it('should preSign a hash for the caller if called without a signature', async () => { - const order = await maker.signOrderAsync(); - const orderHash = orderHashUtils.getOrderHashHex(order); - const data = deployment.exchange.preSign(orderHash).getABIEncodedTransactionData(); - const transaction = await takers[0].signTransactionAsync({ data }); - let isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync(); - expect(isPreSigned).to.be.eq(false); - await deployment.exchange - .executeTransaction(transaction, constants.NULL_BYTES) - .awaitTransactionSuccessAsync({ from: takers[0].address }); - isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync(); - expect(isPreSigned).to.be.eq(true); - }); - }); - describe('setSignatureValidatorApproval', () => { - it('should approve a validator for the signer', async () => { - const validatorAddress = randomAddress(); - const shouldApprove = true; - const data = deployment.exchange - .setSignatureValidatorApproval(validatorAddress, shouldApprove) - .getABIEncodedTransactionData(); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, transaction.signature) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { - signerAddress: takers[0].address, - validatorAddress, - isApproved: shouldApprove, - }, - ], - ExchangeEvents.SignatureValidatorApproval, - ); - }); - it('should approve a validator for the caller if called with no signature', async () => { - const validatorAddress = randomAddress(); - const shouldApprove = true; - const data = deployment.exchange - .setSignatureValidatorApproval(validatorAddress, shouldApprove) - .getABIEncodedTransactionData(); - const transaction = await takers[0].signTransactionAsync({ data }); - const transactionReceipt = await deployment.exchange - .executeTransaction(transaction, constants.NULL_BYTES) - .awaitTransactionSuccessAsync({ from: takers[0].address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { - signerAddress: takers[0].address, - validatorAddress, - isApproved: shouldApprove, - }, - ], - ExchangeEvents.SignatureValidatorApproval, - ); - }); - }); - }); - describe('batchExecuteTransactions', () => { - it('should successfully call fillOrder via 2 transactions with different taker signatures', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await takers[1].signTransactionAsync({ data: data2 }); - const transactionReceipt = await deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .awaitTransactionSuccessAsync({ from: sender.address }); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) }, - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) }, - ], - ExchangeEvents.TransactionExecution, - ); - verifyEventsFromLogs( - transactionReceipt.logs, - [defaultFillEvent(order1), { ...defaultFillEvent(order2), takerAddress: takers[1].address }], - ExchangeEvents.Fill, - ); - }); - it('should successfully call fillOrder via 2 transactions when called by taker with no signatures', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await takers[0].signTransactionAsync({ data: data2 }); - transaction1.signature = constants.NULL_BYTES; - transaction2.signature = constants.NULL_BYTES; - const transactionReceipt = await deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .awaitTransactionSuccessAsync({ from: takers[0].address }); - - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) }, - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) }, - ], - ExchangeEvents.TransactionExecution, - ); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { ...defaultFillEvent(order1), senderAddress: takers[0].address }, - { ...defaultFillEvent(order2), senderAddress: takers[0].address }, - ], - ExchangeEvents.Fill, - ); - }); - it('should successfully call fillOrder via 2 transactions when one is signed by taker1 and executeTransaction is called by taker2', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await takers[1].signTransactionAsync({ data: data2 }); - const transactionReceipt = await deployment.exchange - .batchExecuteTransactions([transaction1, transaction2], [transaction1.signature, constants.NULL_BYTES]) - .awaitTransactionSuccessAsync({ from: takers[1].address }); - - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) }, - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) }, - ], - ExchangeEvents.TransactionExecution, - ); - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { ...defaultFillEvent(order1), senderAddress: takers[1].address }, - { - ...defaultFillEvent(order2), - takerAddress: takers[1].address, - senderAddress: takers[1].address, - }, - ], - ExchangeEvents.Fill, - ); - }); - it('should return the correct data for 2 different fillOrder calls', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await takers[1].signTransactionAsync({ data: data2 }); - const returnData = await deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .callAsync({ from: sender.address }); - const fillResults1: FillResults = deployment.exchange.getABIDecodedReturnData('fillOrder', returnData[0]); - const fillResults2: FillResults = deployment.exchange.getABIDecodedReturnData('fillOrder', returnData[1]); - expect(fillResults1).to.deep.equal( - ReferenceFunctions.calculateFillResults( - order1, - order1.takerAssetAmount, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - ), - ); - expect(fillResults2).to.deep.equal( - ReferenceFunctions.calculateFillResults( - order2, - order2.takerAssetAmount, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - ), - ); - }); - it('should successfully call fillOrder and cancelOrder via 2 transactions', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order2]); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await maker.signTransactionAsync({ data: data2 }); - const transactionReceipt = await deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .awaitTransactionSuccessAsync({ from: sender.address }); - - verifyEventsFromLogs( - transactionReceipt.logs, - [ - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) }, - { transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) }, - ], - ExchangeEvents.TransactionExecution, - ); - - const fillLogIndex = transactionReceipt.logs.findIndex( - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - const cancelLogIndex = transactionReceipt.logs.findIndex( - log => (log as LogWithDecodedArgs).event === 'Cancel', - ); - expect(cancelLogIndex).to.greaterThan(fillLogIndex); - - verifyEventsFromLogs( - transactionReceipt.logs, - [defaultFillEvent(order1)], - ExchangeEvents.Fill, - ); - verifyEventsFromLogs( - transactionReceipt.logs, - [defaultCancelEvent(order2)], - ExchangeEvents.Cancel, - ); - }); - it('should return the correct data for a fillOrder and cancelOrder call', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order2]); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await maker.signTransactionAsync({ data: data2 }); - const returnData = await deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .callAsync({ from: sender.address }); - const fillResults: FillResults = deployment.exchange.getABIDecodedReturnData('fillOrder', returnData[0]); - expect(fillResults).to.deep.equal( - ReferenceFunctions.calculateFillResults( - order1, - order1.takerAssetAmount, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - ), - ); - expect(returnData[1]).to.eq(constants.NULL_BYTES); - }); - it('should revert if a single transaction reverts', async () => { - const order = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]); - const transaction1 = await maker.signTransactionAsync({ data: data1 }); - const transaction2 = await takers[0].signTransactionAsync({ data: data2 }); - const tx = deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .awaitTransactionSuccessAsync({ from: sender.address }); - const nestedError = new ExchangeRevertErrors.OrderStatusError( - orderHashUtils.getOrderHashHex(order), - OrderStatus.Cancelled, - ).encode(); - const expectedError = new ExchangeRevertErrors.TransactionExecutionError( - transactionHashUtils.getTransactionHashHex(transaction2), - nestedError, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if a single transaction is expired', async () => { - const order1 = await maker.signOrderAsync(); - const order2 = await maker.signOrderAsync(); - const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]); - const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]); - const currentTimestamp = await getLatestBlockTimestampAsync(); - const transaction1 = await takers[0].signTransactionAsync({ data: data1 }); - const transaction2 = await takers[1].signTransactionAsync({ - data: data2, - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const tx = deployment.exchange - .batchExecuteTransactions( - [transaction1, transaction2], - [transaction1.signature, transaction2.signature], - ) - .awaitTransactionSuccessAsync({ from: sender.address }); - const expiredTransactionHash = transactionHashUtils.getTransactionHashHex(transaction2); - const expectedError = new ExchangeRevertErrors.TransactionError( - ExchangeRevertErrors.TransactionErrorCode.Expired, - expiredTransactionHash, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); diff --git a/contracts/integrations/test/forwarder/bridge_test.ts b/contracts/integrations/test/forwarder/bridge_test.ts deleted file mode 100644 index 83ee16a510..0000000000 --- a/contracts/integrations/test/forwarder/bridge_test.ts +++ /dev/null @@ -1,362 +0,0 @@ -import { encodeERC20AssetData, encodeERC20BridgeAssetData, encodeERC721AssetData } from '@0x/contracts-asset-proxy'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { ForwarderContract } from '@0x/contracts-exchange-forwarder'; -import { blockchainTests, constants, getLatestBlockTimestampAsync, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { generatePseudoRandomSalt } from '@0x/order-utils'; -import { SignatureType, SignedOrder } from '@0x/types'; -import { AbiEncoder, BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils'; - -import { deployEth2DaiBridgeAsync } from '../bridges/deploy_eth2dai_bridge'; -import { deployUniswapBridgeAsync } from '../bridges/deploy_uniswap_bridge'; -import { Actor } from '../framework/actors/base'; -import { FeeRecipient } from '../framework/actors/fee_recipient'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { TestEth2DaiContract, TestUniswapExchangeContract } from '../wrappers'; - -import { deployForwarderAsync } from './deploy_forwarder'; -import { ForwarderTestFactory } from './forwarder_test_factory'; - -blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => { - let deployment: DeploymentManager; - let balanceStore: BlockchainBalanceStore; - let testFactory: ForwarderTestFactory; - - let forwarder: ForwarderContract; - let eth2Dai: TestEth2DaiContract; - let uniswapExchange: TestUniswapExchangeContract; - - let erc721Token: DummyERC721TokenContract; - let nftId: BigNumber; - let makerTokenAssetData: string; - let makerFeeTokenAssetData: string; - let eth2DaiBridgeAssetData: string; - let uniswapBridgeAssetData: string; - - let maker: Maker; - let taker: Taker; - let orderFeeRecipient: FeeRecipient; - let forwarderFeeRecipient: FeeRecipient; - - let eth2DaiBridgeOrder: SignedOrder; - let uniswapBridgeOrder: SignedOrder; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 2, - numErc721TokensToDeploy: 1, - numErc1155TokensToDeploy: 0, - }); - const [makerToken, makerFeeToken] = deployment.tokens.erc20; - [erc721Token] = deployment.tokens.erc721; - - forwarder = await deployForwarderAsync(deployment, env); - const eth2DaiContracts = await deployEth2DaiBridgeAsync(deployment, env); - const [eth2DaiBridge] = eth2DaiContracts; - [, eth2Dai] = eth2DaiContracts; - const uniswapContracts = await deployUniswapBridgeAsync(deployment, env, [makerToken.address]); - const [uniswapBridge] = uniswapContracts; - [, [uniswapExchange]] = uniswapContracts; - - makerTokenAssetData = encodeERC20AssetData(makerToken.address); - makerFeeTokenAssetData = encodeERC20AssetData(makerFeeToken.address); - const wethAssetData = encodeERC20AssetData(deployment.tokens.weth.address); - - const bridgeDataEncoder = AbiEncoder.create([{ name: 'fromTokenAddress', type: 'address' }]); - const bridgeData = bridgeDataEncoder.encode([deployment.tokens.weth.address]); - eth2DaiBridgeAssetData = encodeERC20BridgeAssetData(makerToken.address, eth2DaiBridge.address, bridgeData); - uniswapBridgeAssetData = encodeERC20BridgeAssetData(makerToken.address, uniswapBridge.address, bridgeData); - - taker = new Taker({ name: 'Taker', deployment }); - orderFeeRecipient = new FeeRecipient({ - name: 'Order fee recipient', - deployment, - }); - forwarderFeeRecipient = new FeeRecipient({ - name: 'Forwarder fee recipient', - deployment, - }); - - const fifteenMinutesInSeconds = 15 * 60; - const currentBlockTimestamp = await getLatestBlockTimestampAsync(); - const orderDefaults = { - chainId: deployment.chainId, - exchangeAddress: deployment.exchange.address, - takerAddress: constants.NULL_ADDRESS, - feeRecipientAddress: orderFeeRecipient.address, - senderAddress: constants.NULL_ADDRESS, - makerAssetAmount: toBaseUnitAmount(2), - takerAssetAmount: toBaseUnitAmount(1), - takerAssetData: wethAssetData, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerFeeAssetData: makerFeeTokenAssetData, - takerFeeAssetData: wethAssetData, - expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(fifteenMinutesInSeconds), - salt: generatePseudoRandomSalt(), - signature: hexUtils.concat(SignatureType.Wallet), - }; - eth2DaiBridgeOrder = { - ...orderDefaults, - makerAddress: eth2DaiBridge.address, - makerAssetData: eth2DaiBridgeAssetData, - }; - uniswapBridgeOrder = { - ...orderDefaults, - makerAddress: uniswapBridge.address, - makerAssetData: uniswapBridgeAssetData, - }; - - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig: { ...orderDefaults, makerFee: toBaseUnitAmount(0.01) }, - }); - await maker.configureERC20TokenAsync(makerToken); - await maker.configureERC20TokenAsync(makerFeeToken); - await forwarder.approveMakerAssetProxy(makerTokenAssetData).awaitTransactionSuccessAsync(); - [nftId] = await maker.configureERC721TokenAsync(erc721Token); - - // We need to top up the TestUniswapExchange with some ETH so that it can perform tokenToEthSwapInput - await uniswapExchange.topUpEth().awaitTransactionSuccessAsync({ - from: forwarderFeeRecipient.address, - value: constants.ONE_ETHER.times(10), - }); - - const tokenOwners = { - ...actorAddressesByName([maker, taker, orderFeeRecipient, forwarderFeeRecipient]), - Forwarder: forwarder.address, - StakingProxy: deployment.staking.stakingProxy.address, - }; - const tokenContracts = { - erc20: { makerToken, makerFeeToken, wETH: deployment.tokens.weth }, - erc721: { erc721Token }, - }; - const tokenIds = { erc721: { [erc721Token.address]: [nftId] } }; - balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts, tokenIds); - - testFactory = new ForwarderTestFactory(forwarder, deployment, balanceStore, taker); - }); - - after(async () => { - Actor.reset(); - }); - - describe('marketSellOrdersWithEth', () => { - it('should fully fill a single Eth2DaiBridge order without a taker fee', async () => { - await testFactory.marketSellTestAsync([eth2DaiBridgeOrder], 1); - }); - it('should partially fill a single Eth2DaiBridge order without a taker fee', async () => { - await testFactory.marketSellTestAsync([eth2DaiBridgeOrder], 0.34); - }); - it('should correctly handle excess maker asset acquired from Eth2Dai', async () => { - const bridgeExcessBuyAmount = new BigNumber(1); - await eth2Dai.setExcessBuyAmount(bridgeExcessBuyAmount).awaitTransactionSuccessAsync(); - await testFactory.marketSellTestAsync([eth2DaiBridgeOrder], 0.34, { bridgeExcessBuyAmount }); - }); - it('should fill a single Eth2DaiBridge order with a WETH taker fee', async () => { - const order = { - ...eth2DaiBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - }; - await testFactory.marketSellTestAsync([order], 0.78); - }); - it('should fill a single Eth2DaiBridge order with a percentage taker fee', async () => { - const order = { - ...eth2DaiBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - takerFeeAssetData: makerTokenAssetData, - }; - await testFactory.marketSellTestAsync([order], 0.78); - }); - it('should fill an Eth2DaiBridge order along with non-bridge orders, with an affiliate fee', async () => { - const orders = [ - // ERC721 order - await maker.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: encodeERC721AssetData(erc721Token.address, nftId), - takerFee: toBaseUnitAmount(0.01), - }), - eth2DaiBridgeOrder, - await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20 - ]; - await testFactory.marketSellTestAsync(orders, 2.56, { - forwarderFeeAmounts: [toBaseUnitAmount(0.1)], - forwarderFeeRecipientAddresses: [forwarderFeeRecipient.address], - }); - }); - it('should fully fill a single UniswapBridge order without a taker fee', async () => { - await testFactory.marketSellTestAsync([uniswapBridgeOrder], 1); - }); - it('should partially fill a single UniswapBridge order without a taker fee', async () => { - await testFactory.marketSellTestAsync([uniswapBridgeOrder], 0.34); - }); - it('should correctly handle excess maker asset acquired from Uniswap', async () => { - const bridgeExcessBuyAmount = new BigNumber(1); - await uniswapExchange.setExcessBuyAmount(bridgeExcessBuyAmount).awaitTransactionSuccessAsync(); - await testFactory.marketSellTestAsync([uniswapBridgeOrder], 0.34, { bridgeExcessBuyAmount }); - }); - it('should fill a single UniswapBridge order with a WETH taker fee', async () => { - const order = { - ...uniswapBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - }; - await testFactory.marketSellTestAsync([order], 0.78); - }); - it('should fill a single UniswapBridge order with a percentage taker fee', async () => { - const order = { - ...uniswapBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - takerFeeAssetData: makerTokenAssetData, - }; - await testFactory.marketSellTestAsync([order], 0.78); - }); - it('should fill an UniswapBridge order along with non-bridge orders', async () => { - const orders = [ - // ERC721 order - await maker.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: encodeERC721AssetData(erc721Token.address, nftId), - takerFee: toBaseUnitAmount(0.01), - }), - uniswapBridgeOrder, - await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20 - ]; - await testFactory.marketSellTestAsync(orders, 2.56); - }); - it('should fill multiple bridge orders', async () => { - await testFactory.marketSellTestAsync([eth2DaiBridgeOrder, uniswapBridgeOrder], 1.23); - }); - it('should revert if the takerFee is denominated in a different token', async () => { - const order = { - ...eth2DaiBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - takerFeeAssetData: makerFeeTokenAssetData, - }; - const expectedError = new ExchangeForwarderRevertErrors.UnsupportedFeeError(makerFeeTokenAssetData); - await testFactory.marketSellTestAsync([order], 1.23, { revertError: expectedError }); - }); - }); - describe('marketBuyOrdersWithEth', () => { - it('should fully fill a single Eth2DaiBridge order without a taker fee', async () => { - await testFactory.marketBuyTestAsync([eth2DaiBridgeOrder], 1); - }); - it('should partially fill a single Eth2DaiBridge order without a taker fee', async () => { - await testFactory.marketBuyTestAsync([eth2DaiBridgeOrder], 0.34); - }); - it('should return excess ETH', async () => { - await testFactory.marketBuyTestAsync([eth2DaiBridgeOrder], 1, { ethValueAdjustment: 1 }); - }); - it('should correctly handle excess maker asset acquired from Eth2Dai', async () => { - const bridgeExcessBuyAmount = new BigNumber(1); - await eth2Dai.setExcessBuyAmount(bridgeExcessBuyAmount).awaitTransactionSuccessAsync(); - await testFactory.marketBuyTestAsync([eth2DaiBridgeOrder], 0.34, { bridgeExcessBuyAmount }); - }); - it('should fill a single Eth2DaiBridge order with a WETH taker fee', async () => { - const order = { - ...eth2DaiBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - }; - await testFactory.marketBuyTestAsync([order], 0.78); - }); - it('should fill a single Eth2DaiBridge order with a percentage taker fee', async () => { - const order = { - ...eth2DaiBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - takerFeeAssetData: makerTokenAssetData, - }; - await testFactory.marketBuyTestAsync([order], 0.78); - }); - it('should fill an Eth2DaiBridge order along with non-bridge orders, with an affiliate fee', async () => { - const orders = [ - // ERC721 order - await maker.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: encodeERC721AssetData(erc721Token.address, nftId), - takerFee: toBaseUnitAmount(0.01), - }), - eth2DaiBridgeOrder, - await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20 - ]; - await testFactory.marketBuyTestAsync(orders, 2.56, { - forwarderFeeAmounts: [toBaseUnitAmount(0.1)], - forwarderFeeRecipientAddresses: [forwarderFeeRecipient.address], - }); - }); - it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount (Eth2Dai)', async () => { - const expectedError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError( - eth2DaiBridgeOrder.makerAssetAmount.times(0.5), - constants.ZERO_AMOUNT, - ); - await testFactory.marketBuyTestAsync([eth2DaiBridgeOrder], 0.5, { - ethValueAdjustment: -2, - revertError: expectedError, - }); - }); - it('should fully fill a single UniswapBridge order without a taker fee', async () => { - await testFactory.marketBuyTestAsync([uniswapBridgeOrder], 1); - }); - it('should partially fill a single UniswapBridge order without a taker fee', async () => { - await testFactory.marketBuyTestAsync([uniswapBridgeOrder], 0.34); - }); - it('should correctly handle excess maker asset acquired from Uniswap', async () => { - const bridgeExcessBuyAmount = new BigNumber(1); - await uniswapExchange.setExcessBuyAmount(bridgeExcessBuyAmount).awaitTransactionSuccessAsync(); - await testFactory.marketBuyTestAsync([uniswapBridgeOrder], 0.34, { bridgeExcessBuyAmount }); - }); - it('should fill a single UniswapBridge order with a WETH taker fee', async () => { - const order = { - ...uniswapBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - }; - await testFactory.marketBuyTestAsync([order], 0.78); - }); - it('should fill a single UniswapBridge order with a percentage taker fee', async () => { - const order = { - ...uniswapBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - takerFeeAssetData: makerTokenAssetData, - }; - await testFactory.marketBuyTestAsync([order], 0.78); - }); - it('should fill an UniswapBridge order along with non-bridge orders', async () => { - const orders = [ - // ERC721 order - await maker.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: encodeERC721AssetData(erc721Token.address, nftId), - takerFee: toBaseUnitAmount(0.01), - }), - uniswapBridgeOrder, - await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20 - ]; - await testFactory.marketBuyTestAsync(orders, 2.56); - }); - it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount (Uniswap)', async () => { - const expectedError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError( - uniswapBridgeOrder.makerAssetAmount.times(0.5), - constants.ZERO_AMOUNT, - ); - await testFactory.marketBuyTestAsync([uniswapBridgeOrder], 0.5, { - ethValueAdjustment: -2, - revertError: expectedError, - }); - }); - it('should fill multiple bridge orders', async () => { - await testFactory.marketBuyTestAsync([eth2DaiBridgeOrder, uniswapBridgeOrder], 1.23); - }); - it('should revert if the takerFee is denominated in a different token', async () => { - const order = { - ...eth2DaiBridgeOrder, - takerFee: toBaseUnitAmount(0.01), - takerFeeAssetData: makerFeeTokenAssetData, - }; - const expectedError = new ExchangeForwarderRevertErrors.UnsupportedFeeError(makerFeeTokenAssetData); - await testFactory.marketBuyTestAsync([order], 1.23, { revertError: expectedError }); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/forwarder/deploy_forwarder.ts b/contracts/integrations/test/forwarder/deploy_forwarder.ts deleted file mode 100644 index 1654dd06ba..0000000000 --- a/contracts/integrations/test/forwarder/deploy_forwarder.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange'; -import { artifacts, ForwarderContract } from '@0x/contracts-exchange-forwarder'; -import { BlockchainTestsEnvironment, constants } from '@0x/contracts-test-utils'; - -import { DeploymentManager } from '../framework/deployment_manager'; - -/** - * Deploys a Forwarder contract configured to work alongside the provided `deployment`. - */ -export async function deployForwarderAsync( - deployment: DeploymentManager, - environment: BlockchainTestsEnvironment, -): Promise { - return ForwarderContract.deployFrom0xArtifactAsync( - artifacts.Forwarder, - environment.provider, - deployment.txDefaults, - { ...exchangeArtifacts, ...artifacts }, - deployment.exchange.address, - constants.NULL_ADDRESS, // ExchangeV2 not tested on Ganache - deployment.tokens.weth.address, - ); -} diff --git a/contracts/integrations/test/forwarder/forwarder_mainnet_test.ts b/contracts/integrations/test/forwarder/forwarder_mainnet_test.ts deleted file mode 100644 index 4318dca0b0..0000000000 --- a/contracts/integrations/test/forwarder/forwarder_mainnet_test.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { ForwarderContract, IExchangeV2Contract } from '@0x/contracts-exchange-forwarder'; -import { - blockchainTests, - constants, - expect, - getLatestBlockTimestampAsync, - orderHashUtils, - signingUtils, -} from '@0x/contracts-test-utils'; -import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { Order, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as ethUtil from 'ethereumjs-util'; - -import { contractAddresses } from '../mainnet_fork_utils'; - -import { SignedV2Order } from './types'; - -blockchainTests.fork.resets('Forwarder mainnet tests', env => { - const forwarder = new ForwarderContract(contractAddresses.forwarder, env.provider, env.txDefaults); - const exchangeV2 = new IExchangeV2Contract(contractAddresses.exchangeV2, env.provider, env.txDefaults); - const wethAssetData = assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken); - const v2OrderId = '0x770501f8'; - let makerAddress: string; - let takerAddress: string; - let makerAssetData: string; - let makerToken: DummyERC20TokenContract; - let makerPrivateKey: Buffer; - - before(async () => { - [makerAddress, takerAddress] = await env.web3Wrapper.getAvailableAddressesAsync(); - makerToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyERC20Token, - env.provider, - env.txDefaults, - erc20Artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - await makerToken.setBalance(makerAddress, constants.INITIAL_ERC20_BALANCE).awaitTransactionSuccessAsync(); - await makerToken - .approve(contractAddresses.erc20Proxy, constants.INITIAL_ERC20_ALLOWANCE) - .awaitTransactionSuccessAsync({ from: makerAddress }); - makerAssetData = assetDataUtils.encodeERC20AssetData(makerToken.address); - makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[0]; - }); - - async function createOrderAsync(orderParams: Partial = {}): Promise { - const currentBlockTimestamp = await getLatestBlockTimestampAsync(); - const fifteenMinutesInSeconds = 15 * 60; - const order = { - chainId: 1, - exchangeAddress: contractAddresses.exchange, - makerAddress, - takerAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - feeRecipientAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(fifteenMinutesInSeconds), - salt: generatePseudoRandomSalt(), - makerAssetData, - takerAssetData: wethAssetData, - makerFeeAssetData: makerAssetData, - takerFeeAssetData: wethAssetData, - makerAssetAmount: constants.INITIAL_ERC20_BALANCE.dividedToIntegerBy(2), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(0.001, 18), - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - ...orderParams, - }; - const orderHashHex = - order.makerFeeAssetData === v2OrderId - ? (await exchangeV2.getOrderInfo(order).callAsync()).orderHash - : orderHashUtils.getOrderHashHex(order); - const signature = `0x${signingUtils - .signMessage(ethUtil.toBuffer(orderHashHex), makerPrivateKey, SignatureType.EthSign) - .toString('hex')}`; - return { - ...order, - signature, - }; - } - - describe('marketSellOrdersWithEth', () => { - it('should fill a single v2 order with no fees', async () => { - const order = await createOrderAsync({ makerFeeAssetData: v2OrderId }); - const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder - .marketSellOrdersWithEth([order], [order.signature], [], []) - .callAsync({ - from: takerAddress, - value: order.takerAssetAmount, - }); - expect(wethSpentAmount).to.bignumber.eq(order.takerAssetAmount); - expect(makerAssetAcquiredAmount).to.bignumber.eq(order.makerAssetAmount); - }); - it('should fill multiple v2 orders', async () => { - const orders = [ - await createOrderAsync({ makerFeeAssetData: v2OrderId }), - await createOrderAsync({ makerFeeAssetData: v2OrderId }), - ]; - const ethSellAmount = BigNumber.sum( - orders[0].takerAssetAmount, - orders[1].takerAssetAmount.dividedToIntegerBy(2), - ); - const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder - .marketSellOrdersWithEth( - orders, - orders.map(o => o.signature), - [], - [], - ) - .callAsync({ - from: takerAddress, - value: ethSellAmount, - }); - expect(wethSpentAmount).to.bignumber.eq(ethSellAmount); - expect(makerAssetAcquiredAmount).to.bignumber.eq( - BigNumber.sum(orders[0].makerAssetAmount, orders[1].makerAssetAmount.dividedToIntegerBy(2)), - ); - }); - it.skip('should fill multiple v2/v3 orders', async () => { - const v2Order = await createOrderAsync({ makerFeeAssetData: v2OrderId }); - const v3Order = await createOrderAsync(); - const protocolFee = new BigNumber(150000).times(constants.DEFAULT_GAS_PRICE); - const ethSellAmount = BigNumber.sum( - v2Order.takerAssetAmount, - v3Order.takerAssetAmount.dividedToIntegerBy(2), - ); - const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder - .marketSellOrdersWithEth([v2Order, v3Order], [v2Order.signature, v3Order.signature], [], []) - .callAsync({ - from: takerAddress, - value: ethSellAmount.plus(protocolFee), - gasPrice: constants.DEFAULT_GAS_PRICE, - }); - expect(wethSpentAmount).to.bignumber.eq(ethSellAmount.plus(protocolFee)); - expect(makerAssetAcquiredAmount).to.bignumber.eq( - BigNumber.sum(v2Order.makerAssetAmount, v3Order.makerAssetAmount.dividedToIntegerBy(2)), - ); - }); - }); - - describe('marketBuyOrdersWithEth', () => { - it('should fill a single v2 order', async () => { - const order = await createOrderAsync({ makerFeeAssetData: v2OrderId }); - const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder - .marketBuyOrdersWithEth([order], order.makerAssetAmount, [order.signature], [], []) - .callAsync({ from: takerAddress, value: order.takerAssetAmount }); - expect(wethSpentAmount).to.bignumber.eq(order.takerAssetAmount); - expect(makerAssetAcquiredAmount).to.bignumber.eq(order.makerAssetAmount); - }); - it('should fill multiple v2 orders', async () => { - const orders = [ - await createOrderAsync({ makerFeeAssetData: v2OrderId }), - await createOrderAsync({ makerFeeAssetData: v2OrderId }), - ]; - const ethSellAmount = BigNumber.sum( - orders[0].takerAssetAmount, - orders[1].takerAssetAmount.dividedToIntegerBy(2), - ); - const makerAssetBuyAmount = BigNumber.sum( - orders[0].makerAssetAmount, - orders[1].makerAssetAmount.dividedToIntegerBy(2), - ); - const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder - .marketBuyOrdersWithEth( - orders, - makerAssetBuyAmount, - orders.map(o => o.signature), - [], - [], - ) - .callAsync({ - from: takerAddress, - value: ethSellAmount, - }); - expect(wethSpentAmount).to.bignumber.eq(ethSellAmount); - expect(makerAssetAcquiredAmount).to.bignumber.eq(makerAssetBuyAmount); - }); - it.skip('should fill multiple v2/v3 orders', async () => { - const v2Order = await createOrderAsync({ makerFeeAssetData: v2OrderId }); - const v3Order = await createOrderAsync(); - const protocolFee = new BigNumber(150000).times(constants.DEFAULT_GAS_PRICE); - const ethSellAmount = BigNumber.sum( - v2Order.takerAssetAmount, - v3Order.takerAssetAmount.dividedToIntegerBy(2), - ); - const makerAssetBuyAmount = BigNumber.sum( - v2Order.makerAssetAmount, - v3Order.makerAssetAmount.dividedToIntegerBy(2), - ); - const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder - .marketBuyOrdersWithEth( - [v2Order, v3Order], - makerAssetBuyAmount, - [v2Order.signature, v3Order.signature], - [], - [], - ) - .callAsync({ - from: takerAddress, - value: ethSellAmount.plus(protocolFee), - gasPrice: constants.DEFAULT_GAS_PRICE, - }); - expect(wethSpentAmount).to.bignumber.eq(ethSellAmount.plus(protocolFee)); - expect(makerAssetAcquiredAmount).to.bignumber.eq(makerAssetBuyAmount); - }); - }); -}); diff --git a/contracts/integrations/test/forwarder/forwarder_test.ts b/contracts/integrations/test/forwarder/forwarder_test.ts deleted file mode 100644 index a797c34c78..0000000000 --- a/contracts/integrations/test/forwarder/forwarder_test.ts +++ /dev/null @@ -1,788 +0,0 @@ -import { - artifacts as assetProxyArtifacts, - encodeERC20AssetData, - encodeERC721AssetData, - encodeMultiAssetData, - encodeStaticCallAssetData, - TestStaticCallTargetContract, -} from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange'; -import { artifacts, ExchangeForwarderRevertErrors, ForwarderContract } from '@0x/contracts-exchange-forwarder'; -import { MixinWethUtilsRevertErrors } from '@0x/contracts-extensions'; -import { - blockchainTests, - constants, - expect, - getLatestBlockTimestampAsync, - randomAddress, - toBaseUnitAmount, -} from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { Actor } from '../framework/actors/base'; -import { FeeRecipient } from '../framework/actors/fee_recipient'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { actorAddressesByName } from '../framework/actors/utils'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -import { deployForwarderAsync } from './deploy_forwarder'; -import { ForwarderTestFactory } from './forwarder_test_factory'; - -blockchainTests('Forwarder integration tests', env => { - let deployment: DeploymentManager; - let forwarder: ForwarderContract; - let balanceStore: BlockchainBalanceStore; - let testFactory: ForwarderTestFactory; - - let makerToken: DummyERC20TokenContract; - let makerFeeToken: DummyERC20TokenContract; - let anotherErc20Token: DummyERC20TokenContract; - let erc721Token: DummyERC721TokenContract; - let nftId: BigNumber; - let wethAssetData: string; - let makerAssetData: string; - let staticCallSuccessAssetData: string; - let staticCallFailureAssetData: string; - - let maker: Maker; - let taker: Taker; - let orderFeeRecipient: FeeRecipient; - let forwarderFeeRecipient: FeeRecipient; - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 3, - numErc721TokensToDeploy: 1, - numErc1155TokensToDeploy: 0, - }); - forwarder = await deployForwarderAsync(deployment, env); - - const staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.TestStaticCallTarget, - env.provider, - env.txDefaults, - assetProxyArtifacts, - ); - - [makerToken, makerFeeToken, anotherErc20Token] = deployment.tokens.erc20; - [erc721Token] = deployment.tokens.erc721; - wethAssetData = encodeERC20AssetData(deployment.tokens.weth.address); - makerAssetData = encodeERC20AssetData(makerToken.address); - staticCallSuccessAssetData = encodeStaticCallAssetData( - staticCallTarget.address, - staticCallTarget.assertEvenNumber(new BigNumber(2)).getABIEncodedTransactionData(), - constants.KECCAK256_NULL, - ); - staticCallFailureAssetData = encodeStaticCallAssetData( - staticCallTarget.address, - staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(), - constants.KECCAK256_NULL, - ); - - taker = new Taker({ name: 'Taker', deployment }); - orderFeeRecipient = new FeeRecipient({ - name: 'Order fee recipient', - deployment, - }); - forwarderFeeRecipient = new FeeRecipient({ - name: 'Forwarder fee recipient', - deployment, - }); - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig: { - feeRecipientAddress: orderFeeRecipient.address, - makerAssetAmount: toBaseUnitAmount(2), - takerAssetAmount: toBaseUnitAmount(1), - makerAssetData, - takerAssetData: wethAssetData, - takerFee: constants.ZERO_AMOUNT, - makerFeeAssetData: encodeERC20AssetData(makerFeeToken.address), - takerFeeAssetData: wethAssetData, - }, - }); - - await maker.configureERC20TokenAsync(makerToken); - await maker.configureERC20TokenAsync(makerFeeToken); - await maker.configureERC20TokenAsync(anotherErc20Token); - await forwarder.approveMakerAssetProxy(makerAssetData).awaitTransactionSuccessAsync(); - [nftId] = await maker.configureERC721TokenAsync(erc721Token); - - const tokenOwners = { - ...actorAddressesByName([maker, taker, orderFeeRecipient, forwarderFeeRecipient]), - Forwarder: forwarder.address, - StakingProxy: deployment.staking.stakingProxy.address, - }; - const tokenContracts = { - erc20: { makerToken, makerFeeToken, anotherErc20Token, wETH: deployment.tokens.weth }, - erc721: { erc721Token }, - }; - const tokenIds = { erc721: { [erc721Token.address]: [nftId] } }; - balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts, tokenIds); - - testFactory = new ForwarderTestFactory(forwarder, deployment, balanceStore, taker); - }); - - after(async () => { - Actor.reset(); - }); - - blockchainTests.resets('constructor', () => { - it('should revert if assetProxy is unregistered', async () => { - const chainId = await env.getChainIdAsync(); - const exchange = await ExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.Exchange, - env.provider, - env.txDefaults, - {}, - new BigNumber(chainId), - ); - const deployForwarder = ForwarderContract.deployFrom0xArtifactAsync( - artifacts.Forwarder, - env.provider, - env.txDefaults, - {}, - exchange.address, - constants.NULL_ADDRESS, - deployment.tokens.weth.address, - ); - await expect(deployForwarder).to.revertWith( - new ExchangeForwarderRevertErrors.UnregisteredAssetProxyError(), - ); - }); - }); - blockchainTests.resets('marketSellOrdersWithEth without extra fees', () => { - it('should fill a single order without a taker fee', async () => { - const orderWithoutFee = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([orderWithoutFee], 0.78); - }); - it('should fill multiple orders without taker fees', async () => { - const firstOrder = await maker.signOrderAsync(); - const secondOrder = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(285), - takerAssetAmount: toBaseUnitAmount(21), - }); - const orders = [firstOrder, secondOrder]; - await testFactory.marketSellTestAsync(orders, 1.51); - }); - it('should fill a single order with a percentage fee', async () => { - const orderWithPercentageFee = await maker.signOrderAsync({ - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: makerAssetData, - }); - await testFactory.marketSellTestAsync([orderWithPercentageFee], 0.58); - }); - it('should fill multiple orders with percentage fees', async () => { - const firstOrder = await maker.signOrderAsync({ - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: makerAssetData, - }); - const secondOrder = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(190), - takerAssetAmount: toBaseUnitAmount(31), - takerFee: toBaseUnitAmount(2), - takerFeeAssetData: makerAssetData, - }); - const orders = [firstOrder, secondOrder]; - await testFactory.marketSellTestAsync(orders, 1.34); - }); - it('should fail to fill an order with a percentage fee if the asset proxy is not yet approved', async () => { - const unapprovedAsset = encodeERC20AssetData(anotherErc20Token.address); - const order = await maker.signOrderAsync({ - makerAssetData: unapprovedAsset, - takerFee: toBaseUnitAmount(2), - takerFeeAssetData: unapprovedAsset, - }); - - await balanceStore.updateBalancesAsync(); - // Execute test case - const tx = await forwarder - .marketSellOrdersWithEth([order], [order.signature], [], []) - .awaitTransactionSuccessAsync({ - value: order.takerAssetAmount.plus(DeploymentManager.protocolFee), - from: taker.address, - }); - - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.burnGas(tx.from, DeploymentManager.gasPrice.times(tx.gasUsed)); - - // Verify balances - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it('should fill a single order with a WETH fee', async () => { - const orderWithWethFee = await maker.signOrderAsync({ - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: wethAssetData, - }); - await testFactory.marketSellTestAsync([orderWithWethFee], 0.13); - }); - it('should fill multiple orders with WETH fees', async () => { - const firstOrder = await maker.signOrderAsync({ - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: wethAssetData, - }); - const secondOrderWithWethFee = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(97), - takerAssetAmount: toBaseUnitAmount(33), - takerFee: toBaseUnitAmount(2), - takerFeeAssetData: wethAssetData, - }); - const orders = [firstOrder, secondOrderWithWethFee]; - await testFactory.marketSellTestAsync(orders, 1.25); - }); - it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => { - const order = await maker.signOrderAsync(); - const ethValue = order.takerAssetAmount.plus(DeploymentManager.protocolFee).plus(2); - const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(taker.address); - const tx = await forwarder - .marketSellOrdersWithEth([order], [order.signature], [], []) - .awaitTransactionSuccessAsync({ - value: ethValue, - from: taker.address, - }); - const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(taker.address); - const totalEthSpent = order.takerAssetAmount - .plus(DeploymentManager.protocolFee) - .plus(DeploymentManager.gasPrice.times(tx.gasUsed)); - expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); - }); - it('should fill orders with different makerAssetData', async () => { - const firstOrder = await maker.signOrderAsync(); - const secondOrderMakerAssetData = encodeERC20AssetData(anotherErc20Token.address); - const secondOrder = await maker.signOrderAsync({ - makerAssetData: secondOrderMakerAssetData, - }); - await forwarder.approveMakerAssetProxy(secondOrderMakerAssetData).awaitTransactionSuccessAsync(); - const orders = [firstOrder, secondOrder]; - await testFactory.marketSellTestAsync(orders, 1.5); - }); - it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => { - const takerFeeAssetData = encodeERC20AssetData(anotherErc20Token.address); - const order = await maker.signOrderAsync({ - takerFeeAssetData, - takerFee: toBaseUnitAmount(1), - }); - const revertError = new ExchangeForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData); - await testFactory.marketSellTestAsync([order], 0.5, { - revertError, - }); - }); - it('should fill a partially-filled order without a taker fee', async () => { - const order = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([order], 0.3); - await testFactory.marketSellTestAsync([order], 0.8); - }); - it('should skip over an order with an invalid maker asset amount', async () => { - const unfillableOrder = await maker.signOrderAsync({ - makerAssetAmount: constants.ZERO_AMOUNT, - }); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over an order with an invalid taker asset amount', async () => { - const unfillableOrder = await maker.signOrderAsync({ - takerAssetAmount: constants.ZERO_AMOUNT, - }); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over an expired order', async () => { - const currentTimestamp = await getLatestBlockTimestampAsync(); - const expiredOrder = await maker.signOrderAsync({ - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over a fully filled order', async () => { - const fullyFilledOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([fullyFilledOrder], 1); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over a cancelled order', async () => { - const cancelledOrder = await maker.signOrderAsync(); - await maker.cancelOrderAsync(cancelledOrder); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - for (const orderAssetData of ['makerAssetData', 'makerFeeAssetData']) { - it(`should fill an order with StaticCall ${orderAssetData} if the StaticCall succeeds`, async () => { - const staticCallOrder = await maker.signOrderAsync({ - [orderAssetData]: staticCallSuccessAssetData, - }); - const nonStaticCallOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([staticCallOrder, nonStaticCallOrder], 1.5); - }); - it(`should not fill an order with StaticCall ${orderAssetData} if the StaticCall fails`, async () => { - const staticCallOrder = await maker.signOrderAsync({ - [orderAssetData]: staticCallFailureAssetData, - }); - const nonStaticCallOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([staticCallOrder, nonStaticCallOrder], 1.5, { noopOrders: [0] }); - }); - } - it('should fill an order with multiAsset makerAssetData', async () => { - const multiAssetData = encodeMultiAssetData([new BigNumber(2)], [makerAssetData]); - const multiAssetOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - }); - const nonMultiAssetOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3); - }); - it('should fill an order with multiAsset makerAssetData (nested StaticCall succeeds)', async () => { - const multiAssetData = encodeMultiAssetData( - [new BigNumber(2), new BigNumber(3)], - [makerAssetData, staticCallSuccessAssetData], - ); - const multiAssetOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - }); - const nonMultiAssetOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3); - }); - it('should skip over an order with multiAsset makerAssetData where the nested StaticCall fails', async () => { - const multiAssetData = encodeMultiAssetData( - [new BigNumber(2), new BigNumber(3)], - [makerAssetData, staticCallFailureAssetData], - ); - const multiAssetOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - }); - const nonMultiAssetOrder = await maker.signOrderAsync(); - await testFactory.marketSellTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3, { noopOrders: [0] }); - }); - }); - blockchainTests.resets('marketSellOrdersWithEth with extra fees', () => { - it('should fill the order and send fee to feeRecipient', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts: [toBaseUnitAmount(0.2)], - forwarderFeeRecipientAddresses: [forwarderFeeRecipient.address], - }); - }); - it('should fill the order and send the same fees to different feeRecipient addresses', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.2)], - forwarderFeeRecipientAddresses: [randomAddress(), randomAddress()], - }); - }); - it('should fill the order and send different fees to different feeRecipient addresses', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.1)], - forwarderFeeRecipientAddresses: [randomAddress(), randomAddress()], - }); - }); - it('should fill the order and send the same fees to multiple instances of the same feeRecipient address', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - const feeRecipient = randomAddress(); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.2)], - forwarderFeeRecipientAddresses: [feeRecipient, feeRecipient], - }); - }); - it('should fill the order and send different fees to multiple instances of the same feeRecipient address', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - const feeRecipient = randomAddress(); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.1)], - forwarderFeeRecipientAddresses: [feeRecipient, feeRecipient], - }); - }); - it('should fail if ethFeeAmounts is longer than feeRecipients', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - const forwarderFeeAmounts = [toBaseUnitAmount(0.2)]; - const forwarderFeeRecipientAddresses: string[] = []; - const revertError = new MixinWethUtilsRevertErrors.EthFeeLengthMismatchError( - new BigNumber(forwarderFeeAmounts.length), - new BigNumber(forwarderFeeRecipientAddresses.length), - ); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts, - forwarderFeeRecipientAddresses, - revertError, - }); - }); - it('should fail if feeRecipients is longer than ethFeeAmounts', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(157), - takerAssetAmount: toBaseUnitAmount(36), - }); - const forwarderFeeAmounts: BigNumber[] = []; - const forwarderFeeRecipientAddresses = [randomAddress()]; - const revertError = new MixinWethUtilsRevertErrors.EthFeeLengthMismatchError( - new BigNumber(forwarderFeeAmounts.length), - new BigNumber(forwarderFeeRecipientAddresses.length), - ); - await testFactory.marketSellTestAsync([order], 0.67, { - forwarderFeeAmounts, - forwarderFeeRecipientAddresses, - revertError, - }); - }); - }); - blockchainTests.resets('marketSellAmountWithEth', () => { - it('should fail if the supplied amount is not sold', async () => { - const order = await maker.signOrderAsync(); - const ethSellAmount = order.takerAssetAmount; - const revertError = new ExchangeForwarderRevertErrors.CompleteSellFailedError( - ethSellAmount, - order.takerAssetAmount.times(0.5).plus(DeploymentManager.protocolFee), - ); - await testFactory.marketSellAmountTestAsync([order], ethSellAmount, 0.5, { - revertError, - }); - }); - it('should sell the supplied amount', async () => { - const order = await maker.signOrderAsync(); - const ethSellAmount = order.takerAssetAmount; - await testFactory.marketSellAmountTestAsync([order], ethSellAmount, 1); - }); - }); - blockchainTests.resets('marketBuyOrdersWithEth without extra fees', () => { - it('should buy the exact amount of makerAsset in a single order', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(131), - takerAssetAmount: toBaseUnitAmount(20), - }); - await testFactory.marketBuyTestAsync([order], 0.62); - }); - it('should buy the exact amount of makerAsset in multiple orders', async () => { - const firstOrder = await maker.signOrderAsync(); - const secondOrder = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(77), - takerAssetAmount: toBaseUnitAmount(11), - }); - const orders = [firstOrder, secondOrder]; - await testFactory.marketBuyTestAsync(orders, 1.96); - }); - it('should buy exactly makerAssetBuyAmount in orders with different makerAssetData', async () => { - const firstOrder = await maker.signOrderAsync(); - const secondOrderMakerAssetData = encodeERC20AssetData(anotherErc20Token.address); - const secondOrder = await maker.signOrderAsync({ - makerAssetData: secondOrderMakerAssetData, - }); - await forwarder.approveMakerAssetProxy(secondOrderMakerAssetData).awaitTransactionSuccessAsync(); - const orders = [firstOrder, secondOrder]; - await testFactory.marketBuyTestAsync(orders, 1.5); - }); - it('should buy the exact amount of makerAsset and return excess ETH', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(80), - takerAssetAmount: toBaseUnitAmount(17), - }); - await testFactory.marketBuyTestAsync([order], 0.57, { - ethValueAdjustment: 2, - }); - }); - it('should buy the exact amount of makerAsset from a single order with a WETH fee', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(79), - takerAssetAmount: toBaseUnitAmount(16), - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: wethAssetData, - }); - await testFactory.marketBuyTestAsync([order], 0.38); - }); - it('should buy the exact amount of makerAsset from a single order with a percentage fee', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(80), - takerAssetAmount: toBaseUnitAmount(17), - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: makerAssetData, - }); - await testFactory.marketBuyTestAsync([order], 0.52); - }); - it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => { - const order = await maker.signOrderAsync(); - const revertError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError( - order.makerAssetAmount.times(0.5), - constants.ZERO_AMOUNT, - ); - await testFactory.marketBuyTestAsync([order], 0.5, { - ethValueAdjustment: -2, - revertError, - }); - }); - it('should buy an ERC721 asset from a single order', async () => { - const erc721Order = await maker.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: encodeERC721AssetData(erc721Token.address, nftId), - takerFeeAssetData: wethAssetData, - }); - await testFactory.marketBuyTestAsync([erc721Order], 1); - }); - it('should buy an ERC721 asset and pay a WETH fee', async () => { - const erc721orderWithWethFee = await maker.signOrderAsync({ - makerAssetAmount: new BigNumber(1), - makerAssetData: encodeERC721AssetData(erc721Token.address, nftId), - takerFee: toBaseUnitAmount(1), - takerFeeAssetData: wethAssetData, - }); - await testFactory.marketBuyTestAsync([erc721orderWithWethFee], 1); - }); - it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => { - const takerFeeAssetData = encodeERC20AssetData(anotherErc20Token.address); - const order = await maker.signOrderAsync({ - takerFeeAssetData, - takerFee: toBaseUnitAmount(1), - }); - const revertError = new ExchangeForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData); - await testFactory.marketBuyTestAsync([order], 0.5, { - revertError, - }); - }); - it('should fill a partially-filled order without a taker fee', async () => { - const order = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([order], 0.3); - await testFactory.marketBuyTestAsync([order], 0.8); - }); - it('should skip over an order with an invalid maker asset amount', async () => { - const unfillableOrder = await maker.signOrderAsync({ - makerAssetAmount: constants.ZERO_AMOUNT, - }); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over an order with an invalid taker asset amount', async () => { - const unfillableOrder = await maker.signOrderAsync({ - takerAssetAmount: constants.ZERO_AMOUNT, - }); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over an expired order', async () => { - const currentTimestamp = await getLatestBlockTimestampAsync(); - const expiredOrder = await maker.signOrderAsync({ - expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10), - }); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over a fully filled order', async () => { - const fullyFilledOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([fullyFilledOrder], 1); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - it('should skip over a cancelled order', async () => { - const cancelledOrder = await maker.signOrderAsync(); - await maker.cancelOrderAsync(cancelledOrder); - const fillableOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5, { noopOrders: [0] }); - }); - 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 - const order = await maker.signOrderAsync({ - makerAssetAmount: new BigNumber('30'), - takerAssetAmount: new BigNumber('20'), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - const desiredMakerAssetFillAmount = new BigNumber('5'); - const makerAssetFillAmount = new BigNumber('6'); - const primaryTakerAssetFillAmount = new BigNumber('4'); - const ethValue = primaryTakerAssetFillAmount.plus(DeploymentManager.protocolFee); - - await balanceStore.updateBalancesAsync(); - // Execute test case - const tx = await forwarder - .marketBuyOrdersWithEth([order], desiredMakerAssetFillAmount, [order.signature], [], []) - .awaitTransactionSuccessAsync({ - value: ethValue, - from: taker.address, - }); - - // Compute expected balances - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.transferAsset(maker.address, taker.address, makerAssetFillAmount, makerAssetData); - expectedBalances.wrapEth(taker.address, deployment.tokens.weth.address, ethValue); - expectedBalances.transferAsset(taker.address, maker.address, primaryTakerAssetFillAmount, wethAssetData); - expectedBalances.transferAsset( - taker.address, - deployment.staking.stakingProxy.address, - DeploymentManager.protocolFee, - wethAssetData, - ); - expectedBalances.burnGas(tx.from, DeploymentManager.gasPrice.times(tx.gasUsed)); - - // Verify balances - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - 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. - const order = await maker.signOrderAsync({ - makerAssetAmount: new BigNumber('268166666666666666666'), - takerAssetAmount: new BigNumber('219090625878836371'), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - }); - // The taker will receive more than the desired amount of makerAsset due to rounding - const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000'); - const takerAssetFillAmount = new BigNumber('4084971271824171'); - const makerAssetFillAmount = takerAssetFillAmount - .times(order.makerAssetAmount) - .dividedToIntegerBy(order.takerAssetAmount); - - await balanceStore.updateBalancesAsync(); - // Execute test case - const tx = await forwarder - .marketBuyOrdersWithEth([order], desiredMakerAssetFillAmount, [order.signature], [], []) - .awaitTransactionSuccessAsync({ - value: takerAssetFillAmount.plus(DeploymentManager.protocolFee), - from: taker.address, - }); - - // Compute expected balances - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.transferAsset(maker.address, taker.address, makerAssetFillAmount, makerAssetData); - expectedBalances.wrapEth( - taker.address, - deployment.tokens.weth.address, - takerAssetFillAmount.plus(DeploymentManager.protocolFee), - ); - expectedBalances.transferAsset(taker.address, maker.address, takerAssetFillAmount, wethAssetData); - expectedBalances.transferAsset( - taker.address, - deployment.staking.stakingProxy.address, - DeploymentManager.protocolFee, - wethAssetData, - ); - expectedBalances.burnGas(tx.from, DeploymentManager.gasPrice.times(tx.gasUsed)); - - // Verify balances - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - for (const orderAssetData of ['makerAssetData', 'makerFeeAssetData', 'takerFeeAssetData']) { - it(`should fill an order with StaticCall ${orderAssetData} if the StaticCall succeeds`, async () => { - const staticCallOrder = await maker.signOrderAsync({ - [orderAssetData]: staticCallSuccessAssetData, - }); - const nonStaticCallOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([staticCallOrder, nonStaticCallOrder], 1.5); - }); - it(`should not fill an order with StaticCall ${orderAssetData} if the StaticCall fails`, async () => { - const staticCallOrder = await maker.signOrderAsync({ - [orderAssetData]: staticCallFailureAssetData, - }); - const nonStaticCallOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([staticCallOrder, nonStaticCallOrder], 1.5, { noopOrders: [0] }); - }); - } - it('should fill an order with multiAsset makerAssetData', async () => { - const multiAssetData = encodeMultiAssetData([new BigNumber(2)], [makerAssetData]); - const multiAssetOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - }); - const nonMultiAssetOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3); - }); - it('should fill an order with multiAsset makerAssetData (nested StaticCall succeeds)', async () => { - const multiAssetData = encodeMultiAssetData( - [new BigNumber(2), new BigNumber(3)], - [makerAssetData, staticCallSuccessAssetData], - ); - const multiAssetOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - }); - const nonMultiAssetOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3); - }); - it('should skip over an order with multiAsset makerAssetData where the nested StaticCall fails', async () => { - const multiAssetData = encodeMultiAssetData( - [new BigNumber(2), new BigNumber(3)], - [makerAssetData, staticCallFailureAssetData], - ); - const multiAssetOrder = await maker.signOrderAsync({ - makerAssetData: multiAssetData, - }); - const nonMultiAssetOrder = await maker.signOrderAsync(); - await testFactory.marketBuyTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3, { noopOrders: [0] }); - }); - }); - blockchainTests.resets('marketBuyOrdersWithEth with extra fees', () => { - it('should buy the asset and send fee to feeRecipient', async () => { - const order = await maker.signOrderAsync({ - makerAssetAmount: toBaseUnitAmount(125), - takerAssetAmount: toBaseUnitAmount(11), - }); - await testFactory.marketBuyTestAsync([order], 0.33, { - forwarderFeeAmounts: [toBaseUnitAmount(0.2)], - forwarderFeeRecipientAddresses: [randomAddress()], - }); - }); - it('should fail if there is not enough ETH remaining to complete the fill', async () => { - const order = await maker.signOrderAsync(); - const forwarderFeeAmounts = [toBaseUnitAmount(1)]; - const revertError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError( - order.takerAssetAmount, - constants.ZERO_AMOUNT, - ); - await testFactory.marketBuyTestAsync([order], 0.5, { - ethValueAdjustment: -1, - forwarderFeeAmounts, - forwarderFeeRecipientAddresses: [randomAddress()], - revertError, - }); - }); - it('should fail if there is not enough ETH remaining to pay the fee', async () => { - const order = await maker.signOrderAsync(); - const forwarderFeeAmounts = [toBaseUnitAmount(1)]; - const value = forwarderFeeAmounts[0].minus(1); - const revertError = new MixinWethUtilsRevertErrors.InsufficientEthForFeeError( - forwarderFeeAmounts[0], - value, - ); - await testFactory.marketBuyTestAsync([order], 0, { - revertError, - ethValueAdjustment: -1, - forwarderFeeAmounts, - forwarderFeeRecipientAddresses: [randomAddress()], - }); - }); - }); -}); -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/forwarder/forwarder_test_factory.ts b/contracts/integrations/test/forwarder/forwarder_test_factory.ts deleted file mode 100644 index c1ac563680..0000000000 --- a/contracts/integrations/test/forwarder/forwarder_test_factory.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { decodeERC20AssetData, decodeERC20BridgeAssetData } from '@0x/contracts-asset-proxy'; -import { ForwarderContract } from '@0x/contracts-exchange-forwarder'; -import { constants, expect, OrderStatus } from '@0x/contracts-test-utils'; -import { AssetProxyId, OrderInfo, SignedOrder } from '@0x/types'; -import { BigNumber, hexUtils, RevertError } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { Taker } from '../framework/actors/taker'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; - -// Necessary bookkeeping to validate Forwarder results -interface ForwarderFillState { - balances: LocalBalanceStore; - wethSpentAmount: BigNumber; - makerAssetAcquiredAmount: BigNumber; -} - -interface MarketSellOptions { - forwarderFeeAmounts: BigNumber[]; - forwarderFeeRecipientAddresses: string[]; - revertError: RevertError; - bridgeExcessBuyAmount: BigNumber; - noopOrders: number[]; // Indices of orders expected to noop on _fillOrderNoThrow (e.g. cancelled orders) -} - -interface MarketBuyOptions extends MarketSellOptions { - ethValueAdjustment: number; // Used to provided insufficient/excess ETH -} - -function areUnderlyingAssetsEqual(assetData1: string, assetData2: string): boolean { - const assetProxyId1 = hexUtils.slice(assetData1, 0, 4); - const assetProxyId2 = hexUtils.slice(assetData2, 0, 4); - if ( - (assetProxyId1 === AssetProxyId.ERC20 || assetProxyId1 === AssetProxyId.ERC20Bridge) && - (assetProxyId2 === AssetProxyId.ERC20 || assetProxyId2 === AssetProxyId.ERC20Bridge) - ) { - const tokenAddress1 = - assetProxyId1 === AssetProxyId.ERC20 - ? decodeERC20AssetData(assetData1) - : decodeERC20BridgeAssetData(assetData1)[0]; - const tokenAddress2 = - assetProxyId2 === AssetProxyId.ERC20 - ? decodeERC20AssetData(assetData2) - : decodeERC20BridgeAssetData(assetData2)[0]; - return tokenAddress2 === tokenAddress1; - } else { - return false; - } -} - -export class ForwarderTestFactory { - constructor( - private readonly _forwarder: ForwarderContract, - private readonly _deployment: DeploymentManager, - private readonly _balanceStore: BlockchainBalanceStore, - private readonly _taker: Taker, - ) {} - - public async marketBuyTestAsync( - orders: SignedOrder[], - fractionalNumberOfOrdersToFill: number, - options: Partial = {}, - ): Promise { - const ethValueAdjustment = options.ethValueAdjustment || 0; - const forwarderFeeAmounts = options.forwarderFeeAmounts || []; - const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || []; - - const orderInfoBefore = await Promise.all( - orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()), - ); - const expectedOrderStatuses = orderInfoBefore.map((orderInfo, i) => - fractionalNumberOfOrdersToFill >= i + 1 && !(options.noopOrders || []).includes(i) - ? OrderStatus.FullyFilled - : orderInfo.orderStatus, - ); - - const { - balances: expectedBalances, - wethSpentAmount, - makerAssetAcquiredAmount, - } = await this._simulateForwarderFillAsync(orders, orderInfoBefore, fractionalNumberOfOrdersToFill, options); - - const tx = this._forwarder - .marketBuyOrdersWithEth( - orders, - makerAssetAcquiredAmount.minus(options.bridgeExcessBuyAmount || 0), - orders.map(signedOrder => signedOrder.signature), - forwarderFeeAmounts, - forwarderFeeRecipientAddresses, - ) - .awaitTransactionSuccessAsync({ - value: wethSpentAmount.plus(BigNumber.sum(0, ...forwarderFeeAmounts)).plus(ethValueAdjustment), - from: this._taker.address, - }); - - if (options.revertError !== undefined) { - await expect(tx).to.revertWith(options.revertError); - } else { - const txReceipt = await tx; - await this._checkResultsAsync(txReceipt, orders, expectedOrderStatuses, expectedBalances); - } - } - - public async marketSellTestAsync( - orders: SignedOrder[], - fractionalNumberOfOrdersToFill: number, - options: Partial = {}, - ): Promise { - const orderInfoBefore = await Promise.all( - orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()), - ); - const expectedOrderStatuses = orderInfoBefore.map((orderInfo, i) => - fractionalNumberOfOrdersToFill >= i + 1 && !(options.noopOrders || []).includes(i) - ? OrderStatus.FullyFilled - : orderInfo.orderStatus, - ); - - const { balances: expectedBalances, wethSpentAmount } = await this._simulateForwarderFillAsync( - orders, - orderInfoBefore, - fractionalNumberOfOrdersToFill, - options, - ); - - const forwarderFeeAmounts = options.forwarderFeeAmounts || []; - const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || []; - - const tx = this._forwarder - .marketSellOrdersWithEth( - orders, - orders.map(signedOrder => signedOrder.signature), - forwarderFeeAmounts, - forwarderFeeRecipientAddresses, - ) - .awaitTransactionSuccessAsync({ - value: wethSpentAmount.plus(BigNumber.sum(0, ...forwarderFeeAmounts)), - from: this._taker.address, - }); - - if (options.revertError !== undefined) { - await expect(tx).to.revertWith(options.revertError); - } else { - const txReceipt = await tx; - await this._checkResultsAsync(txReceipt, orders, expectedOrderStatuses, expectedBalances); - } - } - public async marketSellAmountTestAsync( - orders: SignedOrder[], - ethSellAmount: BigNumber, - fractionalNumberOfOrdersToFill: number, - options: Partial = {}, - ): Promise { - const orderInfoBefore = await Promise.all( - orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()), - ); - const expectedOrderStatuses = orderInfoBefore.map((orderInfo, i) => - fractionalNumberOfOrdersToFill >= i + 1 && !(options.noopOrders || []).includes(i) - ? OrderStatus.FullyFilled - : orderInfo.orderStatus, - ); - - const { balances: expectedBalances, wethSpentAmount } = await this._simulateForwarderFillAsync( - orders, - orderInfoBefore, - fractionalNumberOfOrdersToFill, - options, - ); - - const forwarderFeeAmounts = options.forwarderFeeAmounts || []; - const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || []; - - const tx = this._forwarder - .marketSellAmountWithEth( - orders, - ethSellAmount, - orders.map(signedOrder => signedOrder.signature), - forwarderFeeAmounts, - forwarderFeeRecipientAddresses, - ) - .awaitTransactionSuccessAsync({ - value: wethSpentAmount.plus(BigNumber.sum(0, ...forwarderFeeAmounts)), - from: this._taker.address, - }); - - if (options.revertError !== undefined) { - await expect(tx).to.revertWith(options.revertError); - } else { - const txReceipt = await tx; - await this._checkResultsAsync(txReceipt, orders, expectedOrderStatuses, expectedBalances); - } - } - - private async _checkResultsAsync( - txReceipt: TransactionReceiptWithDecodedLogs, - orders: SignedOrder[], - expectedOrderStatuses: OrderStatus[], - expectedBalances: LocalBalanceStore, - ): Promise { - // Transaction gas cost - expectedBalances.burnGas(txReceipt.from, DeploymentManager.gasPrice.times(txReceipt.gasUsed)); - await this._balanceStore.updateBalancesAsync(); - // Check balances - this._balanceStore.assertEquals(expectedBalances); - - // Get updated order info - const orderInfoAfter = await Promise.all( - orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()), - ); - // Check order statuses - for (const [i, orderInfo] of orderInfoAfter.entries()) { - expect(orderInfo.orderStatus, ` Order ${i} status`).to.equal(expectedOrderStatuses[i]); - } - } - - // Simulates filling some orders via the Forwarder contract. For example, if - // orders = [A, B, C, D] and fractionalNumberOfOrdersToFill = 2.3, then - // we simulate A and B being completely filled, and 0.3 * C being filled. - private async _simulateForwarderFillAsync( - orders: SignedOrder[], - ordersInfoBefore: OrderInfo[], - fractionalNumberOfOrdersToFill: number, - options: Partial, - ): Promise { - await this._balanceStore.updateBalancesAsync(); - const balances = LocalBalanceStore.create(this._balanceStore); - - const forwarderFeeAmounts = options.forwarderFeeAmounts || []; - const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || []; - - forwarderFeeAmounts.forEach((feeAmount, i) => - // In reality the Forwarder is a middleman in this transaction and the ETH gets wrapped and unwrapped. - balances.sendEth(this._taker.address, forwarderFeeRecipientAddresses[i], feeAmount), - ); - - const currentTotal = { - wethSpentAmount: constants.ZERO_AMOUNT, - makerAssetAcquiredAmount: constants.ZERO_AMOUNT, - }; - - let remainingOrdersToFill = fractionalNumberOfOrdersToFill; - for (const [i, order] of orders.entries()) { - if (remainingOrdersToFill === 0) { - break; - } else if ((options.noopOrders || []).includes(i)) { - // If the order won't be filled, skip over it but still count it towards fractionalNumberOfOrdersToFill - remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0); - continue; - } - - const { wethSpentAmount, makerAssetAcquiredAmount } = this._simulateSingleFill( - balances, - order, - ordersInfoBefore[i].orderTakerAssetFilledAmount, - Math.min(remainingOrdersToFill, 1), - options.bridgeExcessBuyAmount || constants.ZERO_AMOUNT, - ); - remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0); - - currentTotal.wethSpentAmount = currentTotal.wethSpentAmount.plus(wethSpentAmount); - currentTotal.makerAssetAcquiredAmount = currentTotal.makerAssetAcquiredAmount.plus( - makerAssetAcquiredAmount, - ); - } - - return { ...currentTotal, balances }; - } - - private _simulateSingleFill( - balances: LocalBalanceStore, - order: SignedOrder, - takerAssetFilled: BigNumber, - fillFraction: number, - bridgeExcessBuyAmount: BigNumber, - ): ForwarderFillState { - let { makerAssetAmount, takerAssetAmount, makerFee, takerFee } = order; - makerAssetAmount = makerAssetAmount.times(fillFraction).integerValue(BigNumber.ROUND_CEIL); - takerAssetAmount = takerAssetAmount.times(fillFraction).integerValue(BigNumber.ROUND_CEIL); - makerFee = makerFee.times(fillFraction).integerValue(BigNumber.ROUND_CEIL); - takerFee = takerFee.times(fillFraction).integerValue(BigNumber.ROUND_CEIL); - - // Accounting for partially filled orders - // As with unfillable orders, these still count as 1 towards fractionalNumberOfOrdersToFill - takerAssetAmount = BigNumber.max(takerAssetAmount.minus(takerAssetFilled), 0); - const makerAssetFilled = takerAssetFilled - .times(order.makerAssetAmount) - .dividedToIntegerBy(order.takerAssetAmount); - makerAssetAmount = BigNumber.max(makerAssetAmount.minus(makerAssetFilled), 0); - const makerFeeFilled = takerAssetFilled.times(order.makerFee).dividedToIntegerBy(order.takerAssetAmount); - makerFee = BigNumber.max(makerFee.minus(makerFeeFilled), 0); - const takerFeeFilled = takerAssetFilled.times(order.takerFee).dividedToIntegerBy(order.takerAssetAmount); - takerFee = BigNumber.max(takerFee.minus(takerFeeFilled), 0); - - makerAssetAmount = makerAssetAmount.plus(bridgeExcessBuyAmount); - let wethSpentAmount = takerAssetAmount.plus(DeploymentManager.protocolFee); - let makerAssetAcquiredAmount = makerAssetAmount; - if (areUnderlyingAssetsEqual(order.takerFeeAssetData, order.makerAssetData)) { - makerAssetAcquiredAmount = makerAssetAcquiredAmount.minus(takerFee); - } else if (order.takerFeeAssetData === order.takerAssetData) { - wethSpentAmount = wethSpentAmount.plus(takerFee); - } - - // Taker sends ETH to Forwarder - balances.sendEth(this._taker.address, this._forwarder.address, wethSpentAmount); - // Forwarder wraps the ETH - balances.wrapEth(this._forwarder.address, this._deployment.tokens.weth.address, wethSpentAmount); - // (In reality this is done all at once, but we simulate it order by order) - - // Forwarder -> Maker - balances.transferAsset(this._forwarder.address, order.makerAddress, takerAssetAmount, order.takerAssetData); - // Maker -> Forwarder - balances.transferAsset(order.makerAddress, this._forwarder.address, makerAssetAmount, order.makerAssetData); - // Forwarder -> Order fee recipient - balances.transferAsset(this._forwarder.address, order.feeRecipientAddress, takerFee, order.takerFeeAssetData); - // Maker -> Order fee recipient - balances.transferAsset(order.makerAddress, order.feeRecipientAddress, makerFee, order.makerFeeAssetData); - // Forwarder pays the protocol fee in WETH - balances.transferAsset( - this._forwarder.address, - this._deployment.staking.stakingProxy.address, - DeploymentManager.protocolFee, - order.takerAssetData, - ); - // Forwarder gives acquired maker asset to taker - balances.transferAsset( - this._forwarder.address, - this._taker.address, - makerAssetAcquiredAmount, - order.makerAssetData, - ); - - return { wethSpentAmount, makerAssetAcquiredAmount, balances }; - } -} diff --git a/contracts/integrations/test/forwarder/types.ts b/contracts/integrations/test/forwarder/types.ts deleted file mode 100644 index 47b01a0cab..0000000000 --- a/contracts/integrations/test/forwarder/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export interface V2Order { - makerAddress: string; - takerAddress: string; - senderAddress: string; - feeRecipientAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - salt: BigNumber; - expirationTimeSeconds: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; -} - -export interface SignedV2Order extends V2Order { - signature: string; -} diff --git a/contracts/integrations/test/framework/actors/base.ts b/contracts/integrations/test/framework/actors/base.ts deleted file mode 100644 index 4e0c5b7896..0000000000 --- a/contracts/integrations/test/framework/actors/base.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from '@0x/contracts-erc1155'; -import { DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { constants, filterLogsToArguments, getRandomInteger, TransactionFactory } from '@0x/contracts-test-utils'; -import { SignatureType, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AssertionResult } from '../assertions/function_assertion'; -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -export type Constructor = new (...args: any[]) => T; - -export interface ActorConfig { - name?: string; - deployment: DeploymentManager; - [mixinProperty: string]: any; -} - -export class Actor { - public static count: number = 0; - public readonly address: string; - public readonly name: string; - public readonly privateKey: Buffer; - public readonly deployment: DeploymentManager; - public simulationEnvironment?: SimulationEnvironment; - public simulationActions: { - [action: string]: AsyncIterableIterator; - } = {}; - public mixins: string[] = []; - protected readonly _transactionFactory: TransactionFactory; - - public static reset(): void { - Actor.count = 0; - } - - constructor(config: ActorConfig) { - Actor.count++; - - // Emit an error if the actor count is too high. - if (Actor.count >= config.deployment.accounts.length) { - throw new Error('Actor count too large'); - } - - this.address = config.deployment.accounts[Actor.count]; - this.name = config.name || this.address; - this.deployment = config.deployment; - this.privateKey = constants.TESTRPC_PRIVATE_KEYS[config.deployment.accounts.indexOf(this.address)]; - this._transactionFactory = new TransactionFactory( - this.privateKey, - config.deployment.exchange.address, - config.deployment.chainId, - ); - } - - /** - * Sets a balance for an ERC20 token and approves a spender (defaults to the ERC20 asset proxy) - * to transfer the token. - */ - public async configureERC20TokenAsync( - token: DummyERC20TokenContract | WETH9Contract, - spender?: string, - amount?: BigNumber, - ): Promise { - if (token instanceof DummyERC20TokenContract) { - await token - .setBalance(this.address, amount || constants.INITIAL_ERC20_BALANCE) - .awaitTransactionSuccessAsync(); - } else { - await token.deposit().awaitTransactionSuccessAsync({ - from: this.address, - value: amount || constants.ONE_ETHER, - }); - } - - await token - .approve(spender || this.deployment.assetProxies.erc20Proxy.address, constants.MAX_UINT256) - .awaitTransactionSuccessAsync({ from: this.address }); - } - - /** - * Mints some number of ERC721 NFTs and approves a spender (defaults to the ERC721 asset proxy) - * to transfer the token. - */ - public async configureERC721TokenAsync( - token: DummyERC721TokenContract, - spender?: string, - numToMint: number = 1, - ): Promise { - const tokenIds: BigNumber[] = []; - _.times(numToMint, async () => { - const tokenId = getRandomInteger(constants.ZERO_AMOUNT, constants.MAX_UINT256); - await token.mint(this.address, tokenId).awaitTransactionSuccessAsync({ - from: this.address, - }); - tokenIds.push(tokenId); - }); - - await token - .setApprovalForAll(spender || this.deployment.assetProxies.erc721Proxy.address, true) - .awaitTransactionSuccessAsync({ - from: this.address, - }); - return tokenIds; - } - - /** - * Mints some number of ERC1115 fungible tokens and approves a spender (defaults to the ERC1155 asset proxy) - * to transfer the token. - */ - public async configureERC1155TokenAsync( - token: ERC1155MintableContract, - spender?: string, - amount?: BigNumber, - ): Promise { - // Create a fungible token. - const receipt = await token.create('', false).awaitTransactionSuccessAsync({ from: this.address }); - const logs = filterLogsToArguments(receipt.logs, 'TransferSingle'); - - // Throw if the wrong number of logs were received. - if (logs.length !== 1) { - throw new Error('Invalid number of `TransferSingle` logs'); - } - const { id } = logs[0]; - - // Mint the token - await token - .mintFungible(id, [this.address], [amount || new BigNumber(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)]) - .awaitTransactionSuccessAsync({ from: this.address }); - - // Set approval for all token types for the spender. - await token - .setApprovalForAll(spender || this.deployment.assetProxies.erc1155Proxy.address, true) - .awaitTransactionSuccessAsync({ from: this.address }); - - return id; - } - - /** - * Signs a transaction. - */ - public async signTransactionAsync( - customTransactionParams: Partial, - signatureType: SignatureType = SignatureType.EthSign, - ): Promise { - return this._transactionFactory.newSignedTransactionAsync( - { - gasPrice: DeploymentManager.gasPrice, - ...customTransactionParams, - }, - signatureType, - ); - } -} diff --git a/contracts/integrations/test/framework/actors/fee_recipient.ts b/contracts/integrations/test/framework/actors/fee_recipient.ts deleted file mode 100644 index a2716df1f6..0000000000 --- a/contracts/integrations/test/framework/actors/fee_recipient.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { BaseContract } from '@0x/base-contract'; -import { ApprovalFactory, SignedCoordinatorApproval } from '@0x/contracts-coordinator'; -import { SignatureType, SignedZeroExTransaction } from '@0x/types'; - -import { Actor, ActorConfig, Constructor } from './base'; - -interface FeeRecipientConfig extends ActorConfig { - verifyingContract?: BaseContract; -} - -export interface FeeRecipientInterface { - approvalFactory?: ApprovalFactory; - signCoordinatorApproval: ( - transaction: SignedZeroExTransaction, - txOrigin: string, - signatureType?: SignatureType, - ) => SignedCoordinatorApproval; -} - -/** - * This mixin encapsulates functionality associated with fee recipients within the 0x ecosystem. - * As of writing, the only extra functionality provided is signing Coordinator approvals. - */ -export function FeeRecipientMixin(Base: TBase): TBase & Constructor { - return class extends Base { - public readonly actor: Actor; - public readonly approvalFactory?: ApprovalFactory; - - /** - * The mixin pattern requires that this constructor uses `...args: any[]`, but this class - * really expects a single `FeeRecipientConfig` parameter (assuming `Actor` is used as the - * base class). - */ - constructor(...args: any[]) { - // tslint:disable-next-line:no-inferred-empty-object-type - super(...args); - this.actor = (this as any) as Actor; - this.actor.mixins.push('FeeRecipient'); - - const { verifyingContract } = args[0] as FeeRecipientConfig; - if (verifyingContract !== undefined) { - this.approvalFactory = new ApprovalFactory(this.actor.privateKey, verifyingContract.address); - } - } - - /** - * Signs an coordinator transaction. - */ - public signCoordinatorApproval( - transaction: SignedZeroExTransaction, - txOrigin: string, - signatureType: SignatureType = SignatureType.EthSign, - ): SignedCoordinatorApproval { - if (this.approvalFactory === undefined) { - throw new Error('No verifying contract provided in FeeRecipient constructor'); - } - return this.approvalFactory.newSignedApproval(transaction, txOrigin, signatureType); - } - }; -} - -export class FeeRecipient extends FeeRecipientMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/hybrids.ts b/contracts/integrations/test/framework/actors/hybrids.ts deleted file mode 100644 index 51a73a43b2..0000000000 --- a/contracts/integrations/test/framework/actors/hybrids.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Actor } from './base'; -import { KeeperMixin } from './keeper'; -import { MakerMixin } from './maker'; -import { PoolOperatorMixin } from './pool_operator'; -import { StakerMixin } from './staker'; -import { TakerMixin } from './taker'; - -export class OperatorMaker extends PoolOperatorMixin(MakerMixin(Actor)) {} -export class StakerMaker extends StakerMixin(MakerMixin(Actor)) {} -export class StakerOperator extends StakerMixin(PoolOperatorMixin(Actor)) {} -export class OperatorStakerMaker extends PoolOperatorMixin(StakerMixin(MakerMixin(Actor))) {} -export class StakerKeeper extends StakerMixin(KeeperMixin(Actor)) {} -export class MakerTaker extends MakerMixin(TakerMixin(Actor)) {} diff --git a/contracts/integrations/test/framework/actors/keeper.ts b/contracts/integrations/test/framework/actors/keeper.ts deleted file mode 100644 index 8486ae7109..0000000000 --- a/contracts/integrations/test/framework/actors/keeper.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { - AggregatedStats, - IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs, - TestStakingEvents, -} from '@0x/contracts-staking'; -import { filterLogsToArguments, web3Wrapper } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { BlockParamLiteral, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { - endEpochTooEarlyAssertion, - endEpochUnfinalizedPoolsAssertion, - validEndEpochAssertion, -} from '../assertions/endEpoch'; -import { validFinalizePoolAssertion } from '../assertions/finalizePool'; -import { AssertionResult } from '../assertions/function_assertion'; -import { Pseudorandom } from '../utils/pseudorandom'; - -import { Actor, Constructor } from './base'; - -export interface KeeperInterface { - endEpochAsync: (shouldFastForward?: boolean) => Promise; - finalizePoolsAsync: (poolIds?: string[]) => Promise; -} - -/** - * This mixin encapsulates functionality associated with keepers within the 0x ecosystem. - * This includes ending epochs sand finalizing pools in the staking system. - */ -export function KeeperMixin(Base: TBase): TBase & Constructor { - return class extends Base { - public readonly actor: Actor; - - /** - * The mixin pattern requires that this constructor uses `...args: any[]`, but this class - * really expects a single `Actor` parameter (assuming `Actor` is used as the base - * class). - */ - constructor(...args: any[]) { - // tslint:disable-next-line:no-inferred-empty-object-type - super(...args); - this.actor = (this as any) as Actor; - this.actor.mixins.push('Keeper'); - - // Register this mixin's assertion generators - this.actor.simulationActions = { - ...this.actor.simulationActions, - validFinalizePool: this._validFinalizePool(), - validEndEpoch: this._validEndEpoch(), - invalidEndEpoch: this._invalidEndEpoch(), - }; - } - - /** - * Ends the current epoch, fast-forwarding to the end of the epoch by default. - */ - public async endEpochAsync(shouldFastForward: boolean = true): Promise { - const { stakingWrapper } = this.actor.deployment.staking; - if (shouldFastForward) { - await this._fastForwardToNextEpochAsync(); - } - return stakingWrapper.endEpoch().awaitTransactionSuccessAsync({ from: this.actor.address }); - } - - /** - * Finalizes staking pools corresponding to the given `poolIds`. If none are provided, - * finalizes all pools that earned rewards in the previous epoch. - */ - public async finalizePoolsAsync(poolIds: string[] = []): Promise { - const { stakingWrapper } = this.actor.deployment.staking; - // If no poolIds provided, finalize all active pools from the previous epoch - if (poolIds.length === 0) { - const previousEpoch = (await stakingWrapper.currentEpoch().callAsync()).minus(1); - const events = filterLogsToArguments( - await stakingWrapper.getLogsAsync( - TestStakingEvents.StakingPoolEarnedRewardsInEpoch, - { fromBlock: BlockParamLiteral.Earliest, toBlock: BlockParamLiteral.Latest }, - { epoch: new BigNumber(previousEpoch) }, - ), - TestStakingEvents.StakingPoolEarnedRewardsInEpoch, - ); - poolIds.concat(events.map(event => event.poolId)); - } - - return Promise.all( - poolIds.map(async poolId => - stakingWrapper.finalizePool(poolId).awaitTransactionSuccessAsync({ - from: this.actor.address, - }), - ), - ); - } - - private async *_validFinalizePool(): AsyncIterableIterator { - const { stakingPools } = this.actor.simulationEnvironment!; - const assertion = validFinalizePoolAssertion(this.actor.deployment, this.actor.simulationEnvironment!); - while (true) { - // Finalize a random pool, or do nothing if there are no pools in the simulation yet. - const poolId = Pseudorandom.sample(Object.keys(stakingPools)); - if (poolId === undefined) { - yield; - } else { - yield assertion.executeAsync([poolId], { from: this.actor.address }); - } - } - } - - private async *_validEndEpoch(): AsyncIterableIterator { - const assertion = validEndEpochAssertion(this.actor.deployment, this.actor.simulationEnvironment!); - const { stakingWrapper } = this.actor.deployment.staking; - while (true) { - const { currentEpoch } = this.actor.simulationEnvironment!; - const aggregatedStats = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(currentEpoch.minus(1)).callAsync(), - ); - if (aggregatedStats.numPoolsToFinalize.isGreaterThan(0)) { - // Can't end the epoch if the previous epoch is not fully finalized. - yield; - } else { - await this._fastForwardToNextEpochAsync(); - yield assertion.executeAsync([], { from: this.actor.address }); - } - } - } - - private async *_invalidEndEpoch(): AsyncIterableIterator { - const { stakingWrapper } = this.actor.deployment.staking; - while (true) { - const { simulationEnvironment } = this.actor; - const aggregatedStats = AggregatedStats.fromArray( - await stakingWrapper - .aggregatedStatsByEpoch(simulationEnvironment!.currentEpoch.minus(1)) - .callAsync(), - ); - const assertion = aggregatedStats.numPoolsToFinalize.isGreaterThan(0) - ? endEpochUnfinalizedPoolsAssertion( - this.actor.deployment, - simulationEnvironment!, - aggregatedStats.numPoolsToFinalize, - ) - : endEpochTooEarlyAssertion(this.actor.deployment); - - yield assertion.executeAsync([], { from: this.actor.address }); - } - } - - private async _fastForwardToNextEpochAsync(): Promise { - const { stakingWrapper } = this.actor.deployment.staking; - - // increase timestamp of next block by how many seconds we need to - // get to the next epoch. - const epochEndTime = await stakingWrapper.getCurrentEpochEarliestEndTimeInSeconds().callAsync(); - const lastBlockTime = await web3Wrapper.getBlockTimestampAsync('latest'); - const dt = Math.max(0, epochEndTime.minus(lastBlockTime).toNumber()); - await web3Wrapper.increaseTimeAsync(dt); - // mine next block - await web3Wrapper.mineBlockAsync(); - } - }; -} - -export class Keeper extends KeeperMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/maker.ts b/contracts/integrations/test/framework/actors/maker.ts deleted file mode 100644 index a725ffb19d..0000000000 --- a/contracts/integrations/test/framework/actors/maker.ts +++ /dev/null @@ -1,247 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { DummyERC20TokenContract } from '@0x/contracts-erc20'; -import { constants, OrderFactory } from '@0x/contracts-test-utils'; -import { Order, SignedOrder } from '@0x/types'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { AssertionResult } from '../assertions/function_assertion'; -import { validJoinStakingPoolAssertion } from '../assertions/joinStakingPool'; -import { Pseudorandom } from '../utils/pseudorandom'; - -import { Actor, ActorConfig, Constructor } from './base'; - -interface MakerConfig extends ActorConfig { - orderConfig: Partial; -} - -export interface MakerInterface { - makerPoolId?: string; - orderFactory: OrderFactory; - signOrderAsync: (customOrderParams?: Partial) => Promise; - cancelOrderAsync: (order: SignedOrder) => Promise; - joinStakingPoolAsync: (poolId: string) => Promise; - createFillableOrderAsync: (taker: Actor) => Promise; - createMatchableOrdersAsync(taker: Actor): Promise<[SignedOrder, SignedOrder]>; -} - -/** - * This mixin encapsulates functionality associated with makers within the 0x ecosystem. - * This includes signing and canceling orders, as well as joining a staking pool as a maker. - */ -export function MakerMixin(Base: TBase): TBase & Constructor { - return class extends Base { - public makerPoolId?: string; - public readonly actor: Actor; - public readonly orderFactory: OrderFactory; - - /** - * The mixin pattern requires that this constructor uses `...args: any[]`, but this class - * really expects a single `MakerConfig` parameter (assuming `Actor` is used as the base - * class). - */ - constructor(...args: any[]) { - // tslint:disable-next-line:no-inferred-empty-object-type - super(...args); - this.actor = (this as any) as Actor; - this.actor.mixins.push('Maker'); - - const { orderConfig } = args[0] as MakerConfig; - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - makerAddress: this.actor.address, - exchangeAddress: this.actor.deployment.exchange.address, - chainId: this.actor.deployment.chainId, - ...orderConfig, - }; - this.orderFactory = new OrderFactory(this.actor.privateKey, defaultOrderParams); - - // Register this mixin's assertion generators - this.actor.simulationActions = { - ...this.actor.simulationActions, - validJoinStakingPool: this._validJoinStakingPool(), - }; - } - - /** - * Signs an order (optionally, with custom parameters) as the maker. - */ - public async signOrderAsync(customOrderParams: Partial = {}): Promise { - return this.orderFactory.newSignedOrderAsync(customOrderParams); - } - - /** - * Cancels one of the maker's orders. - */ - public async cancelOrderAsync(order: SignedOrder): Promise { - return this.actor.deployment.exchange.cancelOrder(order).awaitTransactionSuccessAsync({ - from: this.actor.address, - }); - } - - /** - * Joins the staking pool specified by the given ID. - */ - public async joinStakingPoolAsync(poolId: string): Promise { - const stakingContract = this.actor.deployment.staking.stakingWrapper; - this.makerPoolId = poolId; - return stakingContract.joinStakingPoolAsMaker(poolId).awaitTransactionSuccessAsync({ - from: this.actor.address, - }); - } - - public async createFillableOrderAsync(taker: Actor): Promise { - const { actors, balanceStore } = this.actor.simulationEnvironment!; - await balanceStore.updateErc20BalancesAsync(); - - // Choose the assets for the order - const [makerToken, makerFeeToken, takerToken, takerFeeToken] = Pseudorandom.sampleSize( - this.actor.deployment.tokens.erc20, - 4, // tslint:disable-line:custom-no-magic-numbers - )!; - - // Maker and taker set balances/allowances to guarantee that the fill succeeds. - // Amounts are chosen to be within each actor's balance (divided by 8, in case - // e.g. makerAsset = makerFeeAsset) - const [makerAssetAmount, makerFee, takerAssetAmount, takerFee] = await Promise.all( - [ - [this.actor, makerToken], - [this.actor, makerFeeToken], - [taker, takerToken], - [taker, takerFeeToken], - ].map(async ([owner, token]) => { - let balance = balanceStore.balances.erc20[owner.address][token.address]; - await (owner as Actor).configureERC20TokenAsync(token as DummyERC20TokenContract); - balance = balanceStore.balances.erc20[owner.address][token.address] = - constants.INITIAL_ERC20_BALANCE; - return Pseudorandom.integer(0, balance.dividedToIntegerBy(2)); - }), - ); - // Encode asset data - const [makerAssetData, makerFeeAssetData, takerAssetData, takerFeeAssetData] = [ - makerToken, - makerFeeToken, - takerToken, - takerFeeToken, - ].map(token => encodeERC20AssetData(token.address)); - - // Maker signs the order - return this.signOrderAsync({ - makerAssetData, - takerAssetData, - makerFeeAssetData, - takerFeeAssetData, - makerAssetAmount, - takerAssetAmount, - makerFee, - takerFee, - feeRecipientAddress: Pseudorandom.sample(actors)!.address, - }); - } - - public async createMatchableOrdersAsync(taker: Actor): Promise<[SignedOrder, SignedOrder]> { - const { actors, balanceStore } = this.actor.simulationEnvironment!; - await balanceStore.updateErc20BalancesAsync(); - - // Choose the assets for the orders - const [leftMakerToken, leftTakerToken, makerFeeToken, takerFeeToken] = Pseudorandom.sampleSize( - this.actor.deployment.tokens.erc20, - 4, // tslint:disable-line:custom-no-magic-numbers - )!; - const rightMakerToken = leftTakerToken; - const rightTakerToken = leftMakerToken; - - // Maker and taker set balances/allowances to guarantee that the fill succeeds. - // Amounts are chosen to be within each actor's balance (divided by 2, in case - // e.g. makerAsset = makerFeeAsset) - const [leftMakerAssetAmount, makerFee, leftTakerAssetAmount, takerFee] = await Promise.all( - [ - [this.actor, leftMakerToken], - [this.actor, rightMakerToken], - [this.actor, makerFeeToken], - [taker, takerFeeToken], - ].map(async ([owner, token]) => { - let balance = balanceStore.balances.erc20[owner.address][token.address]; - await (owner as Actor).configureERC20TokenAsync(token as DummyERC20TokenContract); - balance = balanceStore.balances.erc20[owner.address][token.address] = - constants.INITIAL_ERC20_BALANCE; - return Pseudorandom.integer(0, balance.dividedToIntegerBy(8)); - }), - ); - - // Select random amounts for the right order. The only constraint is that the slope - // of the left price curve is greater or equal to the inverse right price curve. - // leftMakerAssetAmount/leftTakerAssetAmount >= rightTakerAssetAmount/rightMakerAssetAmount. - // We set the `rightMakerAssetAmount` equal to the `leftTakerAssetAmount` with probability 1/10, - // otherwise this scenario will never occur. - const shouldSetRightMakerEqualToLeftTakerAmount = Pseudorandom.integer(1, 10).eq(1); - const rightMakerAssetAmount = shouldSetRightMakerEqualToLeftTakerAmount - ? leftTakerAssetAmount - : Pseudorandom.integer(1, constants.INITIAL_ERC20_BALANCE.dividedToIntegerBy(8)); - const rightTakerAssetAmount = Pseudorandom.integer( - 1, - rightMakerAssetAmount.times(leftMakerAssetAmount).dividedToIntegerBy(leftTakerAssetAmount), - ); - - // Encode asset data - const [ - leftMakerAssetData, - leftTakerAssetData, - rightMakerAssetData, - rightTakerAssetData, - makerFeeAssetData, - takerFeeAssetData, - ] = [ - leftMakerToken, - leftTakerToken, - rightMakerToken, - rightTakerToken, - makerFeeToken, - takerFeeToken, - ].map(token => encodeERC20AssetData(token.address)); - - // Construct and sign the left order - const leftOrder = await this.signOrderAsync({ - makerAssetData: leftMakerAssetData, - takerAssetData: leftTakerAssetData, - makerFeeAssetData, - takerFeeAssetData, - makerAssetAmount: leftMakerAssetAmount, - takerAssetAmount: leftTakerAssetAmount, - makerFee, - takerFee, - feeRecipientAddress: Pseudorandom.sample(actors)!.address, - }); - - // Construct and sign the right order - const rightOrder = await this.signOrderAsync({ - makerAssetData: rightMakerAssetData, - takerAssetData: rightTakerAssetData, - makerFeeAssetData, - takerFeeAssetData, - makerAssetAmount: rightMakerAssetAmount, - takerAssetAmount: rightTakerAssetAmount, - makerFee, - takerFee, - feeRecipientAddress: Pseudorandom.sample(actors)!.address, - }); - - return [leftOrder, rightOrder]; - } - - private async *_validJoinStakingPool(): AsyncIterableIterator { - const { stakingPools } = this.actor.simulationEnvironment!; - const assertion = validJoinStakingPoolAssertion(this.actor.deployment); - while (true) { - const poolId = Pseudorandom.sample(Object.keys(stakingPools)); - if (poolId === undefined) { - yield; - } else { - this.makerPoolId = poolId; - yield assertion.executeAsync([poolId], { from: this.actor.address }); - } - } - } - }; -} - -export class Maker extends MakerMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/pool_operator.ts b/contracts/integrations/test/framework/actors/pool_operator.ts deleted file mode 100644 index 9960cbc60f..0000000000 --- a/contracts/integrations/test/framework/actors/pool_operator.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { constants as stakingConstants, StakingPoolById } from '@0x/contracts-staking'; -import { constants } from '@0x/contracts-test-utils'; -import '@azure/core-asynciterator-polyfill'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { invalidCreateStakingPoolAssertion, validCreateStakingPoolAssertion } from '../assertions/createStakingPool'; -import { - invalidDecreaseStakingPoolOperatorShareAssertion, - validDecreaseStakingPoolOperatorShareAssertion, -} from '../assertions/decreaseStakingPoolOperatorShare'; -import { AssertionResult } from '../assertions/function_assertion'; -import { Distributions, Pseudorandom } from '../utils/pseudorandom'; - -import { Actor, Constructor } from './base'; - -export interface PoolOperatorInterface { - createStakingPoolAsync: (operatorShare: number, addOperatorAsMaker?: boolean) => Promise; - decreaseOperatorShareAsync: ( - poolId: string, - newOperatorShare: number, - ) => Promise; -} - -/** - * This mixin encapsulates functionality associated with pool operators within the 0x ecosystem. - * This includes creating staking pools and decreasing the operator share of a pool. - */ -export function PoolOperatorMixin(Base: TBase): TBase & Constructor { - return class extends Base { - public readonly actor: Actor; - - /** - * The mixin pattern requires that this constructor uses `...args: any[]`, but this class - * really expects a single `ActorConfig` parameter (assuming `Actor` is used as the - * base class). - */ - constructor(...args: any[]) { - // tslint:disable-next-line:no-inferred-empty-object-type - super(...args); - this.actor = (this as any) as Actor; - this.actor.mixins.push('PoolOperator'); - - // Register this mixin's assertion generators - this.actor.simulationActions = { - ...this.actor.simulationActions, - validCreateStakingPool: this._validCreateStakingPool(), - invalidCreateStakingPool: this._invalidCreateStakingPool(), - validDecreaseStakingPoolOperatorShare: this._validDecreaseStakingPoolOperatorShare(), - invalidDecreaseStakingPoolOperatorShare: this._invalidDecreaseStakingPoolOperatorShare(), - }; - } - - /** - * Creates a staking pool and returns the ID of the new pool. - */ - public async createStakingPoolAsync( - operatorShare: number, - addOperatorAsMaker: boolean = false, - ): Promise { - const stakingContract = this.actor.deployment.staking.stakingWrapper; - const txReceipt = await stakingContract - .createStakingPool(operatorShare, addOperatorAsMaker) - .awaitTransactionSuccessAsync({ from: this.actor.address }); - - const createStakingPoolLog = txReceipt.logs[0]; - const poolId = (createStakingPoolLog as any).args.poolId; - return poolId; - } - - /** - * Decreases the operator share of a specified staking pool. - */ - public async decreaseOperatorShareAsync( - poolId: string, - newOperatorShare: number, - ): Promise { - const stakingContract = this.actor.deployment.staking.stakingWrapper; - return stakingContract - .decreaseStakingPoolOperatorShare(poolId, newOperatorShare) - .awaitTransactionSuccessAsync({ from: this.actor.address }); - } - - private _getOperatorPoolIds(stakingPools: StakingPoolById): string[] { - const operatorPools = _.pickBy(stakingPools, pool => pool.operator === this.actor.address); - return Object.keys(operatorPools); - } - - private async *_validCreateStakingPool(): AsyncIterableIterator { - const assertion = validCreateStakingPoolAssertion(this.actor.deployment, this.actor.simulationEnvironment!); - while (true) { - const operatorShare = Pseudorandom.integer( - 0, - stakingConstants.PPM, - Distributions.Kumaraswamy(), - ).toNumber(); - yield assertion.executeAsync([operatorShare, false], { from: this.actor.address }); - } - } - - private async *_invalidCreateStakingPool(): AsyncIterableIterator { - const assertion = invalidCreateStakingPoolAssertion(this.actor.deployment); - while (true) { - const operatorShare = Pseudorandom.integer( - (stakingConstants.PPM as number) + 1, - constants.MAX_UINT32, - Distributions.Kumaraswamy(), - ).toNumber(); - yield assertion.executeAsync([operatorShare, false], { from: this.actor.address }); - } - } - - private async *_validDecreaseStakingPoolOperatorShare(): AsyncIterableIterator { - const { stakingPools } = this.actor.simulationEnvironment!; - const assertion = validDecreaseStakingPoolOperatorShareAssertion(this.actor.deployment, stakingPools); - while (true) { - const poolId = Pseudorandom.sample(this._getOperatorPoolIds(stakingPools)); - if (poolId === undefined) { - yield undefined; - } else { - const operatorShare = Pseudorandom.integer( - 0, - stakingPools[poolId].operatorShare, - Distributions.Kumaraswamy(), - ).toNumber(); - yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address }); - } - } - } - - private async *_invalidDecreaseStakingPoolOperatorShare(): AsyncIterableIterator { - const { stakingPools } = this.actor.simulationEnvironment!; - const assertion = invalidDecreaseStakingPoolOperatorShareAssertion(this.actor.deployment); - while (true) { - const poolId = Pseudorandom.sample(this._getOperatorPoolIds(stakingPools)); - if (poolId === undefined) { - yield undefined; - } else { - const operatorShare = Pseudorandom.integer( - (stakingPools[poolId].operatorShare as number) + 1, - constants.MAX_UINT32, - Distributions.Kumaraswamy(), - ).toNumber(); - yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address }); - } - } - } - }; -} - -export class PoolOperator extends PoolOperatorMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/staker.ts b/contracts/integrations/test/framework/actors/staker.ts deleted file mode 100644 index 3eae6f65b6..0000000000 --- a/contracts/integrations/test/framework/actors/staker.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { OwnerStakeByStatus, StakeInfo, StakeStatus, StoredBalance } from '@0x/contracts-staking'; -import { constants } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import '@azure/core-asynciterator-polyfill'; -import * as _ from 'lodash'; - -import { AssertionResult } from '../assertions/function_assertion'; -import { assetProxyTransferFailedAssertion } from '../assertions/generic_assertions'; -import { moveStakeNonexistentPoolAssertion, validMoveStakeAssertion } from '../assertions/moveStake'; -import { validStakeAssertion } from '../assertions/stake'; -import { invalidUnstakeAssertion, validUnstakeAssertion } from '../assertions/unstake'; -import { - invalidWithdrawDelegatorRewardsAssertion, - validWithdrawDelegatorRewardsAssertion, -} from '../assertions/withdrawDelegatorRewards'; -import { Pseudorandom } from '../utils/pseudorandom'; - -import { Actor, Constructor } from './base'; - -export interface StakerInterface { - stakeAsync: (amount: BigNumber, poolId?: string) => Promise; -} - -/** - * This mixin encapsulates functionality associated with stakers within the 0x ecosystem. - * This includes staking ZRX (and optionally delegating it to a specific pool). - */ -export function StakerMixin(Base: TBase): TBase & Constructor { - return class extends Base { - public stake: OwnerStakeByStatus; - public readonly actor: Actor; - - /** - * The mixin pattern requires that this constructor uses `...args: any[]`, but this class - * really expects a single `ActorConfig` parameter (assuming `Actor` is used as the base - * class). - */ - constructor(...args: any[]) { - // tslint:disable-next-line:no-inferred-empty-object-type - super(...args); - this.actor = (this as any) as Actor; - this.actor.mixins.push('Staker'); - - this.stake = { - [StakeStatus.Undelegated]: new StoredBalance(), - [StakeStatus.Delegated]: { total: new StoredBalance() }, - }; - - // Register this mixin's assertion generators - this.actor.simulationActions = { - ...this.actor.simulationActions, - validStake: this._validStake(), - invalidStake: this._invalidStake(), - validUnstake: this._validUnstake(), - invalidUnstake: this._invalidUnstake(), - validMoveStake: this._validMoveStake(), - moveStakeNonexistentPool: this._moveStakeNonexistentPool(), - validWithdrawDelegatorRewards: this._validWithdrawDelegatorRewards(), - invalidWithdrawDelegatorRewards: this._invalidWithdrawDelegatorRewards(), - }; - } - - /** - * Stakes the given amount of ZRX. If `poolId` is provided, subsequently delegates the newly - * staked ZRX with that pool. - */ - public async stakeAsync(amount: BigNumber, poolId?: string): Promise { - const { stakingWrapper } = this.actor.deployment.staking; - await stakingWrapper.stake(amount).awaitTransactionSuccessAsync({ - from: this.actor.address, - }); - if (poolId !== undefined) { - await stakingWrapper - .moveStake( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - amount, - ) - .awaitTransactionSuccessAsync({ from: this.actor.address }); - } - } - - private async *_validStake(): AsyncIterableIterator { - const { zrx } = this.actor.deployment.tokens; - const { deployment, balanceStore } = this.actor.simulationEnvironment!; - const assertion = validStakeAssertion(deployment, this.actor.simulationEnvironment!, this.stake); - - while (true) { - await balanceStore.updateErc20BalancesAsync(); - const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address]; - const amount = Pseudorandom.integer(0, zrxBalance); - yield assertion.executeAsync([amount], { from: this.actor.address }); - } - } - - private async *_invalidStake(): AsyncIterableIterator { - const { zrx } = this.actor.deployment.tokens; - const { deployment, balanceStore } = this.actor.simulationEnvironment!; - const assertion = assetProxyTransferFailedAssertion(deployment.staking.stakingWrapper, 'stake'); - - while (true) { - await balanceStore.updateErc20BalancesAsync(); - const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address]; - const amount = Pseudorandom.integer(zrxBalance.plus(1), constants.MAX_UINT256); - yield assertion.executeAsync([amount], { from: this.actor.address }); - } - } - - private async *_validUnstake(): AsyncIterableIterator { - const { stakingWrapper } = this.actor.deployment.staking; - const { deployment, balanceStore } = this.actor.simulationEnvironment!; - const assertion = validUnstakeAssertion(deployment, this.actor.simulationEnvironment!, this.stake); - - while (true) { - await balanceStore.updateErc20BalancesAsync(); - const undelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(this.actor.address, StakeStatus.Undelegated) - .callAsync(); - const withdrawableStake = BigNumber.min( - undelegatedStake.currentEpochBalance, - undelegatedStake.nextEpochBalance, - ); - const amount = Pseudorandom.integer(0, withdrawableStake); - yield assertion.executeAsync([amount], { from: this.actor.address }); - } - } - - private async *_invalidUnstake(): AsyncIterableIterator { - const { stakingWrapper } = this.actor.deployment.staking; - const { deployment, balanceStore } = this.actor.simulationEnvironment!; - - while (true) { - await balanceStore.updateErc20BalancesAsync(); - const undelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(this.actor.address, StakeStatus.Undelegated) - .callAsync(); - const withdrawableStake = BigNumber.min( - undelegatedStake.currentEpochBalance, - undelegatedStake.nextEpochBalance, - ); - const assertion = invalidUnstakeAssertion(deployment, withdrawableStake); - const amount = Pseudorandom.integer(withdrawableStake.plus(1), constants.MAX_UINT256); - yield assertion.executeAsync([amount], { from: this.actor.address }); - } - } - - private _validMoveParams(): [StakeInfo, StakeInfo, BigNumber] { - const { stakingPools, currentEpoch } = this.actor.simulationEnvironment!; - // Pick a random pool that this staker has delegated to (undefined if no such pools exist) - const fromPoolId = Pseudorandom.sample(Object.keys(_.omit(this.stake[StakeStatus.Delegated], ['total']))); - // The `from` status must be Undelegated if the staker isn't delegated to any pools - // at the moment, or if the chosen pool is unfinalized - const fromStatus = - fromPoolId === undefined || stakingPools[fromPoolId].lastFinalized.isLessThan(currentEpoch.minus(1)) - ? StakeStatus.Undelegated - : (Pseudorandom.sample( - [StakeStatus.Undelegated, StakeStatus.Delegated], - [0.2, 0.8], // 20% chance of `Undelegated`, 80% chance of `Delegated` - ) as StakeStatus); - const from = new StakeInfo(fromStatus, fromPoolId); - - // Pick a random pool to move the stake to - const toPoolId = Pseudorandom.sample(Object.keys(stakingPools)); - // The `from` status must be Undelegated if no pools exist in the simulation yet, - // or if the chosen pool is unfinalized - const toStatus = - toPoolId === undefined || stakingPools[toPoolId].lastFinalized.isLessThan(currentEpoch.minus(1)) - ? StakeStatus.Undelegated - : (Pseudorandom.sample( - [StakeStatus.Undelegated, StakeStatus.Delegated], - [0.2, 0.8], // 20% chance of `Undelegated`, 80% chance of `Delegated` - ) as StakeStatus); - const to = new StakeInfo(toStatus, toPoolId); - - // The next epoch balance of the `from` stake is the amount that can be moved - const moveableStake = - from.status === StakeStatus.Undelegated - ? this.stake[StakeStatus.Undelegated].nextEpochBalance - : this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance; - const amount = Pseudorandom.integer(0, moveableStake); - - return [from, to, amount]; - } - - private async *_validMoveStake(): AsyncIterableIterator { - const assertion = validMoveStakeAssertion( - this.actor.deployment, - this.actor.simulationEnvironment!, - this.stake, - ); - - while (true) { - const [from, to, amount] = this._validMoveParams(); - yield assertion.executeAsync([from, to, amount], { from: this.actor.address }); - } - } - - private async *_moveStakeNonexistentPool(): AsyncIterableIterator { - while (true) { - const [from, to, amount] = this._validMoveParams(); - - // If there is 0 moveable stake for the sampled `to` pool, we need to mutate the - // `from` info, otherwise `moveStake` will just noop - if (amount.isZero()) { - from.poolId = Pseudorandom.hex(); - // Status must be delegated and amount must be nonzero to trigger _assertStakingPoolExists - from.status = StakeStatus.Delegated; - const randomAmount = Pseudorandom.integer(1, constants.MAX_UINT256); - const assertion = moveStakeNonexistentPoolAssertion(this.actor.deployment, from.poolId); - yield assertion.executeAsync([from, to, randomAmount], { from: this.actor.address }); - } else { - // One or both of the `from` and `to` poolId are invalid - const infoToMutate = Pseudorandom.sample([[from], [to], [from, to]]); - let nonExistentPoolId; - for (const info of infoToMutate!) { - info.poolId = Pseudorandom.hex(); - nonExistentPoolId = nonExistentPoolId || info.poolId; - // Status must be delegated and amount must be nonzero to trigger _assertStakingPoolExists - info.status = StakeStatus.Delegated; - } - const assertion = moveStakeNonexistentPoolAssertion( - this.actor.deployment, - nonExistentPoolId as string, - ); - yield assertion.executeAsync([from, to, amount], { from: this.actor.address }); - } - } - } - - private async *_validWithdrawDelegatorRewards(): AsyncIterableIterator { - const { stakingPools } = this.actor.simulationEnvironment!; - const assertion = validWithdrawDelegatorRewardsAssertion( - this.actor.deployment, - this.actor.simulationEnvironment!, - ); - while (true) { - const prevEpoch = this.actor.simulationEnvironment!.currentEpoch.minus(1); - // Pick a finalized pool - const poolId = Pseudorandom.sample( - Object.keys(stakingPools).filter(id => - stakingPools[id].lastFinalized.isGreaterThanOrEqualTo(prevEpoch), - ), - ); - if (poolId === undefined) { - yield; - } else { - yield assertion.executeAsync([poolId], { from: this.actor.address }); - } - } - } - - private async *_invalidWithdrawDelegatorRewards(): AsyncIterableIterator { - const { stakingPools } = this.actor.simulationEnvironment!; - const assertion = invalidWithdrawDelegatorRewardsAssertion( - this.actor.deployment, - this.actor.simulationEnvironment!, - ); - while (true) { - const prevEpoch = this.actor.simulationEnvironment!.currentEpoch.minus(1); - // Pick an unfinalized pool - const poolId = Pseudorandom.sample( - Object.keys(stakingPools).filter(id => stakingPools[id].lastFinalized.isLessThan(prevEpoch)), - ); - if (poolId === undefined) { - yield; - } else { - yield assertion.executeAsync([poolId], { from: this.actor.address }); - } - } - } - }; -} - -export class Staker extends StakerMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/taker.ts b/contracts/integrations/test/framework/actors/taker.ts deleted file mode 100644 index a2aefa9c81..0000000000 --- a/contracts/integrations/test/framework/actors/taker.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; - -import { validFillOrderAssertion } from '../assertions/fillOrder'; -import { AssertionResult } from '../assertions/function_assertion'; -import { validMatchOrdersAssertion } from '../assertions/matchOrders'; -import { validMatchOrdersWithMaximalFillAssertion } from '../assertions/matchOrdersWithMaximalFill'; -import { DeploymentManager } from '../deployment_manager'; -import { Pseudorandom } from '../utils/pseudorandom'; - -import { Actor, Constructor } from './base'; -import { Maker } from './maker'; -import { filterActorsByRole } from './utils'; - -export interface TakerInterface { - fillOrderAsync: ( - order: SignedOrder, - fillAmount: BigNumber, - txData?: Partial, - ) => Promise; -} - -/** - * This mixin encapsulates functionality associated with takers within the 0x ecosystem. - * As of writing, the only extra functionality provided is a utility wrapper around `fillOrder`, - */ -export function TakerMixin(Base: TBase): TBase & Constructor { - return class extends Base { - public readonly actor: Actor; - - /** - * The mixin pattern requires that this constructor uses `...args: any[]`, but this class - * really expects a single `ActorConfig` parameter (assuming `Actor` is used as the base - * class). - */ - constructor(...args: any[]) { - // tslint:disable-next-line:no-inferred-empty-object-type - super(...args); - this.actor = (this as any) as Actor; - this.actor.mixins.push('Taker'); - - // Register this mixin's assertion generators - this.actor.simulationActions = { - ...this.actor.simulationActions, - validFillOrder: this._validFillOrder(), - validMatchOrders: this._validMatchOrders(), - validMatchOrdersWithMaximalFill: this._validMatchOrdersWithMaximalFill(), - }; - } - - /** - * Fills an order by the given `fillAmount`. Defaults to paying the protocol fee in ETH. - */ - public async fillOrderAsync( - order: SignedOrder, - fillAmount: BigNumber, - txData: Partial = {}, - ): Promise { - return this.actor.deployment.exchange - .fillOrder(order, fillAmount, order.signature) - .awaitTransactionSuccessAsync({ - from: this.actor.address, - gasPrice: DeploymentManager.gasPrice, - value: DeploymentManager.protocolFee, - ...txData, - }); - } - - /** - * Matches two orders using `matchOrders`. Defaults to paying the protocol fee in ETH. - */ - public async matchOrdersAsync( - leftOrder: SignedOrder, - rightOrder: SignedOrder, - txData: Partial = {}, - ): Promise { - return this.actor.deployment.exchange - .matchOrders(leftOrder, rightOrder, leftOrder.signature, rightOrder.signature) - .awaitTransactionSuccessAsync({ - from: this.actor.address, - value: DeploymentManager.protocolFee, - ...txData, - }); - } - - /** - * Matches two orders using `matchOrdersWithMaximalFill`. Defaults to paying the protocol fee in ETH. - */ - public async matchOrdersWithMaximalFillAsync( - leftOrder: SignedOrder, - rightOrder: SignedOrder, - txData: Partial = {}, - ): Promise { - return this.actor.deployment.exchange - .matchOrdersWithMaximalFill(leftOrder, rightOrder, leftOrder.signature, rightOrder.signature) - .awaitTransactionSuccessAsync({ - from: this.actor.address, - value: DeploymentManager.protocolFee, - ...txData, - }); - } - - private async *_validFillOrder(): AsyncIterableIterator { - const { actors } = this.actor.simulationEnvironment!; - const assertion = validFillOrderAssertion(this.actor.deployment, this.actor.simulationEnvironment!); - while (true) { - // Choose a maker to be the other side of the order - const maker = Pseudorandom.sample(filterActorsByRole(actors, Maker)); - if (maker === undefined) { - yield; - } else { - // Maker creates and signs a fillable order - const order = await maker.createFillableOrderAsync(this.actor); - // Taker fills the order by a random amount (up to the order's takerAssetAmount) - const fillAmount = Pseudorandom.integer(0, order.takerAssetAmount); - // Taker executes the fill with a random msg.value, so that sometimes the - // protocol fee is paid in ETH and other times it's paid in WETH. - yield assertion.executeAsync([order, fillAmount, order.signature], { - from: this.actor.address, - value: Pseudorandom.integer(0, DeploymentManager.protocolFee.times(2)), - }); - } - } - } - - private async *_validMatchOrders(): AsyncIterableIterator { - const { actors } = this.actor.simulationEnvironment!; - const assertion = validMatchOrdersAssertion(this.actor.deployment, this.actor.simulationEnvironment!); - while (true) { - // Choose a maker to be the other side of the order - const maker = Pseudorandom.sample(filterActorsByRole(actors, Maker)); - if (maker === undefined) { - yield; - } else { - // Maker creates and signs matchable orders - const [leftOrder, rightOrder] = await maker.createMatchableOrdersAsync(this.actor); - - // Taker executes the fill with a random msg.value, so that sometimes the - // protocol fee is paid in ETH and other times it's paid in WETH. - yield assertion.executeAsync([leftOrder, rightOrder, leftOrder.signature, rightOrder.signature], { - from: this.actor.address, - value: Pseudorandom.integer(0, DeploymentManager.protocolFee.times(2)), - }); - } - } - } - - private async *_validMatchOrdersWithMaximalFill(): AsyncIterableIterator { - const { actors } = this.actor.simulationEnvironment!; - const assertion = validMatchOrdersWithMaximalFillAssertion( - this.actor.deployment, - this.actor.simulationEnvironment!, - ); - while (true) { - // Choose a maker to be the other side of the order - const maker = Pseudorandom.sample(filterActorsByRole(actors, Maker)); - if (maker === undefined) { - yield; - } else { - // Maker creates and signs matchable orders - const [leftOrder, rightOrder] = await maker.createMatchableOrdersAsync(this.actor); - - // Taker executes the fill with a random msg.value, so that sometimes the - // protocol fee is paid in ETH and other times it's paid in WETH. - yield assertion.executeAsync([leftOrder, rightOrder, leftOrder.signature, rightOrder.signature], { - from: this.actor.address, - value: Pseudorandom.integer(0, DeploymentManager.protocolFee.times(2)), - }); - } - } - } - }; -} - -export class Taker extends TakerMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/tslint.json b/contracts/integrations/test/framework/actors/tslint.json deleted file mode 100644 index d56fa2fdc4..0000000000 --- a/contracts/integrations/test/framework/actors/tslint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "max-classes-per-file": false, - "no-non-null-assertion": false, - "custom-no-magic-numbers": false - } -} diff --git a/contracts/integrations/test/framework/actors/utils.ts b/contracts/integrations/test/framework/actors/utils.ts deleted file mode 100644 index f913f51362..0000000000 --- a/contracts/integrations/test/framework/actors/utils.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; - -import { Actor, Constructor } from './base'; - -/** - * Utility function to convert Actors into an object mapping readable names to addresses. - * Useful for BalanceStore. - */ -export function actorAddressesByName(actors: Actor[]): ObjectMap { - return _.zipObject( - actors.map(actor => actor.name), - actors.map(actor => actor.address), - ); -} - -/** - * Filters the given actors by role, specified by the class exported by an actor mixin file, - * e.g, 'Maker', 'Taker', etc. - */ -export function filterActorsByRole( - actors: Actor[], - role: TClass, -): Array> { - return actors.filter(actor => actor.mixins.includes(role.name)) as Array>; -} diff --git a/contracts/integrations/test/framework/assertions/createStakingPool.ts b/contracts/integrations/test/framework/assertions/createStakingPool.ts deleted file mode 100644 index 255c2ca265..0000000000 --- a/contracts/integrations/test/framework/assertions/createStakingPool.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { StakingRevertErrors, StoredBalance } from '@0x/contracts-staking'; -import { expect } from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { TxData } from 'ethereum-types'; - -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -// tslint:disable:no-unnecessary-type-assertion - -/** - * Returns a FunctionAssertion for `createStakingPool` which assumes valid input is provided. The - * FunctionAssertion checks that the new poolId is one more than the last poolId. - */ -/* tslint:disable:no-non-null-assertion */ -export function validCreateStakingPoolAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[number, boolean], string, string> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[number, boolean], string, string>(stakingWrapper, 'createStakingPool', { - // Returns the expected ID of the created pool - before: async () => { - const lastPoolId = await stakingWrapper.lastPoolId().callAsync(); - // Effectively the last poolId + 1, but as a bytestring - return hexUtils.leftPad(new BigNumber(lastPoolId).plus(1)); - }, - after: async ( - expectedPoolId: string, - result: FunctionResult, - args: [number, boolean], - txData: Partial, - ) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [operatorShare] = args; - - // Checks the logs for the new poolId, verifies that it is as expected - const log = result.receipt!.logs[0]; - const actualPoolId = (log as any).args.poolId; - expect(actualPoolId).to.equal(expectedPoolId); - - // Adds the new pool to local state - simulationEnvironment.stakingPools[actualPoolId] = { - operator: txData.from!, - operatorShare, - delegatedStake: new StoredBalance(), - lastFinalized: simulationEnvironment.currentEpoch, - }; - }, - }); -} - -/** - * Returns a FunctionAssertion for `createStakingPool` which assumes an invalid operator share (i.e. - * greater than 1,000,000) is provided. The FunctionAssertion checks that the transaction reverts - * with the expected OperatorShareError. - */ -export function invalidCreateStakingPoolAssertion( - deployment: DeploymentManager, -): FunctionAssertion<[number, boolean], string, string> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[number, boolean], string, string>(stakingWrapper, 'createStakingPool', { - // Returns the poolId we are expecting to revert with - before: async () => { - const lastPoolId = await stakingWrapper.lastPoolId().callAsync(); - // Effectively the last poolId + 1, but as a bytestring - return hexUtils.leftPad(new BigNumber(lastPoolId).plus(1)); - }, - after: async (expectedPoolId: string, result: FunctionResult, args: [number, boolean]) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - // Check revert error - const [operatorShare] = args; - expect(result.data).to.equal( - new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - expectedPoolId, - operatorShare, - ), - ); - }, - }); -} -/* tslint:enable:no-non-null-assertion*/ diff --git a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts deleted file mode 100644 index 8078b01a2c..0000000000 --- a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { constants, StakingPoolById, StakingRevertErrors } from '@0x/contracts-staking'; -import { expect } from '@0x/contracts-test-utils'; -import { TxData } from 'ethereum-types'; - -import { DeploymentManager } from '../deployment_manager'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -/** - * Returns a FunctionAssertion for `decreaseStakingPoolOperatorShare` which assumes valid input is - * provided. The FunctionAssertion checks that the operator share actually gets updated. - */ -export function validDecreaseStakingPoolOperatorShareAssertion( - deployment: DeploymentManager, - pools: StakingPoolById, -): FunctionAssertion<[string, number], void, void> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[string, number], void, void>(stakingWrapper, 'decreaseStakingPoolOperatorShare', { - after: async (_beforeInfo: void, result: FunctionResult, args: [string, number], _txData: Partial) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [poolId, expectedOperatorShare] = args; - - // Checks that the on-chain pool's operator share has been updated. - const { operatorShare } = await stakingWrapper.getStakingPool(poolId).callAsync(); - expect(operatorShare).to.bignumber.equal(expectedOperatorShare); - - // Updates the pool in local state. - pools[poolId].operatorShare = operatorShare; - }, - }); -} - -/** - * Returns a FunctionAssertion for `decreaseStakingPoolOperatorShare` which assumes the given - * operator share is larger than the current operator share for the pool. The FunctionAssertion - * checks that the transaction reverts with the correct error in this scenario. - */ -export function invalidDecreaseStakingPoolOperatorShareAssertion( - deployment: DeploymentManager, -): FunctionAssertion<[string, number], void, void> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[string, number], void, void>(stakingWrapper, 'decreaseStakingPoolOperatorShare', { - after: async (_beforeInfo: void, result: FunctionResult, args: [string, number], _txData: Partial) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - // Check revert error - const [poolId, operatorShare] = args; - const expectedError = - operatorShare > constants.PPM - ? new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - poolId, - operatorShare, - ) - : new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.CanOnlyDecreaseOperatorShare, - poolId, - operatorShare, - ); - expect(result.data).to.equal(expectedError); - }, - }); -} diff --git a/contracts/integrations/test/framework/assertions/endEpoch.ts b/contracts/integrations/test/framework/assertions/endEpoch.ts deleted file mode 100644 index 037690e8b9..0000000000 --- a/contracts/integrations/test/framework/assertions/endEpoch.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { WETH9DepositEventArgs, WETH9Events } from '@0x/contracts-erc20'; -import { - AggregatedStats, - StakingEpochEndedEventArgs, - StakingEpochFinalizedEventArgs, - StakingEvents, - StakingRevertErrors, -} from '@0x/contracts-staking'; -import { constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -interface EndEpochBeforeInfo { - wethReservedForPoolRewards: BigNumber; - aggregatedStatsBefore: AggregatedStats; -} - -/** - * Returns a FunctionAssertion for `endEpoch` which assumes valid input is provided. It checks - * that the staking proxy contract wrapped its ETH balance, aggregated stats were updated, and - * EpochFinalized/EpochEnded events were emitted. - */ -export function validEndEpochAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[], EndEpochBeforeInfo, void> { - const { stakingWrapper } = deployment.staking; - const { balanceStore } = simulationEnvironment; - - return new FunctionAssertion(stakingWrapper, 'endEpoch', { - before: async () => { - await balanceStore.updateEthBalancesAsync(); - const aggregatedStatsBefore = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(simulationEnvironment.currentEpoch).callAsync(), - ); - const wethReservedForPoolRewards = await stakingWrapper.wethReservedForPoolRewards().callAsync(); - return { wethReservedForPoolRewards, aggregatedStatsBefore }; - }, - after: async (beforeInfo: EndEpochBeforeInfo, result: FunctionResult, _args: [], _txData: Partial) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const { currentEpoch } = simulationEnvironment; - const logs = result.receipt!.logs; // tslint:disable-line - - // Check WETH deposit event - const previousEthBalance = balanceStore.balances.eth[stakingWrapper.address] || constants.ZERO_AMOUNT; - const expectedDepositEvents = previousEthBalance.isGreaterThan(0) - ? [ - { - _owner: deployment.staking.stakingProxy.address, - _value: previousEthBalance, - }, - ] - : []; - verifyEventsFromLogs(logs, expectedDepositEvents, WETH9Events.Deposit); - - // Check that the aggregated stats were updated - await balanceStore.updateErc20BalancesAsync(); - const { wethReservedForPoolRewards, aggregatedStatsBefore } = beforeInfo; - const expectedAggregatedStats = { - ...aggregatedStatsBefore, - rewardsAvailable: _.get( - balanceStore.balances, - ['erc20', stakingWrapper.address, deployment.tokens.weth.address], - constants.ZERO_AMOUNT, - ).minus(wethReservedForPoolRewards), - }; - const aggregatedStatsAfter = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(currentEpoch).callAsync(), - ); - expect(aggregatedStatsAfter).to.deep.equal(expectedAggregatedStats); - - // Check that an EpochEnded event was emitted - verifyEventsFromLogs( - logs, - [ - { - epoch: currentEpoch, - numPoolsToFinalize: aggregatedStatsAfter.numPoolsToFinalize, - rewardsAvailable: aggregatedStatsAfter.rewardsAvailable, - totalFeesCollected: aggregatedStatsAfter.totalFeesCollected, - totalWeightedStake: aggregatedStatsAfter.totalWeightedStake, - }, - ], - StakingEvents.EpochEnded, - ); - - // If there are no more pools to finalize, an EpochFinalized event should've been emitted - const expectedEpochFinalizedEvents = aggregatedStatsAfter.numPoolsToFinalize.isZero() - ? [ - { - epoch: currentEpoch, - rewardsPaid: constants.ZERO_AMOUNT, - rewardsRemaining: aggregatedStatsAfter.rewardsAvailable, - }, - ] - : []; - verifyEventsFromLogs( - logs, - expectedEpochFinalizedEvents, - StakingEvents.EpochFinalized, - ); - - // The function returns the remaining number of unfinalized pools for the epoch - expect(result.data, 'endEpoch should return the number of unfinalized pools').to.bignumber.equal( - aggregatedStatsAfter.numPoolsToFinalize, - ); - - // Update currentEpoch locally - simulationEnvironment.currentEpoch = currentEpoch.plus(1); - }, - }); -} - -/** - * Returns a FunctionAssertion for `endEpoch` which assumes it has been called while the previous - * epoch hasn't been fully finalized. Checks that the transaction reverts with PreviousEpochNotFinalizedError. - */ -export function endEpochUnfinalizedPoolsAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, - numPoolsToFinalizeFromPrevEpoch: BigNumber, -): FunctionAssertion<[], void, void> { - return new FunctionAssertion(deployment.staking.stakingWrapper, 'endEpoch', { - after: async (_beforeInfo: void, result: FunctionResult) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - // Check revert error - expect(result.data).to.equal( - new StakingRevertErrors.PreviousEpochNotFinalizedError( - simulationEnvironment.currentEpoch.minus(1), - numPoolsToFinalizeFromPrevEpoch, - ), - ); - }, - }); -} - -/** - * Returns a FunctionAssertion for `endEpoch` which assumes it has been called before the full epoch - * duration has elapsed. Checks that the transaction reverts with BlockTimestampTooLowError. - */ -export function endEpochTooEarlyAssertion(deployment: DeploymentManager): FunctionAssertion<[], void, void> { - const { stakingWrapper } = deployment.staking; - return new FunctionAssertion(stakingWrapper, 'endEpoch', { - after: async (_beforeInfo: void, result: FunctionResult) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - // Check revert error - const epochEndTime = await stakingWrapper.getCurrentEpochEarliestEndTimeInSeconds().callAsync(); - const lastBlockTime = await deployment.web3Wrapper.getBlockTimestampAsync('latest'); - expect(result.data).to.equal( - new StakingRevertErrors.BlockTimestampTooLowError(epochEndTime, lastBlockTime), - ); - }, - }); -} diff --git a/contracts/integrations/test/framework/assertions/fillOrder.ts b/contracts/integrations/test/framework/assertions/fillOrder.ts deleted file mode 100644 index 24c974649b..0000000000 --- a/contracts/integrations/test/framework/assertions/fillOrder.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { ERC20TokenEvents, ERC20TokenTransferEventArgs } from '@0x/contracts-erc20'; -import { ExchangeEvents, ExchangeFillEventArgs } from '@0x/contracts-exchange'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { AggregatedStats, PoolStats } from '@0x/contracts-staking'; -import { expect, orderHashUtils, verifyEvents } from '@0x/contracts-test-utils'; -import { FillResults, Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { Maker } from '../actors/maker'; -import { filterActorsByRole } from '../actors/utils'; -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; -import { assertProtocolFeePaidAsync, getPoolInfoAsync } from '../utils/assert_protocol_fee'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -function verifyFillEvents( - txData: Partial, - order: Order, - receipt: TransactionReceiptWithDecodedLogs, - deployment: DeploymentManager, - takerAssetFillAmount: BigNumber, -): void { - const fillResults = ReferenceFunctions.calculateFillResults( - order, - takerAssetFillAmount, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - ); - const takerAddress = txData.from as string; - const value = new BigNumber(txData.value || 0); - // Ensure that the fill event was correct. - verifyEvents( - receipt, - [ - { - makerAddress: order.makerAddress, - feeRecipientAddress: order.feeRecipientAddress, - makerAssetData: order.makerAssetData, - takerAssetData: order.takerAssetData, - makerFeeAssetData: order.makerFeeAssetData, - takerFeeAssetData: order.takerFeeAssetData, - orderHash: orderHashUtils.getOrderHashHex(order), - takerAddress, - senderAddress: takerAddress, - ...fillResults, - }, - ], - ExchangeEvents.Fill, - ); - - const expectedTransferEvents = [ - { - _from: takerAddress, - _to: order.makerAddress, - _value: fillResults.takerAssetFilledAmount, - }, - { - _from: order.makerAddress, - _to: takerAddress, - _value: fillResults.makerAssetFilledAmount, - }, - { - _from: takerAddress, - _to: order.feeRecipientAddress, - _value: fillResults.takerFeePaid, - }, - { - _from: order.makerAddress, - _to: order.feeRecipientAddress, - _value: fillResults.makerFeePaid, - }, - ].filter(event => event._value.isGreaterThan(0)); - - // If not enough wei is sent to cover the protocol fee, there will be an additional WETH transfer event - if (value.isLessThan(DeploymentManager.protocolFee)) { - expectedTransferEvents.push({ - _from: takerAddress, - _to: deployment.staking.stakingProxy.address, - _value: DeploymentManager.protocolFee, - }); - } - - // Ensure that the transfer events were correctly emitted. - verifyEvents(receipt, expectedTransferEvents, ERC20TokenEvents.Transfer); -} - -interface FillOrderBeforeInfo { - poolStats: PoolStats; - aggregatedStats: AggregatedStats; - poolStake: BigNumber; - operatorStake: BigNumber; - poolId: string; -} - -/** - * A function assertion that verifies that a complete and valid fill succeeded and emitted the correct logs. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -/* tslint:disable:no-non-null-assertion */ -export function validFillOrderAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[Order, BigNumber, string], FillOrderBeforeInfo | void, FillResults> { - const { actors } = simulationEnvironment; - const expectedProtocolFee = DeploymentManager.protocolFee; - - return new FunctionAssertion<[Order, BigNumber, string], FillOrderBeforeInfo | void, FillResults>( - deployment.exchange, - 'fillOrder', - { - before: async (args: [Order, BigNumber, string]) => { - const [order] = args; - const maker = filterActorsByRole(actors, Maker).find(actor => actor.address === order.makerAddress); - const poolInfo = getPoolInfoAsync(maker!, simulationEnvironment, deployment); - return poolInfo; - }, - after: async ( - beforeInfo: FillOrderBeforeInfo | void, - result: FunctionResult, - args: [Order, BigNumber, string], - txData: Partial, - ) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [order, fillAmount] = args; - - // Ensure that the correct events were emitted. - verifyFillEvents(txData, order, result.receipt!, deployment, fillAmount); - - // If the maker is in a staking pool then validate the protocol fee. - if (beforeInfo !== undefined) { - await assertProtocolFeePaidAsync( - beforeInfo, - result, - simulationEnvironment, - deployment, - expectedProtocolFee, - ); - } - }, - }, - ); -} -/* tslint:enable:no-non-null-assertion */ -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/finalizePool.ts b/contracts/integrations/test/framework/assertions/finalizePool.ts deleted file mode 100644 index 1603c8ad5d..0000000000 --- a/contracts/integrations/test/framework/assertions/finalizePool.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { WETH9Events, WETH9TransferEventArgs } from '@0x/contracts-erc20'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - AggregatedStats, - constants as stakingConstants, - PoolStats, - StakingEpochFinalizedEventArgs, - StakingEvents, - StakingRewardsPaidEventArgs, -} from '@0x/contracts-staking'; -import { - assertRoughlyEquals, - constants, - expect, - filterLogsToArguments, - toDecimal, - verifyEventsFromLogs, -} from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -const PRECISION = 15; -const COBB_DOUGLAS_ALPHA = toDecimal(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaNumerator).dividedBy( - toDecimal(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaDenominator), -); - -// Reference function for Cobb-Douglas -function cobbDouglas(poolStats: PoolStats, aggregatedStats: AggregatedStats): BigNumber { - const { feesCollected, weightedStake } = poolStats; - const { rewardsAvailable, totalFeesCollected, totalWeightedStake } = aggregatedStats; - - const feeRatio = toDecimal(feesCollected).dividedBy(toDecimal(totalFeesCollected)); - const stakeRatio = toDecimal(weightedStake).dividedBy(toDecimal(totalWeightedStake)); - // totalRewards * feeRatio ^ alpha * stakeRatio ^ (1-alpha) - return new BigNumber( - feeRatio - .pow(COBB_DOUGLAS_ALPHA) - .times(stakeRatio.pow(toDecimal(1).minus(COBB_DOUGLAS_ALPHA))) - .times(toDecimal(rewardsAvailable)) - .toFixed(0, BigNumber.ROUND_FLOOR), - ); -} - -interface FinalizePoolBeforeInfo { - poolStats: PoolStats; - aggregatedStats: AggregatedStats; - poolRewards: BigNumber; - cumulativeRewardsLastStored: BigNumber; - mostRecentCumulativeRewards: { - numerator: BigNumber; - denominator: BigNumber; - }; -} - -/** - * Returns a FunctionAssertion for `finalizePool` which assumes valid input is provided. The `after` - * callback below is annotated with the solidity source of `finalizePool`. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -export function validFinalizePoolAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[string], FinalizePoolBeforeInfo, void> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[string], FinalizePoolBeforeInfo, void>(stakingWrapper, 'finalizePool', { - before: async (args: [string]) => { - const [poolId] = args; - const { currentEpoch } = simulationEnvironment; - const prevEpoch = currentEpoch.minus(1); - - const poolStats = PoolStats.fromArray(await stakingWrapper.poolStatsByEpoch(poolId, prevEpoch).callAsync()); - const aggregatedStats = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(prevEpoch).callAsync(), - ); - const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync(); - const [ - mostRecentCumulativeRewards, - cumulativeRewardsLastStored, - ] = await stakingWrapper.getMostRecentCumulativeReward(poolId).callAsync(); - return { - poolStats, - aggregatedStats, - poolRewards, - cumulativeRewardsLastStored, - mostRecentCumulativeRewards, - }; - }, - after: async (beforeInfo: FinalizePoolBeforeInfo, result: FunctionResult, args: [string]) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const logs = result.receipt!.logs; // tslint:disable-line:no-non-null-assertion - const { stakingPools, currentEpoch } = simulationEnvironment; - const prevEpoch = currentEpoch.minus(1); - const [poolId] = args; - const pool = stakingPools[poolId]; - - // finalizePool noops if there are no pools to finalize or - // the pool did not earn rewards or already finalized (has no fees). - if (beforeInfo.aggregatedStats.numPoolsToFinalize.isZero() || beforeInfo.poolStats.feesCollected.isZero()) { - expect(logs.length, 'Expect no events to be emitted').to.equal(0); - return; - } - - // It should have cleared the pool stats for prevEpoch - const poolStats = PoolStats.fromArray(await stakingWrapper.poolStatsByEpoch(poolId, prevEpoch).callAsync()); - expect(poolStats).to.deep.equal({ - feesCollected: constants.ZERO_AMOUNT, - weightedStake: constants.ZERO_AMOUNT, - membersStake: constants.ZERO_AMOUNT, - }); - - // uint256 rewards = _getUnfinalizedPoolRewardsFromPoolStats(poolStats, aggregatedStats); - const rewards = BigNumber.min( - cobbDouglas(beforeInfo.poolStats, beforeInfo.aggregatedStats), - beforeInfo.aggregatedStats.rewardsAvailable.minus(beforeInfo.aggregatedStats.totalRewardsFinalized), - ); - - // Check that a RewardsPaid event was emitted - const events = filterLogsToArguments(logs, StakingEvents.RewardsPaid); - expect(events.length, 'Number of RewardsPaid events emitted').to.equal(1); - const [rewardsPaidEvent] = events; - expect(rewardsPaidEvent.poolId, 'RewardsPaid event: poolId').to.equal(poolId); - expect(rewardsPaidEvent.epoch, 'RewardsPaid event: currentEpoch_').to.bignumber.equal(currentEpoch); - - // Pull the operator and members' reward from the event - const { operatorReward, membersReward } = rewardsPaidEvent; - const totalReward = operatorReward.plus(membersReward); - // Should be approximately equal to the rewards compute using the Cobb-Douglas reference function - assertRoughlyEquals(totalReward, rewards, PRECISION); - - // Operator takes their share of the rewards - if (beforeInfo.poolStats.membersStake.isZero()) { - expect( - operatorReward, - "operatorReward should equal totalReward if pool's membersStake is 0", - ).to.bignumber.equal(totalReward); - } else { - expect(operatorReward).to.bignumber.equal( - ReferenceFunctions.getPartialAmountCeil( - new BigNumber(pool.operatorShare), - new BigNumber(stakingConstants.PPM), - totalReward, - ), - ); - } - - // Pays the operator in WETH if the operator's reward is non-zero - const expectedTransferEvents = operatorReward.isGreaterThan(0) - ? [ - { - _from: deployment.staking.stakingProxy.address, - _to: pool.operator, - _value: operatorReward, - }, - ] - : []; - - // Check for WETH transfer event emitted when paying out operator's reward. - verifyEventsFromLogs(logs, expectedTransferEvents, WETH9Events.Transfer); - // Check that pool rewards have increased. - const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync(); - expect(poolRewards).to.bignumber.equal(beforeInfo.poolRewards.plus(membersReward)); - - if (membersReward.isGreaterThan(0)) { - // Check that cumulative rewards have increased. - const [ - mostRecentCumulativeRewards, - cumulativeRewardsLastStored, - ] = await stakingWrapper.getMostRecentCumulativeReward(poolId).callAsync(); - expect(cumulativeRewardsLastStored).to.bignumber.equal(currentEpoch); - - let [numerator, denominator] = ReferenceFunctions.LibFractions.add( - beforeInfo.mostRecentCumulativeRewards.numerator, - beforeInfo.mostRecentCumulativeRewards.denominator, - membersReward, - beforeInfo.poolStats.membersStake, - ); - [numerator, denominator] = ReferenceFunctions.LibFractions.normalize(numerator, denominator); - expect(mostRecentCumulativeRewards).to.deep.equal({ numerator, denominator }); - } - - // Check that aggregated stats have been updated - const aggregatedStats = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(prevEpoch).callAsync(), - ); - expect(aggregatedStats).to.deep.equal({ - ...beforeInfo.aggregatedStats, - totalRewardsFinalized: beforeInfo.aggregatedStats.totalRewardsFinalized.plus(totalReward), - numPoolsToFinalize: beforeInfo.aggregatedStats.numPoolsToFinalize.minus(1), - }); - - // If there are no more unfinalized pools remaining, the epoch is finalized. - const expectedEpochFinalizedEvents = aggregatedStats.numPoolsToFinalize.isZero() - ? [ - { - epoch: prevEpoch, - rewardsPaid: aggregatedStats.totalRewardsFinalized, - rewardsRemaining: aggregatedStats.rewardsAvailable.minus( - aggregatedStats.totalRewardsFinalized, - ), - }, - ] - : []; - verifyEventsFromLogs( - logs, - expectedEpochFinalizedEvents, - StakingEvents.EpochFinalized, - ); - - // Update local state - pool.lastFinalized = prevEpoch; - }, - }); -} -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/function_assertion.ts b/contracts/integrations/test/framework/assertions/function_assertion.ts deleted file mode 100644 index 0782c1b1e0..0000000000 --- a/contracts/integrations/test/framework/assertions/function_assertion.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { BaseContract, ContractFunctionObj, ContractTxFunctionObj } from '@0x/base-contract'; -import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { logger } from '../utils/logger'; - -// tslint:disable:max-classes-per-file -export type GenericContractFunction = (...args: any[]) => ContractFunctionObj; - -export interface FunctionResult { - data?: any; - success: boolean; - receipt?: TransactionReceiptWithDecodedLogs; -} - -/** - * This interface represents a condition that can be placed on a contract function. - * This can be used to represent the pre- and post-conditions of a "Hoare Triple" on a - * given contract function. The "Hoare Triple" is a way to represent the way that a - * function changes state. - * @param before A function that will be run before a call to the contract wrapper - * function. Ideally, this will be a "precondition." - * @param after A function that will be run after a call to the contract wrapper - * function. - */ -export interface Condition { - before: (args: TArgs, txData: Partial) => Promise; - after: (beforeInfo: TBefore, result: FunctionResult, args: TArgs, txData: Partial) => Promise; -} - -/** - * The basic unit of abstraction for testing. This just consists of a command that - * can be run. For example, this can represent a simple command that can be run, or - * it can represent a command that executes a "Hoare Triple" (this is what most of - * our `Assertion` implementations will do in practice). - * @param runAsync The function to execute for the assertion. - */ -export interface Assertion { - executeAsync: (args: TArgs, txData: TxData) => Promise; -} - -export interface AssertionResult { - beforeInfo: TBefore; - afterInfo: any; -} - -/** - * This class implements `Assertion` and represents a "Hoare Triple" that can be - * executed. - */ -export class FunctionAssertion implements Assertion { - // A condition that will be applied to `wrapperFunction`. - public readonly condition: Condition; - - constructor( - private readonly _contractWrapper: BaseContract, - private readonly _functionName: string, - condition: Partial> = {}, - ) { - this.condition = { - before: async (_args: TArgs, _txData: Partial) => { - return ({} as any) as TBefore; - }, - after: async (_beforeInfo: TBefore, _result: FunctionResult, _args: TArgs, _txData: Partial) => { - return ({} as any) as TBefore; - }, - ...condition, - }; - } - - /** - * Runs the wrapped function and fails if the before or after assertions fail. - * @param ...args The args to the contract wrapper function. - */ - public async executeAsync(args: TArgs, txData: Partial): Promise> { - // Call the before condition. - const beforeInfo = await this.condition.before(args, txData); - - // Initialize the callResult so that the default success value is true. - const callResult: FunctionResult = { success: true }; - - // Log function name, arguments, and txData - logger.logFunctionAssertion(this._functionName, args, txData); - - // Try to make the call to the function. If it is successful, pass the - // result and receipt to the after condition. - try { - const functionWithArgs = (this._contractWrapper as any)[this._functionName]( - ...args, - ) as ContractTxFunctionObj; - callResult.data = await functionWithArgs.callAsync(txData); - callResult.receipt = - functionWithArgs.awaitTransactionSuccessAsync !== undefined - ? await functionWithArgs.awaitTransactionSuccessAsync(txData) // tslint:disable-line:await-promise - : undefined; - // tslint:enable:await-promise - } catch (error) { - callResult.data = error; - callResult.success = false; - callResult.receipt = undefined; - } - - // Call the after condition. - const afterInfo = await this.condition.after(beforeInfo, callResult, args, txData); - - return { - beforeInfo, - afterInfo, - }; - } -} diff --git a/contracts/integrations/test/framework/assertions/generic_assertions.ts b/contracts/integrations/test/framework/assertions/generic_assertions.ts deleted file mode 100644 index 49febd2ac3..0000000000 --- a/contracts/integrations/test/framework/assertions/generic_assertions.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { BaseContract } from '@0x/base-contract'; -import { expect } from '@0x/contracts-test-utils'; -import { RevertReason } from '@0x/types'; -import { StringRevertError } from '@0x/utils'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -/** - * Returns a generic FunctionAssertion for the given contract function, asserting that the - * function call reverts in an asset proxy contract with TRANSFER_FAILED. - */ -export function assetProxyTransferFailedAssertion( - contract: BaseContract, - functionName: string, -): FunctionAssertion { - return new FunctionAssertion(contract, functionName, { - after: async (_beforeInfo: void, result: FunctionResult) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - // Check revert error - expect(result.data).to.equal(new StringRevertError(RevertReason.TransferFailed)); - }, - }); -} diff --git a/contracts/integrations/test/framework/assertions/joinStakingPool.ts b/contracts/integrations/test/framework/assertions/joinStakingPool.ts deleted file mode 100644 index 363683ef3c..0000000000 --- a/contracts/integrations/test/framework/assertions/joinStakingPool.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { StakingEvents, StakingMakerStakingPoolSetEventArgs } from '@0x/contracts-staking'; -import { expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { TxData } from 'ethereum-types'; - -import { DeploymentManager } from '../deployment_manager'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -/** - * Returns a function assertion that verifies valid pool joining. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -/* tslint:disable:no-non-null-assertion */ -export function validJoinStakingPoolAssertion(deployment: DeploymentManager): FunctionAssertion<[string], void, void> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[string], void, void>(stakingWrapper, 'joinStakingPoolAsMaker', { - after: async (_beforeInfo: void, result: FunctionResult, args: [string], txData: Partial) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [poolId] = args; - - // Verify a MakerStakingPoolSet event was emitted - const logs = result.receipt!.logs; - const logArgs = filterLogsToArguments( - logs, - StakingEvents.MakerStakingPoolSet, - ); - expect(logArgs).to.be.deep.eq([ - { - makerAddress: txData.from!, - poolId, - }, - ]); - // Verify that the maker's pool id has been updated in storage - const joinedPoolId = await deployment.staking.stakingWrapper.poolIdByMaker(txData.from!).callAsync(); - expect(joinedPoolId).to.be.eq(poolId); - }, - }); -} -/* tslint:enable:no-non-null-assertion */ -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/matchOrders.ts b/contracts/integrations/test/framework/assertions/matchOrders.ts deleted file mode 100644 index 6c90e429b6..0000000000 --- a/contracts/integrations/test/framework/assertions/matchOrders.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { MatchedFillResults, Order } from '@0x/types'; -import { TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { Maker } from '../actors/maker'; -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; -import { assertProtocolFeePaidAsync, getPoolInfoAsync, PoolInfo } from '../utils/assert_protocol_fee'; -import { verifyMatchEvents } from '../utils/verify_match_events'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -export const matchOrdersRuntimeAssertion = ( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, - withMaximalFill: boolean, -) => { - const { actors } = simulationEnvironment; - const expectedProtocolFee = DeploymentManager.protocolFee.times(2); - - return { - before: async (args: [Order, Order, string, string]) => { - const [order] = args; - // tslint:disable-next-line no-unnecessary-type-assertion - const maker = actors.find(actor => actor.address === order.makerAddress) as Maker; - const poolInfo = getPoolInfoAsync(maker, simulationEnvironment, deployment); - return poolInfo; - }, - after: async ( - beforeInfo: PoolInfo | void, - result: FunctionResult, - args: [Order, Order, string, string], - txData: Partial, - ) => { - // Ensure that the correct events were emitted. - const [leftOrder, rightOrder] = args; - - verifyMatchEvents( - txData, - leftOrder, - rightOrder, - // tslint:disable-next-line no-non-null-assertion no-unnecessary-type-assertion - result.receipt!, - deployment, - withMaximalFill, - ); - - // If the maker is in a staking pool then validate the protocol fee. - if (beforeInfo !== undefined) { - await assertProtocolFeePaidAsync( - beforeInfo, - result, - simulationEnvironment, - deployment, - expectedProtocolFee, - ); - } - }, - }; -}; - -/** - * A function assertion that verifies that a complete and valid `matchOrders` succeeded and emitted the correct logs. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -/* tslint:disable:no-non-null-assertion */ -export function validMatchOrdersAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[Order, Order, string, string], PoolInfo | void, MatchedFillResults> { - return new FunctionAssertion<[Order, Order, string, string], PoolInfo | void, MatchedFillResults>( - deployment.exchange, - 'matchOrders', - matchOrdersRuntimeAssertion(deployment, simulationEnvironment, false), - ); -} -/* tslint:enable:no-non-null-assertion */ -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/matchOrdersWithMaximalFill.ts b/contracts/integrations/test/framework/assertions/matchOrdersWithMaximalFill.ts deleted file mode 100644 index 7ecdc54f41..0000000000 --- a/contracts/integrations/test/framework/assertions/matchOrdersWithMaximalFill.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MatchedFillResults, Order } from '@0x/types'; -import * as _ from 'lodash'; - -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; -import { PoolInfo } from '../utils/assert_protocol_fee'; - -import { FunctionAssertion } from './function_assertion'; -import { matchOrdersRuntimeAssertion } from './matchOrders'; - -/** - * A function assertion that verifies that a complete and valid `matchOrdersWithMaximalFill` succeeded and emitted the correct logs. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -/* tslint:disable:no-non-null-assertion */ -export function validMatchOrdersWithMaximalFillAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[Order, Order, string, string], PoolInfo | void, MatchedFillResults> { - return new FunctionAssertion<[Order, Order, string, string], PoolInfo | void, MatchedFillResults>( - deployment.exchange, - 'matchOrdersWithMaximalFill', - matchOrdersRuntimeAssertion(deployment, simulationEnvironment, true), - ); -} -/* tslint:enable:no-non-null-assertion */ -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/moveStake.ts b/contracts/integrations/test/framework/assertions/moveStake.ts deleted file mode 100644 index c2ee9f4c14..0000000000 --- a/contracts/integrations/test/framework/assertions/moveStake.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { - decreaseNextBalance, - increaseNextBalance, - loadCurrentBalance, - OwnerStakeByStatus, - StakeInfo, - StakeStatus, - StakingRevertErrors, - StoredBalance, -} from '@0x/contracts-staking'; -import { expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -function updateNextEpochBalances( - ownerStake: OwnerStakeByStatus, - from: StakeInfo, - to: StakeInfo, - amount: BigNumber, - simulationEnvironment: SimulationEnvironment, -): string[] { - const { globalStake, stakingPools, currentEpoch } = simulationEnvironment; - - // The on-chain state of these updated pools will be verified in the `after` of the assertion. - const updatedPools = []; - - // Decrement next epoch balances associated with the `from` stake - if (from.status === StakeStatus.Undelegated) { - // Decrement owner undelegated stake - ownerStake[StakeStatus.Undelegated] = decreaseNextBalance( - ownerStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - // Decrement global undelegated stake - globalStake[StakeStatus.Undelegated] = decreaseNextBalance( - globalStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - } else if (from.status === StakeStatus.Delegated) { - // Decrement owner's delegated stake to this pool - ownerStake[StakeStatus.Delegated][from.poolId] = decreaseNextBalance( - ownerStake[StakeStatus.Delegated][from.poolId], - amount, - currentEpoch, - ); - // Decrement owner's total delegated stake - ownerStake[StakeStatus.Delegated].total = decreaseNextBalance( - ownerStake[StakeStatus.Delegated].total, - amount, - currentEpoch, - ); - // Decrement global delegated stake - globalStake[StakeStatus.Delegated] = decreaseNextBalance( - globalStake[StakeStatus.Delegated], - amount, - currentEpoch, - ); - // Decrement pool's delegated stake - stakingPools[from.poolId].delegatedStake = decreaseNextBalance( - stakingPools[from.poolId].delegatedStake, - amount, - currentEpoch, - ); - updatedPools.push(from.poolId); - - // TODO: Check that delegator rewards have been withdrawn/synced - } - - // Increment next epoch balances associated with the `to` stake - if (to.status === StakeStatus.Undelegated) { - // Increment owner undelegated stake - ownerStake[StakeStatus.Undelegated] = increaseNextBalance( - ownerStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - // Increment global undelegated stake - globalStake[StakeStatus.Undelegated] = increaseNextBalance( - globalStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - } else if (to.status === StakeStatus.Delegated) { - // Initializes the balance for this pool if the user has not previously delegated to it - _.defaults(ownerStake[StakeStatus.Delegated], { - [to.poolId]: new StoredBalance(), - }); - // Increment owner's delegated stake to this pool - ownerStake[StakeStatus.Delegated][to.poolId] = increaseNextBalance( - ownerStake[StakeStatus.Delegated][to.poolId], - amount, - currentEpoch, - ); - // Increment owner's total delegated stake - ownerStake[StakeStatus.Delegated].total = increaseNextBalance( - ownerStake[StakeStatus.Delegated].total, - amount, - currentEpoch, - ); - // Increment global delegated stake - globalStake[StakeStatus.Delegated] = increaseNextBalance( - globalStake[StakeStatus.Delegated], - amount, - currentEpoch, - ); - // Increment pool's delegated stake - stakingPools[to.poolId].delegatedStake = increaseNextBalance( - stakingPools[to.poolId].delegatedStake, - amount, - currentEpoch, - ); - updatedPools.push(to.poolId); - - // TODO: Check that delegator rewards have been withdrawn/synced - } - return updatedPools; -} -/** - * Returns a FunctionAssertion for `moveStake` which assumes valid input is provided. Checks that - * the owner's stake and global stake by status get updated correctly. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -export function validMoveStakeAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, - ownerStake: OwnerStakeByStatus, -): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], void, void> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], void, void>(stakingWrapper, 'moveStake', { - after: async ( - _beforeInfo: void, - result: FunctionResult, - args: [StakeInfo, StakeInfo, BigNumber], - txData: Partial, - ) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [from, to, amount] = args; - const { stakingPools, globalStake, currentEpoch } = simulationEnvironment; - - const owner = txData.from!; // tslint:disable-line:no-non-null-assertion - - // Update local balances to match the expected result of this `moveStake` operation - const updatedPools = updateNextEpochBalances(ownerStake, from, to, amount, simulationEnvironment); - - // Fetches on-chain owner stake balances and checks against local balances - const ownerUndelegatedStake = { - ...new StoredBalance(), - ...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Undelegated).callAsync()), - }; - const ownerDelegatedStake = { - ...new StoredBalance(), - ...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Delegated).callAsync()), - }; - expect(ownerUndelegatedStake).to.deep.equal( - loadCurrentBalance(ownerStake[StakeStatus.Undelegated], currentEpoch), - ); - expect(ownerDelegatedStake).to.deep.equal( - loadCurrentBalance(ownerStake[StakeStatus.Delegated].total, currentEpoch), - ); - - // Fetches on-chain global stake balances and checks against local balances - const globalDelegatedStake = await stakingWrapper.getGlobalStakeByStatus(StakeStatus.Delegated).callAsync(); - const globalUndelegatedStake = await stakingWrapper - .getGlobalStakeByStatus(StakeStatus.Undelegated) - .callAsync(); - expect(globalDelegatedStake).to.deep.equal( - loadCurrentBalance(globalStake[StakeStatus.Delegated], currentEpoch), - ); - expect(globalUndelegatedStake).to.deep.equal( - loadCurrentBalance(globalStake[StakeStatus.Undelegated], currentEpoch), - ); - - // Fetches on-chain pool stake balances and checks against local balances - for (const poolId of updatedPools) { - const stakeDelegatedByOwner = await stakingWrapper - .getStakeDelegatedToPoolByOwner(owner, poolId) - .callAsync(); - const totalStakeDelegated = await stakingWrapper.getTotalStakeDelegatedToPool(poolId).callAsync(); - expect(stakeDelegatedByOwner).to.deep.equal( - loadCurrentBalance(ownerStake[StakeStatus.Delegated][poolId], currentEpoch), - ); - expect(totalStakeDelegated).to.deep.equal( - loadCurrentBalance(stakingPools[poolId].delegatedStake, currentEpoch), - ); - } - }, - }); -} - -/** - * Returns a FunctionAssertion for `moveStake` which asserts that the transaction reverts with a - * PoolExistenceError. - */ -export function moveStakeNonexistentPoolAssertion( - deployment: DeploymentManager, - nonExistentPoolId: string, -): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], void, void> { - return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], void, void>( - deployment.staking.stakingWrapper, - 'moveStake', - { - after: async (_beforeInfo: void, result: FunctionResult) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - // Check revert error - expect(result.data).to.equal(new StakingRevertErrors.PoolExistenceError(nonExistentPoolId, false)); - }, - }, - ); -} -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/stake.ts b/contracts/integrations/test/framework/assertions/stake.ts deleted file mode 100644 index 7f43a2488d..0000000000 --- a/contracts/integrations/test/framework/assertions/stake.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { increaseCurrentAndNextBalance, OwnerStakeByStatus, StakeStatus } from '@0x/contracts-staking'; -import { expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { TxData } from 'ethereum-types'; - -import { LocalBalanceStore } from '../balances/local_balance_store'; -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -/** - * Returns a FunctionAssertion for `stake` which assumes valid input is provided. The - * FunctionAssertion checks that the staker and zrxVault's balances of ZRX decrease and increase, - * respectively, by the input amount. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -export function validStakeAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, - ownerStake: OwnerStakeByStatus, -): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { - const { stakingWrapper, zrxVault } = deployment.staking; - - return new FunctionAssertion(stakingWrapper, 'stake', { - before: async (args: [BigNumber], txData: Partial) => { - const [amount] = args; - const { balanceStore } = simulationEnvironment; - - // Simulates the transfer of ZRX from staker to vault - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.transferAsset( - txData.from as string, - zrxVault.address, - amount, - encodeERC20AssetData(deployment.tokens.zrx.address), - ); - return expectedBalances; - }, - after: async ( - expectedBalances: LocalBalanceStore, - result: FunctionResult, - args: [BigNumber], - txData: Partial, - ) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [amount] = args; - const { balanceStore, currentEpoch, globalStake } = simulationEnvironment; - - // Checks that the ZRX transfer updated balances as expected. - await balanceStore.updateErc20BalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // _increaseCurrentAndNextBalance - ownerStake[StakeStatus.Undelegated] = increaseCurrentAndNextBalance( - ownerStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - globalStake[StakeStatus.Undelegated] = increaseCurrentAndNextBalance( - globalStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - - // Checks that the owner's undelegated stake has increased by the stake amount - const ownerUndelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(txData.from as string, StakeStatus.Undelegated) - .callAsync(); - expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(ownerStake[StakeStatus.Undelegated]); - - // Checks that the global undelegated stake has also increased by the stake amount - const globalUndelegatedStake = await stakingWrapper - .getGlobalStakeByStatus(StakeStatus.Undelegated) - .callAsync(); - expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal( - globalStake[StakeStatus.Undelegated], - ); - }, - }); -} -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/unstake.ts b/contracts/integrations/test/framework/assertions/unstake.ts deleted file mode 100644 index 1546c8901f..0000000000 --- a/contracts/integrations/test/framework/assertions/unstake.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { encodeERC20AssetData } from '@0x/contracts-asset-proxy'; -import { - decreaseCurrentAndNextBalance, - OwnerStakeByStatus, - StakeStatus, - StakingRevertErrors, -} from '@0x/contracts-staking'; -import { expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { TxData } from 'ethereum-types'; - -import { LocalBalanceStore } from '../balances/local_balance_store'; -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -/** - * Returns a FunctionAssertion for `unstake` which assumes valid input is provided. The - * FunctionAssertion checks that the staker and zrxVault's balances of ZRX increase and decrease, - * respectively, by the input amount. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -export function validUnstakeAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, - ownerStake: OwnerStakeByStatus, -): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { - const { stakingWrapper, zrxVault } = deployment.staking; - - return new FunctionAssertion(stakingWrapper, 'unstake', { - before: async (args: [BigNumber], txData: Partial) => { - const [amount] = args; - const { balanceStore } = simulationEnvironment; - - // Simulates the transfer of ZRX from vault to staker - const expectedBalances = LocalBalanceStore.create(balanceStore); - expectedBalances.transferAsset( - zrxVault.address, - txData.from as string, - amount, - encodeERC20AssetData(deployment.tokens.zrx.address), - ); - return expectedBalances; - }, - after: async ( - expectedBalances: LocalBalanceStore, - result: FunctionResult, - args: [BigNumber], - txData: Partial, - ) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [amount] = args; - const { balanceStore, currentEpoch, globalStake } = simulationEnvironment; - - // Checks that the ZRX transfer updated balances as expected. - await balanceStore.updateErc20BalancesAsync(); - balanceStore.assertEquals(expectedBalances); - - // _decreaseCurrentAndNextBalance - ownerStake[StakeStatus.Undelegated] = decreaseCurrentAndNextBalance( - ownerStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - globalStake[StakeStatus.Undelegated] = decreaseCurrentAndNextBalance( - globalStake[StakeStatus.Undelegated], - amount, - currentEpoch, - ); - - // Checks that the owner's undelegated stake has decreased by the stake amount - const ownerUndelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(txData.from as string, StakeStatus.Undelegated) - .callAsync(); - expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(ownerStake[StakeStatus.Undelegated]); - - // Checks that the global undelegated stake has also increased by the stake amount - const globalUndelegatedStake = await stakingWrapper - .getGlobalStakeByStatus(StakeStatus.Undelegated) - .callAsync(); - expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal( - globalStake[StakeStatus.Undelegated], - ); - }, - }); -} - -/** - * Returns a FunctionAssertion for `unstake` which assumes that the input exceeds the amount that - * can be unstaked. Checks that the call reverts with an InsufficientBalanceError. Note that we - * close over `withdrawableStake` to avoid duplicating work done in the assertion generator. - */ -export function invalidUnstakeAssertion( - deployment: DeploymentManager, - withdrawableStake: BigNumber, -): FunctionAssertion<[BigNumber], void, void> { - return new FunctionAssertion<[BigNumber], void, void>(deployment.staking.stakingWrapper, 'unstake', { - after: async (_beforeInfo: void, result: FunctionResult, args: [BigNumber]) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - const [amount] = args; - expect(result.data).to.equal(new StakingRevertErrors.InsufficientBalanceError(amount, withdrawableStake)); - }, - }); -} -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/withdrawDelegatorRewards.ts b/contracts/integrations/test/framework/assertions/withdrawDelegatorRewards.ts deleted file mode 100644 index 6b14666abf..0000000000 --- a/contracts/integrations/test/framework/assertions/withdrawDelegatorRewards.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { WETH9Events, WETH9TransferEventArgs } from '@0x/contracts-erc20'; -import { loadCurrentBalance, StakingRevertErrors, StoredBalance } from '@0x/contracts-staking'; -import { expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { TxData } from 'ethereum-types'; - -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionAssertion, FunctionResult } from './function_assertion'; - -interface WithdrawDelegatorRewardsBeforeInfo { - delegatorStake: StoredBalance; - poolRewards: BigNumber; - wethReservedForPoolRewards: BigNumber; -} - -/** - * Returns a FunctionAssertion for `withdrawDelegatorRewards` which assumes valid input is provided. - * It checks that the delegator's stake gets synced and pool rewards are updated to reflect the - * amount withdrawn. - */ -/* tslint:disable:no-unnecessary-type-assertion */ -export function validWithdrawDelegatorRewardsAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[string], WithdrawDelegatorRewardsBeforeInfo, void> { - const { stakingWrapper } = deployment.staking; - - return new FunctionAssertion(stakingWrapper, 'withdrawDelegatorRewards', { - before: async (args: [string], txData: Partial) => { - const [poolId] = args; - - const delegatorStake = await stakingWrapper - .getStakeDelegatedToPoolByOwner(txData.from as string, poolId) - .callAsync(); - const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync(); - const wethReservedForPoolRewards = await stakingWrapper.wethReservedForPoolRewards().callAsync(); - return { delegatorStake, poolRewards, wethReservedForPoolRewards }; - }, - after: async ( - beforeInfo: WithdrawDelegatorRewardsBeforeInfo, - result: FunctionResult, - args: [string], - txData: Partial, - ) => { - // Ensure that the tx succeeded. - expect(result.success, `Error: ${result.data}`).to.be.true(); - - const [poolId] = args; - const { currentEpoch } = simulationEnvironment; - - // Check that delegator stake has been synced - const expectedDelegatorStake = loadCurrentBalance(beforeInfo.delegatorStake, currentEpoch); - const delegatorStake = await stakingWrapper - .getStakeDelegatedToPoolByOwner(txData.from as string, poolId) - .callAsync(); - expect(delegatorStake).to.deep.equal(expectedDelegatorStake); - - // Check that pool rewards have been updated to reflect the amount withdrawn. - const transferEvents = filterLogsToArguments( - result.receipt!.logs, // tslint:disable-line:no-non-null-assertion - WETH9Events.Transfer, - ); - const expectedPoolRewards = - transferEvents.length > 0 - ? beforeInfo.poolRewards.minus(transferEvents[0]._value) - : beforeInfo.poolRewards; - const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync(); - expect(poolRewards).to.bignumber.equal(expectedPoolRewards); - - // TODO: Check CR - }, - }); -} - -/** - * Returns a FunctionAssertion for `withdrawDelegatorRewards` which assumes the given pool hasn't - * been finalized for the previous epoch. It checks that the call reverts with a PoolNotFinalizedError. - */ -export function invalidWithdrawDelegatorRewardsAssertion( - deployment: DeploymentManager, - simulationEnvironment: SimulationEnvironment, -): FunctionAssertion<[string], void, void> { - return new FunctionAssertion(deployment.staking.stakingWrapper, 'withdrawDelegatorRewards', { - after: async (_beforeInfo: void, result: FunctionResult, args: [string]) => { - // Ensure that the tx reverted. - expect(result.success).to.be.false(); - - // Check revert error - const [poolId] = args; - const { currentEpoch } = simulationEnvironment; - expect(result.data).to.equal(new StakingRevertErrors.PoolNotFinalizedError(poolId, currentEpoch.minus(1))); - }, - }); -} -/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/balances/balance_store.ts b/contracts/integrations/test/framework/balances/balance_store.ts deleted file mode 100644 index ea9b5d6eaa..0000000000 --- a/contracts/integrations/test/framework/balances/balance_store.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { BaseContract } from '@0x/base-contract'; -import { constants, expect, replaceKeysDeep, TokenBalances } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { TokenAddresses, TokenContractsByName, TokenOwnersByName } from './types'; - -export class BalanceStore { - public balances: TokenBalances; - protected _tokenAddresses: TokenAddresses; - protected _ownerAddresses: string[]; - private _addressNames: { - [address: string]: string; - }; - - /** - * Constructor. - * @param tokenOwnersByName Addresses of token owners to track balances of. - * @param tokenContractsByName Contracts of tokens to track balances of. - */ - public constructor(tokenOwnersByName: TokenOwnersByName, tokenContractsByName: Partial) { - this.balances = { erc20: {}, erc721: {}, erc1155: {}, eth: {} }; - this._ownerAddresses = Object.values(tokenOwnersByName); - - _.defaults(tokenContractsByName, { erc20: {}, erc721: {}, erc1155: {} }); - const tokenAddressesByName = _.mapValues( - { ...tokenContractsByName.erc20, ...tokenContractsByName.erc721, ...tokenContractsByName.erc1155 }, - contract => (contract as BaseContract).address, - ); - this._addressNames = _.invert({ ...tokenOwnersByName, ...tokenAddressesByName }); - - this._tokenAddresses = { - erc20: Object.values(tokenContractsByName.erc20 || {}).map(contract => contract.address), - erc721: Object.values(tokenContractsByName.erc721 || {}).map(contract => contract.address), - erc1155: Object.values(tokenContractsByName.erc1155 || {}).map(contract => contract.address), - }; - } - - /** - * Registers the given token owner in this balance store. The token owner's balance will be - * tracked in subsequent operations. - * @param address Address of the token owner - * @param name Name of the token owner - */ - public registerTokenOwner(address: string, name: string): void { - this._ownerAddresses.push(address); - this._addressNames[address] = name; - } - - /** - * Throws iff balance stores do not have the same entries. - * @param rhs Balance store to compare to - */ - public assertEquals(rhs: BalanceStore): void { - this._assertEthBalancesEqual(rhs); - this._assertErc20BalancesEqual(rhs); - this._assertErc721BalancesEqual(rhs); - this._assertErc1155BalancesEqual(rhs); - } - - /** - * Copies from an existing balance store. - * @param balanceStore to copy from. - */ - public cloneFrom(balanceStore: BalanceStore): void { - this.balances = _.cloneDeep(balanceStore.balances); - this._tokenAddresses = _.cloneDeep(balanceStore._tokenAddresses); - this._ownerAddresses = _.cloneDeep(balanceStore._ownerAddresses); - this._addressNames = _.cloneDeep(balanceStore._addressNames); - } - - /** - * Returns a version of balances where keys are replaced with their readable counterparts, if - * they exist. - */ - public toReadable(): _.Dictionary<{}> { - return replaceKeysDeep(this.balances, this._readableAddressName.bind(this)); - } - - /** - * Returns the human-readable name for the given address, if it exists. - * @param address The address to get the name for. - */ - private _readableAddressName(address: string): string { - return this._addressNames[address] || address; - } - - /** - * Throws iff balance stores do not have the same ETH balances. - * @param rhs Balance store to compare to - */ - private _assertEthBalancesEqual(rhs: BalanceStore): void { - for (const ownerAddress of [...this._ownerAddresses, ...rhs._ownerAddresses]) { - const thisBalance = _.get(this.balances.eth, [ownerAddress], constants.ZERO_AMOUNT); - const rhsBalance = _.get(rhs.balances.eth, [ownerAddress], constants.ZERO_AMOUNT); - expect(thisBalance, `${this._readableAddressName(ownerAddress)} ETH balance`).to.bignumber.equal( - rhsBalance, - ); - } - } - - /** - * Throws iff balance stores do not have the same ERC20 balances. - * @param rhs Balance store to compare to - */ - private _assertErc20BalancesEqual(rhs: BalanceStore): void { - for (const ownerAddress of [...this._ownerAddresses, ...rhs._ownerAddresses]) { - for (const tokenAddress of [...this._tokenAddresses.erc20, ...rhs._tokenAddresses.erc20]) { - const thisBalance = _.get(this.balances.erc20, [ownerAddress, tokenAddress], constants.ZERO_AMOUNT); - const rhsBalance = _.get(rhs.balances.erc20, [ownerAddress, tokenAddress], constants.ZERO_AMOUNT); - expect( - thisBalance, - `${this._readableAddressName(ownerAddress)} ${this._readableAddressName(tokenAddress)} balance`, - ).to.bignumber.equal(rhsBalance); - } - } - } - - /** - * Throws iff balance stores do not have the same ERC721 balances. - * @param rhs Balance store to compare to - */ - private _assertErc721BalancesEqual(rhs: BalanceStore): void { - for (const ownerAddress of [...this._ownerAddresses, ...rhs._ownerAddresses]) { - for (const tokenAddress of [...this._tokenAddresses.erc721, ...rhs._tokenAddresses.erc721]) { - const thisBalance = _.get(this.balances.erc721, [ownerAddress, tokenAddress], []); - const rhsBalance = _.get(rhs.balances.erc721, [ownerAddress, tokenAddress], []); - expect( - thisBalance, - `${this._readableAddressName(ownerAddress)} ${this._readableAddressName(tokenAddress)} balance`, - ).to.deep.equal(rhsBalance); - } - } - } - - /** - * Throws iff balance stores do not have the same ERC1155 balances. - * @param rhs Balance store to compare to - */ - private _assertErc1155BalancesEqual(rhs: BalanceStore): void { - for (const ownerAddress of [...this._ownerAddresses, ...rhs._ownerAddresses]) { - for (const tokenAddress of [...this._tokenAddresses.erc1155, ...rhs._tokenAddresses.erc1155]) { - const thisBalance = _.get(this.balances.erc1155, [ownerAddress, tokenAddress], {}); - const rhsBalance = _.get(rhs.balances.erc1155, [ownerAddress, tokenAddress], {}); - expect( - thisBalance, - `${this._readableAddressName(ownerAddress)} ${this._readableAddressName(tokenAddress)} balance`, - ).to.deep.equal(rhsBalance); - } - } - } -} diff --git a/contracts/integrations/test/framework/balances/blockchain_balance_store.ts b/contracts/integrations/test/framework/balances/blockchain_balance_store.ts deleted file mode 100644 index cd31207578..0000000000 --- a/contracts/integrations/test/framework/balances/blockchain_balance_store.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { web3Wrapper } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as combinatorics from 'js-combinatorics'; -import * as _ from 'lodash'; - -import { BalanceStore } from './balance_store'; -import { TokenContracts, TokenContractsByName, TokenIds, TokenOwnersByName } from './types'; - -export class BlockchainBalanceStore extends BalanceStore { - private readonly _tokenContracts: TokenContracts; - private readonly _tokenIds: TokenIds; - - /** - * Constructor. - * @param tokenOwnersByName The addresses of token owners whose balances will be tracked. - * @param tokenContractsByName The contracts of tokens to track. - * @param tokenIds The tokenIds of ERC721 and ERC1155 assets to track. - */ - public constructor( - tokenOwnersByName: TokenOwnersByName, - tokenContractsByName: Partial, - tokenIds: Partial = {}, - ) { - super(tokenOwnersByName, tokenContractsByName); - this._tokenContracts = { - erc20: Object.values(tokenContractsByName.erc20 || {}), - erc721: Object.values(tokenContractsByName.erc721 || {}), - erc1155: Object.values(tokenContractsByName.erc1155 || {}), - }; - this._tokenIds = { - erc721: tokenIds.erc721 || {}, - erc1155: tokenIds.erc1155 || {}, - }; - } - - /** - * Updates balances by querying on-chain values. - */ - public async updateBalancesAsync(): Promise { - await Promise.all([ - this.updateEthBalancesAsync(), - this.updateErc20BalancesAsync(), - this.updateErc721BalancesAsync(), - this.updateErc1155BalancesAsync(), - ]); - } - - /** - * Updates ETH balances. - */ - public async updateEthBalancesAsync(): Promise { - const ethBalances = _.zipObject( - this._ownerAddresses, - await Promise.all(this._ownerAddresses.map(address => web3Wrapper.getBalanceInWeiAsync(address))), - ); - this.balances.eth = ethBalances; - } - - /** - * Updates ERC20 balances. - */ - public async updateErc20BalancesAsync(): Promise { - const balances = await Promise.all( - this._ownerAddresses.map(async account => - _.zipObject( - this._tokenContracts.erc20.map(token => token.address), - await Promise.all(this._tokenContracts.erc20.map(token => token.balanceOf(account).callAsync())), - ), - ), - ); - this.balances.erc20 = _.zipObject(this._ownerAddresses, balances); - } - - /** - * Updates ERC721 balances. - */ - public async updateErc721BalancesAsync(): Promise { - const erc721ContractsByAddress = _.zipObject( - this._tokenContracts.erc721.map(contract => contract.address), - this._tokenContracts.erc721, - ); - - this.balances.erc721 = {}; - for (const [tokenAddress, tokenIds] of Object.entries(this._tokenIds.erc721)) { - for (const tokenId of tokenIds) { - const tokenOwner = await erc721ContractsByAddress[tokenAddress].ownerOf(tokenId).callAsync(); - _.update(this.balances.erc721, [tokenOwner, tokenAddress], nfts => _.union([tokenId], nfts).sort()); - } - } - } - - /** - * Updates ERC1155 balances. - */ - public async updateErc1155BalancesAsync(): Promise { - const erc1155ContractsByAddress = _.zipObject( - this._tokenContracts.erc1155.map(contract => contract.address), - this._tokenContracts.erc1155, - ); - - for (const [tokenAddress, { fungible, nonFungible }] of Object.entries(this._tokenIds.erc1155)) { - const contract = erc1155ContractsByAddress[tokenAddress]; - const tokenIds = [...fungible, ...nonFungible]; - if (this._ownerAddresses.length === 0 || tokenIds.length === 0) { - continue; - } - - const [_tokenIds, _tokenOwners] = _.unzip( - combinatorics.cartesianProduct(tokenIds, this._ownerAddresses).toArray(), - ); - const balances = await contract - .balanceOfBatch(_tokenOwners as string[], _tokenIds as BigNumber[]) - .callAsync(); - - let i = 0; - for (const tokenOwner of this._ownerAddresses) { - // Fungible tokens - _.set(this.balances.erc1155, [tokenOwner, tokenAddress, 'fungible'], {}); - for (const tokenId of fungible) { - _.set( - this.balances.erc1155, - [tokenOwner, tokenAddress, 'fungible', tokenId.toString()], - balances[i++], - ); - } - // Non-fungible tokens - _.set(this.balances.erc1155, [tokenOwner, tokenAddress, 'nonFungible'], []); - for (const tokenId of nonFungible) { - const isOwner = balances[i++]; - if (isOwner.isEqualTo(1)) { - _.update(this.balances.erc1155, [tokenOwner, tokenAddress, 'nonFungible'], nfts => - _.union([tokenId], nfts).sort(), - ); - } - } - } - } - } -} diff --git a/contracts/integrations/test/framework/balances/local_balance_store.ts b/contracts/integrations/test/framework/balances/local_balance_store.ts deleted file mode 100644 index 626fb55148..0000000000 --- a/contracts/integrations/test/framework/balances/local_balance_store.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { - decodeERC1155AssetData, - decodeERC20AssetData, - decodeERC20BridgeAssetData, - decodeERC721AssetData, - decodeMultiAssetData, - encodeERC20AssetData, -} from '@0x/contracts-asset-proxy'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { constants, Numberish } from '@0x/contracts-test-utils'; -import { AssetProxyId, SignedOrder } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DeploymentManager } from '../deployment_manager'; - -import { BalanceStore } from './balance_store'; -import { TokenContractsByName, TokenOwnersByName } from './types'; - -export class LocalBalanceStore extends BalanceStore { - /** - * Creates a new balance store based on an existing one. - * @param sourceBalanceStore Existing balance store whose values should be copied. - */ - public static create(sourceBalanceStore?: BalanceStore): LocalBalanceStore { - const localBalanceStore = new LocalBalanceStore(); - if (sourceBalanceStore !== undefined) { - localBalanceStore.cloneFrom(sourceBalanceStore); - } - return localBalanceStore; - } - - /** - * Constructor. - * Note that parameters are given {} defaults because `LocalBalanceStore`s will typically - * be initialized via `create`. - */ - protected constructor( - tokenOwnersByName: TokenOwnersByName = {}, - tokenContractsByName: Partial = {}, - ) { - super(tokenOwnersByName, tokenContractsByName); - } - - /** - * Decreases the ETH balance of an address to simulate gas usage. - * @param senderAddress Address whose ETH balance to decrease. - * @param amount Amount to decrease the balance by. - */ - public burnGas(senderAddress: string, amount: Numberish): void { - this.balances.eth[senderAddress] = this.balances.eth[senderAddress].minus(amount); - } - - /** - * Converts some amount of the ETH balance of an address to WETH balance to simulate wrapping ETH. - * @param senderAddress Address whose ETH to wrap. - * @param amount Amount to wrap. - */ - public wrapEth(senderAddress: string, wethAddress: string, amount: Numberish): void { - this.balances.eth[senderAddress] = this.balances.eth[senderAddress].minus(amount); - _.update(this.balances.erc20, [senderAddress, wethAddress], balance => - (balance || constants.ZERO_AMOUNT).plus(amount), - ); - } - - /** - * Converts some amount of the ETH balance of an address to WETH balance to simulate wrapping ETH. - * @param senderAddress Address whose ETH to wrap. - * @param amount Amount to wrap. - */ - public unwrapEth(senderAddress: string, wethAddress: string, amount: Numberish): void { - this.balances.eth[senderAddress] = this.balances.eth[senderAddress].plus(amount); - _.update(this.balances.erc20, [senderAddress, wethAddress], balance => balance.minus(amount)); - } - - /** - * Sends ETH from `fromAddress` to `toAddress`. - * @param fromAddress Sender of ETH. - * @param toAddress Receiver of ETH. - * @param amount Amount of ETH to transfer. - */ - public sendEth(fromAddress: string, toAddress: string, amount: Numberish): void { - this.balances.eth[toAddress] = this.balances.eth[toAddress] || constants.ZERO_AMOUNT; - this.balances.eth[fromAddress] = this.balances.eth[fromAddress].minus(amount); - this.balances.eth[toAddress] = this.balances.eth[toAddress].plus(amount); - } - - /** - * Transfers assets from `fromAddress` to `toAddress`. - * @param fromAddress Sender of asset(s) - * @param toAddress Receiver of asset(s) - * @param amount Amount of asset(s) to transfer - * @param assetData Asset data of assets being transferred. - */ - public transferAsset(fromAddress: string, toAddress: string, amount: BigNumber, assetData: string): void { - if (fromAddress === toAddress || amount.isZero()) { - return; - } - const assetProxyId = hexUtils.slice(assetData, 0, 4); - switch (assetProxyId) { - case AssetProxyId.ERC20: { - const tokenAddress = decodeERC20AssetData(assetData); - _.update(this.balances.erc20, [fromAddress, tokenAddress], balance => balance.minus(amount)); - _.update(this.balances.erc20, [toAddress, tokenAddress], balance => - (balance || constants.ZERO_AMOUNT).plus(amount), - ); - break; - } - case AssetProxyId.ERC20Bridge: { - const [tokenAddress] = decodeERC20BridgeAssetData(assetData); - // The test bridge contract (TestEth2DaiBridge or TestUniswapBridge) will be the - // fromAddress in this case, and it simply mints the amount of token it needs to transfer. - _.update(this.balances.erc20, [fromAddress, tokenAddress], balance => - (balance || constants.ZERO_AMOUNT).minus(amount), - ); - _.update(this.balances.erc20, [toAddress, tokenAddress], balance => - (balance || constants.ZERO_AMOUNT).plus(amount), - ); - break; - } - case AssetProxyId.ERC721: { - const [tokenAddress, tokenId] = decodeERC721AssetData(assetData); - const fromTokens = _.get(this.balances.erc721, [fromAddress, tokenAddress], []); - const toTokens = _.get(this.balances.erc721, [toAddress, tokenAddress], []); - if (amount.gte(1)) { - const tokenIndex = _.findIndex(fromTokens as BigNumber[], t => t.eq(tokenId)); - if (tokenIndex !== -1) { - fromTokens.splice(tokenIndex, 1); - toTokens.push(tokenId); - toTokens.sort(); - } - } - _.set(this.balances.erc721, [fromAddress, tokenAddress], fromTokens); - _.set(this.balances.erc721, [toAddress, tokenAddress], toTokens); - break; - } - case AssetProxyId.ERC1155: { - const [tokenAddress, tokenIds, tokenValues] = decodeERC1155AssetData(assetData); - const fromBalances = { - // tslint:disable-next-line:no-inferred-empty-object-type - fungible: _.get(this.balances.erc1155, [fromAddress, tokenAddress, 'fungible'], {}), - nonFungible: _.get(this.balances.erc1155, [fromAddress, tokenAddress, 'nonFungible'], []), - }; - const toBalances = { - // tslint:disable-next-line:no-inferred-empty-object-type - fungible: _.get(this.balances.erc1155, [toAddress, tokenAddress, 'fungible'], {}), - nonFungible: _.get(this.balances.erc1155, [toAddress, tokenAddress, 'nonFungible'], []), - }; - for (const [i, tokenId] of tokenIds.entries()) { - const tokenValue = tokenValues[i]; - const tokenAmount = amount.times(tokenValue); - if (tokenAmount.gt(0)) { - const tokenIndex = _.findIndex(fromBalances.nonFungible as BigNumber[], t => t.eq(tokenId)); - if (tokenIndex !== -1) { - // Transfer a non-fungible. - fromBalances.nonFungible.splice(tokenIndex, 1); - toBalances.nonFungible.push(tokenId); - // sort NFT's by name - toBalances.nonFungible.sort(); - } else { - // Transfer a fungible. - const _tokenId = tokenId.toString(); - _.update(fromBalances.fungible, [_tokenId], balance => balance.minus(tokenAmount)); - _.update(toBalances.fungible, [_tokenId], balance => - (balance || constants.ZERO_AMOUNT).plus(tokenAmount), - ); - } - } - } - _.set(this.balances.erc1155, [fromAddress, tokenAddress], fromBalances); - _.set(this.balances.erc1155, [toAddress, tokenAddress], toBalances); - break; - } - case AssetProxyId.MultiAsset: { - const [amounts, nestedAssetData] = decodeMultiAssetData(assetData); - for (const [i, amt] of amounts.entries()) { - const nestedAmount = amount.times(amt); - this.transferAsset(fromAddress, toAddress, nestedAmount, nestedAssetData[i]); - } - break; - } - case AssetProxyId.StaticCall: - // Do nothing - break; - default: - throw new Error(`Unhandled asset proxy ID: ${assetProxyId}`); - } - } - - public simulateFills( - orders: SignedOrder[], - takerAddresses: string[] | string, - txReceipt: TransactionReceiptWithDecodedLogs, - deployment: DeploymentManager, - msgValue: BigNumber = constants.ZERO_AMOUNT, - takerAssetFillAmounts?: BigNumber[], - ): void { - let remainingValue = msgValue; - // Transaction gas cost - this.burnGas(txReceipt.from, DeploymentManager.gasPrice.times(txReceipt.gasUsed)); - - for (const [index, order] of orders.entries()) { - const takerAddress = Array.isArray(takerAddresses) ? takerAddresses[index] : takerAddresses; - const fillResults = ReferenceFunctions.calculateFillResults( - order, - takerAssetFillAmounts ? takerAssetFillAmounts[index] : order.takerAssetAmount, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - ); - - // Taker -> Maker - this.transferAsset( - takerAddress, - order.makerAddress, - fillResults.takerAssetFilledAmount, - order.takerAssetData, - ); - // Maker -> Taker - this.transferAsset( - order.makerAddress, - takerAddress, - fillResults.makerAssetFilledAmount, - order.makerAssetData, - ); - // Taker -> Fee Recipient - this.transferAsset( - takerAddress, - order.feeRecipientAddress, - fillResults.takerFeePaid, - order.takerFeeAssetData, - ); - // Maker -> Fee Recipient - this.transferAsset( - order.makerAddress, - order.feeRecipientAddress, - fillResults.makerFeePaid, - order.makerFeeAssetData, - ); - - // Protocol fee - if (remainingValue.isGreaterThanOrEqualTo(fillResults.protocolFeePaid)) { - this.sendEth(txReceipt.from, deployment.staking.stakingProxy.address, fillResults.protocolFeePaid); - remainingValue = remainingValue.minus(fillResults.protocolFeePaid); - } else { - this.transferAsset( - takerAddress, - deployment.staking.stakingProxy.address, - fillResults.protocolFeePaid, - encodeERC20AssetData(deployment.tokens.weth.address), - ); - } - } - } -} diff --git a/contracts/integrations/test/framework/balances/types.ts b/contracts/integrations/test/framework/balances/types.ts deleted file mode 100644 index 75789b614b..0000000000 --- a/contracts/integrations/test/framework/balances/types.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ERC1155MintableContract } from '@0x/contracts-erc1155'; -import { DummyERC20TokenContract, DummyNoReturnERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20'; -import { DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { BigNumber } from '@0x/utils'; - -// alias for clarity -type address = string; - -interface TokenData { - erc20: TERC20; - erc721: TERC721; - erc1155: TERC1155; -} - -export type TokenAddresses = TokenData; - -export type TokenContracts = TokenData< - Array, - DummyERC721TokenContract[], - ERC1155MintableContract[] ->; - -interface Named { - [readableName: string]: T; -} - -export type TokenOwnersByName = Named
; - -export type TokenAddressesByName = TokenData, Named
, Named
>; - -export type TokenContractsByName = TokenData< - Named, - Named, - Named ->; - -interface ERC721TokenIds { - [tokenAddress: string]: BigNumber[]; -} - -interface ERC1155TokenIds { - [tokenAddress: string]: { - fungible: BigNumber[]; - nonFungible: BigNumber[]; - }; -} - -export interface TokenIds { - erc721: ERC721TokenIds; - erc1155: ERC1155TokenIds; -} diff --git a/contracts/integrations/test/framework/deployment_manager.ts b/contracts/integrations/test/framework/deployment_manager.ts deleted file mode 100644 index fae0ffc519..0000000000 --- a/contracts/integrations/test/framework/deployment_manager.ts +++ /dev/null @@ -1,538 +0,0 @@ -import { - artifacts as assetProxyArtifacts, - ERC1155ProxyContract, - ERC20BridgeProxyContract, - ERC20ProxyContract, - ERC721ProxyContract, - MultiAssetProxyContract, - StaticCallProxyContract, -} from '@0x/contracts-asset-proxy'; -import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; -import { artifacts as ERC1155Artifacts, ERC1155MintableContract } from '@0x/contracts-erc1155'; -import { artifacts as ERC20Artifacts, DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20'; -import { artifacts as ERC721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange'; -import { artifacts as multisigArtifacts, ZeroExGovernorContract } from '@0x/contracts-multisig'; -import { - artifacts as stakingArtifacts, - StakingProxyContract, - TestStakingContract, - ZrxVaultContract, -} from '@0x/contracts-staking'; -import { BlockchainTestsEnvironment, constants } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { AssetProxyDispatcher, Authorizable, Ownable } from './utils/wrapper_interfaces'; - -/** - * Adds a batch of authorities to a list of authorizable contracts. - * @param owner The owner of the authorizable contracts. - * @param authorizers The authorizable contracts. - * @param authorities A list of addresses to authorize in each authorizer contract. - */ -async function batchAddAuthorizedAddressAsync( - owner: string, - authorizers: Authorizable[], - authorities: string[], -): Promise { - for (const authorizer of authorizers) { - for (const authority of authorities) { - await authorizer.addAuthorizedAddress(authority).awaitTransactionSuccessAsync({ from: owner }); - } - } -} - -/** - * Batch registers asset proxies in a list of registry contracts. - * @param owner The owner of the registry accounts. - * @param registries The registries that the asset proxies should be registered in. - * @param proxies A list of proxy contracts to register. - */ -async function batchRegisterAssetProxyAsync( - owner: string, - registries: AssetProxyDispatcher[], - proxies: string[], -): Promise { - for (const registry of registries) { - for (const proxy of proxies) { - await registry.registerAssetProxy(proxy).awaitTransactionSuccessAsync({ from: owner }); - } - } -} - -/** - * Transfers ownership of several contracts from one address to another. - * @param owner The address that currently owns the contract instances. - * @param newOwner The address that will be given ownership of the contract instances. - * @param ownedContracts The contracts whose ownership will be transferred. - */ -async function batchTransferOwnershipAsync( - owner: string, - newOwner: ZeroExGovernorContract, - ownedContracts: Ownable[], -): Promise { - for (const ownedContract of ownedContracts) { - await ownedContract.transferOwnership(newOwner.address).awaitTransactionSuccessAsync({ from: owner }); - } -} - -// Contract wrappers for all of the asset proxies -interface AssetProxyContracts { - erc20Proxy: ERC20ProxyContract; - erc721Proxy: ERC721ProxyContract; - erc1155Proxy: ERC1155ProxyContract; - multiAssetProxy: MultiAssetProxyContract; - staticCallProxy: StaticCallProxyContract; - erc20BridgeProxy: ERC20BridgeProxyContract; -} - -// Contract wrappers for all of the staking contracts -interface StakingContracts { - stakingLogic: TestStakingContract; - stakingProxy: StakingProxyContract; - stakingWrapper: TestStakingContract; - zrxVault: ZrxVaultContract; -} - -// Contract wrappers for tokens. -interface TokenContracts { - erc20: DummyERC20TokenContract[]; - erc721: DummyERC721TokenContract[]; - erc1155: ERC1155MintableContract[]; - weth: WETH9Contract; - zrx: DummyERC20TokenContract; -} - -// Options to be passed to `deployAsync` -export interface DeploymentOptions { - owner: string; - numErc1155TokensToDeploy: number; - numErc20TokensToDeploy: number; - numErc721TokensToDeploy: number; -} - -export class DeploymentManager { - public static readonly protocolFeeMultiplier = new BigNumber(150000); - public static readonly gasPrice = new BigNumber(1e9); // 1 Gwei - public static readonly protocolFee = DeploymentManager.gasPrice.times(DeploymentManager.protocolFeeMultiplier); - - /** - * Fully deploy the 0x exchange and staking contracts and configure the system with the - * asset proxy owner multisig. - * @param environment A blockchain test environment to use for contracts deployment. - * @param options Specifies the owner address and number of tokens to deploy. - */ - public static async deployAsync( - environment: BlockchainTestsEnvironment, - options: Partial = {}, - ): Promise { - const chainId = await environment.getChainIdAsync(); - const accounts = await environment.getAccountAddressesAsync(); - - const owner = options.owner || (await environment.getAccountAddressesAsync())[0]; - const txDefaults = { - ...environment.txDefaults, - from: owner, - gasPrice: DeploymentManager.gasPrice, - }; - - // Deploy the contracts using the same owner and environment. - const assetProxies = await DeploymentManager._deployAssetProxyContractsAsync(environment, txDefaults); - const exchange = await ExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.Exchange, - environment.provider, - txDefaults, - { ...ERC20Artifacts, ...exchangeArtifacts, ...stakingArtifacts, ...assetProxyArtifacts }, - new BigNumber(chainId), - ); - const governor = await ZeroExGovernorContract.deployFrom0xArtifactAsync( - multisigArtifacts.ZeroExGovernor, - environment.provider, - txDefaults, - multisigArtifacts, - [], - [], - [], - [owner], - new BigNumber(1), - constants.ZERO_AMOUNT, - ); - const tokens = await DeploymentManager._deployTokenContractsAsync(environment, txDefaults, options); - const staking = await DeploymentManager._deployStakingContractsAsync( - environment, - owner, - txDefaults, - tokens, - assetProxies, - ); - - // Configure the asset proxies with the exchange and the exchange with the staking contracts. - await DeploymentManager._configureAssetProxiesWithExchangeAsync(assetProxies, exchange, owner); - await DeploymentManager._configureExchangeWithStakingAsync(exchange, staking, owner); - - // Authorize the asset-proxy owner in the staking proxy and in the zrx vault. - await staking.stakingProxy.addAuthorizedAddress(governor.address).awaitTransactionSuccessAsync({ - from: owner, - }); - await staking.zrxVault.addAuthorizedAddress(governor.address).awaitTransactionSuccessAsync({ - from: owner, - }); - - // Remove authorization for the original owner address. - await staking.stakingProxy.removeAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner }); - await staking.zrxVault.removeAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner }); - - // Transfer complete ownership of the system to the asset proxy owner. - await batchTransferOwnershipAsync(owner, governor, [ - assetProxies.erc20Proxy, - assetProxies.erc721Proxy, - assetProxies.erc1155Proxy, - assetProxies.multiAssetProxy, - assetProxies.erc20BridgeProxy, - exchange, - staking.stakingProxy, - ]); - const devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - devUtilsArtifacts.DevUtils, - devUtilsArtifacts, - environment.provider, - environment.txDefaults, - devUtilsArtifacts, - exchange.address, - constants.NULL_ADDRESS, - constants.NULL_ADDRESS, - ); - - // Construct the new instance and return it. - return new DeploymentManager( - environment.web3Wrapper, - assetProxies, - governor, - exchange, - staking, - tokens, - chainId, - accounts, - txDefaults, - devUtils, - ); - } - - /** - * Configures a set of asset proxies with an exchange contract. - * @param assetProxies A set of asset proxies to be configured. - * @param exchange An exchange contract to configure with the asset proxies. - * @param owner An owner address to use when configuring the asset proxies. - */ - protected static async _configureAssetProxiesWithExchangeAsync( - assetProxies: AssetProxyContracts, - exchange: ExchangeContract, - owner: string, - ): Promise { - // Register the asset proxies in the exchange contract. - await batchRegisterAssetProxyAsync( - owner, - [exchange], - [ - assetProxies.erc20Proxy.address, - assetProxies.erc721Proxy.address, - assetProxies.erc1155Proxy.address, - assetProxies.multiAssetProxy.address, - assetProxies.staticCallProxy.address, - assetProxies.erc20BridgeProxy.address, - ], - ); - - // Register the asset proxies in the multi-asset proxy. - await batchRegisterAssetProxyAsync( - owner, - [assetProxies.multiAssetProxy], - [ - assetProxies.erc20Proxy.address, - assetProxies.erc721Proxy.address, - assetProxies.erc1155Proxy.address, - assetProxies.staticCallProxy.address, - assetProxies.erc20BridgeProxy.address, - ], - ); - - // Add the multi-asset proxy as an authorized address of the token proxies. - await batchAddAuthorizedAddressAsync( - owner, - [ - assetProxies.erc20Proxy, - assetProxies.erc721Proxy, - assetProxies.erc1155Proxy, - assetProxies.erc20BridgeProxy, - ], - [assetProxies.multiAssetProxy.address], - ); - - // Add the exchange as an authorized address in all of the proxies. - await batchAddAuthorizedAddressAsync( - owner, - [ - assetProxies.erc20Proxy, - assetProxies.erc721Proxy, - assetProxies.erc1155Proxy, - assetProxies.multiAssetProxy, - assetProxies.erc20BridgeProxy, - ], - [exchange.address], - ); - } - - /** - * Configures an exchange contract with staking contracts - * @param exchange The Exchange contract. - * @param staking The Staking contracts. - * @param owner An owner address to use when configuring the asset proxies. - */ - protected static async _configureExchangeWithStakingAsync( - exchange: ExchangeContract, - staking: StakingContracts, - owner: string, - ): Promise { - // Configure the exchange for staking. - await exchange.setProtocolFeeCollectorAddress(staking.stakingProxy.address).awaitTransactionSuccessAsync({ - from: owner, - }); - await exchange.setProtocolFeeMultiplier(DeploymentManager.protocolFeeMultiplier).awaitTransactionSuccessAsync(); - - // Register the exchange contract in staking. - await staking.stakingWrapper.addExchangeAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner }); - } - - /** - * Deploy a set of asset proxy contracts. - * @param environment The blockchain environment to use. - * @param txDefaults Defaults to use when deploying the asset proxies. - */ - protected static async _deployAssetProxyContractsAsync( - environment: BlockchainTestsEnvironment, - txDefaults: Partial, - ): Promise { - const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC20Proxy, - environment.provider, - txDefaults, - assetProxyArtifacts, - ); - const erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC721Proxy, - environment.provider, - txDefaults, - assetProxyArtifacts, - ); - const erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC1155Proxy, - environment.provider, - txDefaults, - assetProxyArtifacts, - ); - const multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.MultiAssetProxy, - environment.provider, - txDefaults, - assetProxyArtifacts, - ); - const staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.StaticCallProxy, - environment.provider, - txDefaults, - assetProxyArtifacts, - ); - const erc20BridgeProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC20BridgeProxy, - environment.provider, - txDefaults, - assetProxyArtifacts, - ); - return { - erc20Proxy, - erc721Proxy, - erc1155Proxy, - multiAssetProxy, - staticCallProxy, - erc20BridgeProxy, - }; - } - - /** - * Deploy a set of staking contracts. - * @param environment The blockchain environment to use. - * @param owner An owner address to use when configuring the asset proxies. - * @param txDefaults Defaults to use when deploying the asset proxies. - * @param tokens A set of token contracts to use during deployment of the staking contracts. - * @param assetProxies A set of asset proxies to use with the staking contracts. - */ - protected static async _deployStakingContractsAsync( - environment: BlockchainTestsEnvironment, - owner: string, - txDefaults: Partial, - tokens: TokenContracts, - assetProxies: AssetProxyContracts, - ): Promise { - const zrxVault = await ZrxVaultContract.deployFrom0xArtifactAsync( - stakingArtifacts.ZrxVault, - environment.provider, - txDefaults, - stakingArtifacts, - assetProxies.erc20Proxy.address, - tokens.zrx.address, - ); - const stakingLogic = await TestStakingContract.deployFrom0xArtifactAsync( - stakingArtifacts.TestStaking, - environment.provider, - txDefaults, - stakingArtifacts, - tokens.weth.address, - zrxVault.address, - ); - const stakingProxy = await StakingProxyContract.deployFrom0xArtifactAsync( - stakingArtifacts.StakingProxy, - environment.provider, - txDefaults, - stakingArtifacts, - stakingLogic.address, - ); - - const logDecoderDependencies = _.mapValues( - { ...stakingArtifacts, ...ERC20Artifacts }, - v => v.compilerOutput.abi, - ); - const stakingWrapper = new TestStakingContract( - stakingProxy.address, - environment.provider, - txDefaults, - logDecoderDependencies, - ); - - // Add the zrx vault and the weth contract to the staking proxy. - await stakingWrapper.setWethContract(tokens.weth.address).awaitTransactionSuccessAsync({ from: owner }); - await stakingWrapper.setZrxVault(zrxVault.address).awaitTransactionSuccessAsync({ from: owner }); - - // Authorize the owner address in the staking proxy and the zrx vault. - await stakingProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner }); - await zrxVault.addAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner }); - - // Authorize the zrx vault in the erc20 proxy - await assetProxies.erc20Proxy.addAuthorizedAddress(zrxVault.address).awaitTransactionSuccessAsync({ - from: owner, - }); - - // Configure the zrx vault and the staking contract. - await zrxVault.setStakingProxy(stakingProxy.address).awaitTransactionSuccessAsync({ from: owner }); - - return { - stakingLogic, - stakingProxy, - stakingWrapper, - zrxVault, - }; - } - - /** - * Deploy a set of token contracts. - * @param environment The blockchain environment to use. - * @param txDefaults Defaults to use when deploying the asset proxies. - * @param options Specifies how many tokens of each standard to deploy. - */ - protected static async _deployTokenContractsAsync( - environment: BlockchainTestsEnvironment, - txDefaults: Partial, - options: Partial, - ): Promise { - const numErc20TokensToDeploy = - options.numErc20TokensToDeploy !== undefined - ? options.numErc20TokensToDeploy - : constants.NUM_DUMMY_ERC20_TO_DEPLOY; - const numErc721TokensToDeploy = - options.numErc721TokensToDeploy !== undefined - ? options.numErc721TokensToDeploy - : constants.NUM_DUMMY_ERC721_TO_DEPLOY; - const numErc1155TokensToDeploy = - options.numErc1155TokensToDeploy !== undefined - ? options.numErc1155TokensToDeploy - : constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY; - - const erc20 = await Promise.all( - _.times(numErc20TokensToDeploy, async () => - DummyERC20TokenContract.deployFrom0xArtifactAsync( - ERC20Artifacts.DummyERC20Token, - environment.provider, - txDefaults, - ERC20Artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ), - ), - ); - const erc721 = await Promise.all( - _.times(numErc721TokensToDeploy, async () => - DummyERC721TokenContract.deployFrom0xArtifactAsync( - ERC721Artifacts.DummyERC721Token, - environment.provider, - txDefaults, - ERC721Artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - ), - ), - ); - const erc1155 = await Promise.all( - _.times(numErc1155TokensToDeploy, async () => - ERC1155MintableContract.deployFrom0xArtifactAsync( - ERC1155Artifacts.ERC1155Mintable, - environment.provider, - txDefaults, - ERC1155Artifacts, - ), - ), - ); - - const weth = await WETH9Contract.deployFrom0xArtifactAsync( - ERC20Artifacts.WETH9, - environment.provider, - txDefaults, - ERC20Artifacts, - ); - const zrx = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - ERC20Artifacts.DummyERC20Token, - environment.provider, - txDefaults, - ERC20Artifacts, - constants.DUMMY_TOKEN_NAME, - constants.DUMMY_TOKEN_SYMBOL, - constants.DUMMY_TOKEN_DECIMALS, - constants.DUMMY_TOKEN_TOTAL_SUPPLY, - ); - - return { - erc20, - erc721, - erc1155, - weth, - zrx, - }; - } - - protected constructor( - public web3Wrapper: Web3Wrapper, - public assetProxies: AssetProxyContracts, - public governor: ZeroExGovernorContract, - public exchange: ExchangeContract, - public staking: StakingContracts, - public tokens: TokenContracts, - public chainId: number, - public accounts: string[], - public txDefaults: Partial, - public devUtils: DevUtilsContract, - ) {} -} -// tslint:disable:max-file-line-count diff --git a/contracts/integrations/test/framework/simulation.ts b/contracts/integrations/test/framework/simulation.ts deleted file mode 100644 index 807f397b8a..0000000000 --- a/contracts/integrations/test/framework/simulation.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - constants as stakingConstants, - GlobalStakeByStatus, - StakeStatus, - StakingPoolById, - StoredBalance, -} from '@0x/contracts-staking'; -import { BigNumber } from '@0x/utils'; - -import { Actor } from './actors/base'; -import { AssertionResult } from './assertions/function_assertion'; -import { BlockchainBalanceStore } from './balances/blockchain_balance_store'; -import { DeploymentManager } from './deployment_manager'; -import { logger } from './utils/logger'; - -// tslint:disable:max-classes-per-file - -export class SimulationEnvironment { - public globalStake: GlobalStakeByStatus = { - [StakeStatus.Undelegated]: new StoredBalance(), - [StakeStatus.Delegated]: new StoredBalance(), - }; - public stakingPools: StakingPoolById = {}; - public currentEpoch: BigNumber = stakingConstants.INITIAL_EPOCH; - - public constructor( - public readonly deployment: DeploymentManager, - public balanceStore: BlockchainBalanceStore, - public readonly actors: Actor[] = [], - ) { - for (const actor of actors) { - // Set the actor's simulation environment - actor.simulationEnvironment = this; - // Register each actor in the balance store - this.balanceStore.registerTokenOwner(actor.address, actor.name); - } - } - - public state(): any { - return { - globalStake: this.globalStake, - stakingPools: this.stakingPools, - balanceStore: this.balanceStore.toReadable(), - currentEpoch: this.currentEpoch, - }; - } -} - -export abstract class Simulation { - public readonly generator = this._assertionGenerator(); - public resets = false; - - constructor(public environment: SimulationEnvironment) {} - - public async fuzzAsync(steps?: number): Promise { - if (steps !== undefined) { - for (let i = 0; i < steps; i++) { - await this._stepAsync(); - } - } else { - while (true) { - await this._stepAsync(); - } - } - } - - protected abstract _assertionGenerator(): AsyncIterableIterator; - - private async _stepAsync(): Promise { - const snapshotId = this.resets ? await this.environment.deployment.web3Wrapper.takeSnapshotAsync() : undefined; - try { - await this.generator.next(); - } catch (error) { - logger.logFailure(error, this.environment.state()); - throw error; - } - if (snapshotId !== undefined) { - await this.environment.deployment.web3Wrapper.revertSnapshotAsync(snapshotId); - } - } -} diff --git a/contracts/integrations/test/framework/tests/deployment_manager_test.ts b/contracts/integrations/test/framework/tests/deployment_manager_test.ts deleted file mode 100644 index 2a08e150c0..0000000000 --- a/contracts/integrations/test/framework/tests/deployment_manager_test.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { constants as stakingConstants } from '@0x/contracts-staking'; -import { blockchainTests, expect } from '@0x/contracts-test-utils'; - -import { DeploymentManager } from '../deployment_manager'; -import { Authorizable, Ownable } from '../utils/wrapper_interfaces'; - -blockchainTests('Deployment Manager', env => { - let owner: string; - let deploymentManager: DeploymentManager; - - before(async () => { - [owner] = await env.getAccountAddressesAsync(); - deploymentManager = await DeploymentManager.deployAsync(env); - }); - - async function batchAssertAuthorizedAsync( - authorizedAddress: string, - authorizedContracts: Authorizable[], - ): Promise { - for (const authorized of authorizedContracts) { - expect(await authorized.authorized(authorizedAddress).callAsync()).to.be.true(); - } - } - - async function batchAssertOwnerAsync(ownerAddress: string, owners: Ownable[]): Promise { - for (const ownerContract of owners) { - expect(await ownerContract.owner().callAsync()).to.be.eq(ownerAddress); - } - } - - describe('asset proxy owner', () => { - it('should be owned by `owner`', async () => { - // Ensure that the owners of the asset proxy only contain the owner. - const owners = await deploymentManager.governor.getOwners().callAsync(); - expect(owners).to.be.deep.eq([owner]); - }); - }); - - describe('asset proxies', () => { - it('should be owned be the asset proxy owner', async () => { - await batchAssertOwnerAsync(deploymentManager.governor.address, [ - deploymentManager.assetProxies.erc1155Proxy, - deploymentManager.assetProxies.erc20Proxy, - deploymentManager.assetProxies.erc721Proxy, - deploymentManager.assetProxies.multiAssetProxy, - ]); - }); - - it('should have authorized the multi-asset proxy', async () => { - await batchAssertAuthorizedAsync(deploymentManager.assetProxies.multiAssetProxy.address, [ - deploymentManager.assetProxies.erc1155Proxy, - deploymentManager.assetProxies.erc20Proxy, - deploymentManager.assetProxies.erc721Proxy, - ]); - }); - - it('should have authorized the exchange', async () => { - await batchAssertAuthorizedAsync(deploymentManager.exchange.address, [ - deploymentManager.assetProxies.erc1155Proxy, - deploymentManager.assetProxies.erc20Proxy, - deploymentManager.assetProxies.erc721Proxy, - deploymentManager.assetProxies.multiAssetProxy, - ]); - }); - - it('should have the correct authorities list', async () => { - // The multi-asset proxy should only have the exchange in the authorities list. - const authorities = await deploymentManager.assetProxies.multiAssetProxy - .getAuthorizedAddresses() - .callAsync(); - expect(authorities).to.be.deep.eq([deploymentManager.exchange.address]); - - // The other asset proxies should have the exchange and the multi-asset proxy in their - // authorities list. - const erc20ProxyAuthorities = await deploymentManager.assetProxies.erc20Proxy - .getAuthorizedAddresses() - .callAsync(); - expect(erc20ProxyAuthorities).to.deep.eq([ - deploymentManager.staking.zrxVault.address, - deploymentManager.assetProxies.multiAssetProxy.address, - deploymentManager.exchange.address, - ]); - - const erc1155ProxyAuthorities = await deploymentManager.assetProxies.erc1155Proxy - .getAuthorizedAddresses() - .callAsync(); - expect(erc1155ProxyAuthorities).to.deep.eq([ - deploymentManager.assetProxies.multiAssetProxy.address, - deploymentManager.exchange.address, - ]); - - const erc721ProxyAuthorities = await deploymentManager.assetProxies.erc721Proxy - .getAuthorizedAddresses() - .callAsync(); - expect(erc721ProxyAuthorities).to.deep.eq([ - deploymentManager.assetProxies.multiAssetProxy.address, - deploymentManager.exchange.address, - ]); - }); - }); - - describe('exchange', () => { - it('should be owned by the asset proxy owner', async () => { - const exchangeOwner = await deploymentManager.exchange.owner().callAsync(); - expect(exchangeOwner).to.be.eq(deploymentManager.governor.address); - }); - - /* - TODO(jalextowle): This test should be enabled once the Exchange is - made an Authorizable contract. - it('should have authorized the asset proxy owner', async () => { - const isAuthorized = await deploymentManager.exchange.owner( - deploymentManager.governor.address, - ).callAsync(); - expect(isAuthorized).to.be.true(); - }); - */ - - it('should have registered the staking proxy', async () => { - const feeCollector = await deploymentManager.exchange.protocolFeeCollector().callAsync(); - expect(feeCollector).to.be.eq(deploymentManager.staking.stakingProxy.address); - }); - - it('should have set the protocol fee multiplier', async () => { - const feeMultiplier = await deploymentManager.exchange.protocolFeeMultiplier().callAsync(); - expect(feeMultiplier).bignumber.to.be.eq(DeploymentManager.protocolFeeMultiplier); - }); - }); - - describe('staking', () => { - it('should be owned by the asset proxy owner', async () => { - const stakingOwner = await deploymentManager.staking.stakingProxy.owner().callAsync(); - expect(stakingOwner).to.be.eq(deploymentManager.governor.address); - }); - - it('should have authorized the asset proxy owner in the staking proxy', async () => { - const isAuthorized = await deploymentManager.staking.stakingProxy - .authorized(deploymentManager.governor.address) - .callAsync(); - expect(isAuthorized).to.be.true(); - }); - - it('should have registered the exchange in the staking proxy', async () => { - const isValid = await deploymentManager.staking.stakingProxy - .validExchanges(deploymentManager.exchange.address) - .callAsync(); - expect(isValid).to.be.true(); - }); - - it('should have registered the staking contract in the staking proxy', async () => { - const stakingContract = await deploymentManager.staking.stakingProxy.stakingContract().callAsync(); - expect(stakingContract).to.be.eq(deploymentManager.staking.stakingLogic.address); - }); - - it('should have registered the weth contract in the staking contract', async () => { - const weth = await deploymentManager.staking.stakingWrapper.testWethAddress().callAsync(); - expect(weth).to.be.eq(deploymentManager.tokens.weth.address); - }); - - it('should have registered the zrx vault in the staking contract', async () => { - const zrxVault = await deploymentManager.staking.stakingWrapper.testZrxVaultAddress().callAsync(); - expect(zrxVault).to.be.eq(deploymentManager.staking.zrxVault.address); - }); - - it('should have registered the staking proxy in the zrx vault', async () => { - const stakingProxy = await deploymentManager.staking.zrxVault.stakingProxyAddress().callAsync(); - expect(stakingProxy).to.be.eq(deploymentManager.staking.stakingProxy.address); - }); - - it('should have correctly set the params', async () => { - const params = await deploymentManager.staking.stakingWrapper.getParams().callAsync(); - expect(params).to.be.deep.eq([ - stakingConstants.DEFAULT_PARAMS.epochDurationInSeconds, - stakingConstants.DEFAULT_PARAMS.rewardDelegatedStakeWeight, - stakingConstants.DEFAULT_PARAMS.minimumPoolStake, - stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaNumerator, - stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaDenominator, - ]); - }); - }); -}); diff --git a/contracts/integrations/test/framework/tests/function_assertion_test.ts b/contracts/integrations/test/framework/tests/function_assertion_test.ts deleted file mode 100644 index 75b25947ec..0000000000 --- a/contracts/integrations/test/framework/tests/function_assertion_test.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { blockchainTests, constants, expect, filterLogsToArguments, getRandomInteger } from '@0x/contracts-test-utils'; -import { BigNumber, StringRevertError } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; - -import { artifacts } from '../../artifacts'; -import { TestFrameworkContract, TestFrameworkEventEventArgs, TestFrameworkEvents } from '../../wrappers'; -import { FunctionAssertion, FunctionResult } from '../assertions/function_assertion'; - -const { ZERO_AMOUNT, MAX_UINT256 } = constants; - -blockchainTests.resets('FunctionAssertion Unit Tests', env => { - let exampleContract: TestFrameworkContract; - - before(async () => { - exampleContract = await TestFrameworkContract.deployFrom0xArtifactAsync( - artifacts.TestFramework, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('executeAsync', () => { - it('should call the before function with the provided arguments', async () => { - let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>(exampleContract, 'returnInteger', { - before: async (args: [BigNumber], txData: Partial) => { - sideEffectTarget = randomInput; - }, - }); - const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync([randomInput], {}); - expect(sideEffectTarget).bignumber.to.be.eq(randomInput); - }); - - it('should call the after function with the provided arguments', async () => { - let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>(exampleContract, 'returnInteger', { - after: async ( - _beforeInfo: any, - _result: FunctionResult, - args: [BigNumber], - txData: Partial, - ) => { - [sideEffectTarget] = args; - }, - }); - const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync([randomInput], {}); - expect(sideEffectTarget).bignumber.to.be.eq(randomInput); - }); - - it('should not fail immediately if the wrapped function fails', async () => { - const assertion = new FunctionAssertion<[], {}, void>(exampleContract, 'emptyRevert'); - await assertion.executeAsync([], {}); - }); - - it('should pass the return value of "before" to "after"', async () => { - const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion<[BigNumber], BigNumber, BigNumber>( - exampleContract, - 'returnInteger', - { - before: async (_args: [BigNumber], _txData: Partial) => { - return randomInput; - }, - after: async ( - beforeInfo: any, - _result: FunctionResult, - _args: [BigNumber], - _txData: Partial, - ) => { - sideEffectTarget = beforeInfo; - }, - }, - ); - await assertion.executeAsync([randomInput], {}); - expect(sideEffectTarget).bignumber.to.be.eq(randomInput); - }); - - it('should pass the result from the function call to "after"', async () => { - let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>(exampleContract, 'returnInteger', { - after: async ( - _beforeInfo: any, - result: FunctionResult, - _args: [BigNumber], - _txData: Partial, - ) => { - sideEffectTarget = result.data; - }, - }); - const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync([randomInput], {}); - expect(sideEffectTarget).bignumber.to.be.eq(randomInput); - }); - - it('should pass the receipt from the function call to "after"', async () => { - let sideEffectTarget: TransactionReceiptWithDecodedLogs; - const assertion = new FunctionAssertion<[string], void, void>(exampleContract, 'emitEvent', { - after: async (_beforeInfo: any, result: FunctionResult, _args: [string], _txData: Partial) => { - if (result.receipt) { - sideEffectTarget = result.receipt; - } - }, - }); - - const input = 'emitted data'; - await assertion.executeAsync([input], {}); - - // Ensure that the correct events were emitted. - const [event] = filterLogsToArguments( - sideEffectTarget!.logs, // tslint:disable-line:no-non-null-assertion - TestFrameworkEvents.Event, - ); - expect(event).to.be.deep.eq({ input }); - }); - - it('should pass the error to "after" if the function call fails', async () => { - let sideEffectTarget: Error; - const assertion = new FunctionAssertion<[string], void, void>(exampleContract, 'stringRevert', { - after: async (_beforeInfo: any, result: FunctionResult, _args: [string], _txData: Partial) => { - sideEffectTarget = result.data; - }, - }); - const message = 'error message'; - await assertion.executeAsync([message], {}); - - const expectedError = new StringRevertError(message); - return expect(Promise.reject(sideEffectTarget!)).to.revertWith(expectedError); // tslint:disable-line - }); - }); -}); diff --git a/contracts/integrations/test/framework/utils/assert_protocol_fee.ts b/contracts/integrations/test/framework/utils/assert_protocol_fee.ts deleted file mode 100644 index fefeac146e..0000000000 --- a/contracts/integrations/test/framework/utils/assert_protocol_fee.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - AggregatedStats, - constants as stakingConstants, - PoolStats, - StakingEvents, - StakingStakingPoolEarnedRewardsInEpochEventArgs, -} from '@0x/contracts-staking'; -import { expect, verifyEvents } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { Maker } from '../actors/maker'; -import { DeploymentManager } from '../deployment_manager'; -import { SimulationEnvironment } from '../simulation'; - -import { FunctionResult } from '../assertions/function_assertion'; - -export interface PoolInfo { - poolStats: PoolStats; - aggregatedStats: AggregatedStats; - poolStake: BigNumber; - operatorStake: BigNumber; - poolId: string; -} - -/** - * Gets info for a given maker's pool. - */ -export async function getPoolInfoAsync( - maker: Maker, - simulationEnvironment: SimulationEnvironment, - deployment: DeploymentManager, -): Promise { - const { stakingWrapper } = deployment.staking; - // tslint:disable-next-line no-non-null-assertion no-unnecessary-type-assertion - const poolId = maker.makerPoolId; - const { currentEpoch } = simulationEnvironment; - if (poolId === undefined) { - return; - } else { - const poolStats = PoolStats.fromArray(await stakingWrapper.poolStatsByEpoch(poolId, currentEpoch).callAsync()); - const aggregatedStats = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(currentEpoch).callAsync(), - ); - const { currentEpochBalance: poolStake } = await stakingWrapper - .getTotalStakeDelegatedToPool(poolId) - .callAsync(); - const { currentEpochBalance: operatorStake } = await stakingWrapper - .getStakeDelegatedToPoolByOwner(simulationEnvironment.stakingPools[poolId].operator, poolId) - .callAsync(); - return { poolStats, aggregatedStats, poolStake, poolId, operatorStake }; - } -} - -/** - * Asserts that a protocol fee was paid. - */ -export async function assertProtocolFeePaidAsync( - poolInfo: PoolInfo, - result: FunctionResult, - simulationEnvironment: SimulationEnvironment, - deployment: DeploymentManager, - expectedProtocolFee: BigNumber, -): Promise { - const { currentEpoch } = simulationEnvironment; - const { stakingWrapper } = deployment.staking; - const expectedPoolStats = { ...poolInfo.poolStats }; - const expectedAggregatedStats = { ...poolInfo.aggregatedStats }; - const expectedEvents = []; - - // Refer to `payProtocolFee` - if (poolInfo.poolStake.isGreaterThanOrEqualTo(stakingConstants.DEFAULT_PARAMS.minimumPoolStake)) { - if (poolInfo.poolStats.feesCollected.isZero()) { - const membersStakeInPool = poolInfo.poolStake.minus(poolInfo.operatorStake); - const weightedStakeInPool = poolInfo.operatorStake.plus( - ReferenceFunctions.getPartialAmountFloor( - stakingConstants.DEFAULT_PARAMS.rewardDelegatedStakeWeight, - new BigNumber(stakingConstants.PPM), - membersStakeInPool, - ), - ); - expectedPoolStats.membersStake = membersStakeInPool; - expectedPoolStats.weightedStake = weightedStakeInPool; - expectedAggregatedStats.totalWeightedStake = poolInfo.aggregatedStats.totalWeightedStake.plus( - weightedStakeInPool, - ); - expectedAggregatedStats.numPoolsToFinalize = poolInfo.aggregatedStats.numPoolsToFinalize.plus(1); - // StakingPoolEarnedRewardsInEpoch event emitted - expectedEvents.push({ - epoch: currentEpoch, - poolId: poolInfo.poolId, - }); - } - // Credit a protocol fee to the maker's staking pool - expectedPoolStats.feesCollected = poolInfo.poolStats.feesCollected.plus(expectedProtocolFee); - // Update aggregated stats - expectedAggregatedStats.totalFeesCollected = poolInfo.aggregatedStats.totalFeesCollected.plus( - expectedProtocolFee, - ); - } - - // Check for updated stats and event - const poolStats = PoolStats.fromArray( - await stakingWrapper.poolStatsByEpoch(poolInfo.poolId, currentEpoch).callAsync(), - ); - const aggregatedStats = AggregatedStats.fromArray( - await stakingWrapper.aggregatedStatsByEpoch(currentEpoch).callAsync(), - ); - expect(poolStats).to.deep.equal(expectedPoolStats); - expect(aggregatedStats).to.deep.equal(expectedAggregatedStats); - verifyEvents( - // tslint:disable-next-line no-non-null-assertion no-unnecessary-type-assertion - result.receipt!, - expectedEvents, - StakingEvents.StakingPoolEarnedRewardsInEpoch, - ); -} diff --git a/contracts/integrations/test/framework/utils/logger.ts b/contracts/integrations/test/framework/utils/logger.ts deleted file mode 100644 index 20be7e6d7a..0000000000 --- a/contracts/integrations/test/framework/utils/logger.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { TxData } from 'ethereum-types'; - -import { Pseudorandom } from '../utils/pseudorandom'; - -// tslint:disable:no-console - -class Logger { - private _step = 0; - - constructor() { - console.warn( - JSON.stringify({ - level: 'info', - time: new Date(), - msg: `Pseudorandom seed: ${Pseudorandom.seed}`, - }), - ); - } - - /* - * Logs the name of the function executed, the arguments and transaction data it was - * called with, and the current step of the simulation. - */ - public logFunctionAssertion(functionName: string, functionArgs: any[], txData: Partial): void { - console.warn( - JSON.stringify({ - level: 'info', - time: new Date(), - msg: `Function called: ${functionName}(${functionArgs - .map(arg => JSON.stringify(arg).replace(/"/g, "'")) - .join(', ')})`, - step: ++this._step, - txData, - }), - ); - } - - /* - * Logs information about a assertion failure. Dumps the error thrown and arbitrary data from - * the calling context. - */ - public logFailure(error: Error, data: string): void { - console.warn( - JSON.stringify({ - level: 'error', - time: new Date(), - step: this._step, - error, - data, - }), - ); - } -} - -export const logger = new Logger(); diff --git a/contracts/integrations/test/framework/utils/pseudorandom.ts b/contracts/integrations/test/framework/utils/pseudorandom.ts deleted file mode 100644 index 59863104b3..0000000000 --- a/contracts/integrations/test/framework/utils/pseudorandom.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Numberish } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; -import * as seedrandom from 'seedrandom'; - -class PRNGWrapper { - public readonly seed = process.env.SEED || Math.random().toString(); - public readonly rng = seedrandom(this.seed); - - /* - * Pseudorandom version of _.sample. Picks an element of the given array. If an array of weights - * is provided, elements of `arr` are weighted according to the value in the corresponding index - * of `weights`. Otherwise, the samples are chosen uniformly at random. Return undefined if the - * array is empty. - */ - public sample(arr: T[], weights?: number[]): T | undefined { - if (arr.length === 0) { - return undefined; - } - - let index: number; - if (weights !== undefined) { - const cdf = weights.map((_weight, i) => _.sum(weights.slice(0, i + 1)) / _.sum(weights)); - const x = this.rng(); - index = cdf.findIndex(value => value > x); - } else { - index = Math.abs(this.rng.int32()) % arr.length; - } - return arr[index]; - } - - /* - * Pseudorandom version of _.sampleSize. Returns an array of `n` samples from the given array - * (with replacement). If an array of weights is provided, elements of `arr` are weighted - * according to the value in the corresponding index of `weights`. Otherwise, the samples are - * chosen uniformly at random. Return undefined if the array is empty. - */ - public sampleSize(arr: T[], n: number, weights?: number[]): T[] | undefined { - if (arr.length === 0) { - return undefined; - } - const samples = []; - for (let i = 0; i < n; i++) { - samples.push(this.sample(arr, weights) as T); - } - return samples; - } - - /* - * Pseudorandom version of getRandomPortion/getRandomInteger. If no distribution is provided, - * samples an integer between the min and max uniformly at random. If a distribution is - * provided, samples an integer from the given distribution (assumed to be defined on the - * interval [0, 1]) scaled to [min, max]. - */ - public integer(min: Numberish, max: Numberish, distribution: () => Numberish = this.rng): BigNumber { - const range = new BigNumber(max).minus(min); - return new BigNumber(distribution()) - .times(range) - .integerValue(BigNumber.ROUND_HALF_UP) - .plus(min); - } - - /* - * Returns a function that produces samples from the Kumaraswamy distribution parameterized by - * the given alpha and beta. The Kumaraswamy distribution is like the beta distribution, but - * with a nice closed form. More info: - * https://en.wikipedia.org/wiki/Kumaraswamy_distribution - * https://www.johndcook.com/blog/2009/11/24/kumaraswamy-distribution/ - * Alpha and beta default to 0.2, so that the distribution favors the extremes of the domain. - * The PDF for alpha=0.2, beta=0.2: - * https://www.wolframalpha.com/input/?i=0.2*0.2*x%5E%280.2-1%29*%281-x%5E0.2%29%5E%280.2-1%29+from+0+to+1 - */ - public kumaraswamy(this: PRNGWrapper, alpha: Numberish = 0.2, beta: Numberish = 0.2): () => BigNumber { - const ONE = new BigNumber(1); - return () => { - const u = new BigNumber(this.rng()).modulo(ONE); // u ~ Uniform(0, 1) - // Evaluate the inverse CDF at `u` to obtain a sample from Kumaraswamy(alpha, beta) - return ONE.minus(ONE.minus(u).exponentiatedBy(ONE.dividedBy(beta))).exponentiatedBy(ONE.dividedBy(alpha)); - }; - } - - /* - * Pseudorandom version of `hexRandom()`. If no distribution is provided, - * samples all byte values uniformly. - */ - public hex(bytesLength: number = 32, distribution: () => Numberish = this.rng): string { - const buf = Buffer.from(_.times(bytesLength, () => this.integer(0, 255, distribution).toNumber())).toString( - 'hex', - ); - return `0x${buf}`; - } -} - -export const Pseudorandom = new PRNGWrapper(); -export const Distributions = { - Uniform: Pseudorandom.rng, - Kumaraswamy: Pseudorandom.kumaraswamy.bind(Pseudorandom), -}; diff --git a/contracts/integrations/test/framework/utils/verify_match_events.ts b/contracts/integrations/test/framework/utils/verify_match_events.ts deleted file mode 100644 index 334c5dc7aa..0000000000 --- a/contracts/integrations/test/framework/utils/verify_match_events.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { ERC20TokenEvents, ERC20TokenTransferEventArgs } from '@0x/contracts-erc20'; -import { ExchangeEvents, ExchangeFillEventArgs } from '@0x/contracts-exchange'; -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { constants, orderHashUtils, verifyEvents } from '@0x/contracts-test-utils'; -import { MatchedFillResults, Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DeploymentManager } from '../deployment_manager'; - -/** - * Verifies `Fill` and `Transfer` events emitted by `matchOrders` or `matchOrdersWithMaximalFill`. - */ -export function verifyMatchEvents( - txData: Partial, - leftOrder: Order, - rightOrder: Order, - receipt: TransactionReceiptWithDecodedLogs, - deployment: DeploymentManager, - withMaximalFill: boolean, -): void { - const matchResults = ReferenceFunctions.calculateMatchResults( - leftOrder, - rightOrder, - DeploymentManager.protocolFeeMultiplier, - DeploymentManager.gasPrice, - withMaximalFill, - ); - const takerAddress = txData.from as string; - const value = new BigNumber(txData.value || 0); - - verifyMatchFilledEvents(leftOrder, rightOrder, receipt, matchResults, takerAddress); - verifyMatchTransferEvents(leftOrder, rightOrder, receipt, matchResults, takerAddress, value, deployment); -} - -/** - * Verifies `Fill` events emitted by `matchOrders` or `matchOrdersWithMaximalFill`. - */ -const verifyMatchFilledEvents = ( - leftOrder: Order, - rightOrder: Order, - receipt: TransactionReceiptWithDecodedLogs, - matchResults: MatchedFillResults, - takerAddress: string, -) => { - const expectedFillEvents = [ - { - makerAddress: leftOrder.makerAddress, - feeRecipientAddress: leftOrder.feeRecipientAddress, - makerAssetData: leftOrder.makerAssetData, - takerAssetData: leftOrder.takerAssetData, - makerFeeAssetData: leftOrder.makerFeeAssetData, - takerFeeAssetData: leftOrder.takerFeeAssetData, - orderHash: orderHashUtils.getOrderHashHex(leftOrder), - takerAddress, - senderAddress: takerAddress, - ...matchResults.left, - }, - { - makerAddress: rightOrder.makerAddress, - feeRecipientAddress: rightOrder.feeRecipientAddress, - makerAssetData: rightOrder.makerAssetData, - takerAssetData: rightOrder.takerAssetData, - makerFeeAssetData: rightOrder.makerFeeAssetData, - takerFeeAssetData: rightOrder.takerFeeAssetData, - orderHash: orderHashUtils.getOrderHashHex(rightOrder), - takerAddress, - senderAddress: takerAddress, - ...matchResults.right, - }, - ]; - - verifyEvents(receipt, expectedFillEvents, ExchangeEvents.Fill); -}; - -/** - * Verifies `Transfer` events emitted by `matchOrders` or `matchOrdersWithMaximalFill`. - */ -const verifyMatchTransferEvents = ( - leftOrder: Order, - rightOrder: Order, - receipt: TransactionReceiptWithDecodedLogs, - matchResults: MatchedFillResults, - takerAddress: string, - value: BigNumber, - deployment: DeploymentManager, -) => { - const expectedTransferEvents = [ - { - _from: rightOrder.makerAddress, - _to: leftOrder.makerAddress, - _value: matchResults.left.takerAssetFilledAmount, - }, - { - _from: leftOrder.makerAddress, - _to: rightOrder.makerAddress, - _value: matchResults.right.takerAssetFilledAmount, - }, - { - _from: rightOrder.makerAddress, - _to: rightOrder.feeRecipientAddress, - _value: matchResults.right.makerFeePaid, - }, - { - _from: leftOrder.makerAddress, - _to: leftOrder.feeRecipientAddress, - _value: matchResults.left.makerFeePaid, - }, - { - _from: leftOrder.makerAddress, - _to: takerAddress, - _value: matchResults.left.makerAssetFilledAmount.minus(matchResults.right.takerAssetFilledAmount), - }, - { - _from: rightOrder.makerAddress, - _to: takerAddress, - _value: matchResults.right.makerAssetFilledAmount.minus(matchResults.left.takerAssetFilledAmount), - }, - { - _from: takerAddress, - _to: deployment.staking.stakingProxy.address, - _value: value.isLessThan(DeploymentManager.protocolFee.times(2)) - ? DeploymentManager.protocolFee - : constants.ZERO_AMOUNT, - }, - { - _from: takerAddress, - _to: deployment.staking.stakingProxy.address, - _value: value.isLessThan(DeploymentManager.protocolFee) ? DeploymentManager.protocolFee : new BigNumber(0), - }, - { - _from: takerAddress, - _to: rightOrder.feeRecipientAddress, - _value: - leftOrder.feeRecipientAddress === rightOrder.feeRecipientAddress - ? constants.ZERO_AMOUNT - : matchResults.right.takerFeePaid, - }, - { - _from: takerAddress, - _to: leftOrder.feeRecipientAddress, - _value: - leftOrder.feeRecipientAddress === rightOrder.feeRecipientAddress - ? matchResults.left.takerFeePaid.plus(matchResults.right.takerFeePaid) - : matchResults.left.takerFeePaid, - }, - ].filter(event => event._value.isGreaterThan(0)); - - verifyEvents(receipt, expectedTransferEvents, ERC20TokenEvents.Transfer); -}; diff --git a/contracts/integrations/test/framework/utils/wrapper_interfaces.ts b/contracts/integrations/test/framework/utils/wrapper_interfaces.ts deleted file mode 100644 index 983a1cbd3d..0000000000 --- a/contracts/integrations/test/framework/utils/wrapper_interfaces.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ContractFunctionObj, ContractTxFunctionObj } from '@0x/base-contract'; -import { BlockParam, CallData } from 'ethereum-types'; - -// tslint:disable:max-classes-per-file -// Generated Wrapper Interfaces -export abstract class AssetProxyDispatcher { - public abstract registerAssetProxy(assetProxy: string): ContractTxFunctionObj; - public abstract getAssetProxy(assetProxyId: string): ContractFunctionObj; -} - -export abstract class Ownable { - public abstract transferOwnership(newOwner: string): ContractTxFunctionObj; - - public abstract owner(callData?: Partial, defaultBlock?: BlockParam): ContractFunctionObj; -} -export abstract class Authorizable extends Ownable { - public abstract addAuthorizedAddress(target: string): ContractTxFunctionObj; - public abstract removeAuthorizedAddress(target: string): ContractTxFunctionObj; - public abstract authorized(authority: string): ContractFunctionObj; - public abstract getAuthorizedAddresses(): ContractFunctionObj; -} diff --git a/contracts/integrations/test/fuzz_tests/exchange_signature_validation_test.ts b/contracts/integrations/test/fuzz_tests/exchange_signature_validation_test.ts deleted file mode 100644 index 4a81930215..0000000000 --- a/contracts/integrations/test/fuzz_tests/exchange_signature_validation_test.ts +++ /dev/null @@ -1,736 +0,0 @@ -import { ExchangeContract } from '@0x/contracts-exchange'; -import { - blockchainTests, - constants, - expect, - orderHashUtils, - signingUtils, - transactionHashUtils, -} from '@0x/contracts-test-utils'; -import { Order, SignatureType, ZeroExTransaction } from '@0x/types'; -import { hexUtils, logUtils } from '@0x/utils'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { AssertionResult } from '../framework/assertions/function_assertion'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { Simulation, SimulationEnvironment } from '../framework/simulation'; -import { Pseudorandom } from '../framework/utils/pseudorandom'; -import { TestSignatureValidationWalletContract } from '../wrappers'; - -// tslint:disable: max-classes-per-file no-non-null-assertion no-unnecessary-type-assertion -const tests = process.env.FUZZ_TEST === 'exchange/signature_validation' ? blockchainTests : blockchainTests.skip; - -tests('Exchange signature validation fuzz tests', env => { - const ALL_SIGNATURE_TYPES = [ - SignatureType.Illegal, - SignatureType.Invalid, - SignatureType.EthSign, - SignatureType.EIP712, - SignatureType.Wallet, - SignatureType.Validator, - SignatureType.PreSigned, - SignatureType.EIP1271Wallet, - ]; - const ALL_WORKING_SIGNATURE_TYPES = [ - SignatureType.EthSign, - SignatureType.EIP712, - SignatureType.Wallet, - SignatureType.Validator, - SignatureType.PreSigned, - SignatureType.EIP1271Wallet, - ]; - const HASH_COMPATIBLE_SIGNATURE_TYPES = [ - SignatureType.EthSign, - SignatureType.EIP712, - SignatureType.Wallet, - SignatureType.PreSigned, - ]; - const STATIC_SIGNATURE_TYPES = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.PreSigned]; - const ALWAYS_FAILING_SIGNATURE_TYPES = [SignatureType.Illegal, SignatureType.Invalid]; - const WALLET_SIGNATURE_TYPES = [SignatureType.Wallet, SignatureType.EIP1271Wallet]; - const STRICT_LENGTH_SIGNATURE_TYPES = [SignatureType.EthSign, SignatureType.EIP712]; - const CALLBACK_SIGNATURE_TYPES = [SignatureType.Wallet, SignatureType.EIP1271Wallet, SignatureType.Validator]; - - let walletContractAddress: string; - let notWalletContractAddress: string; - let deployment: DeploymentManager; - let exchange: ExchangeContract; - let accounts: string[]; - let privateKeys: { [address: string]: Buffer }; - let chainId: number; - - interface SignatureTestParams { - signatureType: SignatureType; - signer: string; - signature: string; - hash: string; - signerKey?: Buffer; - validator?: string; - payload?: string; - order?: Order; - transaction?: ZeroExTransaction; - } - - before(async () => { - chainId = await env.web3Wrapper.getChainIdAsync(); - accounts = await env.getAccountAddressesAsync(); - privateKeys = _.zipObject( - accounts, - accounts.map((a, i) => constants.TESTRPC_PRIVATE_KEYS[i]), - ); - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 0, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - exchange = deployment.exchange; - walletContractAddress = ( - await TestSignatureValidationWalletContract.deployFrom0xArtifactAsync( - artifacts.TestSignatureValidationWallet, - env.provider, - env.txDefaults, - {}, - ) - ).address; - // This just has to be a contract address that doesn't implement the - // wallet spec. - notWalletContractAddress = exchange.address; - }); - - function randomPayload(): string { - return Pseudorandom.hex(Pseudorandom.integer(0, 66).toNumber()); - } - - async function presignHashAsync(signer: string, hash: string): Promise { - await exchange.preSign(hash).awaitTransactionSuccessAsync({ from: signer }); - } - - async function approveValidatorAsync(signer: string, validator: string, approved: boolean = true): Promise { - await exchange - .setSignatureValidatorApproval(validator, approved) - .awaitTransactionSuccessAsync({ from: signer }); - } - - function createSignature(params: { - signatureType: SignatureType; - hash?: string; - signerKey?: Buffer; - validator?: string; - payload?: string; - }): string { - const payload = params.payload || constants.NULL_BYTES; - const signatureByte = hexUtils.leftPad(params.signatureType, 1); - switch (params.signatureType) { - default: - case SignatureType.Illegal: - case SignatureType.Invalid: - case SignatureType.PreSigned: - return hexUtils.concat(payload, signatureByte); - case SignatureType.EIP712: - case SignatureType.EthSign: - return hexUtils.concat( - payload, - ethUtil.bufferToHex( - signingUtils.signMessage( - ethUtil.toBuffer(params.hash), - params.signerKey!, - params.signatureType, - ), - ), - ); - case SignatureType.Wallet: - case SignatureType.EIP1271Wallet: - return hexUtils.concat(payload, params.signatureType); - case SignatureType.Validator: - return hexUtils.concat(payload, params.validator!, params.signatureType); - } - } - - async function mangleSignatureParamsAsync(params: SignatureTestParams): Promise { - const mangled = { ...params }; - const MANGLE_MODES = [ - 'TRUNCATE_SIGNATURE', - 'RETYPE_SIGNATURE', - 'RANDOM_HASH', - 'RANDOM_ORDER', - 'RANDOM_TRANSACTION', - 'RANDOM_SIGNER', - ]; - const invalidModes = []; - if (!STRICT_LENGTH_SIGNATURE_TYPES.includes(mangled.signatureType)) { - invalidModes.push('TRUNCATE_SIGNATURE'); - } - if (CALLBACK_SIGNATURE_TYPES.includes(mangled.signatureType)) { - invalidModes.push('RANDOM_HASH'); - } - if (params.transaction === undefined) { - invalidModes.push('RANDOM_TRANSACTION'); - } - if (params.order === undefined) { - invalidModes.push('RANDOM_ORDER'); - } - if (params.order !== undefined || params.hash !== undefined) { - invalidModes.push('RANDOM_HASH'); - } - const mode = Pseudorandom.sample(_.without(MANGLE_MODES, ...invalidModes))!; - switch (mode) { - case 'TRUNCATE_SIGNATURE': - while (hexUtils.slice(mangled.signature, -1) === hexUtils.leftPad(mangled.signatureType, 1)) { - mangled.signature = hexUtils.slice(mangled.signature, 0, -1); - } - break; - case 'RETYPE_SIGNATURE': - mangled.signatureType = WALLET_SIGNATURE_TYPES.includes(mangled.signatureType) - ? Pseudorandom.sample(_.without(ALL_SIGNATURE_TYPES, ...WALLET_SIGNATURE_TYPES))! - : Pseudorandom.sample(_.without(ALL_SIGNATURE_TYPES, mangled.signatureType))!; - mangled.signature = hexUtils.concat(hexUtils.slice(mangled.signature, 0, -1), mangled.signatureType); - break; - case 'RANDOM_SIGNER': - mangled.signer = Pseudorandom.hex(constants.ADDRESS_LENGTH); - if (mangled.order) { - mangled.order.makerAddress = mangled.signer; - } - if (mangled.transaction) { - mangled.transaction.signerAddress = mangled.signer; - } - break; - case 'RANDOM_HASH': - mangled.hash = Pseudorandom.hex(); - break; - case 'RANDOM_ORDER': - mangled.order = randomOrder({ - exchangeAddress: mangled.order!.exchangeAddress, - chainId: mangled.order!.chainId, - }); - mangled.hash = orderHashUtils.getOrderHashHex(mangled.order); - break; - case 'RANDOM_TRANSACTION': - mangled.transaction = randomTransaction({ - domain: mangled.transaction!.domain, - }); - mangled.hash = await transactionHashUtils.getTransactionHashHex(mangled.transaction); - break; - default: - throw new Error(`Unhandled mangle mode: ${mode}`); - } - return mangled; - } - - function createHashTestParams(fields: Partial = {}): SignatureTestParams { - const signatureType = - fields.signatureType === undefined - ? Pseudorandom.sample(HASH_COMPATIBLE_SIGNATURE_TYPES)! - : fields.signatureType; - const signer = - fields.signer || - (WALLET_SIGNATURE_TYPES.includes(signatureType) ? walletContractAddress : Pseudorandom.sample(accounts)!); - const validator = - fields.validator || (signatureType === SignatureType.Validator ? walletContractAddress : undefined); - const signerKey = fields.signerKey || privateKeys[signer]; - const hash = fields.hash || Pseudorandom.hex(); - const payload = - fields.payload || - (STRICT_LENGTH_SIGNATURE_TYPES.includes(signatureType) ? constants.NULL_BYTES : randomPayload()); - const signature = createSignature({ signatureType, hash, signerKey, payload, validator }); - return { - hash, - payload, - signature, - signatureType, - signer, - signerKey, - validator, - }; - } - - async function assertValidHashSignatureAsync(params: { - hash: string; - signer: string; - signature: string; - isValid: boolean; - }): Promise { - try { - let result; - try { - result = await exchange.isValidHashSignature(params.hash, params.signer, params.signature).callAsync(); - } catch (err) { - if (params.isValid) { - throw err; - } - return; - } - expect(result).to.eq(!!params.isValid); - } catch (err) { - logUtils.warn(params); - throw err; - } - } - - async function* validTestHashSignature(): AsyncIterableIterator { - while (true) { - const { hash, signature, signatureType, signer } = createHashTestParams(); - yield (async () => { - if (signatureType === SignatureType.PreSigned) { - await presignHashAsync(signer, hash); - } - await assertValidHashSignatureAsync({ - hash, - signer, - signature, - isValid: true, - }); - })(); - } - } - - async function* invalidTestHashStaticSignature(): AsyncIterableIterator { - while (true) { - const randomSignerKey = ethUtil.toBuffer(Pseudorandom.hex()); - const signer = Pseudorandom.sample([notWalletContractAddress, walletContractAddress, ...accounts])!; - const { hash, signature } = createHashTestParams({ - signatureType: Pseudorandom.sample([...STATIC_SIGNATURE_TYPES, ...ALWAYS_FAILING_SIGNATURE_TYPES])!, - signer, - // Always sign with a random key. - signerKey: randomSignerKey, - }); - yield assertValidHashSignatureAsync({ - hash, - signer, - signature, - isValid: false, - }); - } - } - - async function* invalidTestHashWalletSignature(): AsyncIterableIterator { - while (true) { - const signer = Pseudorandom.sample([notWalletContractAddress, ...accounts])!; - const { hash, signature } = createHashTestParams({ - signatureType: SignatureType.Wallet, - signer, - }); - yield assertValidHashSignatureAsync({ - hash, - signer, - signature, - isValid: false, - }); - } - } - - async function* invalidTestHashValidatorSignature(): AsyncIterableIterator { - while (true) { - const isNotApproved = Pseudorandom.sample([true, false])!; - const signer = Pseudorandom.sample([...accounts])!; - const validator = isNotApproved - ? walletContractAddress - : Pseudorandom.sample([ - // All validator signatures are invalid for the hash test, so passing a valid - // wallet contract should still fail. - walletContractAddress, - notWalletContractAddress, - ...accounts, - ])!; - const { hash, signature } = createHashTestParams({ - signatureType: SignatureType.Validator, - validator, - }); - yield (async () => { - if (!isNotApproved) { - await approveValidatorAsync(signer, validator); - } - await assertValidHashSignatureAsync({ - hash, - signer, - signature, - isValid: false, - }); - })(); - } - } - - async function* invalidTestHashMangledSignature(): AsyncIterableIterator { - while (true) { - const params = createHashTestParams({ signatureType: Pseudorandom.sample(ALL_SIGNATURE_TYPES)! }); - const mangled = await mangleSignatureParamsAsync(params); - yield (async () => { - await assertValidHashSignatureAsync({ - hash: mangled.hash, - signer: mangled.signer, - signature: mangled.signature, - isValid: false, - }); - })(); - } - } - - function randomOrder(fields: Partial = {}): Order { - return { - chainId, - exchangeAddress: exchange.address, - expirationTimeSeconds: Pseudorandom.integer(1, 2 ** 32), - salt: Pseudorandom.integer(0, constants.MAX_UINT256), - makerAssetData: Pseudorandom.hex(36), - takerAssetData: Pseudorandom.hex(36), - makerFeeAssetData: Pseudorandom.hex(36), - takerFeeAssetData: Pseudorandom.hex(36), - makerAssetAmount: Pseudorandom.integer(0, 100e18), - takerAssetAmount: Pseudorandom.integer(0, 100e18), - makerFee: Pseudorandom.integer(0, 100e18), - takerFee: Pseudorandom.integer(0, 100e18), - feeRecipientAddress: Pseudorandom.hex(constants.ADDRESS_LENGTH), - makerAddress: Pseudorandom.hex(constants.ADDRESS_LENGTH), - takerAddress: Pseudorandom.hex(constants.ADDRESS_LENGTH), - senderAddress: Pseudorandom.hex(constants.ADDRESS_LENGTH), - ...fields, - }; - } - - async function createOrderTestParamsAsync( - fields: Partial = {}, - ): Promise { - const signatureType = - fields.signatureType === undefined - ? Pseudorandom.sample(ALL_WORKING_SIGNATURE_TYPES)! - : fields.signatureType; - const signer = - fields.signer || - (WALLET_SIGNATURE_TYPES.includes(signatureType) ? walletContractAddress : Pseudorandom.sample(accounts)!); - const validator = - fields.validator || (signatureType === SignatureType.Validator ? walletContractAddress : undefined); - const signerKey = fields.signerKey || privateKeys[signer]; - const order = fields.order || randomOrder({ makerAddress: signer }); - const hash = fields.hash || orderHashUtils.getOrderHashHex(order); - const payload = - fields.payload || - (STRICT_LENGTH_SIGNATURE_TYPES.includes(signatureType) ? constants.NULL_BYTES : randomPayload()); - const signature = createSignature({ signatureType, hash, signerKey, payload, validator }); - return { - hash, - order, - payload, - signature, - signatureType, - signer, - signerKey, - validator, - }; - } - - async function assertValidOrderSignatureAsync(params: { - order: Order; - signature: string; - isValid: boolean; - }): Promise { - try { - let result; - try { - result = await exchange.isValidOrderSignature(params.order, params.signature).callAsync(); - } catch (err) { - if (params.isValid) { - throw err; - } - return; - } - expect(result).to.eq(!!params.isValid); - } catch (err) { - logUtils.warn(params); - throw err; - } - } - - async function* validTestOrderSignature(): AsyncIterableIterator { - while (true) { - const { hash, order, signature, signatureType, signer, validator } = await createOrderTestParamsAsync(); - yield (async () => { - if (signatureType === SignatureType.PreSigned) { - await presignHashAsync(signer, hash); - } else if (signatureType === SignatureType.Validator) { - await approveValidatorAsync(signer, validator!); - } - await assertValidOrderSignatureAsync({ - order, - signature, - isValid: true, - }); - })(); - } - } - - async function* invalidTestOrderStaticSignature(): AsyncIterableIterator { - while (true) { - const randomSignerKey = ethUtil.toBuffer(Pseudorandom.hex()); - const signer = Pseudorandom.sample([notWalletContractAddress, walletContractAddress, ...accounts])!; - const { order, signature } = await createOrderTestParamsAsync({ - signatureType: Pseudorandom.sample([...STATIC_SIGNATURE_TYPES, ...ALWAYS_FAILING_SIGNATURE_TYPES])!, - signer, - // Always sign with a random key. - signerKey: randomSignerKey, - }); - yield assertValidOrderSignatureAsync({ - order, - signature, - isValid: false, - }); - } - } - - async function* invalidTestOrderWalletSignature(): AsyncIterableIterator { - while (true) { - const signer = Pseudorandom.sample([notWalletContractAddress, ...accounts])!; - const { order, signature } = await createOrderTestParamsAsync({ - signatureType: Pseudorandom.sample(WALLET_SIGNATURE_TYPES)!, - signer, - }); - yield assertValidOrderSignatureAsync({ - order, - signature, - isValid: false, - }); - } - } - - async function* invalidTestOrderValidatorSignature(): AsyncIterableIterator { - while (true) { - const isNotApproved = Pseudorandom.sample([true, false])!; - const signer = Pseudorandom.sample([...accounts])!; - const validator = isNotApproved - ? walletContractAddress - : Pseudorandom.sample([notWalletContractAddress, ...accounts])!; - const { order, signature } = await createOrderTestParamsAsync({ - signatureType: SignatureType.Validator, - validator, - }); - yield (async () => { - if (!isNotApproved) { - await approveValidatorAsync(signer, validator); - } - await assertValidOrderSignatureAsync({ - order, - signature, - isValid: false, - }); - })(); - } - } - - async function* invalidTestOrderMangledSignature(): AsyncIterableIterator { - while (true) { - const params = await createOrderTestParamsAsync({ - signatureType: Pseudorandom.sample(ALL_SIGNATURE_TYPES)!, - }); - const mangled = await mangleSignatureParamsAsync(params); - yield (async () => { - await assertValidOrderSignatureAsync({ - order: mangled.order!, - signature: mangled.signature, - isValid: false, - }); - })(); - } - } - - function randomTransaction(fields: Partial = {}): ZeroExTransaction { - return { - domain: { - chainId, - verifyingContract: exchange.address, - name: '0x Protocol', - version: '3.0.0', - }, - gasPrice: Pseudorandom.integer(1e9, 100e9), - expirationTimeSeconds: Pseudorandom.integer(1, 2 ** 32), - salt: Pseudorandom.integer(0, constants.MAX_UINT256), - signerAddress: Pseudorandom.hex(constants.ADDRESS_LENGTH), - data: Pseudorandom.hex(Pseudorandom.integer(4, 128).toNumber()), - ...fields, - }; - } - - async function createTransactionTestParamsAsync( - fields: Partial = {}, - ): Promise { - const signatureType = - fields.signatureType === undefined - ? Pseudorandom.sample(ALL_WORKING_SIGNATURE_TYPES)! - : fields.signatureType; - const signer = - fields.signer || - (WALLET_SIGNATURE_TYPES.includes(signatureType) ? walletContractAddress : Pseudorandom.sample(accounts)!); - const validator = - fields.validator || (signatureType === SignatureType.Validator ? walletContractAddress : undefined); - const signerKey = fields.signerKey || privateKeys[signer]; - const transaction = fields.transaction || randomTransaction({ signerAddress: signer }); - const hash = fields.hash || transactionHashUtils.getTransactionHashHex(transaction); - const payload = - fields.payload || - (STRICT_LENGTH_SIGNATURE_TYPES.includes(signatureType) ? constants.NULL_BYTES : randomPayload()); - const signature = createSignature({ signatureType, hash, signerKey, payload, validator }); - return { - hash, - transaction, - payload, - signature, - signatureType, - signer, - signerKey, - validator, - }; - } - - async function assertValidTransactionSignatureAsync(params: { - transaction: ZeroExTransaction; - signature: string; - isValid: boolean; - }): Promise { - try { - let result; - try { - result = await exchange.isValidTransactionSignature(params.transaction, params.signature).callAsync(); - } catch (err) { - if (params.isValid) { - throw err; - } - return; - } - expect(result).to.eq(!!params.isValid); - } catch (err) { - logUtils.warn(params); - throw err; - } - } - - async function* validTestTransactionSignature(): AsyncIterableIterator { - while (true) { - const { - hash, - transaction, - signature, - signatureType, - signer, - validator, - } = await createTransactionTestParamsAsync(); - yield (async () => { - if (signatureType === SignatureType.PreSigned) { - await presignHashAsync(signer, hash); - } else if (signatureType === SignatureType.Validator) { - await approveValidatorAsync(signer, validator!); - } - await assertValidTransactionSignatureAsync({ - transaction, - signature, - isValid: true, - }); - })(); - } - } - - async function* invalidTestTransactionStaticSignature(): AsyncIterableIterator { - while (true) { - const randomSignerKey = ethUtil.toBuffer(Pseudorandom.hex()); - const signer = Pseudorandom.sample([notWalletContractAddress, walletContractAddress, ...accounts])!; - const { transaction, signature } = await createTransactionTestParamsAsync({ - signatureType: Pseudorandom.sample([...STATIC_SIGNATURE_TYPES, ...ALWAYS_FAILING_SIGNATURE_TYPES])!, - signer, - // Always sign with a random key. - signerKey: randomSignerKey, - }); - yield assertValidTransactionSignatureAsync({ - transaction, - signature, - isValid: false, - }); - } - } - - async function* invalidTestTransactionWalletSignature(): AsyncIterableIterator { - while (true) { - const signer = Pseudorandom.sample([notWalletContractAddress, ...accounts])!; - const { transaction, signature } = await createTransactionTestParamsAsync({ - signatureType: Pseudorandom.sample(WALLET_SIGNATURE_TYPES)!, - signer, - }); - yield assertValidTransactionSignatureAsync({ - transaction, - signature, - isValid: false, - }); - } - } - - async function* invalidTestTransactionValidatorSignature(): AsyncIterableIterator { - while (true) { - const isNotApproved = Pseudorandom.sample([true, false])!; - const signer = Pseudorandom.sample([...accounts])!; - const validator = isNotApproved - ? walletContractAddress - : Pseudorandom.sample([notWalletContractAddress, ...accounts])!; - const { transaction, signature } = await createTransactionTestParamsAsync({ - signatureType: SignatureType.Validator, - validator, - }); - yield (async () => { - if (!isNotApproved) { - await approveValidatorAsync(signer, validator); - } - await assertValidTransactionSignatureAsync({ - transaction, - signature, - isValid: false, - }); - })(); - } - } - - async function* invalidTestTransactionMangledSignature(): AsyncIterableIterator { - while (true) { - const params = await createTransactionTestParamsAsync({ - signatureType: Pseudorandom.sample(ALL_SIGNATURE_TYPES)!, - }); - const mangled = await mangleSignatureParamsAsync(params); - yield (async () => { - await assertValidTransactionSignatureAsync({ - transaction: mangled.transaction!, - signature: mangled.signature, - isValid: false, - }); - })(); - } - } - - it('fuzz', async () => { - const FUZZ_ACTIONS = [ - validTestHashSignature(), - invalidTestHashStaticSignature(), - invalidTestHashWalletSignature(), - invalidTestHashValidatorSignature(), - invalidTestHashMangledSignature(), - validTestOrderSignature(), - invalidTestOrderStaticSignature(), - invalidTestOrderWalletSignature(), - invalidTestOrderValidatorSignature(), - invalidTestOrderMangledSignature(), - validTestTransactionSignature(), - invalidTestTransactionStaticSignature(), - invalidTestTransactionWalletSignature(), - invalidTestTransactionValidatorSignature(), - invalidTestTransactionMangledSignature(), - ]; - const simulationEnvironment = new SimulationEnvironment(deployment, new BlockchainBalanceStore({}, {}), []); - const simulation = new (class extends Simulation { - // tslint:disable-next-line: prefer-function-over-method - protected async *_assertionGenerator(): AsyncIterableIterator { - while (true) { - const action = Pseudorandom.sample(FUZZ_ACTIONS)!; - yield (await action!.next()).value; - } - } - })(simulationEnvironment); - simulation.resets = true; - return simulation.fuzzAsync(); - }); -}); -// tslint:disable-next-line max-file-line-count diff --git a/contracts/integrations/test/fuzz_tests/match_orders_test.ts b/contracts/integrations/test/fuzz_tests/match_orders_test.ts deleted file mode 100644 index ac95ec8ebf..0000000000 --- a/contracts/integrations/test/fuzz_tests/match_orders_test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { PoolOperator } from '../framework/actors/pool_operator'; -import { Taker } from '../framework/actors/taker'; -import { filterActorsByRole } from '../framework/actors/utils'; -import { AssertionResult } from '../framework/assertions/function_assertion'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { Simulation, SimulationEnvironment } from '../framework/simulation'; -import { Pseudorandom } from '../framework/utils/pseudorandom'; - -import { PoolManagementSimulation } from './pool_management_test'; - -export class MatchOrdersSimulation extends Simulation { - protected async *_assertionGenerator(): AsyncIterableIterator { - const { actors } = this.environment; - const makers = filterActorsByRole(actors, Maker); - const takers = filterActorsByRole(actors, Taker); - - const poolManagement = new PoolManagementSimulation(this.environment); - - const [actions, weights] = _.unzip([ - // 20% chance of executing validJoinStakingPool for a random maker - ...makers.map(maker => [maker.simulationActions.validJoinStakingPool, 0.2 / makers.length]), - // 30% chance of executing matchOrders for a random taker - ...takers.map(taker => [taker.simulationActions.validMatchOrders, 0.3]), - // 30% chance of executing matchOrders for a random taker - ...takers.map(taker => [taker.simulationActions.validMatchOrdersWithMaximalFill, 0.3]), - // 20% chance of executing an assertion generated from the pool management simulation - [poolManagement.generator, 0.2], - ]) as [Array>, number[]]; - while (true) { - const action = Pseudorandom.sample(actions, weights); - yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion - } - } -} - -blockchainTests('Match Orders fuzz test', env => { - before(function(): void { - if (process.env.FUZZ_TEST !== 'match_orders') { - this.skip(); - } - }); - after(async () => { - Actor.reset(); - }); - - it('fuzz', async () => { - // Deploy contracts - const deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 4, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - - // Set up balance store - const balanceStore = new BlockchainBalanceStore({}, {}); - - // Spin up actors - const actors = [ - new Maker({ deployment, name: 'Maker 1' }), - new Taker({ deployment, name: 'Taker 1' }), - new PoolOperator({ deployment, name: 'PoolOperator 1' }), - ]; - - // Set up simulation environment - const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore, actors); - - // Takers need to set a WETH allowance for the staking proxy in case they pay the protocol fee in WETH - const takers = filterActorsByRole(actors, Taker); - for (const taker of takers) { - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - } - - // Run simulation - const simulation = new MatchOrdersSimulation(simulationEnvironment); - return simulation.fuzzAsync(); - }); -}); diff --git a/contracts/integrations/test/fuzz_tests/pool_management_test.ts b/contracts/integrations/test/fuzz_tests/pool_management_test.ts deleted file mode 100644 index 639a7d672d..0000000000 --- a/contracts/integrations/test/fuzz_tests/pool_management_test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { Actor } from '../framework/actors/base'; -import { PoolOperator } from '../framework/actors/pool_operator'; -import { filterActorsByRole } from '../framework/actors/utils'; -import { AssertionResult } from '../framework/assertions/function_assertion'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { Simulation, SimulationEnvironment } from '../framework/simulation'; -import { Pseudorandom } from '../framework/utils/pseudorandom'; - -export class PoolManagementSimulation extends Simulation { - protected async *_assertionGenerator(): AsyncIterableIterator { - const { actors } = this.environment; - const operators = filterActorsByRole(actors, PoolOperator); - - const [actions, weights] = _.unzip([ - // 38% chance of executing validCreateStakingPool assertion for a random operator - ...operators.map(operator => [operator.simulationActions.validCreateStakingPool, 0.38]), - // 2% chance of executing invalidCreateStakingPool assertion for a random operator - ...operators.map(operator => [operator.simulationActions.invalidCreateStakingPool, 0.02]), - // 58% chance of executing validDecreaseStakingPoolOperatorShare for a random operator - ...operators.map(operator => [operator.simulationActions.validDecreaseStakingPoolOperatorShare, 0.58]), - // 2% chance of executing invalidDecreaseStakingPoolOperatorShare for a random operator - ...operators.map(operator => [operator.simulationActions.invalidDecreaseStakingPoolOperatorShare, 0.02]), - ]) as [Array>, number[]]; - while (true) { - const action = Pseudorandom.sample(actions, weights); - yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion - } - } -} - -blockchainTests('Pool management fuzz test', env => { - before(function(): void { - if (process.env.FUZZ_TEST !== 'pool_management') { - this.skip(); - } - }); - after(async () => { - Actor.reset(); - }); - - it('fuzz', async () => { - const deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 0, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const balanceStore = new BlockchainBalanceStore({}, {}); - - const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore, [ - new PoolOperator({ deployment, name: 'Operator 1' }), - new PoolOperator({ deployment, name: 'Operator 2' }), - ]); - - const simulation = new PoolManagementSimulation(simulationEnvironment); - return simulation.fuzzAsync(); - }); -}); diff --git a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts deleted file mode 100644 index 2a9842caa3..0000000000 --- a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { Actor } from '../framework/actors/base'; -import { MakerTaker } from '../framework/actors/hybrids'; -import { Maker } from '../framework/actors/maker'; -import { PoolOperator } from '../framework/actors/pool_operator'; -import { Taker } from '../framework/actors/taker'; -import { filterActorsByRole } from '../framework/actors/utils'; -import { AssertionResult } from '../framework/assertions/function_assertion'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { Simulation, SimulationEnvironment } from '../framework/simulation'; -import { Pseudorandom } from '../framework/utils/pseudorandom'; - -import { PoolManagementSimulation } from './pool_management_test'; - -export class PoolMembershipSimulation extends Simulation { - protected async *_assertionGenerator(): AsyncIterableIterator { - const { actors } = this.environment; - const makers = filterActorsByRole(actors, Maker); - const takers = filterActorsByRole(actors, Taker); - - const poolManagement = new PoolManagementSimulation(this.environment); - - const [actions, weights] = _.unzip([ - // 20% chance of executing validJoinStakingPool for a random maker - ...makers.map(maker => [maker.simulationActions.validJoinStakingPool, 0.2 / makers.length]), - // 60% chance of executing validFillOrder for a random taker - ...takers.map(taker => [taker.simulationActions.validFillOrder, 0.6 / takers.length]), - // 20% chance of executing an assertion generated from the pool management simulation - [poolManagement.generator, 0.2], - ]) as [Array>, number[]]; - - while (true) { - const action = Pseudorandom.sample(actions, weights); - yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion - } - } -} - -blockchainTests('pool membership fuzz test', env => { - before(async function(): Promise { - if (process.env.FUZZ_TEST !== 'pool_membership') { - this.skip(); - } - }); - - after(async () => { - Actor.reset(); - }); - - it('fuzz', async () => { - const deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 4, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - - const balanceStore = new BlockchainBalanceStore( - { - StakingProxy: deployment.staking.stakingProxy.address, - ZRXVault: deployment.staking.zrxVault.address, - }, - { erc20: { ZRX: deployment.tokens.zrx } }, - ); - - const actors = [ - new Maker({ deployment, name: 'Maker 1' }), - new Maker({ deployment, name: 'Maker 2' }), - new Taker({ deployment, name: 'Taker 1' }), - new Taker({ deployment, name: 'Taker 2' }), - new MakerTaker({ deployment, name: 'Maker/Taker' }), - new PoolOperator({ deployment, name: 'Operator 1' }), - new PoolOperator({ deployment, name: 'Operator 2' }), - ]; - - const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore, actors); - - const takers = filterActorsByRole(actors, Taker); - for (const taker of takers) { - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - } - - const simulation = new PoolMembershipSimulation(simulationEnvironment); - return simulation.fuzzAsync(); - }); -}); diff --git a/contracts/integrations/test/fuzz_tests/stake_management_test.ts b/contracts/integrations/test/fuzz_tests/stake_management_test.ts deleted file mode 100644 index e9087c9362..0000000000 --- a/contracts/integrations/test/fuzz_tests/stake_management_test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { Actor } from '../framework/actors/base'; -import { StakerOperator } from '../framework/actors/hybrids'; -import { PoolOperator } from '../framework/actors/pool_operator'; -import { Staker } from '../framework/actors/staker'; -import { filterActorsByRole } from '../framework/actors/utils'; -import { AssertionResult } from '../framework/assertions/function_assertion'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { Simulation, SimulationEnvironment } from '../framework/simulation'; -import { Pseudorandom } from '../framework/utils/pseudorandom'; - -import { PoolManagementSimulation } from './pool_management_test'; - -export class StakeManagementSimulation extends Simulation { - protected async *_assertionGenerator(): AsyncIterableIterator { - const { actors } = this.environment; - const stakers = filterActorsByRole(actors, Staker); - - const poolManagement = new PoolManagementSimulation(this.environment); - - const [actions, weights] = _.unzip([ - // 28% chance of executing validStake for a random staker - ...stakers.map(staker => [staker.simulationActions.validStake, 0.28 / stakers.length]), - // 2% chance of executing invalidUnstake for a random staker - ...stakers.map(staker => [staker.simulationActions.invalidStake, 0.02 / stakers.length]), - // 28% chance of executing validUnstake for a random staker - ...stakers.map(staker => [staker.simulationActions.validStake, 0.28 / stakers.length]), - // 2% chance of executing invalidUnstake for a random staker - ...stakers.map(staker => [staker.simulationActions.validUnstake, 0.02 / stakers.length]), - // 28% chance of executing validMoveStake for a random staker - ...stakers.map(staker => [staker.simulationActions.validMoveStake, 0.28 / stakers.length]), - // 2% chance of executing moveStakeNonexistentPool for a random staker - ...stakers.map(staker => [staker.simulationActions.moveStakeNonexistentPool, 0.02 / stakers.length]), - // 20% chance of executing an assertion generated from the pool management simulation - [poolManagement.generator, 0.2], - ]) as [Array>, number[]]; - - while (true) { - const action = Pseudorandom.sample(actions, weights); - yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion - } - } -} - -blockchainTests('Stake management fuzz test', env => { - before(function(): void { - if (process.env.FUZZ_TEST !== 'stake_management') { - this.skip(); - } - }); - - after(async () => { - Actor.reset(); - }); - - it('fuzz', async () => { - const deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 0, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const balanceStore = new BlockchainBalanceStore( - { - StakingProxy: deployment.staking.stakingProxy.address, - ZRXVault: deployment.staking.zrxVault.address, - }, - { erc20: { ZRX: deployment.tokens.zrx } }, - ); - - const actors = [ - new Staker({ name: 'Staker 1', deployment }), - new Staker({ name: 'Staker 2', deployment }), - new StakerOperator({ name: 'Staker/Operator', deployment }), - new PoolOperator({ name: 'Operator', deployment }), - ]; - - const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore, actors); - - const stakers = filterActorsByRole(actors, Staker); - for (const staker of stakers) { - await staker.configureERC20TokenAsync(deployment.tokens.zrx); - } - - const simulation = new StakeManagementSimulation(simulationEnvironment); - return simulation.fuzzAsync(); - }); -}); diff --git a/contracts/integrations/test/fuzz_tests/staking_rewards_test.ts b/contracts/integrations/test/fuzz_tests/staking_rewards_test.ts deleted file mode 100644 index 8a4bd1ac28..0000000000 --- a/contracts/integrations/test/fuzz_tests/staking_rewards_test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { Actor } from '../framework/actors/base'; -import { - MakerTaker, - OperatorStakerMaker, - StakerKeeper, - StakerMaker, - StakerOperator, -} from '../framework/actors/hybrids'; -import { Keeper } from '../framework/actors/keeper'; -import { Maker } from '../framework/actors/maker'; -import { PoolOperator } from '../framework/actors/pool_operator'; -import { Staker } from '../framework/actors/staker'; -import { Taker } from '../framework/actors/taker'; -import { filterActorsByRole } from '../framework/actors/utils'; -import { AssertionResult } from '../framework/assertions/function_assertion'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { Simulation, SimulationEnvironment } from '../framework/simulation'; -import { Pseudorandom } from '../framework/utils/pseudorandom'; - -import { PoolMembershipSimulation } from './pool_membership_test'; -import { StakeManagementSimulation } from './stake_management_test'; - -export class StakingRewardsSimulation extends Simulation { - protected async *_assertionGenerator(): AsyncIterableIterator { - const { actors } = this.environment; - const stakers = filterActorsByRole(actors, Staker); - const keepers = filterActorsByRole(actors, Keeper); - - const poolMembership = new PoolMembershipSimulation(this.environment); - const stakeManagement = new StakeManagementSimulation(this.environment); - - const [actions, weights] = _.unzip([ - // 10% chance of executing validWithdrawDelegatorRewards for a random staker - ...stakers.map(staker => [staker.simulationActions.validWithdrawDelegatorRewards, 0.1 / stakers.length]), - // 10% chance of executing validFinalizePool for a random keeper - ...keepers.map(keeper => [keeper.simulationActions.validFinalizePool, 0.1 / keepers.length]), - // 7% chance of executing validEndEpoch for a random keeper - ...keepers.map(keeper => [keeper.simulationActions.validEndEpoch, 0.07 / keepers.length]), - // 3% chance of executing invalidEndEpoch for a random keeper - ...keepers.map(keeper => [keeper.simulationActions.invalidEndEpoch, 0.03 / keepers.length]), - // 50% chance of executing an assertion generated from the pool membership simulation - [poolMembership.generator, 0.5], - // 20% chance of executing an assertion generated from the stake management simulation - [stakeManagement.generator, 0.2], - ]) as [Array>, number[]]; - while (true) { - const action = Pseudorandom.sample(actions, weights); - yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion - } - } -} - -blockchainTests('Staking rewards fuzz test', env => { - before(function(): void { - if (process.env.FUZZ_TEST !== 'staking_rewards') { - this.skip(); - } - }); - - after(async () => { - Actor.reset(); - }); - - it('fuzz', async () => { - // Deploy contracts - const deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 4, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const [ERC20TokenA, ERC20TokenB, ERC20TokenC, ERC20TokenD] = deployment.tokens.erc20; - - // Set up balance store - const balanceStore = new BlockchainBalanceStore( - { - StakingProxy: deployment.staking.stakingProxy.address, - ZRXVault: deployment.staking.zrxVault.address, - }, - { - erc20: { - ZRX: deployment.tokens.zrx, - WETH: deployment.tokens.weth, - ERC20TokenA, - ERC20TokenB, - ERC20TokenC, - ERC20TokenD, - }, - }, - ); - - // Spin up actors - const actors = [ - new Maker({ deployment, name: 'Maker 1' }), - new Maker({ deployment, name: 'Maker 2' }), - new Taker({ deployment, name: 'Taker 1' }), - new Taker({ deployment, name: 'Taker 2' }), - new MakerTaker({ deployment, name: 'Maker/Taker' }), - new Staker({ deployment, name: 'Staker 1' }), - new Staker({ deployment, name: 'Staker 2' }), - new Keeper({ deployment, name: 'Keeper' }), - new StakerKeeper({ deployment, name: 'Staker/Keeper' }), - new StakerMaker({ deployment, name: 'Staker/Maker' }), - new PoolOperator({ deployment, name: 'Pool Operator' }), - new StakerOperator({ deployment, name: 'Staker/Operator' }), - new OperatorStakerMaker({ deployment, name: 'Operator/Staker/Maker' }), - ]; - - // Set up simulation environment - const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore, actors); - - // Takers need to set a WETH allowance for the staking proxy in case they pay the protocol fee in WETH - const takers = filterActorsByRole(actors, Taker); - for (const taker of takers) { - await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address); - } - // Stakers need to set a ZRX allowance to deposit their ZRX into the zrxVault - const stakers = filterActorsByRole(actors, Staker); - for (const staker of stakers) { - await staker.configureERC20TokenAsync(deployment.tokens.zrx); - } - const simulation = new StakingRewardsSimulation(simulationEnvironment); - return simulation.fuzzAsync(); - }); -}); diff --git a/contracts/integrations/test/fuzz_tests/tslint.json b/contracts/integrations/test/fuzz_tests/tslint.json deleted file mode 100644 index 75d8721a39..0000000000 --- a/contracts/integrations/test/fuzz_tests/tslint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "no-invalid-this": false, - "custom-no-magic-numbers": false - } -} diff --git a/contracts/integrations/test/mainnet_configs_test.ts b/contracts/integrations/test/mainnet_configs_test.ts deleted file mode 100644 index eec17117b5..0000000000 --- a/contracts/integrations/test/mainnet_configs_test.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { ContractWrappers } from '@0x/contract-wrappers'; -import { ERC20ProxyContract, MultiAssetProxyContract } from '@0x/contracts-asset-proxy'; -import { StakingProxyContract, ZrxVaultContract } from '@0x/contracts-staking'; -import { blockchainTests, describe, expect } from '@0x/contracts-test-utils'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { contractAddresses, getContractwrappers } from './mainnet_fork_utils'; - -blockchainTests.live('Mainnet configs tests', env => { - let contractWrappers: ContractWrappers; - - before(async () => { - contractWrappers = getContractwrappers(env.provider); - }); - - describe('Exchange', () => { - it('should be owned by the ZeroExGovernor ', async () => { - const owner = await contractWrappers.exchange.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('ERC20Proxy should be registered', async () => { - const erc20Proxy = await contractWrappers.exchange.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(erc20Proxy).to.eq(contractAddresses.erc20Proxy); - }); - it('ERC721Proxy should be registered', async () => { - const erc721Proxy = await contractWrappers.exchange.getAssetProxy(AssetProxyId.ERC721).callAsync(); - expect(erc721Proxy).to.eq(contractAddresses.erc721Proxy); - }); - it('ERC1155Proxy should be registered', async () => { - const erc1155Proxy = await contractWrappers.exchange.getAssetProxy(AssetProxyId.ERC1155).callAsync(); - expect(erc1155Proxy).to.eq(contractAddresses.erc1155Proxy); - }); - it('ERC20BridgeProxy should be registered', async () => { - const erc20BridgeProxy = await contractWrappers.exchange - .getAssetProxy(AssetProxyId.ERC20Bridge) - .callAsync(); - expect(erc20BridgeProxy).to.eq(contractAddresses.erc20BridgeProxy); - }); - it('MultiAssetProxy should be registered', async () => { - const multiAssetProxy = await contractWrappers.exchange.getAssetProxy(AssetProxyId.MultiAsset).callAsync(); - expect(multiAssetProxy).to.eq(contractAddresses.multiAssetProxy); - }); - it('StaticCallProxy should be registered', async () => { - const staticCallProxy = await contractWrappers.exchange.getAssetProxy(AssetProxyId.StaticCall).callAsync(); - expect(staticCallProxy).to.eq(contractAddresses.staticCallProxy); - }); - it('StakingProxy should be attached', async () => { - const stakingProxy = await contractWrappers.exchange.protocolFeeCollector().callAsync(); - expect(stakingProxy).to.eq(contractAddresses.stakingProxy); - }); - it('should have the correct protocol fee multiplier', async () => { - const protocolFeeMultiplier = await contractWrappers.exchange.protocolFeeMultiplier().callAsync(); - expect(protocolFeeMultiplier).to.bignumber.eq(150000); - }); - }); - describe('ERC20Proxy', () => { - const erc20Proxy = new ERC20ProxyContract(contractAddresses.erc20Proxy, env.provider); - it('should be owned by the ZeroExGovernor ', async () => { - const owner = await erc20Proxy.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await erc20Proxy.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(4); - expect(authorizedAddresses.includes(contractAddresses.exchangeV2), 'ExchangeV2'); - expect(authorizedAddresses.includes(contractAddresses.exchange), 'Exchange'); - expect(authorizedAddresses.includes(contractAddresses.multiAssetProxy), 'MultiAssetProxy'); - expect(authorizedAddresses.includes(contractAddresses.zrxVault), 'ZrxVault'); - }); - }); - describe('ERC721Proxy', () => { - const erc721Proxy = new ERC20ProxyContract(contractAddresses.erc721Proxy, env.provider); - it('should be owned by the ZeroExGovernor ', async () => { - const owner = await erc721Proxy.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await erc721Proxy.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(3); - expect(authorizedAddresses.includes(contractAddresses.exchangeV2), 'ExchangeV2'); - expect(authorizedAddresses.includes(contractAddresses.exchange), 'Exchange'); - expect(authorizedAddresses.includes(contractAddresses.multiAssetProxy), 'MultiAssetProxy'); - }); - }); - describe('ERC1155Proxy', () => { - const erc1155Proxy = new ERC20ProxyContract(contractAddresses.erc1155Proxy, env.provider); - it('should be owned by the ZeroExGovernor ', async () => { - const owner = await erc1155Proxy.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await erc1155Proxy.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(3); - expect(authorizedAddresses.includes(contractAddresses.exchangeV2), 'ExchangeV2'); - expect(authorizedAddresses.includes(contractAddresses.exchange), 'Exchange'); - expect(authorizedAddresses.includes(contractAddresses.multiAssetProxy), 'MultiAssetProxy'); - }); - }); - describe('ERC20BridgeProxy', () => { - const erc20BridgeProxy = new ERC20ProxyContract(contractAddresses.erc20BridgeProxy, env.provider); - it('should be owned by the ZeroExGovernor ', async () => { - const owner = await erc20BridgeProxy.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await erc20BridgeProxy.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(2); - expect(authorizedAddresses.includes(contractAddresses.exchange), 'Exchange'); - expect(authorizedAddresses.includes(contractAddresses.multiAssetProxy), 'MultiAssetProxy'); - }); - }); - describe('MultiAssetProxy', () => { - const multiAssetProxy = new MultiAssetProxyContract(contractAddresses.multiAssetProxy, env.provider); - it('should be owned by the ZeroExGovernor ', async () => { - const owner = await multiAssetProxy.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await multiAssetProxy.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(2); - expect(authorizedAddresses.includes(contractAddresses.exchangeV2), 'ExchangeV2'); - expect(authorizedAddresses.includes(contractAddresses.exchange), 'Exchange'); - }); - it('ERC20Proxy should be registered', async () => { - const erc20Proxy = await multiAssetProxy.getAssetProxy(AssetProxyId.ERC20).callAsync(); - expect(erc20Proxy).to.eq(contractAddresses.erc20Proxy); - }); - it('ERC721Proxy should be registered', async () => { - const erc721Proxy = await multiAssetProxy.getAssetProxy(AssetProxyId.ERC721).callAsync(); - expect(erc721Proxy).to.eq(contractAddresses.erc721Proxy); - }); - it('ERC1155Proxy should be registered', async () => { - const erc1155Proxy = await multiAssetProxy.getAssetProxy(AssetProxyId.ERC1155).callAsync(); - expect(erc1155Proxy).to.eq(contractAddresses.erc1155Proxy); - }); - it('ERC20BridgeProxy should be registered', async () => { - const erc20BridgeProxy = await multiAssetProxy.getAssetProxy(AssetProxyId.ERC20Bridge).callAsync(); - expect(erc20BridgeProxy).to.eq(contractAddresses.erc20BridgeProxy); - }); - it('StaticCallProxy should be registered', async () => { - const staticCallProxy = await multiAssetProxy.getAssetProxy(AssetProxyId.StaticCall).callAsync(); - expect(staticCallProxy).to.eq(contractAddresses.staticCallProxy); - }); - }); - describe('StakingProxy', () => { - const stakingProxy = new StakingProxyContract(contractAddresses.stakingProxy, env.provider); - it('should be owned by ZeroExGovernor', async () => { - const owner = await stakingProxy.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('Staking contract should be attached', async () => { - const staking = await stakingProxy.stakingContract().callAsync(); - expect(staking).to.eq(contractAddresses.staking); - }); - it('Exchange should be registered', async () => { - const isRegistered = await contractWrappers.staking.validExchanges(contractAddresses.exchange).callAsync(); - expect(isRegistered).to.be.true(); - }); - it('ZrxVault should be set', async () => { - const zrxVault = await contractWrappers.staking.getZrxVault().callAsync(); - expect(zrxVault).to.eq(contractAddresses.zrxVault); - }); - it('WETH should be set', async () => { - const weth = await contractWrappers.staking.getWethContract().callAsync(); - expect(weth).to.eq(contractAddresses.etherToken); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await stakingProxy.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(1); - expect(authorizedAddresses.includes(contractAddresses.zeroExGovernor), 'ZeroExGovernor'); - }); - it('should have the correct params set', async () => { - const params = await contractWrappers.staking.getParams().callAsync(); - const epochDurationInSeconds = 10 * 24 * 60 * 60; - const rewardDelegatedStakeWeight = 10 ** 6 * 0.9; - const mimimumPoolStake = new BigNumber(10).pow(18).times(100); - const cobbDouglasAlphaNumerator = 2; - const cobbDouglasAlphaDenominator = 3; - expect(params[0]).to.bignumber.eq(epochDurationInSeconds, 'epochDurationInSeconds'); - expect(params[1]).to.bignumber.eq(rewardDelegatedStakeWeight, 'rewardDelegatedStakeWeight'); - expect(params[2]).to.bignumber.eq(mimimumPoolStake, 'mimimumPoolStake'); - expect(params[3]).to.bignumber.eq(cobbDouglasAlphaNumerator, 'cobbDouglasAlphaNumerator'); - expect(params[4]).to.bignumber.eq(cobbDouglasAlphaDenominator, 'cobbDouglasAlphaDenominator'); - }); - }); - describe('ZrxVault', () => { - const zrxVault = new ZrxVaultContract(contractAddresses.zrxVault, env.provider); - it('should be owned by ZeroExGovernor', async () => { - const owner = await zrxVault.owner().callAsync(); - expect(owner).to.eq(contractAddresses.zeroExGovernor); - }); - it('should have the correct authorized addresses', async () => { - const authorizedAddresses = await zrxVault.getAuthorizedAddresses().callAsync(); - expect(authorizedAddresses.length).to.eq(1); - expect(authorizedAddresses.includes(contractAddresses.zeroExGovernor), 'ZeroExGovernor'); - }); - it('ERC20Proxy should be set', async () => { - const erc20Proxy = await zrxVault.zrxAssetProxy().callAsync(); - expect(erc20Proxy).to.eq(contractAddresses.erc20Proxy); - }); - it('StakingProxy should be set', async () => { - const stakingProxy = await zrxVault.stakingProxyAddress().callAsync(); - expect(stakingProxy).to.eq(contractAddresses.stakingProxy); - }); - }); -}); diff --git a/contracts/integrations/test/mainnet_contract_wrapper_test.ts b/contracts/integrations/test/mainnet_contract_wrapper_test.ts deleted file mode 100644 index e6b020c1ca..0000000000 --- a/contracts/integrations/test/mainnet_contract_wrapper_test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { blockchainTests, expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { TestContractWrapperContract } from './wrappers'; - -blockchainTests.live('Contract wrapper mainnet callAsync revert behavior tests', env => { - // Mainnet address of the `TestContractWrapper` contract. - const TEST_CONTRACT_ADDRESS = '0x3C120F51aa2360E6C7078dbc849591dd14F21405'; - const REVERT_STRING = 'ERROR'; - const VALID_RESULT = new BigNumber('0xf984f922a56ea9a20a32a32f0f60f2d216ff0c0a0d16c986a97a7f1897a6613b'); - let testContract: TestContractWrapperContract; - - before(async () => { - testContract = new TestContractWrapperContract(TEST_CONTRACT_ADDRESS, env.provider, env.txDefaults); - }); - - describe('callAsync()', () => { - it('can decode valid result', async () => { - const result = await testContract.returnValid().callAsync(); - expect(result).to.bignumber.eq(VALID_RESULT); - }); - - it('can decode an empty result', async () => { - const result = await testContract.returnEmpty().callAsync(); - expect(result).to.eq(undefined); - }); - - it('catches a string revert', async () => { - const tx = testContract.throwStringRevert().callAsync(); - return expect(tx).to.revertWith(REVERT_STRING); - }); - - it('catches an empty revert', async () => { - const tx = testContract.throwEmptyRevert().callAsync(); - return expect(tx).to.be.rejectedWith('reverted with no data'); - }); - - it('catches invalid opcode', async () => { - const tx = testContract.throwInvalidOpcode().callAsync(); - return expect(tx).to.be.rejectedWith('reverted with no data'); - }); - - it('catches a forced empty result', async () => { - const tx = testContract.returnForcedEmpty().callAsync(); - return expect(tx).to.be.rejectedWith('reverted with no data'); - }); - - it('catches a truncated result', async () => { - const tx = testContract.returnTruncated().callAsync(); - return expect(tx).to.be.rejectedWith('decode beyond the end of calldata'); - }); - }); -}); diff --git a/contracts/integrations/test/mainnet_fork_utils.ts b/contracts/integrations/test/mainnet_fork_utils.ts deleted file mode 100644 index be69c87a63..0000000000 --- a/contracts/integrations/test/mainnet_fork_utils.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { ContractWrappers } from '@0x/contract-wrappers'; -import { Web3ProviderEngine } from '@0x/dev-utils'; - -const chainId = 1; -export const dydxAccountOwner = '0xfdac948232c5bfbe24b770326ee4dff7a8dd8484'; -export const contractAddresses = getContractAddressesForChainOrThrow(chainId); - -/** - * Create contract wrappers for the mainnet given a mainnet/forked provider. - */ -export function getContractwrappers(provider: Web3ProviderEngine): ContractWrappers { - return new ContractWrappers(provider, { chainId, contractAddresses }); -} diff --git a/contracts/integrations/test/stop-limit/chainlink_stop_limit_test.ts b/contracts/integrations/test/stop-limit/chainlink_stop_limit_test.ts deleted file mode 100644 index cb3928fddf..0000000000 --- a/contracts/integrations/test/stop-limit/chainlink_stop_limit_test.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { ExchangeRevertErrors } from '@0x/contracts-exchange'; -import { - blockchainTests, - constants, - expect, - getRandomInteger, - orderHashUtils, - randomAddress, -} from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber, StringRevertError } from '@0x/utils'; - -import { - decodeChainlinkStopLimitData, - decodeStopLimitStaticCallData, - encodeChainlinkStopLimitData, - encodeStopLimitStaticCallData, -} from '../../src/chainlink_utils'; - -import { artifacts } from '../artifacts'; -import { Actor } from '../framework/actors/base'; -import { Maker } from '../framework/actors/maker'; -import { Taker } from '../framework/actors/taker'; -import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store'; -import { LocalBalanceStore } from '../framework/balances/local_balance_store'; -import { DeploymentManager } from '../framework/deployment_manager'; -import { ChainlinkStopLimitContract, TestChainlinkAggregatorContract } from '../wrappers'; - -blockchainTests.resets('Chainlink stop-limit order tests', env => { - let deployment: DeploymentManager; - let balanceStore: BlockchainBalanceStore; - let initialBalances: LocalBalanceStore; - - let chainLinkAggregator: TestChainlinkAggregatorContract; - let chainlinkStopLimit: ChainlinkStopLimitContract; - - let maker: Maker; - let taker: Taker; - - let order: SignedOrder; - - const minPrice = new BigNumber(42); - const maxPrice = new BigNumber(1337); - - before(async () => { - deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 2, - numErc721TokensToDeploy: 0, - numErc1155TokensToDeploy: 0, - }); - const [makerToken, takerToken] = deployment.tokens.erc20; - - chainlinkStopLimit = await ChainlinkStopLimitContract.deployFrom0xArtifactAsync( - artifacts.ChainlinkStopLimit, - env.provider, - env.txDefaults, - artifacts, - ); - chainLinkAggregator = await TestChainlinkAggregatorContract.deployFrom0xArtifactAsync( - artifacts.TestChainlinkAggregator, - env.provider, - env.txDefaults, - artifacts, - ); - - const makerAssetData = assetDataUtils.encodeMultiAssetData( - [new BigNumber(1), new BigNumber(1)], - [ - assetDataUtils.encodeERC20AssetData(makerToken.address), - encodeStopLimitStaticCallData(chainlinkStopLimit.address, { - oracle: chainLinkAggregator.address, - minPrice, - maxPrice, - }), - ], - ); - - const orderConfig = { - feeRecipientAddress: constants.NULL_ADDRESS, - makerAssetData, - takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address), - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - }; - - maker = new Maker({ - name: 'Maker', - deployment, - orderConfig, - }); - taker = new Taker({ name: 'Taker', deployment }); - - // Set balances and allowances - await maker.configureERC20TokenAsync(makerToken); - await taker.configureERC20TokenAsync(takerToken); - - order = await maker.signOrderAsync(); - - // Set up balance stores - const tokenOwners = { - Maker: maker.address, - Taker: taker.address, - }; - const tokenContracts = { - erc20: { makerToken, takerToken }, - }; - balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts); - await balanceStore.updateBalancesAsync(); - initialBalances = LocalBalanceStore.create(balanceStore); - }); - - after(async () => { - Actor.reset(); - }); - - describe('filling stop-limit orders', () => { - it('fillOrder reverts if price < minPrice', async () => { - await chainLinkAggregator.setPrice(minPrice.minus(1)).awaitTransactionSuccessAsync(); - const tx = taker.fillOrderAsync(order, order.takerAssetAmount); - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashUtils.getOrderHashHex(order), - order.makerAssetData, - new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(), - ); - return expect(tx).to.revertWith(expectedError); - }); - it('fillOrder reverts price > maxPrice', async () => { - await chainLinkAggregator.setPrice(maxPrice.plus(1)).awaitTransactionSuccessAsync(); - const tx = taker.fillOrderAsync(order, order.takerAssetAmount); - const expectedError = new ExchangeRevertErrors.AssetProxyTransferError( - orderHashUtils.getOrderHashHex(order), - order.makerAssetData, - new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(), - ); - return expect(tx).to.revertWith(expectedError); - }); - it('fillOrder succeeds if price = minPrice', async () => { - await chainLinkAggregator.setPrice(minPrice).awaitTransactionSuccessAsync(); - const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount); - const expectedBalances = LocalBalanceStore.create(initialBalances); - expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it('fillOrder succeeds if price = maxPrice', async () => { - await chainLinkAggregator.setPrice(maxPrice).awaitTransactionSuccessAsync(); - const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount); - const expectedBalances = LocalBalanceStore.create(initialBalances); - expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - it('fillOrder succeeds if minPrice < price < maxPrice', async () => { - await chainLinkAggregator - .setPrice(minPrice.plus(maxPrice).dividedToIntegerBy(2)) - .awaitTransactionSuccessAsync(); - const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount); - const expectedBalances = LocalBalanceStore.create(initialBalances); - expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee); - await balanceStore.updateBalancesAsync(); - balanceStore.assertEquals(expectedBalances); - }); - }); - - describe('Data encoding/decoding tools', () => { - const MAX_INT256 = new BigNumber(2).exponentiatedBy(255).minus(1); - - it('correctly decodes chainlink stop-limit params', async () => { - const params = { - oracle: randomAddress(), - minPrice: getRandomInteger(0, MAX_INT256), - maxPrice: getRandomInteger(0, MAX_INT256), - }; - const encoded = encodeChainlinkStopLimitData(params); - const decoded = decodeChainlinkStopLimitData(encoded); - expect(decoded).to.deep.equal(params); - }); - it('correctly decodes stop-limit assetData', async () => { - const params = { - oracle: randomAddress(), - minPrice: getRandomInteger(0, MAX_INT256), - maxPrice: getRandomInteger(0, MAX_INT256), - }; - const encoded = encodeStopLimitStaticCallData(chainlinkStopLimit.address, params); - const decoded = decodeStopLimitStaticCallData(encoded); - expect(decoded).to.deep.equal(params); - }); - }); -}); diff --git a/contracts/integrations/test/wrappers.ts b/contracts/integrations/test/wrappers.ts deleted file mode 100644 index 943a45404c..0000000000 --- a/contracts/integrations/test/wrappers.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/chainlink_stop_limit'; -export * from '../test/generated-wrappers/i_chainlink_aggregator'; -export * from '../test/generated-wrappers/test_chainlink_aggregator'; -export * from '../test/generated-wrappers/test_contract_wrapper'; -export * from '../test/generated-wrappers/test_dydx_user'; -export * from '../test/generated-wrappers/test_eth2_dai'; -export * from '../test/generated-wrappers/test_eth2_dai_bridge'; -export * from '../test/generated-wrappers/test_fixin_protocol_fees_integration'; -export * from '../test/generated-wrappers/test_framework'; -export * from '../test/generated-wrappers/test_mainnet_aggregator_fills'; -export * from '../test/generated-wrappers/test_signature_validation_wallet'; -export * from '../test/generated-wrappers/test_staking'; -export * from '../test/generated-wrappers/test_uniswap_bridge'; -export * from '../test/generated-wrappers/test_uniswap_exchange'; -export * from '../test/generated-wrappers/test_uniswap_exchange_factory'; -export * from '../test/generated-wrappers/test_weth_integration'; diff --git a/contracts/integrations/test/zero-ex/protocol_fees_staking_test.ts b/contracts/integrations/test/zero-ex/protocol_fees_staking_test.ts deleted file mode 100644 index 3ec33cfb9e..0000000000 --- a/contracts/integrations/test/zero-ex/protocol_fees_staking_test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; - -import { artifacts } from '../artifacts'; -import { - TestFixinProtocolFeesIntegrationContract, - TestStakingContract, - TestWethIntegrationContract, -} from '../wrappers'; - -blockchainTests.resets('ProtocolFeeIntegration', env => { - const FEE_MULTIPLIER = 70e3; - let owner: string; - let taker: string; - let protocolFees: TestFixinProtocolFeesIntegrationContract; - let staking: TestStakingContract; - let weth: TestWethIntegrationContract; - let singleFeeAmount: BigNumber; - - before(async () => { - [owner, taker] = await env.getAccountAddressesAsync(); - weth = await TestWethIntegrationContract.deployFrom0xArtifactAsync( - artifacts.TestWethIntegration, - env.provider, - env.txDefaults, - artifacts, - ); - staking = await TestStakingContract.deployFrom0xArtifactAsync( - artifacts.TestStaking, - env.provider, - env.txDefaults, - artifacts, - constants.NULL_ADDRESS, // exchange address, which we don't know yet - weth.address, - ); - protocolFees = await TestFixinProtocolFeesIntegrationContract.deployFrom0xArtifactAsync( - artifacts.TestFixinProtocolFeesIntegration, - env.provider, - { ...env.txDefaults, from: taker }, - artifacts, - weth.address, - staking.address, - FEE_MULTIPLIER, - ); - await staking.addAuthorizedAddress(owner).awaitTransactionSuccessAsync(); - await staking.addExchangeAddress(protocolFees.address).awaitTransactionSuccessAsync({ from: owner }); - await weth.mint(taker, constants.ONE_ETHER).awaitTransactionSuccessAsync(); - await weth.approve(protocolFees.address, constants.ONE_ETHER).awaitTransactionSuccessAsync({ from: taker }); - - singleFeeAmount = await protocolFees.getSingleProtocolFee().callAsync(); - }); - - describe('fee collection integration', () => { - const pool0 = constants.NULL_BYTES32; - const poolId = hexUtils.random(); - - it('should collect fees for pool 0', async () => { - await protocolFees.collectProtocolFee(pool0).awaitTransactionSuccessAsync({ value: singleFeeAmount }); - await protocolFees.transferFeesForPool(pool0).awaitTransactionSuccessAsync(); - - // Fees in the pool bytes32(0) don't get attributed to a pool. - await expect( - (await staking.getStakingPoolStatsThisEpoch(pool0).callAsync()).feesCollected, - ).to.bignumber.equal(constants.ZERO_AMOUNT); - - // Expected amount is singleFeeAmount - 1 because we leave 1 wei of WETH behind for future gas savings. - return expect(await weth.balanceOf(staking.address).callAsync()).to.bignumber.equal( - singleFeeAmount.minus(1), - ); - }); - - it('should collect fees for non-zero pool', async () => { - const eth100 = constants.ONE_ETHER.multipliedBy(100); - await staking.createTestPool(poolId, eth100, eth100).awaitTransactionSuccessAsync(); - - await protocolFees.collectProtocolFee(poolId).awaitTransactionSuccessAsync({ value: singleFeeAmount }); - await protocolFees.transferFeesForPool(poolId).awaitTransactionSuccessAsync(); - - // Expected amount is singleFeeAmount - 1 because we leave 1 wei of WETH behind for future gas savings. - return expect( - (await staking.getStakingPoolStatsThisEpoch(poolId).callAsync()).feesCollected, - ).to.bignumber.equal(singleFeeAmount.minus(1)); - }); - }); -}); diff --git a/contracts/integrations/tsconfig.json b/contracts/integrations/tsconfig.json deleted file mode 100644 index 580a48601d..0000000000 --- a/contracts/integrations/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/TestFramework.json", - "test/generated-artifacts/ChainlinkStopLimit.json", - "test/generated-artifacts/IChainlinkAggregator.json", - "test/generated-artifacts/TestChainlinkAggregator.json", - "test/generated-artifacts/TestContractWrapper.json", - "test/generated-artifacts/TestDydxUser.json", - "test/generated-artifacts/TestEth2Dai.json", - "test/generated-artifacts/TestEth2DaiBridge.json", - "test/generated-artifacts/TestFixinProtocolFeesIntegration.json", - "test/generated-artifacts/TestFramework.json", - "test/generated-artifacts/TestMainnetAggregatorFills.json", - "test/generated-artifacts/TestSignatureValidationWallet.json", - "test/generated-artifacts/TestStaking.json", - "test/generated-artifacts/TestUniswapBridge.json", - "test/generated-artifacts/TestUniswapExchange.json", - "test/generated-artifacts/TestUniswapExchangeFactory.json", - "test/generated-artifacts/TestWethIntegration.json" - ] -} diff --git a/contracts/integrations/tslint.json b/contracts/integrations/tslint.json deleted file mode 100644 index 720dab4e9e..0000000000 --- a/contracts/integrations/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - }, - "linterOptions": { - "exclude": ["src/artifacts.ts", "test/artifacts.ts"] - } -} diff --git a/contracts/multisig/.npmignore b/contracts/multisig/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/multisig/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/multisig/CHANGELOG.json b/contracts/multisig/CHANGELOG.json deleted file mode 100644 index b4d9474c40..0000000000 --- a/contracts/multisig/CHANGELOG.json +++ /dev/null @@ -1,746 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "4.1.38", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "4.1.37", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "4.1.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "4.1.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "4.1.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "4.1.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "4.1.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "4.1.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "4.1.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "4.1.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "4.1.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "4.1.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "4.1.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "4.1.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "4.1.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "4.1.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "4.1.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "4.1.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "4.1.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "4.1.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "4.1.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "4.1.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "4.1.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "4.1.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "4.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "4.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "4.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "4.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "4.1.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "4.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "4.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "4.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "4.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "4.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "4.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "4.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "4.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "4.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.1.0", - "changes": [ - { - "note": "Fix broken tests", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "4.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "4.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "4.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "4.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "4.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "4.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - } - ], - "timestamp": 1575296764 - }, - { - "version": "3.2.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "3.2.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "3.2.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - } - ], - "timestamp": 1574030254 - }, - { - "version": "3.2.0-beta.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1573159180 - }, - { - "version": "3.2.0-beta.0", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1570135330 - }, - { - "timestamp": 1568744790, - "version": "3.1.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1567521715, - "version": "3.1.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1566446343, - "version": "3.1.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1565296576, - "version": "3.1.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.10", - "changes": [ - { - "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564607468 - }, - { - "timestamp": 1563957393, - "version": "3.1.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "3.1.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "3.1.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "3.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "3.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "3.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557799313, - "version": "3.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557507213, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553183790 - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Do not reexport external dependencies", - "pr": 1682 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "2.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "2.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "2.0.2", - "changes": [ - { - "note": "Fake publish to enable pinning" - } - ], - "timestamp": 1549504360 - }, - { - "timestamp": 1549452781, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - }, - { - "note": "Add AssetProxyOwner contract", - "pr": 1539 - }, - { - "note": "Rename multisig directory to src", - "pr": 1539 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547747677, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547561734, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547040760, - "version": "1.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1544741676, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - } -] diff --git a/contracts/multisig/CHANGELOG.md b/contracts/multisig/CHANGELOG.md deleted file mode 100644 index 0268a8f074..0000000000 --- a/contracts/multisig/CHANGELOG.md +++ /dev/null @@ -1,332 +0,0 @@ - - -CHANGELOG - -## v4.1.38 - _August 16, 2021_ - - * Dependencies updated - -## v4.1.37 - _August 11, 2021_ - - * Dependencies updated - -## v4.1.36 - _August 6, 2021_ - - * Dependencies updated - -## v4.1.35 - _June 22, 2021_ - - * Dependencies updated - -## v4.1.34 - _June 11, 2021_ - - * Dependencies updated - -## v4.1.33 - _June 2, 2021_ - - * Dependencies updated - -## v4.1.32 - _May 25, 2021_ - - * Dependencies updated - -## v4.1.31 - _May 21, 2021_ - - * Dependencies updated - -## v4.1.30 - _May 5, 2021_ - - * Dependencies updated - -## v4.1.29 - _April 28, 2021_ - - * Dependencies updated - -## v4.1.28 - _April 1, 2021_ - - * Dependencies updated - -## v4.1.27 - _March 17, 2021_ - - * Dependencies updated - -## v4.1.26 - _February 24, 2021_ - - * Dependencies updated - -## v4.1.25 - _February 10, 2021_ - - * Dependencies updated - -## v4.1.24 - _January 26, 2021_ - - * Dependencies updated - -## v4.1.23 - _January 13, 2021_ - - * Dependencies updated - -## v4.1.22 - _January 4, 2021_ - - * Dependencies updated - -## v4.1.21 - _December 23, 2020_ - - * Dependencies updated - -## v4.1.20 - _December 17, 2020_ - - * Dependencies updated - -## v4.1.19 - _December 16, 2020_ - - * Dependencies updated - -## v4.1.18 - _December 9, 2020_ - - * Dependencies updated - -## v4.1.17 - _December 7, 2020_ - - * Dependencies updated - -## v4.1.16 - _December 3, 2020_ - - * Dependencies updated - -## v4.1.15 - _November 19, 2020_ - - * Dependencies updated - -## v4.1.14 - _November 13, 2020_ - - * Dependencies updated - -## v4.1.13 - _November 3, 2020_ - - * Dependencies updated - -## v4.1.12 - _November 3, 2020_ - - * Dependencies updated - -## v4.1.11 - _November 2, 2020_ - - * Dependencies updated - -## v4.1.10 - _October 28, 2020_ - - * Dependencies updated - -## v4.1.9 - _October 27, 2020_ - - * Dependencies updated - -## v4.1.8 - _October 21, 2020_ - - * Dependencies updated - -## v4.1.7 - _July 15, 2020_ - - * Dependencies updated - -## v4.1.6 - _June 24, 2020_ - - * Dependencies updated - -## v4.1.5 - _March 3, 2020_ - - * Dependencies updated - -## v4.1.4 - _February 27, 2020_ - - * Dependencies updated - -## v4.1.3 - _February 26, 2020_ - - * Dependencies updated - -## v4.1.2 - _February 25, 2020_ - - * Dependencies updated - -## v4.1.1 - _February 15, 2020_ - - * Dependencies updated - -## v4.1.0 - _February 8, 2020_ - - * Fix broken tests (#2462) - -## v4.0.6 - _February 6, 2020_ - - * Dependencies updated - -## v4.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v4.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v4.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v4.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v4.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v4.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - -## v3.2.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v3.2.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v3.2.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - -## v3.2.0-beta.1 - _November 7, 2019_ - - * Dependencies updated - -## v3.2.0-beta.0 - _October 3, 2019_ - - * Dependencies updated - -## v3.1.14 - _September 17, 2019_ - - * Dependencies updated - -## v3.1.13 - _September 3, 2019_ - - * Dependencies updated - -## v3.1.12 - _August 22, 2019_ - - * Dependencies updated - -## v3.1.11 - _August 8, 2019_ - - * Dependencies updated - -## v3.1.10 - _July 31, 2019_ - - * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) - -## v3.1.9 - _July 24, 2019_ - - * Dependencies updated - -## v3.1.8 - _July 15, 2019_ - - * Dependencies updated - -## v3.1.7 - _July 13, 2019_ - - * Dependencies updated - -## v3.1.6 - _July 13, 2019_ - - * Dependencies updated - -## v3.1.5 - _May 24, 2019_ - - * Dependencies updated - -## v3.1.4 - _May 15, 2019_ - - * Dependencies updated - -## v3.1.3 - _May 14, 2019_ - - * Dependencies updated - -## v3.1.2 - _May 10, 2019_ - - * Dependencies updated - -## v3.1.1 - _April 11, 2019_ - - * Dependencies updated - -## v3.1.0 - _March 21, 2019_ - - * Run Web3ProviderEngine without excess block polling (#1695) - -## v3.0.0 - _March 20, 2019_ - - * Do not reexport external dependencies (#1682) - -## v2.0.8 - _March 1, 2019_ - - * Dependencies updated - -## v2.0.7 - _February 27, 2019_ - - * Dependencies updated - -## v2.0.6 - _February 26, 2019_ - - * Dependencies updated - -## v2.0.5 - _February 25, 2019_ - - * Dependencies updated - -## v2.0.4 - _February 9, 2019_ - - * Dependencies updated - -## v2.0.3 - _February 7, 2019_ - - * Dependencies updated - -## v2.0.2 - _February 7, 2019_ - - * Fake publish to enable pinning - -## v2.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v2.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - * Add AssetProxyOwner contract (#1539) - * Rename multisig directory to src (#1539) - -## v1.0.6 - _January 17, 2019_ - - * Dependencies updated - -## v1.0.5 - _January 15, 2019_ - - * Dependencies updated - -## v1.0.4 - _January 11, 2019_ - - * Dependencies updated - -## v1.0.3 - _January 9, 2019_ - - * Dependencies updated - -## v1.0.2 - _December 13, 2018_ - - * Dependencies updated diff --git a/contracts/multisig/DEPLOYS.json b/contracts/multisig/DEPLOYS.json deleted file mode 100644 index ea4e7ff89f..0000000000 --- a/contracts/multisig/DEPLOYS.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "name": "AssetProxyOwner", - "version": "1.0.0", - "changes": [ - { - "note": "protocol v2 deploy", - "networks": { - "1": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6", - "3": "0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b", - "4": "0x1da52d1d3a3acfa0a1836b737393b4e9931268fc", - "42": "0x2c824d2882baa668e0d5202b1e7f2922278703f8" - } - } - ] - } -] diff --git a/contracts/multisig/README.md b/contracts/multisig/README.md deleted file mode 100644 index c48da8b780..0000000000 --- a/contracts/multisig/README.md +++ /dev/null @@ -1,69 +0,0 @@ -## MultiSignature Contracts - -This package contains various types of multisignature wallet contracts, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that is responsible for upgrading the 0x protocol smart contracts. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package. - -## Installation - -**Install** - -```bash -npm install @0x/contracts-multisig --save -``` - -## 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=@0x/contracts-multisig yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-multisig yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` - -#### Testing options - -Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md). diff --git a/contracts/multisig/compiler.json b/contracts/multisig/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/multisig/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/multisig/contracts/src/MultiSigWallet.sol b/contracts/multisig/contracts/src/MultiSigWallet.sol deleted file mode 100644 index 69012b0b0f..0000000000 --- a/contracts/multisig/contracts/src/MultiSigWallet.sol +++ /dev/null @@ -1,462 +0,0 @@ -// solhint-disable -pragma solidity ^0.5.9; - - -/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. -/// @author Stefan George - -contract MultiSigWallet { - - /* - * Events - */ - event Confirmation(address indexed sender, uint256 indexed transactionId); - event Revocation(address indexed sender, uint256 indexed transactionId); - event Submission(uint256 indexed transactionId); - event Execution(uint256 indexed transactionId); - event ExecutionFailure(uint256 indexed transactionId); - event Deposit(address indexed sender, uint256 value); - event OwnerAddition(address indexed owner); - event OwnerRemoval(address indexed owner); - event RequirementChange(uint256 required); - - /* - * Constants - */ - uint256 constant public MAX_OWNER_COUNT = 50; - - /* - * Storage - */ - mapping (uint256 => Transaction) public transactions; - mapping (uint256 => mapping (address => bool)) public confirmations; - mapping (address => bool) public isOwner; - address[] public owners; - uint256 public required; - uint256 public transactionCount; - - struct Transaction { - address destination; - uint256 value; - bytes data; - bool executed; - } - - /* - * Modifiers - */ - modifier onlyWallet() { - require( - msg.sender == address(this), - "ONLY_CALLABLE_BY_WALLET" - ); - _; - } - - modifier ownerDoesNotExist(address owner) { - require( - !isOwner[owner], - "OWNER_EXISTS" - ); - _; - } - - modifier ownerExists(address owner) { - require( - isOwner[owner], - "OWNER_DOESNT_EXIST" - ); - _; - } - - modifier transactionExists(uint256 transactionId) { - require( - transactions[transactionId].destination != address(0), - "TX_DOESNT_EXIST" - ); - _; - } - - modifier confirmed(uint256 transactionId, address owner) { - require( - confirmations[transactionId][owner], - "TX_NOT_CONFIRMED" - ); - _; - } - - modifier notConfirmed(uint256 transactionId, address owner) { - require( - !confirmations[transactionId][owner], - "TX_ALREADY_CONFIRMED" - ); - _; - } - - modifier notExecuted(uint256 transactionId) { - require( - !transactions[transactionId].executed, - "TX_ALREADY_EXECUTED" - ); - _; - } - - modifier notNull(address _address) { - require( - _address != address(0), - "NULL_ADDRESS" - ); - _; - } - - modifier validRequirement(uint256 ownerCount, uint256 _required) { - require( - ownerCount <= MAX_OWNER_COUNT - && _required <= ownerCount - && _required != 0 - && ownerCount != 0, - "INVALID_REQUIREMENTS" - ); - _; - } - - /// @dev Fallback function allows to deposit ether. - function() - external - payable - { - if (msg.value > 0) { - emit 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. - constructor( - address[] memory _owners, - uint256 _required - ) - public - validRequirement(_owners.length, _required) - { - for (uint256 i = 0; i < _owners.length; i++) { - require( - !isOwner[_owners[i]] && _owners[i] != address(0), - "DUPLICATE_OR_NULL_OWNER" - ); - 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); - emit 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 (uint256 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); - } - emit 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 (uint256 i = 0; i < owners.length; i++) { - if (owners[i] == owner) { - owners[i] = newOwner; - break; - } - } - isOwner[owner] = false; - isOwner[newOwner] = true; - emit OwnerRemoval(owner); - emit 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(uint256 _required) - public - onlyWallet - validRequirement(owners.length, _required) - { - required = _required; - emit 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, uint256 value, bytes memory data) - public - returns (uint256 transactionId) - { - transactionId = _addTransaction(destination, value, data); - confirmTransaction(transactionId); - } - - /// @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) - { - confirmations[transactionId][msg.sender] = true; - emit Confirmation(msg.sender, transactionId); - executeTransaction(transactionId); - } - - /// @dev Allows an owner to revoke a confirmation for a transaction. - /// @param transactionId Transaction ID. - function revokeConfirmation(uint256 transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - confirmations[transactionId][msg.sender] = false; - emit Revocation(msg.sender, transactionId); - } - - /// @dev Allows anyone to execute a confirmed transaction. - /// @param transactionId Transaction ID. - function executeTransaction(uint256 transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - { - if (isConfirmed(transactionId)) { - Transaction storage txn = transactions[transactionId]; - txn.executed = true; - if ( - _externalCall( - txn.destination, - txn.value, - txn.data.length, - txn.data - ) - ) { - emit Execution(transactionId); - } else { - emit 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 _externalCall( - address destination, - uint256 value, - uint256 dataLength, - bytes memory 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(uint256 transactionId) - public - view - returns (bool) - { - uint256 count = 0; - for (uint256 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, - uint256 value, - bytes memory data - ) - internal - notNull(destination) - returns (uint256 transactionId) - { - transactionId = transactionCount; - transactions[transactionId] = Transaction({ - destination: destination, - value: value, - data: data, - executed: false - }); - transactionCount += 1; - emit Submission(transactionId); - } - - /* - * Web3 call functions - */ - /// @dev Returns number of confirmations of a transaction. - /// @param transactionId Transaction ID. - /// @return Number of confirmations. - function getConfirmationCount(uint256 transactionId) - public - view - returns (uint256 count) - { - for (uint256 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 - view - returns (uint256 count) - { - for (uint256 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 - view - returns (address[] memory) - { - return owners; - } - - /// @dev Returns array with owner addresses, which confirmed transaction. - /// @param transactionId Transaction ID. - /// @return Returns array of owner addresses. - function getConfirmations(uint256 transactionId) - public - view - returns (address[] memory _confirmations) - { - address[] memory confirmationsTemp = new address[](owners.length); - uint256 count = 0; - uint256 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( - uint256 from, - uint256 to, - bool pending, - bool executed - ) - public - view - returns (uint256[] memory _transactionIds) - { - uint256[] memory transactionIdsTemp = new uint256[](transactionCount); - uint256 count = 0; - uint256 i; - for (i = 0; i < transactionCount; i++) { - if (pending && !transactions[i].executed || executed && transactions[i].executed) { - transactionIdsTemp[count] = i; - count += 1; - } - } - _transactionIds = new uint256[](to - from); - for (i = from; i < to; i++) { - _transactionIds[i - from] = transactionIdsTemp[i]; - } - } -} diff --git a/contracts/multisig/contracts/src/MultiSigWalletWithTimeLock.sol b/contracts/multisig/contracts/src/MultiSigWalletWithTimeLock.sol deleted file mode 100644 index 22d41fb8e3..0000000000 --- a/contracts/multisig/contracts/src/MultiSigWalletWithTimeLock.sol +++ /dev/null @@ -1,124 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -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 - -// solhint-disable not-rely-on-time -contract MultiSigWalletWithTimeLock is - MultiSigWallet -{ - using LibSafeMath for uint256; - - event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime); - event TimeLockChange(uint256 secondsTimeLocked); - - uint256 public secondsTimeLocked; - - mapping (uint256 => uint256) public confirmationTimes; - - modifier fullyConfirmed(uint256 transactionId) { - require( - isConfirmed(transactionId), - "TX_NOT_FULLY_CONFIRMED" - ); - _; - } - - modifier pastTimeLock(uint256 transactionId) { - require( - block.timestamp >= confirmationTimes[transactionId].safeAdd(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[] memory _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) - { - bool isTxFullyConfirmedBeforeConfirmation = isConfirmed(transactionId); - - confirmations[transactionId][msg.sender] = true; - emit Confirmation(msg.sender, transactionId); - - if (!isTxFullyConfirmedBeforeConfirmation && 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 (_externalCall(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/contracts/multisig/contracts/src/ZeroExGovernor.sol b/contracts/multisig/contracts/src/ZeroExGovernor.sol deleted file mode 100644 index b4f1d137bc..0000000000 --- a/contracts/multisig/contracts/src/ZeroExGovernor.sol +++ /dev/null @@ -1,220 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./MultiSigWalletWithTimeLock.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; - - -contract ZeroExGovernor is - MultiSigWalletWithTimeLock -{ - using LibBytes for bytes; - using LibSafeMath for uint256; - - struct TimeLock { - bool hasCustomTimeLock; - uint128 secondsTimeLocked; - } - - event FunctionCallTimeLockRegistration( - bytes4 functionSelector, - address destination, - bool hasCustomTimeLock, - uint128 newSecondsTimeLocked - ); - - // Function selector => destination => seconds timelocked - mapping (bytes4 => mapping (address => TimeLock)) public functionCallTimeLocks; - - /// @dev Contract constructor sets initial owners, required number of confirmations, and default time lock - /// It will also register unique timelocks for each passed in function selector / destination combo. - /// @param _functionSelectors Array of function selectors for registered functions. - /// @param _destinations Array of destinations for registered function calls. - /// @param _functionCallTimeLockSeconds Array of seconds that each registered function call will be timelocked. - /// @param _owners List of initial owners. - /// @param _required Number of required confirmations. - /// @param _defaultSecondsTimeLocked Default duration in seconds needed after a transaction is confirmed to become executable. - constructor ( - bytes4[] memory _functionSelectors, - address[] memory _destinations, - uint128[] memory _functionCallTimeLockSeconds, - address[] memory _owners, - uint256 _required, - uint256 _defaultSecondsTimeLocked - ) - public - MultiSigWalletWithTimeLock( - _owners, - _required, - _defaultSecondsTimeLocked - ) - { - uint256 length = _functionSelectors.length; - require( - length == _destinations.length && length == _functionCallTimeLockSeconds.length, - "EQUAL_LENGTHS_REQUIRED" - ); - - // Register function timelocks - for (uint256 i = 0; i != length; i++) { - _registerFunctionCall( - true, // all functions registered in constructor are assumed to have a custom timelock - _functionSelectors[i], - _destinations[i], - _functionCallTimeLockSeconds[i] - ); - } - } - - /// @dev Registers a custom timelock to a specific function selector / destination combo - /// @param hasCustomTimeLock True if timelock is custom. - /// @param functionSelector 4 byte selector of registered function. - /// @param destination Address of destination where function will be called. - /// @param newSecondsTimeLocked Duration in seconds needed after a transaction is confirmed to become executable. - function registerFunctionCall( - bool hasCustomTimeLock, - bytes4 functionSelector, - address destination, - uint128 newSecondsTimeLocked - ) - external - onlyWallet - { - _registerFunctionCall( - hasCustomTimeLock, - functionSelector, - destination, - newSecondsTimeLocked - ); - } - - /// @dev Allows anyone to execute a confirmed transaction. - /// Transactions *must* encode the values with the signature "bytes[] data, address[] destinations, uint256[] values" - /// The `destination` and `value` fields of the transaction in storage are ignored. - /// All function calls must be successful or the entire call will revert. - /// @param transactionId Transaction ID. - function executeTransaction(uint256 transactionId) - public - notExecuted(transactionId) - fullyConfirmed(transactionId) - { - Transaction storage transaction = transactions[transactionId]; - transaction.executed = true; - - // Decode batch transaction data from transaction.data - // `destination` and `value` fields of transaction are ignored - // Note that `destination` must be non-0, or the transaction cannot be submitted - // solhint-disable - ( - bytes[] memory data, - address[] memory destinations, - uint256[] memory values - ) = abi.decode( - transaction.data, - (bytes[], address[], uint256[]) - ); - // solhint-enable - - // Ensure lengths of array properties are equal - uint256 length = data.length; - require( - length == destinations.length && length == values.length, - "EQUAL_LENGTHS_REQUIRED" - ); - - uint256 transactionConfirmationTime = confirmationTimes[transactionId]; - for (uint i = 0; i != length; i++) { - // Ensure that each function call is past its timelock - _assertValidFunctionCall( - transactionConfirmationTime, - data[i], - destinations[i] - ); - // Call each function - // solhint-disable-next-line avoid-call-value - (bool didSucceed,) = destinations[i].call.value(values[i])(data[i]); - // Ensure that function call was successful - require( - didSucceed, - "FAILED_EXECUTION" - ); - } - emit Execution(transactionId); - } - - /// @dev Registers a custom timelock to a specific function selector / destination combo - /// @param hasCustomTimeLock True if timelock is custom. - /// @param functionSelector 4 byte selector of registered function. - /// @param destination Address of destination where function will be called. - /// @param newSecondsTimeLocked Duration in seconds needed after a transaction is confirmed to become executable. - function _registerFunctionCall( - bool hasCustomTimeLock, - bytes4 functionSelector, - address destination, - uint128 newSecondsTimeLocked - ) - internal - { - // Clear the previous secondsTimeLocked if custom timelock not used - uint128 _secondsTimeLocked = hasCustomTimeLock ? newSecondsTimeLocked : 0; - TimeLock memory timeLock = TimeLock({ - hasCustomTimeLock: hasCustomTimeLock, - secondsTimeLocked: _secondsTimeLocked - }); - functionCallTimeLocks[functionSelector][destination] = timeLock; - emit FunctionCallTimeLockRegistration( - functionSelector, - destination, - hasCustomTimeLock, - _secondsTimeLocked - ); - } - - /// @dev Ensures that the function call has past its timelock. - /// @param transactionConfirmationTime Timestamp at which transaction was fully confirmed. - /// @param data Function calldata. - /// @param destination Address to call function on. - function _assertValidFunctionCall( - uint256 transactionConfirmationTime, - bytes memory data, - address destination - ) - internal - view - { - bytes4 functionSelector = data.readBytes4(0); - TimeLock memory timeLock = functionCallTimeLocks[functionSelector][destination]; - // solhint-disable not-rely-on-time - if (timeLock.hasCustomTimeLock) { - require( - block.timestamp >= transactionConfirmationTime.safeAdd(timeLock.secondsTimeLocked), - "CUSTOM_TIME_LOCK_INCOMPLETE" - ); - } else { - require( - block.timestamp >= transactionConfirmationTime.safeAdd(secondsTimeLocked), - "DEFAULT_TIME_LOCK_INCOMPLETE" - ); - } - // solhint-enable not-rely-on-time - } -} diff --git a/contracts/multisig/contracts/test/ContractCallReceiver.sol b/contracts/multisig/contracts/test/ContractCallReceiver.sol deleted file mode 100644 index a3505e543c..0000000000 --- a/contracts/multisig/contracts/test/ContractCallReceiver.sol +++ /dev/null @@ -1,51 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; - - -contract ContractCallReceiver { - - using LibBytes for bytes; - - event ContractCall( - bytes4 functionSelector, - bytes data, - uint256 value - ); - - bytes4 constant internal ALWAYS_REVERT_SELECTOR = 0xF1F2F3F4; - - function () - external - payable - { - bytes4 selector = msg.data.readBytes4(0); - if (selector == ALWAYS_REVERT_SELECTOR) { - revert(); - } - - emit ContractCall( - selector, - msg.data, - msg.value - ); - } -} \ No newline at end of file diff --git a/contracts/multisig/contracts/test/TestRejectEther.sol b/contracts/multisig/contracts/test/TestRejectEther.sol deleted file mode 100644 index 7df961c20d..0000000000 --- a/contracts/multisig/contracts/test/TestRejectEther.sol +++ /dev/null @@ -1,23 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -// solhint-disable no-empty-blocks -contract TestRejectEther {} diff --git a/contracts/multisig/contracts/test/TestZeroExGovernor.sol b/contracts/multisig/contracts/test/TestZeroExGovernor.sol deleted file mode 100644 index 4504098fde..0000000000 --- a/contracts/multisig/contracts/test/TestZeroExGovernor.sol +++ /dev/null @@ -1,78 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/ZeroExGovernor.sol"; - - -// solhint-disable no-empty-blocks -contract TestZeroExGovernor is - ZeroExGovernor -{ - constructor ( - bytes4[] memory _functionSelectors, - address[] memory _destinations, - uint128[] memory _functionCallTimeLockSeconds, - address[] memory _owners, - uint256 _required, - uint256 _defaultSecondsTimeLocked - ) - public - ZeroExGovernor( - _functionSelectors, - _destinations, - _functionCallTimeLockSeconds, - _owners, - _required, - _defaultSecondsTimeLocked - ) - {} - - function registerFunctionCallBypassWallet( - bool hasCustomTimeLock, - bytes4 functionSelector, - address destination, - uint128 newSecondsTimeLocked - ) - external - { - _registerFunctionCall( - hasCustomTimeLock, - functionSelector, - destination, - newSecondsTimeLocked - ); - } - - function assertValidFunctionCall( - uint256 transactionConfirmationTime, - bytes calldata data, - address destination - ) - external - view - { - _assertValidFunctionCall( - transactionConfirmationTime, - data, - destination - ); - } -} diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json deleted file mode 100644 index f575aaef53..0000000000 --- a/contracts/multisig/package.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "@0x/contracts-multisig", - "version": "4.1.38", - "engines": { - "node": ">=6.12" - }, - "description": "Multisig contracts used by 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 contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" - }, - "config": { - "publicInterfaceContracts": "MultiSigWalletWithTimeLock,ZeroExGovernor", - "abis": "./test/generated-artifacts/@(ContractCallReceiver|MultiSigWallet|MultiSigWalletWithTimeLock|TestRejectEther|TestZeroExGovernor|ZeroExGovernor).json", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/sol-compiler": "^4.7.3", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "tslint": "5.11.0", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/typescript-typings": "^5.2.0", - "ethereum-types": "^3.5.0" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/multisig/src/artifacts.ts b/contracts/multisig/src/artifacts.ts deleted file mode 100644 index b9f2145823..0000000000 --- a/contracts/multisig/src/artifacts.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as MultiSigWalletWithTimeLock from '../generated-artifacts/MultiSigWalletWithTimeLock.json'; -import * as ZeroExGovernor from '../generated-artifacts/ZeroExGovernor.json'; -export const artifacts = { - MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact, - ZeroExGovernor: ZeroExGovernor as ContractArtifact, -}; diff --git a/contracts/multisig/src/index.ts b/contracts/multisig/src/index.ts deleted file mode 100644 index cb85aa0d18..0000000000 --- a/contracts/multisig/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { artifacts } from './artifacts'; -export * from './wrappers'; diff --git a/contracts/multisig/src/wrappers.ts b/contracts/multisig/src/wrappers.ts deleted file mode 100644 index e4ae7b41c1..0000000000 --- a/contracts/multisig/src/wrappers.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/multi_sig_wallet_with_time_lock'; -export * from '../generated-wrappers/zero_ex_governor'; diff --git a/contracts/multisig/test/artifacts.ts b/contracts/multisig/test/artifacts.ts deleted file mode 100644 index 35da180f3a..0000000000 --- a/contracts/multisig/test/artifacts.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as ContractCallReceiver from '../test/generated-artifacts/ContractCallReceiver.json'; -import * as MultiSigWallet from '../test/generated-artifacts/MultiSigWallet.json'; -import * as MultiSigWalletWithTimeLock from '../test/generated-artifacts/MultiSigWalletWithTimeLock.json'; -import * as TestRejectEther from '../test/generated-artifacts/TestRejectEther.json'; -import * as TestZeroExGovernor from '../test/generated-artifacts/TestZeroExGovernor.json'; -import * as ZeroExGovernor from '../test/generated-artifacts/ZeroExGovernor.json'; -export const artifacts = { - MultiSigWallet: MultiSigWallet as ContractArtifact, - MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact, - ZeroExGovernor: ZeroExGovernor as ContractArtifact, - ContractCallReceiver: ContractCallReceiver as ContractArtifact, - TestRejectEther: TestRejectEther as ContractArtifact, - TestZeroExGovernor: TestZeroExGovernor as ContractArtifact, -}; diff --git a/contracts/multisig/test/global_hooks.ts b/contracts/multisig/test/global_hooks.ts deleted file mode 100644 index 12b942e07a..0000000000 --- a/contracts/multisig/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { env, EnvVars } from '@0x/dev-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); - -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(); - } - provider.stop(); -}); diff --git a/contracts/multisig/test/multi_sig_with_time_lock.ts b/contracts/multisig/test/multi_sig_with_time_lock.ts deleted file mode 100644 index dd8bebf4f9..0000000000 --- a/contracts/multisig/test/multi_sig_with_time_lock.ts +++ /dev/null @@ -1,324 +0,0 @@ -import { blockchainTests, constants, expect, increaseTimeAndMineBlockAsync } from '@0x/contracts-test-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { - MultiSigWalletWithTimeLockConfirmationEventArgs, - MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs, - MultiSigWalletWithTimeLockContract, - MultiSigWalletWithTimeLockExecutionEventArgs, - MultiSigWalletWithTimeLockExecutionFailureEventArgs, - MultiSigWalletWithTimeLockSubmissionEventArgs, - TestRejectEtherContract, -} from './wrappers'; - -import { MultiSigWrapper } from './utils/multi_sig_wrapper'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('MultiSigWalletWithTimeLock', env => { - let owners: string[]; - let notOwner: string; - const REQUIRED_APPROVALS = new BigNumber(2); - const SECONDS_TIME_LOCKED = new BigNumber(1000000); - - before(async () => { - const accounts = await env.getAccountAddressesAsync(); - owners = [accounts[0], accounts[1], accounts[2]]; - notOwner = accounts[3]; - }); - - let multiSig: MultiSigWalletWithTimeLockContract; - let multiSigWrapper: MultiSigWrapper; - - describe('external_call', () => { - it('should be internal', async () => { - const secondsTimeLocked = new BigNumber(0); - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - env.provider, - env.txDefaults, - artifacts, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - expect((multiSig as any).external_call === undefined).to.be.equal(true); - }); - }); - describe('confirmTransaction', () => { - let txId: BigNumber; - beforeEach(async () => { - const secondsTimeLocked = new BigNumber(0); - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - env.provider, - env.txDefaults, - artifacts, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, env.provider); - const destination = notOwner; - const data = constants.NULL_BYTES; - const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]); - txId = (txReceipt.logs[0] as LogWithDecodedArgs).args - .transactionId; - }); - it('should revert if called by a non-owner', async () => { - return expect(multiSigWrapper.confirmTransactionAsync(txId, notOwner)).to.revertWith('OWNER_DOESNT_EXIST'); - }); - it('should revert if transaction does not exist', async () => { - const nonexistentTxId = new BigNumber(123456789); - return expect(multiSigWrapper.confirmTransactionAsync(nonexistentTxId, owners[1])).to.revertWith( - 'TX_DOESNT_EXIST', - ); - }); - it('should revert if transaction is already confirmed by caller', async () => { - return expect(multiSigWrapper.confirmTransactionAsync(txId, owners[0])).to.revertWith( - 'TX_ALREADY_CONFIRMED', - ); - }); - it('should confirm transaction for caller and log a Confirmation event', async () => { - const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - expect(txReceipt.logs.length).to.equal(2); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - 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 set the confirmation time of the transaction if it becomes fully confirmed', async () => { - const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - expect(txReceipt.logs.length).to.equal(2); - const blockNum = await env.web3Wrapper.getBlockNumberAsync(); - const timestamp = new BigNumber(await env.web3Wrapper.getBlockTimestampAsync(blockNum)); - const log = txReceipt.logs[1] as LogWithDecodedArgs; - expect(log.args.confirmationTime).to.be.bignumber.equal(timestamp); - expect(log.args.transactionId).to.be.bignumber.equal(txId); - }); - it('should confirm transaction for caller but not reset the confirmation time if tx is already fully confirmed', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - const confirmationTimeBefore = await multiSig.confirmationTimes(txId).callAsync(); - const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[2]); - const confirmationTimeAfter = await multiSig.confirmationTimes(txId).callAsync(); - expect(confirmationTimeBefore).to.bignumber.equal(confirmationTimeAfter); - expect(txReceipt.logs.length).to.equal(1); - const log = txReceipt.logs[0] as LogWithDecodedArgs; - expect(log.event).to.be.equal('Confirmation'); - expect(log.args.sender).to.be.equal(owners[2]); - 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, - env.provider, - env.txDefaults, - artifacts, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, env.provider); - const destination = notOwner; - const data = constants.NULL_BYTES; - const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]); - txId = (txReceipt.logs[0] as LogWithDecodedArgs).args - .transactionId; - }); - it('should revert if transaction has not been fully confirmed', async () => { - await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber()); - return expect(multiSigWrapper.executeTransactionAsync(txId, owners[1])).to.revertWith( - RevertReason.TxNotFullyConfirmed, - ); - }); - it('should revert if time lock has not passed', async () => { - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - expect(multiSigWrapper.executeTransactionAsync(txId, owners[1])).to.revertWith( - 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; - 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; - 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]); - return expect(multiSigWrapper.executeTransactionAsync(txId, owners[1])).to.revertWith( - 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; - expect(log.args.transactionId).to.be.bignumber.equal(txId); - return expect(multiSigWrapper.executeTransactionAsync(txId, owners[1])).to.revertWith( - 'TX_ALREADY_EXECUTED', - ); - }); - it("should log an ExecutionFailure event and not update the transaction's execution state if unsuccessful", async () => { - const contractWithoutFallback = await TestRejectEtherContract.deployFrom0xArtifactAsync( - artifacts.TestRejectEther, - env.provider, - env.txDefaults, - artifacts, - ); - 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('deploy a wallet', async () => { - const secondsTimeLocked = new BigNumber(0); - multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync( - artifacts.MultiSigWalletWithTimeLock, - env.provider, - env.txDefaults, - artifacts, - owners, - REQUIRED_APPROVALS, - secondsTimeLocked, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, env.provider); - }); - - it('should revert when not called by wallet', async () => { - return expect( - multiSig.changeTimeLock(SECONDS_TIME_LOCKED).sendTransactionAsync({ from: owners[0] }), - ).to.revertWith('ONLY_CALLABLE_BY_WALLET'); - }); - - it('should revert without enough confirmations', async () => { - const destination = multiSig.address; - const changeTimeLockData = multiSig.changeTimeLock(SECONDS_TIME_LOCKED).getABIEncodedTransactionData(); - const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); - const log = res.logs[0] as LogWithDecodedArgs; - const txId = log.args.transactionId; - return expect( - multiSig.executeTransaction(txId).sendTransactionAsync({ from: owners[0] }), - ).to.revertWith(RevertReason.TxNotFullyConfirmed); - }); - - it('should set confirmation time with enough confirmations', async () => { - const destination = multiSig.address; - const changeTimeLockData = multiSig.changeTimeLock(SECONDS_TIME_LOCKED).getABIEncodedTransactionData(); - const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); - const subLog = subRes.logs[0] as LogWithDecodedArgs; - const txId = subLog.args.transactionId; - - const confirmRes = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - expect(confirmRes.logs).to.have.length(2); - - const blockNum = await env.web3Wrapper.getBlockNumberAsync(); - const blockInfo = await env.web3Wrapper.getBlockIfExistsAsync(blockNum); - if (blockInfo === undefined) { - throw new Error(`Unexpectedly failed to fetch block at #${blockNum}`); - } - const timestamp = new BigNumber(blockInfo.timestamp); - const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes(txId).callAsync()); - - 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(SECONDS_TIME_LOCKED).getABIEncodedTransactionData(); - const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]); - const subLog = subRes.logs[0] as LogWithDecodedArgs; - 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 () => { - 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, - env.provider, - env.txDefaults, - artifacts, - owners, - REQUIRED_APPROVALS, - SECONDS_TIME_LOCKED, - ); - multiSigWrapper = new MultiSigWrapper(multiSig, env.provider); - - const changeTimeLockData = multiSig.changeTimeLock(newSecondsTimeLocked).getABIEncodedTransactionData(); - const res = await multiSigWrapper.submitTransactionAsync( - multiSig.address, - changeTimeLockData, - owners[0], - ); - const log = res.logs[0] as LogWithDecodedArgs; - txId = log.args.transactionId; - await multiSigWrapper.confirmTransactionAsync(txId, owners[1]); - }); - - it('should revert if it has enough confirmations but is not past the time lock', async () => { - return expect( - multiSig.executeTransaction(txId).sendTransactionAsync({ from: owners[0] }), - ).to.revertWith(RevertReason.TimeLockIncomplete); - }); - - it('should execute if it has enough confirmations and is past the time lock', async () => { - await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber()); - await multiSig - .executeTransaction(txId) - .awaitTransactionSuccessAsync( - { from: owners[0] }, - { pollingIntervalMs: 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/contracts/multisig/test/utils/index.ts b/contracts/multisig/test/utils/index.ts deleted file mode 100644 index 7ecfd79e74..0000000000 --- a/contracts/multisig/test/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './multi_sig_wrapper'; -export * from './zero_ex_governor_wrapper'; diff --git a/contracts/multisig/test/utils/multi_sig_wrapper.ts b/contracts/multisig/test/utils/multi_sig_wrapper.ts deleted file mode 100644 index 2912b09b98..0000000000 --- a/contracts/multisig/test/utils/multi_sig_wrapper.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { LogDecoder, Web3ProviderEngine } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { artifacts } from '../artifacts'; -import { MultiSigWalletContract, MultiSigWalletWithTimeLockContract } from '../wrappers'; - -export class MultiSigWrapper { - private readonly _multiSig: MultiSigWalletContract | MultiSigWalletWithTimeLockContract; - private readonly _web3Wrapper: Web3Wrapper; - private readonly _logDecoder: LogDecoder; - constructor( - multiSigContract: MultiSigWalletContract | MultiSigWalletWithTimeLockContract, - provider: Web3ProviderEngine, - ) { - this._multiSig = multiSigContract; - this._web3Wrapper = new Web3Wrapper(provider); - this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); - } - public async submitTransactionAsync( - destination: string, - data: string, - from: string, - opts: { value?: BigNumber } = {}, - ): Promise { - const value = opts.value === undefined ? new BigNumber(0) : opts.value; - const txHash = await this._multiSig.submitTransaction(destination, value, data).sendTransactionAsync({ - from, - }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async confirmTransactionAsync(txId: BigNumber, from: string): Promise { - const txHash = await this._multiSig.confirmTransaction(txId).sendTransactionAsync({ from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async revokeConfirmationAsync(txId: BigNumber, from: string): Promise { - const txHash = await this._multiSig.revokeConfirmation(txId).sendTransactionAsync({ from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } - public async executeTransactionAsync( - txId: BigNumber, - from: string, - opts: { gas?: number } = {}, - ): Promise { - const txHash = await this._multiSig.executeTransaction(txId).sendTransactionAsync({ - from, - gas: opts.gas, - }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; - } -} diff --git a/contracts/multisig/test/utils/zero_ex_governor_wrapper.ts b/contracts/multisig/test/utils/zero_ex_governor_wrapper.ts deleted file mode 100644 index 9209c75b15..0000000000 --- a/contracts/multisig/test/utils/zero_ex_governor_wrapper.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { constants, increaseTimeAndMineBlockAsync } from '@0x/contracts-test-utils'; -import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils'; -import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { TestZeroExGovernorContract, ZeroExGovernorContract, ZeroExGovernorSubmissionEventArgs } from '../wrappers'; - -// tslint:disable: no-unnecessary-type-assertion -export class ZeroExGovernorWrapper { - private readonly _governor: ZeroExGovernorContract | TestZeroExGovernorContract; - constructor(assetproxyOwnerContract: ZeroExGovernorContract | TestZeroExGovernorContract) { - this._governor = assetproxyOwnerContract; - } - public async submitTransactionAsync( - data: string[], - destinations: string[], - from: string, - opts: { values?: BigNumber[] } = {}, - ): Promise<{ txReceipt: TransactionReceiptWithDecodedLogs; txId: BigNumber }> { - const values = opts.values === undefined ? data.map(() => constants.ZERO_AMOUNT) : opts.values; - const batchTransactionEncoder = AbiEncoder.create('(bytes[],address[],uint256[])'); - const batchTransactionData = batchTransactionEncoder.encode([data, destinations, values]); - const txReceipt = await this._governor - .submitTransaction( - hexUtils.random(20), // submitTransaction will fail if this is a null address - constants.ZERO_AMOUNT, - batchTransactionData, - ) - .awaitTransactionSuccessAsync({ from }); - const txId = (txReceipt.logs[0] as LogWithDecodedArgs).args.transactionId; - return { txReceipt, txId }; - } - public async submitConfirmAndExecuteTransactionAsync( - data: string[], - destinations: string[], - signerAddresses: string[], - increaseTimeSeconds: number, - opts: { values?: BigNumber[]; executeFromAddress?: string; requiredSignatures?: number } = {}, - ): Promise<{ executionTxReceipt: TransactionReceiptWithDecodedLogs; txId: BigNumber }> { - const submitResults = await this.submitTransactionAsync(data, destinations, signerAddresses[0], opts); - const requiredSignatures = opts.requiredSignatures === undefined ? 2 : opts.requiredSignatures; - for (const index of _.range(1, requiredSignatures)) { - await this._governor.confirmTransaction(submitResults.txId).awaitTransactionSuccessAsync({ - from: signerAddresses[index], - }); - } - await increaseTimeAndMineBlockAsync(increaseTimeSeconds); - const executionTxReceipt = await this._governor - .executeTransaction(submitResults.txId) - .awaitTransactionSuccessAsync({ - from: opts.executeFromAddress === undefined ? signerAddresses[0] : opts.executeFromAddress, - }); - return { executionTxReceipt, txId: submitResults.txId }; - } -} diff --git a/contracts/multisig/test/wrappers.ts b/contracts/multisig/test/wrappers.ts deleted file mode 100644 index 199d7c282f..0000000000 --- a/contracts/multisig/test/wrappers.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/contract_call_receiver'; -export * from '../test/generated-wrappers/multi_sig_wallet'; -export * from '../test/generated-wrappers/multi_sig_wallet_with_time_lock'; -export * from '../test/generated-wrappers/test_reject_ether'; -export * from '../test/generated-wrappers/test_zero_ex_governor'; -export * from '../test/generated-wrappers/zero_ex_governor'; diff --git a/contracts/multisig/test/zero_ex_governor.ts b/contracts/multisig/test/zero_ex_governor.ts deleted file mode 100644 index 1dbc71ab5d..0000000000 --- a/contracts/multisig/test/zero_ex_governor.ts +++ /dev/null @@ -1,671 +0,0 @@ -import { blockchainTests, constants, expect, getLatestBlockTimestampAsync } from '@0x/contracts-test-utils'; -import { LibBytesRevertErrors } from '@0x/contracts-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { LogEntry, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { ZeroExGovernorWrapper } from './utils/zero_ex_governor_wrapper'; - -import { artifacts } from './artifacts'; -import { - ContractCallReceiverContract, - ContractCallReceiverEventArgs, - TestZeroExGovernorContract, - ZeroExGovernorExecutionEventArgs, - ZeroExGovernorFunctionCallTimeLockRegistrationEventArgs, -} from './wrappers'; - -// tslint:disable: no-unnecessary-type-assertion -blockchainTests.resets('ZeroExGovernor', env => { - let governor: TestZeroExGovernorContract; - let governorWrapper: ZeroExGovernorWrapper; - let receiver: ContractCallReceiverContract; - let signerAddresses: string[]; - let notSignerAddress: string; - - const TOTAL_SIGNERS = 3; - const REQUIRED_SIGNERS = 2; - const DEFAULT_TIME_LOCK = 1000; - const INITIAL_BALANCE = new BigNumber(1000); - - before(async () => { - const accounts = await env.web3Wrapper.getAvailableAddressesAsync(); - signerAddresses = accounts.slice(0, TOTAL_SIGNERS); - notSignerAddress = accounts[TOTAL_SIGNERS]; - governor = await TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - [], - [], - [], - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - await env.web3Wrapper.awaitTransactionMinedAsync( - await env.web3Wrapper.sendTransactionAsync({ - from: signerAddresses[0], - to: governor.address, - value: INITIAL_BALANCE, - }), - ); - governorWrapper = new ZeroExGovernorWrapper(governor); - receiver = await ContractCallReceiverContract.deployFrom0xArtifactAsync( - artifacts.ContractCallReceiver, - env.provider, - env.txDefaults, - {}, - ); - }); - - function createFunctionRegistration( - functionSelectorLength: number = 0, - destinationsLength?: number, - functionCallTimeLockSecondsLength?: number, - ): { functionSelectors: string[]; destinations: string[]; functionCallTimeLockSeconds: BigNumber[] } { - const _destinationsLength = destinationsLength === undefined ? functionSelectorLength : destinationsLength; - const _functionCallTimeLockSecondsLength = - functionCallTimeLockSecondsLength === undefined - ? functionSelectorLength - : functionCallTimeLockSecondsLength; - const functionSelectors = _.times(functionSelectorLength, () => hexUtils.random(4)); - const destinations = _.times(_destinationsLength, () => hexUtils.random(20)); - const functionCallTimeLockSeconds = _.times(_functionCallTimeLockSecondsLength, () => - BigNumber.random() // random int > 0 and < 1000 - .times(10000000) - .integerValue() - .mod(1000), - ); - return { functionSelectors, destinations, functionCallTimeLockSeconds }; - } - blockchainTests.resets('constructor', () => { - it('should fail if destinations.length != functionSelectors.length', async () => { - const reg = createFunctionRegistration(1, 2, 1); - const tx = TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - reg.functionSelectors, - reg.destinations, - reg.functionCallTimeLockSeconds, - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - await expect(tx).to.revertWith(RevertReason.EqualLengthsRequired); - }); - it('should fail if functionCallTimeLockSeconds.length != functionSelectors.length', async () => { - const reg = createFunctionRegistration(1, 1, 2); - const tx = TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - reg.functionSelectors, - reg.destinations, - reg.functionCallTimeLockSeconds, - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - await expect(tx).to.revertWith(RevertReason.EqualLengthsRequired); - }); - it('should fail if functionCallTimeLockSeconds.length != destinations.length', async () => { - const reg = createFunctionRegistration(2, 1, 1); - const tx = TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - reg.functionSelectors, - reg.destinations, - reg.functionCallTimeLockSeconds, - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - await expect(tx).to.revertWith(RevertReason.EqualLengthsRequired); - }); - it('should allow no function calls to be registered', async () => { - const tx = TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - [], - [], - [], - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - expect(tx).to.be.fulfilled(''); - }); - it('should register a single functon call', async () => { - const reg = createFunctionRegistration(1, 1, 1); - const governorContract = await TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - reg.functionSelectors, - reg.destinations, - reg.functionCallTimeLockSeconds, - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - const timelock = await governorContract - .functionCallTimeLocks(reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(timelock[0]).to.equal(true); - expect(timelock[1]).to.bignumber.equal(reg.functionCallTimeLockSeconds[0]); - }); - it('should register multiple function calls', async () => { - const reg = createFunctionRegistration(2, 2, 2); - const governorContract = await TestZeroExGovernorContract.deployFrom0xArtifactAsync( - artifacts.TestZeroExGovernor, - env.provider, - env.txDefaults, - artifacts, - reg.functionSelectors, - reg.destinations, - reg.functionCallTimeLockSeconds, - signerAddresses, - new BigNumber(REQUIRED_SIGNERS), - new BigNumber(DEFAULT_TIME_LOCK), - ); - for (const [index, selector] of reg.functionSelectors.entries()) { - const timelock = await governorContract - .functionCallTimeLocks(selector, reg.destinations[index]) - .callAsync(); - expect(timelock[0]).to.equal(true); - expect(timelock[1]).to.bignumber.equal(reg.functionCallTimeLockSeconds[index]); - } - }); - }); - - blockchainTests.resets('registerFunctionCall', () => { - it('should revert if not called by wallet', async () => { - const reg = createFunctionRegistration(1, 1, 1); - const tx = governor - .registerFunctionCall( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync({ from: signerAddresses[0] }); - expect(tx).to.revertWith(RevertReason.OnlyCallableByWallet); - }); - it('should register a function call', async () => { - const reg = createFunctionRegistration(1, 1, 1); - const txReceipt = await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync(); - expect(txReceipt.logs.length).to.eq(1); - const logArgs = (txReceipt.logs[0] as LogWithDecodedArgs< - ZeroExGovernorFunctionCallTimeLockRegistrationEventArgs - >).args; - expect(logArgs.functionSelector).to.eq(reg.functionSelectors[0]); - expect(logArgs.destination).to.eq(reg.destinations[0]); - expect(logArgs.hasCustomTimeLock).to.eq(true); - expect(logArgs.newSecondsTimeLocked).to.bignumber.eq(reg.functionCallTimeLockSeconds[0]); - const timelock = await governor - .functionCallTimeLocks(reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(timelock[0]).to.equal(true); - expect(timelock[1]).to.bignumber.equal(reg.functionCallTimeLockSeconds[0]); - }); - it('should be able to overwrite existing function calls', async () => { - const reg = createFunctionRegistration(1, 1, 1); - await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync(); - const newTimeLock = reg.functionCallTimeLockSeconds[0].plus(1000); - await governor - .registerFunctionCallBypassWallet(true, reg.functionSelectors[0], reg.destinations[0], newTimeLock) - .awaitTransactionSuccessAsync(); - const timelock = await governor - .functionCallTimeLocks(reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(timelock[0]).to.equal(true); - expect(timelock[1]).to.bignumber.equal(newTimeLock); - }); - it('should clear the function timelock if hasCustomTimeLock is set to false', async () => { - const reg = createFunctionRegistration(1, 1, 1); - await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync(); - await governor - .registerFunctionCallBypassWallet( - false, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync(); - const timelock = await governor - .functionCallTimeLocks(reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(timelock[0]).to.equal(false); - expect(timelock[1]).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - - describe('assertValidFunctionCall', () => { - it('should revert if the data is less than 4 bytes long', async () => { - const result = governor - .assertValidFunctionCall(constants.ZERO_AMOUNT, constants.NULL_BYTES, constants.NULL_ADDRESS) - .callAsync(); - const expectedError = new LibBytesRevertErrors.InvalidByteOperationError( - LibBytesRevertErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsFourRequired, - constants.ZERO_AMOUNT, - new BigNumber(4), - ); - expect(result).to.revertWith(expectedError); - }); - it('should revert if an unregistered function is called before the default timelock', async () => { - const latestTimestamp = await getLatestBlockTimestampAsync(); - const transactionConfirmationTime = new BigNumber(latestTimestamp); - const reg = createFunctionRegistration(1, 1, 1); - const result = governor - .assertValidFunctionCall(transactionConfirmationTime, reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(result).to.revertWith(RevertReason.DefaultTimeLockIncomplete); - }); - it('should revert if a registered function is called before the custom timelock', async () => { - const reg = createFunctionRegistration(1, 1, 1); - await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync(); - const latestTimestamp = await getLatestBlockTimestampAsync(); - const transactionConfirmationTime = new BigNumber(latestTimestamp); - const result = governor - .assertValidFunctionCall(transactionConfirmationTime, reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(result).to.revertWith(RevertReason.CustomTimeLockIncomplete); - }); - it('should revert if a registered function is called before the custom timelock and after the default timelock', async () => { - const reg = createFunctionRegistration(1, 1, 1); - await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - new BigNumber(DEFAULT_TIME_LOCK).times(2), - ) - .awaitTransactionSuccessAsync(); - const latestTimestamp = await getLatestBlockTimestampAsync(); - const transactionConfirmationTime = new BigNumber(latestTimestamp).minus(DEFAULT_TIME_LOCK); - const result = governor - .assertValidFunctionCall(transactionConfirmationTime, reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(result).to.revertWith(RevertReason.CustomTimeLockIncomplete); - }); - it('should be successful if an unregistered function is called after the default timelock', async () => { - const latestTimestamp = await getLatestBlockTimestampAsync(); - const transactionConfirmationTime = new BigNumber(latestTimestamp).minus(DEFAULT_TIME_LOCK); - const reg = createFunctionRegistration(1, 1, 1); - const result = governor - .assertValidFunctionCall(transactionConfirmationTime, reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(result).to.be.fulfilled(''); - }); - it('should be successful if a registered function is called after the custom timelock', async () => { - const reg = createFunctionRegistration(1, 1, 1); - await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .awaitTransactionSuccessAsync(); - const latestTimestamp = await getLatestBlockTimestampAsync(); - const transactionConfirmationTime = new BigNumber(latestTimestamp).minus( - reg.functionCallTimeLockSeconds[0], - ); - const result = governor - .assertValidFunctionCall(transactionConfirmationTime, reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(result).to.be.fulfilled(''); - }); - it('should allow a custom timelock to be set to 0', async () => { - const reg = createFunctionRegistration(1, 1, 1); - await governor - .registerFunctionCallBypassWallet( - true, - reg.functionSelectors[0], - reg.destinations[0], - constants.ZERO_AMOUNT, - ) - .awaitTransactionSuccessAsync(); - const latestTimestamp = await getLatestBlockTimestampAsync(); - const result = governor - .assertValidFunctionCall(new BigNumber(latestTimestamp), reg.functionSelectors[0], reg.destinations[0]) - .callAsync(); - expect(result).to.be.fulfilled(''); - }); - }); - - blockchainTests.resets('executeTransaction', () => { - function assertReceiverCalledFromLogs( - logs: LogEntry[], - data: string[], - destinations: string[], - txId: BigNumber, - values?: BigNumber[], - ): void { - expect(logs.length).to.eq(data.length + 1); - data.forEach((calldata: string, i: number) => { - expect(logs[i].address).to.eq(destinations[i]); - const contractCallLogArgs = (logs[i] as LogWithDecodedArgs).args; - expect(contractCallLogArgs.functionSelector).to.eq(data[i].slice(0, 10)); - expect(contractCallLogArgs.data).to.eq(data[i]); - const value = values === undefined ? constants.ZERO_AMOUNT : values[i]; - expect(contractCallLogArgs.value).to.bignumber.eq(value); - }); - const executionLog = logs[data.length] as LogWithDecodedArgs; - expect(executionLog.event).to.eq('Execution'); - expect(executionLog.args.transactionId).to.bignumber.eq(txId); - } - it('should revert if the transaction is not confirmed by the required amount of signers', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const results = await governorWrapper.submitTransactionAsync(data, destinations, signerAddresses[0]); - const tx = governor.executeTransaction(results.txId).awaitTransactionSuccessAsync({ - from: signerAddresses[1], - }); - expect(tx).to.revertWith(RevertReason.TxNotFullyConfirmed); - }); - it('should revert if the transaction is not confirmed by the required amount of signers and called by the submitter', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const results = await governorWrapper.submitTransactionAsync(data, destinations, signerAddresses[0]); - const tx = governor.executeTransaction(results.txId).awaitTransactionSuccessAsync({ - from: signerAddresses[0], - }); - expect(tx).to.revertWith(RevertReason.TxNotFullyConfirmed); - }); - it('should be able to execute an unregistered function after the default timelock with no value', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should be able to execute an unregistered function after the default timelock with a value', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const values = [INITIAL_BALANCE]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - { values }, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId, values); - }); - it('should be able to execute a registered function after a custom timelock with no value', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const newTimeLock = new BigNumber(DEFAULT_TIME_LOCK).dividedToIntegerBy(2); - await governor - .registerFunctionCallBypassWallet(true, data[0].slice(0, 10), receiver.address, newTimeLock) - .awaitTransactionSuccessAsync(); - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - newTimeLock.toNumber(), - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should be able to execute a registered function with no timelock', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const newTimeLock = constants.ZERO_AMOUNT; - await governor - .registerFunctionCallBypassWallet(true, data[0].slice(0, 10), receiver.address, newTimeLock) - .awaitTransactionSuccessAsync(); - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - newTimeLock.toNumber(), - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should be able to execute a registered function after a custom timelock with a value', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const newTimeLock = new BigNumber(DEFAULT_TIME_LOCK).dividedToIntegerBy(2); - await governor - .registerFunctionCallBypassWallet(true, data[0].slice(0, 10), receiver.address, newTimeLock) - .awaitTransactionSuccessAsync(); - const values = [INITIAL_BALANCE]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - newTimeLock.toNumber(), - { values }, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId, values); - }); - it('should be able to call multiple functions with a single destination and no values', async () => { - const data = [hexUtils.random(), hexUtils.random()]; - const destinations = [receiver.address, receiver.address]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should be able to call multiple functions with different destinations and values', async () => { - const receiver2 = await ContractCallReceiverContract.deployFrom0xArtifactAsync( - artifacts.ContractCallReceiver, - env.provider, - env.txDefaults, - {}, - ); - const data = [hexUtils.random(), hexUtils.random()]; - const destinations = [receiver.address, receiver2.address]; - const values = [INITIAL_BALANCE.dividedToIntegerBy(4), INITIAL_BALANCE.dividedToIntegerBy(3)]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - { values }, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId, values); - }); - it('should be able to call a combination of registered and unregistered functions', async () => { - const data = [hexUtils.random(), hexUtils.random()]; - const destinations = [receiver.address, receiver.address]; - const newTimeLock = new BigNumber(DEFAULT_TIME_LOCK).dividedToIntegerBy(2); - await governor - .registerFunctionCallBypassWallet(true, data[0].slice(0, 10), receiver.address, newTimeLock) - .awaitTransactionSuccessAsync(); - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should fail if a single function has not passed the timelock', async () => { - const data = [hexUtils.random(), hexUtils.random()]; - const destinations = [receiver.address, receiver.address]; - const newTimeLock = new BigNumber(DEFAULT_TIME_LOCK).dividedToIntegerBy(2); - await governor - .registerFunctionCallBypassWallet(true, data[0].slice(0, 10), receiver.address, newTimeLock) - .awaitTransactionSuccessAsync(); - const tx = governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - newTimeLock.toNumber(), - ); - expect(tx).to.revertWith(RevertReason.DefaultTimeLockIncomplete); - }); - it('should be able to execute a transaction if called by any address', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - { executeFromAddress: notSignerAddress }, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should be able to send value without data if past the default timelock', async () => { - // NOTE: elements of `data` must be at least 4 bytes long - const data = [constants.NULL_BYTES4]; - const destinations = [receiver.address]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should not call a function if the input array lengths are 0', async () => { - const data: string[] = []; - const destinations: string[] = []; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - assertReceiverCalledFromLogs(results.executionTxReceipt.logs, data, destinations, results.txId); - }); - it('should revert if destinations.length != data.length', async () => { - const data = [hexUtils.random(), hexUtils.random()]; - const destinations = [receiver.address]; - const tx = governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - expect(tx).to.revertWith(RevertReason.EqualLengthsRequired); - }); - it('should revert if values.length != data.length', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const values = [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT]; - const tx = governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - { values }, - ); - expect(tx).to.revertWith(RevertReason.EqualLengthsRequired); - }); - it('should revert if the transaction is already executed', async () => { - const data = [hexUtils.random()]; - const destinations = [receiver.address]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - const tx = governor.executeTransaction(results.txId).awaitTransactionSuccessAsync(); - expect(tx).to.revertWith(RevertReason.TxAlreadyExecuted); - }); - it('should revert if the only call is unsuccessful', async () => { - const alwaysRevertSelector = '0xF1F2F3F4'; - const data = [alwaysRevertSelector]; - const destinations = [receiver.address]; - const tx = governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - expect(tx).to.revertWith(RevertReason.FailedExecution); - }); - it('should revert if the any call is unsuccessful', async () => { - const alwaysRevertSelector = '0xF1F2F3F4'; - const data = [hexUtils.random(), alwaysRevertSelector]; - const destinations = [receiver.address, receiver.address]; - const tx = governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - expect(tx).to.revertWith(RevertReason.FailedExecution); - }); - it('should be able to call registerFunctionCall after the default timelock', async () => { - const reg = createFunctionRegistration(1, 1, 1); - const data = [ - governor - .registerFunctionCall( - true, - reg.functionSelectors[0], - reg.destinations[0], - reg.functionCallTimeLockSeconds[0], - ) - .getABIEncodedTransactionData(), - ]; - const destinations = [governor.address]; - const results = await governorWrapper.submitConfirmAndExecuteTransactionAsync( - data, - destinations, - signerAddresses, - DEFAULT_TIME_LOCK, - ); - expect(results.executionTxReceipt.logs.length).to.eq(2); - const registrationLogArgs = (results.executionTxReceipt.logs[0] as LogWithDecodedArgs< - ZeroExGovernorFunctionCallTimeLockRegistrationEventArgs - >).args; - expect(registrationLogArgs.destination).to.eq(reg.destinations[0]); - expect(registrationLogArgs.functionSelector).to.eq(reg.functionSelectors[0]); - expect(registrationLogArgs.hasCustomTimeLock).to.eq(true); - expect(registrationLogArgs.newSecondsTimeLocked).to.bignumber.eq(reg.functionCallTimeLockSeconds[0]); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/multisig/truffle-config.js b/contracts/multisig/truffle-config.js deleted file mode 100644 index 8c95491cdc..0000000000 --- a/contracts/multisig/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.9', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/multisig/tsconfig.json b/contracts/multisig/tsconfig.json deleted file mode 100644 index 033cabd126..0000000000 --- a/contracts/multisig/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/MultiSigWalletWithTimeLock.json", - "generated-artifacts/ZeroExGovernor.json", - "test/generated-artifacts/ContractCallReceiver.json", - "test/generated-artifacts/MultiSigWallet.json", - "test/generated-artifacts/MultiSigWalletWithTimeLock.json", - "test/generated-artifacts/TestRejectEther.json", - "test/generated-artifacts/TestZeroExGovernor.json", - "test/generated-artifacts/ZeroExGovernor.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/multisig/tslint.json b/contracts/multisig/tslint.json deleted file mode 100644 index 1bb3ac2a22..0000000000 --- a/contracts/multisig/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false - } -} diff --git a/contracts/staking/.npmignore b/contracts/staking/.npmignore deleted file mode 100644 index bdf2b8acbe..0000000000 --- a/contracts/staking/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Whitelist Solidity contracts -!contracts/src/**/* -# Blacklist tests in lib -/lib/test/* -# Package specific ignore diff --git a/contracts/staking/CHANGELOG.json b/contracts/staking/CHANGELOG.json deleted file mode 100644 index c15745f8b6..0000000000 --- a/contracts/staking/CHANGELOG.json +++ /dev/null @@ -1,703 +0,0 @@ -[ - { - "timestamp": 1629079369, - "version": "2.0.45", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628665757, - "version": "2.0.44", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "2.0.43", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "2.0.42", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "2.0.41", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "2.0.40", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "2.0.39", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "2.0.38", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.37", - "changes": [ - { - "note": "Patch epoch finalization issue", - "pr": 221 - } - ], - "timestamp": 1620214333 - }, - { - "timestamp": 1619596077, - "version": "2.0.36", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "2.0.35", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "2.0.34", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "2.0.33", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "2.0.32", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "2.0.31", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "2.0.30", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "2.0.29", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "2.0.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "2.0.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608105788, - "version": "2.0.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "2.0.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "2.0.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "2.0.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "2.0.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "2.0.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "2.0.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "2.0.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "2.0.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "2.0.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "2.0.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603265572, - "version": "2.0.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1594788383, - "version": "2.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1592969527, - "version": "2.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "2.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "2.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582677073, - "version": "2.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "2.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "2.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.7", - "changes": [ - { - "note": "Fix revert for `LibFixedMath.mul(x, 0)`.", - "pr": 2462 - }, - { - "note": "Fix broken tests.", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1578272714, - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1576540892, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1575931811, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduce new exports FixedMathRevertErrors and StakingRevertErrors", - "pr": 2321 - }, - { - "note": "Removed handshake when adding maker to pool.", - "pr": 2250 - }, - { - "note": "Removed upper limit on number of makers in a pool.", - "pr": 2250 - }, - { - "note": "Removed operator permissions from makers.", - "pr": 2250 - }, - { - "note": "Pool Id starts at 1 and increases by 1.", - "pr": 2250 - }, - { - "note": "Add more overflow safeguards to `LibFixedMath`", - "pr": 2255 - }, - { - "note": "Refactored finalization state.", - "pr": 2276 - }, - { - "note": "Removed protocol fee != 0 assertion.", - "pr": 2278 - }, - { - "note": "Call `StakingProxy.assertValidStorageParams()` in `MixinParams.setParams()`", - "pr": 2279 - }, - { - "note": "The fallback function in `StakingProxy` reverts if there is no staking contract attached", - "pr": 2310 - }, - { - "note": "Fix overflow w/ `LibFixedMath._mul(-1, -2*255)", - "pr": 2311 - }, - { - "note": "Unit tests for MixinScheduler", - "pr": 2314 - }, - { - "note": "Unit tests for MixinCumulativeRewards", - "pr": 2316 - }, - { - "note": "Created package", - "pr": 1821 - }, - { - "note": "First implementation", - "pr": 1910 - }, - { - "note": "Replace `LibFeeMath` with `LibFixedMath`.", - "pr": 2109 - }, - { - "note": "Use a more precise cobb-douglas implementation.", - "pr": 2109 - }, - { - "note": "Change the way operator stake is computed.", - "pr": 2109 - }, - { - "note": "Denominate pool operator shares in parts-per-million.", - "pr": 2109 - }, - { - "note": "New stake management mechanics. Delay before delegation. Nixed shadow rewards.", - "pr": 2118 - }, - { - "note": "Tests for new stake management mechanics.", - "pr": 2126 - }, - { - "note": "Add `init()` pattern to contracts.", - "pr": 2131 - }, - { - "note": "Replace `MixinDeploymentConstants` with `MixinParams`.", - "pr": 2131 - }, - { - "note": "Reference counting for cumulative rewards.", - "pr": 2154 - }, - { - "note": "Refactored Staking Reward Vault. Moved pool management logic into staking contract.", - "pr": 2156 - }, - { - "note": "Removed MixinStakingPoolRewardVault.sol", - "pr": 2156 - }, - { - "note": "Refactored out `_cobbDouglas()` into its own library", - "pr": 2179 - }, - { - "note": "Introduce multi-block finalization.", - "pr": 2155 - }, - { - "note": "Removed reference counting for cumulative rewards.", - "pr": 2188 - }, - { - "note": "Removed explicit dependency on epoch+1 when delegating.", - "pr": 2188 - } - ], - "timestamp": 1575296764 - }, - { - "version": "1.1.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "1.1.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "1.1.0-beta.2", - "changes": [ - { - "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils", - "pr": 2330 - }, - { - "note": "Introduce new exports FixedMathRevertErrors and StakingRevertErrors", - "pr": 2321 - } - ], - "timestamp": 1574030254 - }, - { - "version": "1.1.0-beta.1", - "changes": [ - { - "note": "Removed handshake when adding maker to pool.", - "pr": 2250 - }, - { - "note": "Removed upper limit on number of makers in a pool.", - "pr": 2250 - }, - { - "note": "Removed operator permissions from makers.", - "pr": 2250 - }, - { - "note": "Pool Id starts at 1 and increases by 1.", - "pr": 2250 - }, - { - "note": "Add more overflow safeguards to `LibFixedMath`", - "pr": 2255 - }, - { - "note": "Refactored finalization state.", - "pr": 2276 - }, - { - "note": "Removed protocol fee != 0 assertion.", - "pr": 2278 - }, - { - "note": "Call `StakingProxy.assertValidStorageParams()` in `MixinParams.setParams()`", - "pr": 2279 - }, - { - "note": "The fallback function in `StakingProxy` reverts if there is no staking contract attached", - "pr": 2310 - }, - { - "note": "Fix overflow w/ `LibFixedMath._mul(-1, -2*255)", - "pr": 2311 - }, - { - "note": "Unit tests for MixinScheduler", - "pr": 2314 - }, - { - "note": "Unit tests for MixinCumulativeRewards", - "pr": 2316 - } - ], - "timestamp": 1573159180 - }, - { - "version": "1.1.0-beta.0", - "changes": [ - { - "note": "Created package", - "pr": 1821 - }, - { - "note": "First implementation", - "pr": 1910 - }, - { - "note": "Replace `LibFeeMath` with `LibFixedMath`.", - "pr": 2109 - }, - { - "note": "Use a more precise cobb-douglas implementation.", - "pr": 2109 - }, - { - "note": "Change the way operator stake is computed.", - "pr": 2109 - }, - { - "note": "Denominate pool operator shares in parts-per-million.", - "pr": 2109 - }, - { - "note": "New stake management mechanics. Delay before delegation. Nixed shadow rewards.", - "pr": 2118 - }, - { - "note": "Tests for new stake management mechanics.", - "pr": 2126 - }, - { - "note": "Add `init()` pattern to contracts.", - "pr": 2131 - }, - { - "note": "Replace `MixinDeploymentConstants` with `MixinParams`.", - "pr": 2131 - }, - { - "note": "Reference counting for cumulative rewards.", - "pr": 2154 - }, - { - "note": "Refactored Staking Reward Vault. Moved pool management logic into staking contract.", - "pr": 2156 - }, - { - "note": "Removed MixinStakingPoolRewardVault.sol", - "pr": 2156 - }, - { - "note": "Refactored out `_cobbDouglas()` into its own library", - "pr": 2179 - }, - { - "note": "Introduce multi-block finalization.", - "pr": 2155 - }, - { - "note": "Removed reference counting for cumulative rewards.", - "pr": 2188 - }, - { - "note": "Removed explicit dependency on epoch+1 when delegating.", - "pr": 2188 - } - ], - "timestamp": 1570135330 - } -] diff --git a/contracts/staking/CHANGELOG.md b/contracts/staking/CHANGELOG.md deleted file mode 100644 index 009efa99f8..0000000000 --- a/contracts/staking/CHANGELOG.md +++ /dev/null @@ -1,269 +0,0 @@ - - -CHANGELOG - -## v2.0.45 - _August 16, 2021_ - - * Dependencies updated - -## v2.0.44 - _August 11, 2021_ - - * Dependencies updated - -## v2.0.43 - _August 6, 2021_ - - * Dependencies updated - -## v2.0.42 - _June 22, 2021_ - - * Dependencies updated - -## v2.0.41 - _June 11, 2021_ - - * Dependencies updated - -## v2.0.40 - _June 2, 2021_ - - * Dependencies updated - -## v2.0.39 - _May 25, 2021_ - - * Dependencies updated - -## v2.0.38 - _May 21, 2021_ - - * Dependencies updated - -## v2.0.37 - _May 5, 2021_ - - * Patch epoch finalization issue (#221) - -## v2.0.36 - _April 28, 2021_ - - * Dependencies updated - -## v2.0.35 - _April 1, 2021_ - - * Dependencies updated - -## v2.0.34 - _March 17, 2021_ - - * Dependencies updated - -## v2.0.33 - _February 24, 2021_ - - * Dependencies updated - -## v2.0.32 - _February 10, 2021_ - - * Dependencies updated - -## v2.0.31 - _January 26, 2021_ - - * Dependencies updated - -## v2.0.30 - _January 13, 2021_ - - * Dependencies updated - -## v2.0.29 - _January 4, 2021_ - - * Dependencies updated - -## v2.0.28 - _December 23, 2020_ - - * Dependencies updated - -## v2.0.27 - _December 17, 2020_ - - * Dependencies updated - -## v2.0.26 - _December 16, 2020_ - - * Dependencies updated - -## v2.0.25 - _December 9, 2020_ - - * Dependencies updated - -## v2.0.24 - _December 7, 2020_ - - * Dependencies updated - -## v2.0.23 - _December 3, 2020_ - - * Dependencies updated - -## v2.0.22 - _November 19, 2020_ - - * Dependencies updated - -## v2.0.21 - _November 13, 2020_ - - * Dependencies updated - -## v2.0.20 - _November 3, 2020_ - - * Dependencies updated - -## v2.0.19 - _November 3, 2020_ - - * Dependencies updated - -## v2.0.18 - _November 2, 2020_ - - * Dependencies updated - -## v2.0.17 - _October 28, 2020_ - - * Dependencies updated - -## v2.0.16 - _October 27, 2020_ - - * Dependencies updated - -## v2.0.15 - _October 21, 2020_ - - * Dependencies updated - -## v2.0.14 - _July 15, 2020_ - - * Dependencies updated - -## v2.0.13 - _June 24, 2020_ - - * Dependencies updated - -## v2.0.12 - _March 3, 2020_ - - * Dependencies updated - -## v2.0.11 - _February 27, 2020_ - - * Dependencies updated - -## v2.0.10 - _February 26, 2020_ - - * Dependencies updated - -## v2.0.9 - _February 25, 2020_ - - * Dependencies updated - -## v2.0.8 - _February 15, 2020_ - - * Dependencies updated - -## v2.0.7 - _February 8, 2020_ - - * Fix revert for `LibFixedMath.mul(x, 0)`. (#2462) - * Fix broken tests. (#2462) - -## v2.0.6 - _February 6, 2020_ - - * Dependencies updated - -## v2.0.5 - _February 4, 2020_ - - * Dependencies updated - -## v2.0.4 - _January 22, 2020_ - - * Dependencies updated - -## v2.0.3 - _January 6, 2020_ - - * Dependencies updated - -## v2.0.2 - _December 17, 2019_ - - * Dependencies updated - -## v2.0.1 - _December 9, 2019_ - - * Dependencies updated - -## v2.0.0 - _December 2, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduce new exports FixedMathRevertErrors and StakingRevertErrors (#2321) - * Removed handshake when adding maker to pool. (#2250) - * Removed upper limit on number of makers in a pool. (#2250) - * Removed operator permissions from makers. (#2250) - * Pool Id starts at 1 and increases by 1. (#2250) - * Add more overflow safeguards to `LibFixedMath` (#2255) - * Refactored finalization state. (#2276) - * Removed protocol fee != 0 assertion. (#2278) - * Call `StakingProxy.assertValidStorageParams()` in `MixinParams.setParams()` (#2279) - * The fallback function in `StakingProxy` reverts if there is no staking contract attached (#2310) - * Fix overflow w/ `LibFixedMath._mul(-1, -2*255) (#2311) - * Unit tests for MixinScheduler (#2314) - * Unit tests for MixinCumulativeRewards (#2316) - * Created package (#1821) - * First implementation (#1910) - * Replace `LibFeeMath` with `LibFixedMath`. (#2109) - * Use a more precise cobb-douglas implementation. (#2109) - * Change the way operator stake is computed. (#2109) - * Denominate pool operator shares in parts-per-million. (#2109) - * New stake management mechanics. Delay before delegation. Nixed shadow rewards. (#2118) - * Tests for new stake management mechanics. (#2126) - * Add `init()` pattern to contracts. (#2131) - * Replace `MixinDeploymentConstants` with `MixinParams`. (#2131) - * Reference counting for cumulative rewards. (#2154) - * Refactored Staking Reward Vault. Moved pool management logic into staking contract. (#2156) - * Removed MixinStakingPoolRewardVault.sol (#2156) - * Refactored out `_cobbDouglas()` into its own library (#2179) - * Introduce multi-block finalization. (#2155) - * Removed reference counting for cumulative rewards. (#2188) - * Removed explicit dependency on epoch+1 when delegating. (#2188) - -## v1.1.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v1.1.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v1.1.0-beta.2 - _November 17, 2019_ - - * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330) - * Introduce new exports FixedMathRevertErrors and StakingRevertErrors (#2321) - -## v1.1.0-beta.1 - _November 7, 2019_ - - * Removed handshake when adding maker to pool. (#2250) - * Removed upper limit on number of makers in a pool. (#2250) - * Removed operator permissions from makers. (#2250) - * Pool Id starts at 1 and increases by 1. (#2250) - * Add more overflow safeguards to `LibFixedMath` (#2255) - * Refactored finalization state. (#2276) - * Removed protocol fee != 0 assertion. (#2278) - * Call `StakingProxy.assertValidStorageParams()` in `MixinParams.setParams()` (#2279) - * The fallback function in `StakingProxy` reverts if there is no staking contract attached (#2310) - * Fix overflow w/ `LibFixedMath._mul(-1, -2*255) (#2311) - * Unit tests for MixinScheduler (#2314) - * Unit tests for MixinCumulativeRewards (#2316) - -## v1.1.0-beta.0 - _October 3, 2019_ - - * Created package (#1821) - * First implementation (#1910) - * Replace `LibFeeMath` with `LibFixedMath`. (#2109) - * Use a more precise cobb-douglas implementation. (#2109) - * Change the way operator stake is computed. (#2109) - * Denominate pool operator shares in parts-per-million. (#2109) - * New stake management mechanics. Delay before delegation. Nixed shadow rewards. (#2118) - * Tests for new stake management mechanics. (#2126) - * Add `init()` pattern to contracts. (#2131) - * Replace `MixinDeploymentConstants` with `MixinParams`. (#2131) - * Reference counting for cumulative rewards. (#2154) - * Refactored Staking Reward Vault. Moved pool management logic into staking contract. (#2156) - * Removed MixinStakingPoolRewardVault.sol (#2156) - * Refactored out `_cobbDouglas()` into its own library (#2179) - * Introduce multi-block finalization. (#2155) - * Removed reference counting for cumulative rewards. (#2188) - * Removed explicit dependency on epoch+1 when delegating. (#2188) diff --git a/contracts/staking/DEPLOYS.json b/contracts/staking/DEPLOYS.json deleted file mode 100644 index fe51488c70..0000000000 --- a/contracts/staking/DEPLOYS.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/contracts/staking/README.md b/contracts/staking/README.md deleted file mode 100644 index 025fabc9ea..0000000000 --- a/contracts/staking/README.md +++ /dev/null @@ -1,85 +0,0 @@ -## Staking Contracts - -This package implements the stake-based liquidity incentives defined by [ZEIP-31](https://github.com/0xProject/ZEIPs/issues/31). - -See the specification [here](https://github.com/0xProject/0x-protocol-specification/blob/3.0/staking/staking-specification.md). - -## Contracts Directory Structure - -The contracts can be found in `contracts/src`. - -``` -* Staking.sol | This is a stateless contract that encapsulates all the staking logic. -* StakingProxy.sol | This is a stateful contract that proxies into the Staking contract. -* ReadOnlyProxy.sol | This is a stateless contract the makes read-only calls from the Staking Proxy to the Staking Contract. -* fees/ | This contains mixins that implement the logic for 0x Protocol fees. -* immutable/ | This contains mixins that are generally immutable. Changing these files can result in catastrophic failures. Exercise extreme caution. -* interfaces/ | This contains interfaces used throughout the entire staking system. -* libs/ | This contains libraries used by the staking contract; for example, math and signature validation. -* stake/ | This contains mixins that implement the core staking logic. -* staking_pools/ | This contains mixins that implement logic for creating and managing staking pools. -* sys/ | This contains mixins that implement system-level functionality, like scheduling and finalization. -* vaults/ | This contains the vaults (like the Zrx Token Vault). -``` - -## Installation - -**Install** - -```bash -npm install @0x/contracts-staking --save -``` - -## 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=@0x/contracts-staking yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/contracts-staking yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` diff --git a/contracts/staking/compiler.json b/contracts/staking/compiler.json deleted file mode 100644 index 20f8637f21..0000000000 --- a/contracts/staking/compiler.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "artifactsDir": "./test/generated-artifacts", - "contractsDir": "./contracts", - "useDockerisedSolc": false, - "isOfflineMode": false, - "shouldSaveStandardInput": true, - "compilerSettings": { - "evmVersion": "istanbul", - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "devdoc", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - } - } -} diff --git a/contracts/staking/contracts/src/Staking.sol b/contracts/staking/contracts/src/Staking.sol deleted file mode 100644 index 0cae856329..0000000000 --- a/contracts/staking/contracts/src/Staking.sol +++ /dev/null @@ -1,46 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./interfaces/IStaking.sol"; -import "./sys/MixinParams.sol"; -import "./stake/MixinStake.sol"; -import "./fees/MixinExchangeFees.sol"; - - -contract Staking is - IStaking, - MixinParams, - MixinStake, - MixinExchangeFees -{ - /// @dev Initialize storage owned by this contract. - /// This function should not be called directly. - /// The StakingProxy contract will call it in `attachStakingContract()`. - function init() - public - onlyAuthorized - { - // DANGER! When performing upgrades, take care to modify this logic - // to prevent accidentally clearing prior state. - _initMixinScheduler(); - _initMixinParams(); - } -} diff --git a/contracts/staking/contracts/src/StakingPatch.sol b/contracts/staking/contracts/src/StakingPatch.sol deleted file mode 100644 index 34cedfdf50..0000000000 --- a/contracts/staking/contracts/src/StakingPatch.sol +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./interfaces/IStaking.sol"; -import "./sys/MixinParams.sol"; -import "./stake/MixinStake.sol"; -import "./fees/MixinExchangeFees.sol"; - - -contract StakingPatch is - IStaking, - MixinParams, - MixinStake, - MixinExchangeFees -{ - /// @dev Initialize storage owned by this contract. - /// This function should not be called directly. - /// The StakingProxy contract will call it in `attachStakingContract()`. - function init() - public - onlyAuthorized - { - uint256 currentEpoch_ = currentEpoch; - uint256 prevEpoch = currentEpoch_.safeSub(1); - - // Patch corrupted state - aggregatedStatsByEpoch[prevEpoch].numPoolsToFinalize = 0; - this.endEpoch(); - - uint256 lastPoolId_ = 57; - for (uint256 i = 1; i <= lastPoolId_; i++) { - this.finalizePool(bytes32(i)); - } - // Ensure that current epoch's state is not corrupted - aggregatedStatsByEpoch[currentEpoch_].numPoolsToFinalize = 0; - } -} diff --git a/contracts/staking/contracts/src/StakingProxy.sol b/contracts/staking/contracts/src/StakingProxy.sol deleted file mode 100644 index 5341790db2..0000000000 --- a/contracts/staking/contracts/src/StakingProxy.sol +++ /dev/null @@ -1,208 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./libs/LibSafeDowncast.sol"; -import "./immutable/MixinStorage.sol"; -import "./immutable/MixinConstants.sol"; -import "./interfaces/IStorageInit.sol"; -import "./interfaces/IStakingProxy.sol"; - - -/// #dev The 0x Staking contract. -contract StakingProxy is - IStakingProxy, - MixinStorage, - MixinConstants -{ - using LibSafeDowncast for uint256; - - /// @dev Constructor. - /// @param _stakingContract Staking contract to delegate calls to. - constructor(address _stakingContract) - public - MixinStorage() - { - // Deployer address must be authorized in order to call `init` - _addAuthorizedAddress(msg.sender); - - // Attach the staking contract and initialize state - _attachStakingContract(_stakingContract); - - // Remove the sender as an authorized address - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - /// @dev Delegates calls to the staking contract, if it is set. - function () - external - payable - { - // Sanity check that we have a staking contract to call - address stakingContract_ = stakingContract; - if (stakingContract_ == NIL_ADDRESS) { - LibRichErrors.rrevert( - LibStakingRichErrors.ProxyDestinationCannotBeNilError() - ); - } - - // Call the staking contract with the provided calldata. - (bool success, bytes memory returnData) = stakingContract_.delegatecall(msg.data); - - // Revert on failure or return on success. - assembly { - switch success - case 0 { - revert(add(0x20, returnData), mload(returnData)) - } - default { - return(add(0x20, returnData), mload(returnData)) - } - } - } - - /// @dev Attach a staking contract; future calls will be delegated to the staking contract. - /// Note that this is callable only by an authorized address. - /// @param _stakingContract Address of staking contract. - function attachStakingContract(address _stakingContract) - external - onlyAuthorized - { - _attachStakingContract(_stakingContract); - } - - /// @dev Detach the current staking contract. - /// Note that this is callable only by an authorized address. - function detachStakingContract() - external - onlyAuthorized - { - stakingContract = NIL_ADDRESS; - emit StakingContractDetachedFromProxy(); - } - - /// @dev Batch executes a series of calls to the staking contract. - /// @param data An array of data that encodes a sequence of functions to - /// call in the staking contracts. - function batchExecute(bytes[] calldata data) - external - returns (bytes[] memory batchReturnData) - { - // Initialize commonly used variables. - bool success; - bytes memory returnData; - uint256 dataLength = data.length; - batchReturnData = new bytes[](dataLength); - address staking = stakingContract; - - // Ensure that a staking contract has been attached to the proxy. - if (staking == NIL_ADDRESS) { - LibRichErrors.rrevert( - LibStakingRichErrors.ProxyDestinationCannotBeNilError() - ); - } - - // Execute all of the calls encoded in the provided calldata. - for (uint256 i = 0; i != dataLength; i++) { - // Call the staking contract with the provided calldata. - (success, returnData) = staking.delegatecall(data[i]); - - // Revert on failure. - if (!success) { - assembly { - revert(add(0x20, returnData), mload(returnData)) - } - } - - // Add the returndata to the batch returndata. - batchReturnData[i] = returnData; - } - - return batchReturnData; - } - - /// @dev Asserts that an epoch is between 5 and 30 days long. - // Asserts that 0 < cobb douglas alpha value <= 1. - // Asserts that a stake weight is <= 100%. - // Asserts that pools allow >= 1 maker. - // Asserts that all addresses are initialized. - function assertValidStorageParams() - public - view - { - // Epoch length must be between 5 and 30 days long - uint256 _epochDurationInSeconds = epochDurationInSeconds; - if (_epochDurationInSeconds < 5 days || _epochDurationInSeconds > 30 days) { - LibRichErrors.rrevert( - LibStakingRichErrors.InvalidParamValueError( - LibStakingRichErrors.InvalidParamValueErrorCodes.InvalidEpochDuration - )); - } - - // Alpha must be 0 < x <= 1 - uint32 _cobbDouglasAlphaDenominator = cobbDouglasAlphaDenominator; - if (cobbDouglasAlphaNumerator > _cobbDouglasAlphaDenominator || _cobbDouglasAlphaDenominator == 0) { - LibRichErrors.rrevert( - LibStakingRichErrors.InvalidParamValueError( - LibStakingRichErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha - )); - } - - // Weight of delegated stake must be <= 100% - if (rewardDelegatedStakeWeight > PPM_DENOMINATOR) { - LibRichErrors.rrevert( - LibStakingRichErrors.InvalidParamValueError( - LibStakingRichErrors.InvalidParamValueErrorCodes.InvalidRewardDelegatedStakeWeight - )); - } - - // Minimum stake must be > 1 - if (minimumPoolStake < 2) { - LibRichErrors.rrevert( - LibStakingRichErrors.InvalidParamValueError( - LibStakingRichErrors.InvalidParamValueErrorCodes.InvalidMinimumPoolStake - )); - } - } - - /// @dev Attach a staking contract; future calls will be delegated to the staking contract. - /// @param _stakingContract Address of staking contract. - function _attachStakingContract(address _stakingContract) - internal - { - // Attach the staking contract - stakingContract = _stakingContract; - emit StakingContractAttachedToProxy(_stakingContract); - - // Call `init()` on the staking contract to initialize storage. - (bool didInitSucceed, bytes memory initReturnData) = stakingContract.delegatecall( - abi.encodeWithSelector(IStorageInit(0).init.selector) - ); - - if (!didInitSucceed) { - assembly { - revert(add(initReturnData, 0x20), mload(initReturnData)) - } - } - - // Assert initialized storage values are valid - assertValidStorageParams(); - } -} diff --git a/contracts/staking/contracts/src/ZrxVault.sol b/contracts/staking/contracts/src/ZrxVault.sol deleted file mode 100644 index 12b5462f6d..0000000000 --- a/contracts/staking/contracts/src/ZrxVault.sol +++ /dev/null @@ -1,252 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/Authorizable.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; -import "./libs/LibStakingRichErrors.sol"; -import "./interfaces/IZrxVault.sol"; - - -contract ZrxVault is - Authorizable, - IZrxVault -{ - using LibSafeMath for uint256; - - // Address of staking proxy contract - address public stakingProxyAddress; - - // True iff vault has been set to Catastrophic Failure Mode - bool public isInCatastrophicFailure; - - // Mapping from staker to ZRX balance - mapping (address => uint256) internal _balances; - - // Zrx Asset Proxy - IAssetProxy public zrxAssetProxy; - - // Zrx Token - IERC20Token internal _zrxToken; - - // Asset data for the ERC20 Proxy - bytes internal _zrxAssetData; - - /// @dev Only stakingProxy can call this function. - modifier onlyStakingProxy() { - _assertSenderIsStakingProxy(); - _; - } - - /// @dev Function can only be called in catastrophic failure mode. - modifier onlyInCatastrophicFailure() { - _assertInCatastrophicFailure(); - _; - } - - /// @dev Function can only be called not in catastropic failure mode - modifier onlyNotInCatastrophicFailure() { - _assertNotInCatastrophicFailure(); - _; - } - - /// @dev Constructor. - /// @param _zrxProxyAddress Address of the 0x Zrx Proxy. - /// @param _zrxTokenAddress Address of the Zrx Token. - constructor( - address _zrxProxyAddress, - address _zrxTokenAddress - ) - public - Authorizable() - { - zrxAssetProxy = IAssetProxy(_zrxProxyAddress); - _zrxToken = IERC20Token(_zrxTokenAddress); - _zrxAssetData = abi.encodeWithSelector( - IAssetData(address(0)).ERC20Token.selector, - _zrxTokenAddress - ); - } - - /// @dev Sets the address of the StakingProxy contract. - /// Note that only the contract owner can call this function. - /// @param _stakingProxyAddress Address of Staking proxy contract. - function setStakingProxy(address _stakingProxyAddress) - external - onlyAuthorized - { - stakingProxyAddress = _stakingProxyAddress; - emit StakingProxySet(_stakingProxyAddress); - } - - /// @dev Vault enters into Catastrophic Failure Mode. - /// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! *** - /// Note that only the contract owner can call this function. - function enterCatastrophicFailure() - external - onlyAuthorized - onlyNotInCatastrophicFailure - { - isInCatastrophicFailure = true; - emit InCatastrophicFailureMode(msg.sender); - } - - /// @dev Sets the Zrx proxy. - /// Note that only an authorized address can call this function. - /// Note that this can only be called when *not* in Catastrophic Failure mode. - /// @param _zrxProxyAddress Address of the 0x Zrx Proxy. - function setZrxProxy(address _zrxProxyAddress) - external - onlyAuthorized - onlyNotInCatastrophicFailure - { - zrxAssetProxy = IAssetProxy(_zrxProxyAddress); - emit ZrxProxySet(_zrxProxyAddress); - } - - /// @dev Deposit an `amount` of Zrx Tokens from `staker` into the vault. - /// Note that only the Staking contract can call this. - /// Note that this can only be called when *not* in Catastrophic Failure mode. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens to deposit. - function depositFrom(address staker, uint256 amount) - external - onlyStakingProxy - onlyNotInCatastrophicFailure - { - // update balance - _balances[staker] = _balances[staker].safeAdd(amount); - - // notify - emit Deposit(staker, amount); - - // deposit ZRX from staker - zrxAssetProxy.transferFrom( - _zrxAssetData, - staker, - address(this), - amount - ); - } - - /// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault. - /// Note that only the Staking contract can call this. - /// Note that this can only be called when *not* in Catastrophic Failure mode. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens to withdraw. - function withdrawFrom(address staker, uint256 amount) - external - onlyStakingProxy - onlyNotInCatastrophicFailure - { - _withdrawFrom(staker, amount); - } - - /// @dev Withdraw ALL Zrx Tokens to `staker` from the vault. - /// Note that this can only be called when *in* Catastrophic Failure mode. - /// @param staker of Zrx Tokens. - function withdrawAllFrom(address staker) - external - onlyInCatastrophicFailure - returns (uint256) - { - // get total balance - uint256 totalBalance = _balances[staker]; - - // withdraw ZRX to staker - _withdrawFrom(staker, totalBalance); - return totalBalance; - } - - /// @dev Returns the balance in Zrx Tokens of the `staker` - /// @return Balance in Zrx. - function balanceOf(address staker) - external - view - returns (uint256) - { - return _balances[staker]; - } - - /// @dev Returns the entire balance of Zrx tokens in the vault. - function balanceOfZrxVault() - external - view - returns (uint256) - { - return _zrxToken.balanceOf(address(this)); - } - - /// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens to withdraw. - function _withdrawFrom(address staker, uint256 amount) - internal - { - // update balance - // note that this call will revert if trying to withdraw more - // than the current balance - _balances[staker] = _balances[staker].safeSub(amount); - - // notify - emit Withdraw(staker, amount); - - // withdraw ZRX to staker - _zrxToken.transfer( - staker, - amount - ); - } - - /// @dev Asserts that sender is stakingProxy contract. - function _assertSenderIsStakingProxy() - private - view - { - if (msg.sender != stakingProxyAddress) { - LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByStakingContractError( - msg.sender - )); - } - } - - /// @dev Asserts that vault is in catastrophic failure mode. - function _assertInCatastrophicFailure() - private - view - { - if (!isInCatastrophicFailure) { - LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableIfInCatastrophicFailureError()); - } - } - - /// @dev Asserts that vault is not in catastrophic failure mode. - function _assertNotInCatastrophicFailure() - private - view - { - if (isInCatastrophicFailure) { - LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableIfNotInCatastrophicFailureError()); - } - } -} diff --git a/contracts/staking/contracts/src/fees/MixinExchangeFees.sol b/contracts/staking/contracts/src/fees/MixinExchangeFees.sol deleted file mode 100644 index 6eba6d1996..0000000000 --- a/contracts/staking/contracts/src/fees/MixinExchangeFees.sol +++ /dev/null @@ -1,178 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../libs/LibStakingRichErrors.sol"; -import "../interfaces/IStructs.sol"; -import "../sys/MixinFinalizer.sol"; -import "../staking_pools/MixinStakingPool.sol"; -import "./MixinExchangeManager.sol"; - - -contract MixinExchangeFees is - MixinExchangeManager, - MixinStakingPool, - MixinFinalizer -{ - using LibSafeMath for uint256; - - /// @dev Pays a protocol fee in ETH or WETH. - /// Only a known 0x exchange can call this method. See - /// (MixinExchangeManager). - /// @param makerAddress The address of the order's maker. - /// @param payerAddress The address of the protocol fee payer. - /// @param protocolFee The protocol fee amount. This is either passed as ETH or transferred as WETH. - function payProtocolFee( - address makerAddress, - address payerAddress, - uint256 protocolFee - ) - external - payable - onlyExchange - { - _assertValidProtocolFee(protocolFee); - - if (protocolFee == 0) { - return; - } - - // Transfer the protocol fee to this address if it should be paid in - // WETH. - if (msg.value == 0) { - require( - getWethContract().transferFrom( - payerAddress, - address(this), - protocolFee - ), - "WETH_TRANSFER_FAILED" - ); - } - - // Get the pool id of the maker address. - bytes32 poolId = poolIdByMaker[makerAddress]; - - // Only attribute the protocol fee payment to a pool if the maker is - // registered to a pool. - if (poolId == NIL_POOL_ID) { - return; - } - - uint256 poolStake = getTotalStakeDelegatedToPool(poolId).currentEpochBalance; - // Ignore pools with dust stake. - if (poolStake < minimumPoolStake) { - return; - } - - // Look up the pool stats and aggregated stats for this epoch. - uint256 currentEpoch_ = currentEpoch; - IStructs.PoolStats storage poolStatsPtr = poolStatsByEpoch[poolId][currentEpoch_]; - IStructs.AggregatedStats storage aggregatedStatsPtr = aggregatedStatsByEpoch[currentEpoch_]; - - // Perform some initialization if this is the pool's first protocol fee in this epoch. - uint256 feesCollectedByPool = poolStatsPtr.feesCollected; - if (feesCollectedByPool == 0) { - // Compute member and total weighted stake. - (uint256 membersStakeInPool, uint256 weightedStakeInPool) = _computeMembersAndWeightedStake(poolId, poolStake); - poolStatsPtr.membersStake = membersStakeInPool; - poolStatsPtr.weightedStake = weightedStakeInPool; - - // Increase the total weighted stake. - aggregatedStatsPtr.totalWeightedStake = aggregatedStatsPtr.totalWeightedStake.safeAdd(weightedStakeInPool); - - // Increase the number of pools to finalize. - aggregatedStatsPtr.numPoolsToFinalize = aggregatedStatsPtr.numPoolsToFinalize.safeAdd(1); - - // Emit an event so keepers know what pools earned rewards this epoch. - emit StakingPoolEarnedRewardsInEpoch(currentEpoch_, poolId); - } - - // Credit the fees to the pool. - poolStatsPtr.feesCollected = feesCollectedByPool.safeAdd(protocolFee); - - // Increase the total fees collected this epoch. - aggregatedStatsPtr.totalFeesCollected = aggregatedStatsPtr.totalFeesCollected.safeAdd(protocolFee); - } - - /// @dev Get stats on a staking pool in this epoch. - /// @param poolId Pool Id to query. - /// @return PoolStats struct for pool id. - function getStakingPoolStatsThisEpoch(bytes32 poolId) - external - view - returns (IStructs.PoolStats memory) - { - return poolStatsByEpoch[poolId][currentEpoch]; - } - - /// @dev Computes the members and weighted stake for a pool at the current - /// epoch. - /// @param poolId ID of the pool. - /// @param totalStake Total (unweighted) stake in the pool. - /// @return membersStake Non-operator stake in the pool. - /// @return weightedStake Weighted stake of the pool. - function _computeMembersAndWeightedStake( - bytes32 poolId, - uint256 totalStake - ) - private - view - returns (uint256 membersStake, uint256 weightedStake) - { - uint256 operatorStake = getStakeDelegatedToPoolByOwner( - _poolById[poolId].operator, - poolId - ).currentEpochBalance; - - membersStake = totalStake.safeSub(operatorStake); - weightedStake = operatorStake.safeAdd( - LibMath.getPartialAmountFloor( - rewardDelegatedStakeWeight, - PPM_DENOMINATOR, - membersStake - ) - ); - return (membersStake, weightedStake); - } - - /// @dev Checks that the protocol fee passed into `payProtocolFee()` is - /// valid. - /// @param protocolFee The `protocolFee` parameter to - /// `payProtocolFee.` - function _assertValidProtocolFee(uint256 protocolFee) - private - view - { - // The protocol fee must equal the value passed to the contract; unless - // the value is zero, in which case the fee is taken in WETH. - if (msg.value != protocolFee && msg.value != 0) { - LibRichErrors.rrevert( - LibStakingRichErrors.InvalidProtocolFeePaymentError( - protocolFee, - msg.value - ) - ); - } - } -} diff --git a/contracts/staking/contracts/src/fees/MixinExchangeManager.sol b/contracts/staking/contracts/src/fees/MixinExchangeManager.sol deleted file mode 100644 index 16801ef558..0000000000 --- a/contracts/staking/contracts/src/fees/MixinExchangeManager.sol +++ /dev/null @@ -1,72 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "../libs/LibStakingRichErrors.sol"; -import "../interfaces/IStakingEvents.sol"; -import "../immutable/MixinStorage.sol"; - - -contract MixinExchangeManager is - IStakingEvents, - MixinStorage -{ - /// @dev Asserts that the call is coming from a valid exchange. - modifier onlyExchange() { - if (!validExchanges[msg.sender]) { - LibRichErrors.rrevert(LibStakingRichErrors.OnlyCallableByExchangeError( - msg.sender - )); - } - _; - } - - /// @dev Adds a new exchange address - /// @param addr Address of exchange contract to add - function addExchangeAddress(address addr) - external - onlyAuthorized - { - if (validExchanges[addr]) { - LibRichErrors.rrevert(LibStakingRichErrors.ExchangeManagerError( - LibStakingRichErrors.ExchangeManagerErrorCodes.ExchangeAlreadyRegistered, - addr - )); - } - validExchanges[addr] = true; - emit ExchangeAdded(addr); - } - - /// @dev Removes an existing exchange address - /// @param addr Address of exchange contract to remove - function removeExchangeAddress(address addr) - external - onlyAuthorized - { - if (!validExchanges[addr]) { - LibRichErrors.rrevert(LibStakingRichErrors.ExchangeManagerError( - LibStakingRichErrors.ExchangeManagerErrorCodes.ExchangeNotRegistered, - addr - )); - } - validExchanges[addr] = false; - emit ExchangeRemoved(addr); - } -} diff --git a/contracts/staking/contracts/src/immutable/MixinConstants.sol b/contracts/staking/contracts/src/immutable/MixinConstants.sol deleted file mode 100644 index 942c6d8c26..0000000000 --- a/contracts/staking/contracts/src/immutable/MixinConstants.sol +++ /dev/null @@ -1,32 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -contract MixinConstants { - - // 100% in parts-per-million. - uint32 constant internal PPM_DENOMINATOR = 10**6; - - bytes32 constant internal NIL_POOL_ID = 0x0000000000000000000000000000000000000000000000000000000000000000; - - address constant internal NIL_ADDRESS = 0x0000000000000000000000000000000000000000; - - uint256 constant internal MIN_TOKEN_VALUE = 10**18; -} diff --git a/contracts/staking/contracts/src/immutable/MixinDeploymentConstants.sol b/contracts/staking/contracts/src/immutable/MixinDeploymentConstants.sol deleted file mode 100644 index 919310dd33..0000000000 --- a/contracts/staking/contracts/src/immutable/MixinDeploymentConstants.sol +++ /dev/null @@ -1,76 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "../interfaces/IZrxVault.sol"; - - -// solhint-disable separate-by-one-line-in-contract -contract MixinDeploymentConstants { - - // @TODO SET THESE VALUES FOR DEPLOYMENT - - // Mainnet WETH9 Address - address constant private WETH_ADDRESS = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); - - // Kovan WETH9 Address - // address constant private WETH_ADDRESS = address(0xd0A1E359811322d97991E03f863a0C30C2cF029C); - - // Ropsten & Rinkeby WETH9 Address - // address constant private WETH_ADDRESS = address(0xc778417E063141139Fce010982780140Aa0cD5Ab); - - // @TODO SET THESE VALUES FOR DEPLOYMENT - - // Mainnet ZrxVault address - address constant private ZRX_VAULT_ADDRESS = address(0xBa7f8b5fB1b19c1211c5d49550fcD149177A5Eaf); - - // Kovan ZrxVault address - // address constant private ZRX_VAULT_ADDRESS = address(0xf36eabdFE986B35b62c8FD5a98A7f2aEBB79B291); - - // Ropsten ZrxVault address - // address constant private ZRX_VAULT_ADDRESS = address(0xffD161026865Ad8B4aB28a76840474935eEc4DfA); - - // Rinkeby ZrxVault address - // address constant private ZRX_VAULT_ADDRESS = address(0xA5Bf6aC73bC40790FC6Ffc9DBbbCE76c9176e224); - - /// @dev An overridable way to access the deployed WETH contract. - /// Must be view to allow overrides to access state. - /// @return wethContract The WETH contract instance. - function getWethContract() - public - view - returns (IEtherToken wethContract) - { - wethContract = IEtherToken(WETH_ADDRESS); - return wethContract; - } - - /// @dev An overridable way to access the deployed zrxVault. - /// Must be view to allow overrides to access state. - /// @return zrxVault The zrxVault contract. - function getZrxVault() - public - view - returns (IZrxVault zrxVault) - { - zrxVault = IZrxVault(ZRX_VAULT_ADDRESS); - return zrxVault; - } -} diff --git a/contracts/staking/contracts/src/immutable/MixinStorage.sol b/contracts/staking/contracts/src/immutable/MixinStorage.sol deleted file mode 100644 index 5e5f3b011f..0000000000 --- a/contracts/staking/contracts/src/immutable/MixinStorage.sol +++ /dev/null @@ -1,118 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/Authorizable.sol"; -import "./MixinConstants.sol"; -import "../interfaces/IZrxVault.sol"; -import "../interfaces/IStructs.sol"; -import "../libs/LibStakingRichErrors.sol"; - - -// solhint-disable max-states-count, no-empty-blocks -contract MixinStorage is - Authorizable -{ - // address of staking contract - address public stakingContract; - - // mapping from StakeStatus to global stored balance - // NOTE: only Status.DELEGATED is used to access this mapping, but this format - // is used for extensibility - mapping (uint8 => IStructs.StoredBalance) internal _globalStakeByStatus; - - // mapping from StakeStatus to address of staker to stored balance - mapping (uint8 => mapping (address => IStructs.StoredBalance)) internal _ownerStakeByStatus; - - // Mapping from Owner to Pool Id to Amount Delegated - mapping (address => mapping (bytes32 => IStructs.StoredBalance)) internal _delegatedStakeToPoolByOwner; - - // Mapping from Pool Id to Amount Delegated - mapping (bytes32 => IStructs.StoredBalance) internal _delegatedStakeByPoolId; - - // tracking Pool Id, a unique identifier for each staking pool. - bytes32 public lastPoolId; - - /// @dev Mapping from Maker Address to pool Id of maker - /// @param 0 Maker address. - /// @return 0 The pool ID. - mapping (address => bytes32) public poolIdByMaker; - - // mapping from Pool Id to Pool - mapping (bytes32 => IStructs.Pool) internal _poolById; - - /// @dev mapping from pool ID to reward balance of members - /// @param 0 Pool ID. - /// @return 0 The total reward balance of members in this pool. - mapping (bytes32 => uint256) public rewardsByPoolId; - - // The current epoch. - uint256 public currentEpoch; - - // The current epoch start time. - uint256 public currentEpochStartTimeInSeconds; - - // mapping from Pool Id to Epoch to Reward Ratio - mapping (bytes32 => mapping (uint256 => IStructs.Fraction)) internal _cumulativeRewardsByPool; - - // mapping from Pool Id to Epoch - mapping (bytes32 => uint256) internal _cumulativeRewardsByPoolLastStored; - - /// @dev Registered 0x Exchange contracts, capable of paying protocol fees. - /// @param 0 The address to check. - /// @return 0 Whether the address is a registered exchange. - mapping (address => bool) public validExchanges; - - /* Tweakable parameters */ - - // Minimum seconds between epochs. - uint256 public epochDurationInSeconds; - - // How much delegated stake is weighted vs operator stake, in ppm. - uint32 public rewardDelegatedStakeWeight; - - // Minimum amount of stake required in a pool to collect rewards. - uint256 public minimumPoolStake; - - // Numerator for cobb douglas alpha factor. - uint32 public cobbDouglasAlphaNumerator; - - // Denominator for cobb douglas alpha factor. - uint32 public cobbDouglasAlphaDenominator; - - /* State for finalization */ - - /// @dev Stats for each pool that generated fees with sufficient stake to earn rewards. - /// See `_minimumPoolStake` in `MixinParams`. - /// @param 0 Pool ID. - /// @param 1 Epoch number. - /// @return 0 Pool fee stats. - mapping (bytes32 => mapping (uint256 => IStructs.PoolStats)) public poolStatsByEpoch; - - /// @dev Aggregated stats across all pools that generated fees with sufficient stake to earn rewards. - /// See `_minimumPoolStake` in MixinParams. - /// @param 0 Epoch number. - /// @return 0 Reward computation stats. - mapping (uint256 => IStructs.AggregatedStats) public aggregatedStatsByEpoch; - - /// @dev The WETH balance of this contract that is reserved for pool reward payouts. - uint256 public wethReservedForPoolRewards; -} diff --git a/contracts/staking/contracts/src/interfaces/IStaking.sol b/contracts/staking/contracts/src/interfaces/IStaking.sol deleted file mode 100644 index fc336aefcc..0000000000 --- a/contracts/staking/contracts/src/interfaces/IStaking.sol +++ /dev/null @@ -1,251 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "./IStructs.sol"; -import "./IZrxVault.sol"; - - -interface IStaking { - - /// @dev Adds a new exchange address - /// @param addr Address of exchange contract to add - function addExchangeAddress(address addr) - external; - - /// @dev Create a new staking pool. The sender will be the operator of this pool. - /// Note that an operator must be payable. - /// @param operatorShare Portion of rewards owned by the operator, in ppm. - /// @param addOperatorAsMaker Adds operator to the created pool as a maker for convenience iff true. - /// @return poolId The unique pool id generated for this pool. - function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker) - external - returns (bytes32 poolId); - - /// @dev Decreases the operator share for the given pool (i.e. increases pool rewards for members). - /// @param poolId Unique Id of pool. - /// @param newOperatorShare The newly decreased percentage of any rewards owned by the operator. - function decreaseStakingPoolOperatorShare(bytes32 poolId, uint32 newOperatorShare) - external; - - /// @dev Begins a new epoch, preparing the prior one for finalization. - /// Throws if not enough time has passed between epochs or if the - /// previous epoch was not fully finalized. - /// @return numPoolsToFinalize The number of unfinalized pools. - function endEpoch() - external - returns (uint256); - - /// @dev Instantly finalizes a single pool that earned rewards in the previous - /// epoch, crediting it rewards for members and withdrawing operator's - /// rewards as WETH. This can be called by internal functions that need - /// to finalize a pool immediately. Does nothing if the pool is already - /// finalized or did not earn rewards in the previous epoch. - /// @param poolId The pool ID to finalize. - function finalizePool(bytes32 poolId) - external; - - /// @dev Initialize storage owned by this contract. - /// This function should not be called directly. - /// The StakingProxy contract will call it in `attachStakingContract()`. - function init() - external; - - /// @dev Allows caller to join a staking pool as a maker. - /// @param poolId Unique id of pool. - function joinStakingPoolAsMaker(bytes32 poolId) - external; - - /// @dev Moves stake between statuses: 'undelegated' or 'delegated'. - /// Delegated stake can also be moved between pools. - /// This change comes into effect next epoch. - /// @param from status to move stake out of. - /// @param to status to move stake into. - /// @param amount of stake to move. - function moveStake( - IStructs.StakeInfo calldata from, - IStructs.StakeInfo calldata to, - uint256 amount - ) - external; - - /// @dev Pays a protocol fee in ETH. - /// @param makerAddress The address of the order's maker. - /// @param payerAddress The address that is responsible for paying the protocol fee. - /// @param protocolFee The amount of protocol fees that should be paid. - function payProtocolFee( - address makerAddress, - address payerAddress, - uint256 protocolFee - ) - external - payable; - - /// @dev Removes an existing exchange address - /// @param addr Address of exchange contract to remove - function removeExchangeAddress(address addr) - external; - - /// @dev Set all configurable parameters at once. - /// @param _epochDurationInSeconds Minimum seconds between epochs. - /// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. - /// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. - /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. - /// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. - function setParams( - uint256 _epochDurationInSeconds, - uint32 _rewardDelegatedStakeWeight, - uint256 _minimumPoolStake, - uint32 _cobbDouglasAlphaNumerator, - uint32 _cobbDouglasAlphaDenominator - ) - external; - - /// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault. - /// Unstake to retrieve the ZRX. Stake is in the 'Active' status. - /// @param amount of ZRX to stake. - function stake(uint256 amount) - external; - - /// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to - /// the staker. Stake must be in the 'undelegated' status in both the - /// current and next epoch in order to be unstaked. - /// @param amount of ZRX to unstake. - function unstake(uint256 amount) - external; - - /// @dev Withdraws the caller's WETH rewards that have accumulated - /// until the last epoch. - /// @param poolId Unique id of pool. - function withdrawDelegatorRewards(bytes32 poolId) - external; - - /// @dev Computes the reward balance in ETH of a specific member of a pool. - /// @param poolId Unique id of pool. - /// @param member The member of the pool. - /// @return totalReward Balance in ETH. - function computeRewardBalanceOfDelegator(bytes32 poolId, address member) - external - view - returns (uint256 reward); - - /// @dev Computes the reward balance in ETH of the operator of a pool. - /// @param poolId Unique id of pool. - /// @return totalReward Balance in ETH. - function computeRewardBalanceOfOperator(bytes32 poolId) - external - view - returns (uint256 reward); - - /// @dev Returns the earliest end time in seconds of this epoch. - /// The next epoch can begin once this time is reached. - /// Epoch period = [startTimeInSeconds..endTimeInSeconds) - /// @return Time in seconds. - function getCurrentEpochEarliestEndTimeInSeconds() - external - view - returns (uint256); - - /// @dev Gets global stake for a given status. - /// @param stakeStatus UNDELEGATED or DELEGATED - /// @return Global stake for given status. - function getGlobalStakeByStatus(IStructs.StakeStatus stakeStatus) - external - view - returns (IStructs.StoredBalance memory balance); - - /// @dev Gets an owner's stake balances by status. - /// @param staker Owner of stake. - /// @param stakeStatus UNDELEGATED or DELEGATED - /// @return Owner's stake balances for given status. - function getOwnerStakeByStatus( - address staker, - IStructs.StakeStatus stakeStatus - ) - external - view - returns (IStructs.StoredBalance memory balance); - - /// @dev Retrieves all configurable parameter values. - /// @return _epochDurationInSeconds Minimum seconds between epochs. - /// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. - /// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. - /// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. - /// @return _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. - function getParams() - external - view - returns ( - uint256 _epochDurationInSeconds, - uint32 _rewardDelegatedStakeWeight, - uint256 _minimumPoolStake, - uint32 _cobbDouglasAlphaNumerator, - uint32 _cobbDouglasAlphaDenominator - ); - - /// @param staker of stake. - /// @param poolId Unique Id of pool. - /// @return Stake delegated to pool by staker. - function getStakeDelegatedToPoolByOwner(address staker, bytes32 poolId) - external - view - returns (IStructs.StoredBalance memory balance); - - /// @dev Returns a staking pool - /// @param poolId Unique id of pool. - function getStakingPool(bytes32 poolId) - external - view - returns (IStructs.Pool memory); - - /// @dev Get stats on a staking pool in this epoch. - /// @param poolId Pool Id to query. - /// @return PoolStats struct for pool id. - function getStakingPoolStatsThisEpoch(bytes32 poolId) - external - view - returns (IStructs.PoolStats memory); - - /// @dev Returns the total stake delegated to a specific staking pool, - /// across all members. - /// @param poolId Unique Id of pool. - /// @return Total stake delegated to pool. - function getTotalStakeDelegatedToPool(bytes32 poolId) - external - view - returns (IStructs.StoredBalance memory balance); - - /// @dev An overridable way to access the deployed WETH contract. - /// Must be view to allow overrides to access state. - /// @return wethContract The WETH contract instance. - function getWethContract() - external - view - returns (IEtherToken wethContract); - - /// @dev An overridable way to access the deployed zrxVault. - /// Must be view to allow overrides to access state. - /// @return zrxVault The zrxVault contract. - function getZrxVault() - external - view - returns (IZrxVault zrxVault); -} diff --git a/contracts/staking/contracts/src/interfaces/IStakingEvents.sol b/contracts/staking/contracts/src/interfaces/IStakingEvents.sol deleted file mode 100644 index e183698013..0000000000 --- a/contracts/staking/contracts/src/interfaces/IStakingEvents.sol +++ /dev/null @@ -1,131 +0,0 @@ -pragma solidity ^0.5.9; - - -interface IStakingEvents { - - /// @dev Emitted by MixinStake when ZRX is staked. - /// @param staker of ZRX. - /// @param amount of ZRX staked. - event Stake( - address indexed staker, - uint256 amount - ); - - /// @dev Emitted by MixinStake when ZRX is unstaked. - /// @param staker of ZRX. - /// @param amount of ZRX unstaked. - event Unstake( - address indexed staker, - uint256 amount - ); - - /// @dev Emitted by MixinStake when ZRX is unstaked. - /// @param staker of ZRX. - /// @param amount of ZRX unstaked. - event MoveStake( - address indexed staker, - uint256 amount, - uint8 fromStatus, - bytes32 indexed fromPool, - uint8 toStatus, - bytes32 indexed toPool - ); - - /// @dev Emitted by MixinExchangeManager when an exchange is added. - /// @param exchangeAddress Address of new exchange. - event ExchangeAdded( - address exchangeAddress - ); - - /// @dev Emitted by MixinExchangeManager when an exchange is removed. - /// @param exchangeAddress Address of removed exchange. - event ExchangeRemoved( - address exchangeAddress - ); - - /// @dev Emitted by MixinExchangeFees when a pool starts earning rewards in an epoch. - /// @param epoch The epoch in which the pool earned rewards. - /// @param poolId The ID of the pool. - event StakingPoolEarnedRewardsInEpoch( - uint256 indexed epoch, - bytes32 indexed poolId - ); - - /// @dev Emitted by MixinFinalizer when an epoch has ended. - /// @param epoch The epoch that ended. - /// @param numPoolsToFinalize Number of pools that earned rewards during `epoch` and must be finalized. - /// @param rewardsAvailable Rewards available to all pools that earned rewards during `epoch`. - /// @param totalWeightedStake Total weighted stake across all pools that earned rewards during `epoch`. - /// @param totalFeesCollected Total fees collected across all pools that earned rewards during `epoch`. - event EpochEnded( - uint256 indexed epoch, - uint256 numPoolsToFinalize, - uint256 rewardsAvailable, - uint256 totalFeesCollected, - uint256 totalWeightedStake - ); - - /// @dev Emitted by MixinFinalizer when an epoch is fully finalized. - /// @param epoch The epoch being finalized. - /// @param rewardsPaid Total amount of rewards paid out. - /// @param rewardsRemaining Rewards left over. - event EpochFinalized( - uint256 indexed epoch, - uint256 rewardsPaid, - uint256 rewardsRemaining - ); - - /// @dev Emitted by MixinFinalizer when rewards are paid out to a pool. - /// @param epoch The epoch when the rewards were paid out. - /// @param poolId The pool's ID. - /// @param operatorReward Amount of reward paid to pool operator. - /// @param membersReward Amount of reward paid to pool members. - event RewardsPaid( - uint256 indexed epoch, - bytes32 indexed poolId, - uint256 operatorReward, - uint256 membersReward - ); - - /// @dev Emitted whenever staking parameters are changed via the `setParams()` function. - /// @param epochDurationInSeconds Minimum seconds between epochs. - /// @param rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. - /// @param minimumPoolStake Minimum amount of stake required in a pool to collect rewards. - /// @param cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. - /// @param cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. - event ParamsSet( - uint256 epochDurationInSeconds, - uint32 rewardDelegatedStakeWeight, - uint256 minimumPoolStake, - uint256 cobbDouglasAlphaNumerator, - uint256 cobbDouglasAlphaDenominator - ); - - /// @dev Emitted by MixinStakingPool when a new pool is created. - /// @param poolId Unique id generated for pool. - /// @param operator The operator (creator) of pool. - /// @param operatorShare The share of rewards given to the operator, in ppm. - event StakingPoolCreated( - bytes32 poolId, - address operator, - uint32 operatorShare - ); - - /// @dev Emitted by MixinStakingPool when a maker sets their pool. - /// @param makerAddress Adress of maker added to pool. - /// @param poolId Unique id of pool. - event MakerStakingPoolSet( - address indexed makerAddress, - bytes32 indexed poolId - ); - - /// @dev Emitted when a staking pool's operator share is decreased. - /// @param poolId Unique Id of pool. - /// @param oldOperatorShare Previous share of rewards owned by operator. - /// @param newOperatorShare Newly decreased share of rewards owned by operator. - event OperatorShareDecreased( - bytes32 indexed poolId, - uint32 oldOperatorShare, - uint32 newOperatorShare - ); -} diff --git a/contracts/staking/contracts/src/interfaces/IStakingProxy.sol b/contracts/staking/contracts/src/interfaces/IStakingProxy.sol deleted file mode 100644 index c4b6448687..0000000000 --- a/contracts/staking/contracts/src/interfaces/IStakingProxy.sol +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./IStructs.sol"; - - -contract IStakingProxy { - - /// @dev Emitted by StakingProxy when a staking contract is attached. - /// @param newStakingContractAddress Address of newly attached staking contract. - event StakingContractAttachedToProxy( - address newStakingContractAddress - ); - - /// @dev Emitted by StakingProxy when a staking contract is detached. - event StakingContractDetachedFromProxy(); - - /// @dev Attach a staking contract; future calls will be delegated to the staking contract. - /// Note that this is callable only by an authorized address. - /// @param _stakingContract Address of staking contract. - function attachStakingContract(address _stakingContract) - external; - - /// @dev Detach the current staking contract. - /// Note that this is callable only by an authorized address. - function detachStakingContract() - external; - - /// @dev Asserts that an epoch is between 5 and 30 days long. - // Asserts that 0 < cobb douglas alpha value <= 1. - // Asserts that a stake weight is <= 100%. - // Asserts that pools allow >= 1 maker. - // Asserts that all addresses are initialized. - function assertValidStorageParams() - external - view; -} diff --git a/contracts/staking/contracts/src/interfaces/IStorage.sol b/contracts/staking/contracts/src/interfaces/IStorage.sol deleted file mode 100644 index 834117706d..0000000000 --- a/contracts/staking/contracts/src/interfaces/IStorage.sol +++ /dev/null @@ -1,87 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../interfaces/IZrxVault.sol"; -import "../interfaces/IStructs.sol"; - - -interface IStorage { - - function stakingContract() - external - view - returns (address); - - function lastPoolId() - external - view - returns (bytes32); - - function numMakersByPoolId(bytes32 poolId) - external - view - returns (uint256); - - function currentEpoch() - external - view - returns (uint256); - - function currentEpochStartTimeInSeconds() - external - view - returns (uint256); - - function protocolFeesThisEpochByPool(bytes32 poolId) - external - view - returns (uint256); - - function validExchanges(address exchangeAddress) - external - view - returns (bool); - - function epochDurationInSeconds() - external - view - returns (uint256); - - function rewardDelegatedStakeWeight() - external - view - returns(uint32); - - function minimumPoolStake() - external - view - returns (uint256); - - function cobbDouglasAlphaNumerator() - external - view - returns (uint32); - - function cobbDouglasAlphaDenominator() - external - view - returns (uint32); -} diff --git a/contracts/staking/contracts/src/interfaces/IStorageInit.sol b/contracts/staking/contracts/src/interfaces/IStorageInit.sol deleted file mode 100644 index b2e42c4ec6..0000000000 --- a/contracts/staking/contracts/src/interfaces/IStorageInit.sol +++ /dev/null @@ -1,27 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IStorageInit { - - /// @dev Initialize storage owned by this contract. - function init() - external; -} diff --git a/contracts/staking/contracts/src/interfaces/IStructs.sol b/contracts/staking/contracts/src/interfaces/IStructs.sol deleted file mode 100644 index 7e8f4f2694..0000000000 --- a/contracts/staking/contracts/src/interfaces/IStructs.sol +++ /dev/null @@ -1,93 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IStructs { - - /// @dev Stats for a pool that earned rewards. - /// @param feesCollected Fees collected in ETH by this pool. - /// @param weightedStake Amount of weighted stake in the pool. - /// @param membersStake Amount of non-operator stake in the pool. - struct PoolStats { - uint256 feesCollected; - uint256 weightedStake; - uint256 membersStake; - } - - /// @dev Holds stats aggregated across a set of pools. - /// @param rewardsAvailable Rewards (ETH) available to the epoch - /// being finalized (the previous epoch). This is simply the balance - /// of the contract at the end of the epoch. - /// @param numPoolsToFinalize The number of pools that have yet to be finalized through `finalizePools()`. - /// @param totalFeesCollected The total fees collected for the epoch being finalized. - /// @param totalWeightedStake The total fees collected for the epoch being finalized. - /// @param totalRewardsFinalized Amount of rewards that have been paid during finalization. - struct AggregatedStats { - uint256 rewardsAvailable; - uint256 numPoolsToFinalize; - uint256 totalFeesCollected; - uint256 totalWeightedStake; - uint256 totalRewardsFinalized; - } - - /// @dev Encapsulates a balance for the current and next epochs. - /// Note that these balances may be stale if the current epoch - /// is greater than `currentEpoch`. - /// @param currentEpoch The current epoch - /// @param currentEpochBalance Balance in the current epoch. - /// @param nextEpochBalance Balance in `currentEpoch+1`. - struct StoredBalance { - uint64 currentEpoch; - uint96 currentEpochBalance; - uint96 nextEpochBalance; - } - - /// @dev Statuses that stake can exist in. - /// Any stake can be (re)delegated effective at the next epoch - /// Undelegated stake can be withdrawn if it is available in both the current and next epoch - enum StakeStatus { - UNDELEGATED, - DELEGATED - } - - /// @dev Info used to describe a status. - /// @param status Status of the stake. - /// @param poolId Unique Id of pool. This is set when status=DELEGATED. - struct StakeInfo { - StakeStatus status; - bytes32 poolId; - } - - /// @dev Struct to represent a fraction. - /// @param numerator Numerator of fraction. - /// @param denominator Denominator of fraction. - struct Fraction { - uint256 numerator; - uint256 denominator; - } - - /// @dev Holds the metadata for a staking pool. - /// @param operator Operator of the pool. - /// @param operatorShare Fraction of the total balance owned by the operator, in ppm. - struct Pool { - address operator; - uint32 operatorShare; - } -} diff --git a/contracts/staking/contracts/src/interfaces/IZrxVault.sol b/contracts/staking/contracts/src/interfaces/IZrxVault.sol deleted file mode 100644 index 0b17be0d11..0000000000 --- a/contracts/staking/contracts/src/interfaces/IZrxVault.sol +++ /dev/null @@ -1,104 +0,0 @@ -/* - - Copyright 2019 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.5.9; - - -interface IZrxVault { - - /// @dev Emmitted whenever a StakingProxy is set in a vault. - event StakingProxySet(address stakingProxyAddress); - - /// @dev Emitted when the Staking contract is put into Catastrophic Failure Mode - /// @param sender Address of sender (`msg.sender`) - event InCatastrophicFailureMode(address sender); - - /// @dev Emitted when Zrx Tokens are deposited into the vault. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens deposited. - event Deposit( - address indexed staker, - uint256 amount - ); - - /// @dev Emitted when Zrx Tokens are withdrawn from the vault. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens withdrawn. - event Withdraw( - address indexed staker, - uint256 amount - ); - - /// @dev Emitted whenever the ZRX AssetProxy is set. - event ZrxProxySet(address zrxProxyAddress); - - /// @dev Sets the address of the StakingProxy contract. - /// Note that only the contract staker can call this function. - /// @param _stakingProxyAddress Address of Staking proxy contract. - function setStakingProxy(address _stakingProxyAddress) - external; - - /// @dev Vault enters into Catastrophic Failure Mode. - /// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! *** - /// Note that only the contract staker can call this function. - function enterCatastrophicFailure() - external; - - /// @dev Sets the Zrx proxy. - /// Note that only the contract staker can call this. - /// Note that this can only be called when *not* in Catastrophic Failure mode. - /// @param zrxProxyAddress Address of the 0x Zrx Proxy. - function setZrxProxy(address zrxProxyAddress) - external; - - /// @dev Deposit an `amount` of Zrx Tokens from `staker` into the vault. - /// Note that only the Staking contract can call this. - /// Note that this can only be called when *not* in Catastrophic Failure mode. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens to deposit. - function depositFrom(address staker, uint256 amount) - external; - - /// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault. - /// Note that only the Staking contract can call this. - /// Note that this can only be called when *not* in Catastrophic Failure mode. - /// @param staker of Zrx Tokens. - /// @param amount of Zrx Tokens to withdraw. - function withdrawFrom(address staker, uint256 amount) - external; - - /// @dev Withdraw ALL Zrx Tokens to `staker` from the vault. - /// Note that this can only be called when *in* Catastrophic Failure mode. - /// @param staker of Zrx Tokens. - function withdrawAllFrom(address staker) - external - returns (uint256); - - /// @dev Returns the balance in Zrx Tokens of the `staker` - /// @return Balance in Zrx. - function balanceOf(address staker) - external - view - returns (uint256); - - /// @dev Returns the entire balance of Zrx tokens in the vault. - function balanceOfZrxVault() - external - view - returns (uint256); -} diff --git a/contracts/staking/contracts/src/libs/LibCobbDouglas.sol b/contracts/staking/contracts/src/libs/LibCobbDouglas.sol deleted file mode 100644 index b956cab0b0..0000000000 --- a/contracts/staking/contracts/src/libs/LibCobbDouglas.sol +++ /dev/null @@ -1,96 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./LibFixedMath.sol"; - - -library LibCobbDouglas { - - /// @dev The cobb-douglas function used to compute fee-based rewards for - /// staking pools in a given epoch. This function does not perform - /// bounds checking on the inputs, but the following conditions - /// need to be true: - /// 0 <= fees / totalFees <= 1 - /// 0 <= stake / totalStake <= 1 - /// 0 <= alphaNumerator / alphaDenominator <= 1 - /// @param totalRewards collected over an epoch. - /// @param fees Fees attributed to the the staking pool. - /// @param totalFees Total fees collected across all pools that earned rewards. - /// @param stake Stake attributed to the staking pool. - /// @param totalStake Total stake across all pools that earned rewards. - /// @param alphaNumerator Numerator of `alpha` in the cobb-douglas function. - /// @param alphaDenominator Denominator of `alpha` in the cobb-douglas - /// function. - /// @return rewards Rewards owed to the staking pool. - function cobbDouglas( - uint256 totalRewards, - uint256 fees, - uint256 totalFees, - uint256 stake, - uint256 totalStake, - uint32 alphaNumerator, - uint32 alphaDenominator - ) - internal - pure - returns (uint256 rewards) - { - int256 feeRatio = LibFixedMath.toFixed(fees, totalFees); - int256 stakeRatio = LibFixedMath.toFixed(stake, totalStake); - if (feeRatio == 0 || stakeRatio == 0) { - return rewards = 0; - } - // The cobb-doublas function has the form: - // `totalRewards * feeRatio ^ alpha * stakeRatio ^ (1-alpha)` - // This is equivalent to: - // `totalRewards * stakeRatio * e^(alpha * (ln(feeRatio / stakeRatio)))` - // However, because `ln(x)` has the domain of `0 < x < 1` - // and `exp(x)` has the domain of `x < 0`, - // and fixed-point math easily overflows with multiplication, - // we will choose the following if `stakeRatio > feeRatio`: - // `totalRewards * stakeRatio / e^(alpha * (ln(stakeRatio / feeRatio)))` - - // Compute - // `e^(alpha * ln(feeRatio/stakeRatio))` if feeRatio <= stakeRatio - // or - // `e^(alpa * ln(stakeRatio/feeRatio))` if feeRatio > stakeRatio - int256 n = feeRatio <= stakeRatio ? - LibFixedMath.div(feeRatio, stakeRatio) : - LibFixedMath.div(stakeRatio, feeRatio); - n = LibFixedMath.exp( - LibFixedMath.mulDiv( - LibFixedMath.ln(n), - int256(alphaNumerator), - int256(alphaDenominator) - ) - ); - // Compute - // `totalRewards * n` if feeRatio <= stakeRatio - // or - // `totalRewards / n` if stakeRatio > feeRatio - // depending on the choice we made earlier. - n = feeRatio <= stakeRatio ? - LibFixedMath.mul(stakeRatio, n) : - LibFixedMath.div(stakeRatio, n); - // Multiply the above with totalRewards. - rewards = LibFixedMath.uintMul(n, totalRewards); - } -} diff --git a/contracts/staking/contracts/src/libs/LibFixedMath.sol b/contracts/staking/contracts/src/libs/LibFixedMath.sol deleted file mode 100644 index d7f1bae198..0000000000 --- a/contracts/staking/contracts/src/libs/LibFixedMath.sol +++ /dev/null @@ -1,391 +0,0 @@ -/* - - Copyright 2017 Bprotocol Foundation, 2019 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.5.9; - -import "./LibFixedMathRichErrors.sol"; - - -// solhint-disable indent -/// @dev Signed, fixed-point, 127-bit precision math library. -library LibFixedMath { - - // 1 - int256 private constant FIXED_1 = int256(0x0000000000000000000000000000000080000000000000000000000000000000); - // 2**255 - int256 private constant MIN_FIXED_VAL = int256(0x8000000000000000000000000000000000000000000000000000000000000000); - // 1^2 (in fixed-point) - int256 private constant FIXED_1_SQUARED = int256(0x4000000000000000000000000000000000000000000000000000000000000000); - // 1 - int256 private constant LN_MAX_VAL = FIXED_1; - // e ^ -63.875 - int256 private constant LN_MIN_VAL = int256(0x0000000000000000000000000000000000000000000000000000000733048c5a); - // 0 - int256 private constant EXP_MAX_VAL = 0; - // -63.875 - int256 private constant EXP_MIN_VAL = -int256(0x0000000000000000000000000000001ff0000000000000000000000000000000); - - /// @dev Get one as a fixed-point number. - function one() internal pure returns (int256 f) { - f = FIXED_1; - } - - /// @dev Returns the addition of two fixed point numbers, reverting on overflow. - function add(int256 a, int256 b) internal pure returns (int256 c) { - c = _add(a, b); - } - - /// @dev Returns the addition of two fixed point numbers, reverting on overflow. - function sub(int256 a, int256 b) internal pure returns (int256 c) { - if (b == MIN_FIXED_VAL) { - LibRichErrors.rrevert(LibFixedMathRichErrors.SignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_SMALL, - b - )); - } - c = _add(a, -b); - } - - /// @dev Returns the multiplication of two fixed point numbers, reverting on overflow. - function mul(int256 a, int256 b) internal pure returns (int256 c) { - c = _mul(a, b) / FIXED_1; - } - - /// @dev Returns the division of two fixed point numbers. - function div(int256 a, int256 b) internal pure returns (int256 c) { - c = _div(_mul(a, FIXED_1), b); - } - - /// @dev Performs (a * n) / d, without scaling for precision. - function mulDiv(int256 a, int256 n, int256 d) internal pure returns (int256 c) { - c = _div(_mul(a, n), d); - } - - /// @dev Returns the unsigned integer result of multiplying a fixed-point - /// number with an integer, reverting if the multiplication overflows. - /// Negative results are clamped to zero. - function uintMul(int256 f, uint256 u) internal pure returns (uint256) { - if (int256(u) < int256(0)) { - LibRichErrors.rrevert(LibFixedMathRichErrors.UnsignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_LARGE, - u - )); - } - int256 c = _mul(f, int256(u)); - if (c <= 0) { - return 0; - } - return uint256(uint256(c) >> 127); - } - - /// @dev Returns the absolute value of a fixed point number. - function abs(int256 f) internal pure returns (int256 c) { - if (f == MIN_FIXED_VAL) { - LibRichErrors.rrevert(LibFixedMathRichErrors.SignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_SMALL, - f - )); - } - if (f >= 0) { - c = f; - } else { - c = -f; - } - } - - /// @dev Returns 1 / `x`, where `x` is a fixed-point number. - function invert(int256 f) internal pure returns (int256 c) { - c = _div(FIXED_1_SQUARED, f); - } - - /// @dev Convert signed `n` / 1 to a fixed-point number. - function toFixed(int256 n) internal pure returns (int256 f) { - f = _mul(n, FIXED_1); - } - - /// @dev Convert signed `n` / `d` to a fixed-point number. - function toFixed(int256 n, int256 d) internal pure returns (int256 f) { - f = _div(_mul(n, FIXED_1), d); - } - - /// @dev Convert unsigned `n` / 1 to a fixed-point number. - /// Reverts if `n` is too large to fit in a fixed-point number. - function toFixed(uint256 n) internal pure returns (int256 f) { - if (int256(n) < int256(0)) { - LibRichErrors.rrevert(LibFixedMathRichErrors.UnsignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_LARGE, - n - )); - } - f = _mul(int256(n), FIXED_1); - } - - /// @dev Convert unsigned `n` / `d` to a fixed-point number. - /// Reverts if `n` / `d` is too large to fit in a fixed-point number. - function toFixed(uint256 n, uint256 d) internal pure returns (int256 f) { - if (int256(n) < int256(0)) { - LibRichErrors.rrevert(LibFixedMathRichErrors.UnsignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_LARGE, - n - )); - } - if (int256(d) < int256(0)) { - LibRichErrors.rrevert(LibFixedMathRichErrors.UnsignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_LARGE, - d - )); - } - f = _div(_mul(int256(n), FIXED_1), int256(d)); - } - - /// @dev Convert a fixed-point number to an integer. - function toInteger(int256 f) internal pure returns (int256 n) { - return f / FIXED_1; - } - - /// @dev Get the natural logarithm of a fixed-point number 0 < `x` <= LN_MAX_VAL - function ln(int256 x) internal pure returns (int256 r) { - if (x > LN_MAX_VAL) { - LibRichErrors.rrevert(LibFixedMathRichErrors.SignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_LARGE, - x - )); - } - if (x <= 0) { - LibRichErrors.rrevert(LibFixedMathRichErrors.SignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_SMALL, - x - )); - } - if (x == FIXED_1) { - return 0; - } - if (x <= LN_MIN_VAL) { - return EXP_MIN_VAL; - } - - int256 y; - int256 z; - int256 w; - - // Rewrite the input as a quotient of negative natural exponents and a single residual q, such that 1 < q < 2 - // For example: log(0.3) = log(e^-1 * e^-0.25 * 1.0471028872385522) - // = 1 - 0.25 - log(1 + 0.0471028872385522) - // e ^ -32 - if (x <= int256(0x00000000000000000000000000000000000000000001c8464f76164760000000)) { - r -= int256(0x0000000000000000000000000000001000000000000000000000000000000000); // - 32 - x = x * FIXED_1 / int256(0x00000000000000000000000000000000000000000001c8464f76164760000000); // / e ^ -32 - } - // e ^ -16 - if (x <= int256(0x00000000000000000000000000000000000000f1aaddd7742e90000000000000)) { - r -= int256(0x0000000000000000000000000000000800000000000000000000000000000000); // - 16 - x = x * FIXED_1 / int256(0x00000000000000000000000000000000000000f1aaddd7742e90000000000000); // / e ^ -16 - } - // e ^ -8 - if (x <= int256(0x00000000000000000000000000000000000afe10820813d78000000000000000)) { - r -= int256(0x0000000000000000000000000000000400000000000000000000000000000000); // - 8 - x = x * FIXED_1 / int256(0x00000000000000000000000000000000000afe10820813d78000000000000000); // / e ^ -8 - } - // e ^ -4 - if (x <= int256(0x0000000000000000000000000000000002582ab704279ec00000000000000000)) { - r -= int256(0x0000000000000000000000000000000200000000000000000000000000000000); // - 4 - x = x * FIXED_1 / int256(0x0000000000000000000000000000000002582ab704279ec00000000000000000); // / e ^ -4 - } - // e ^ -2 - if (x <= int256(0x000000000000000000000000000000001152aaa3bf81cc000000000000000000)) { - r -= int256(0x0000000000000000000000000000000100000000000000000000000000000000); // - 2 - x = x * FIXED_1 / int256(0x000000000000000000000000000000001152aaa3bf81cc000000000000000000); // / e ^ -2 - } - // e ^ -1 - if (x <= int256(0x000000000000000000000000000000002f16ac6c59de70000000000000000000)) { - r -= int256(0x0000000000000000000000000000000080000000000000000000000000000000); // - 1 - x = x * FIXED_1 / int256(0x000000000000000000000000000000002f16ac6c59de70000000000000000000); // / e ^ -1 - } - // e ^ -0.5 - if (x <= int256(0x000000000000000000000000000000004da2cbf1be5828000000000000000000)) { - r -= int256(0x0000000000000000000000000000000040000000000000000000000000000000); // - 0.5 - x = x * FIXED_1 / int256(0x000000000000000000000000000000004da2cbf1be5828000000000000000000); // / e ^ -0.5 - } - // e ^ -0.25 - if (x <= int256(0x0000000000000000000000000000000063afbe7ab2082c000000000000000000)) { - r -= int256(0x0000000000000000000000000000000020000000000000000000000000000000); // - 0.25 - x = x * FIXED_1 / int256(0x0000000000000000000000000000000063afbe7ab2082c000000000000000000); // / e ^ -0.25 - } - // e ^ -0.125 - if (x <= int256(0x0000000000000000000000000000000070f5a893b608861e1f58934f97aea57d)) { - r -= int256(0x0000000000000000000000000000000010000000000000000000000000000000); // - 0.125 - x = x * FIXED_1 / int256(0x0000000000000000000000000000000070f5a893b608861e1f58934f97aea57d); // / e ^ -0.125 - } - // `x` is now our residual in the range of 1 <= x <= 2 (or close enough). - - // Add the taylor series for log(1 + z), where z = x - 1 - z = y = x - FIXED_1; - w = y * y / FIXED_1; - r += z * (0x100000000000000000000000000000000 - y) / 0x100000000000000000000000000000000; z = z * w / FIXED_1; // add y^01 / 01 - y^02 / 02 - r += z * (0x0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - y) / 0x200000000000000000000000000000000; z = z * w / FIXED_1; // add y^03 / 03 - y^04 / 04 - r += z * (0x099999999999999999999999999999999 - y) / 0x300000000000000000000000000000000; z = z * w / FIXED_1; // add y^05 / 05 - y^06 / 06 - r += z * (0x092492492492492492492492492492492 - y) / 0x400000000000000000000000000000000; z = z * w / FIXED_1; // add y^07 / 07 - y^08 / 08 - r += z * (0x08e38e38e38e38e38e38e38e38e38e38e - y) / 0x500000000000000000000000000000000; z = z * w / FIXED_1; // add y^09 / 09 - y^10 / 10 - r += z * (0x08ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b - y) / 0x600000000000000000000000000000000; z = z * w / FIXED_1; // add y^11 / 11 - y^12 / 12 - r += z * (0x089d89d89d89d89d89d89d89d89d89d89 - y) / 0x700000000000000000000000000000000; z = z * w / FIXED_1; // add y^13 / 13 - y^14 / 14 - r += z * (0x088888888888888888888888888888888 - y) / 0x800000000000000000000000000000000; // add y^15 / 15 - y^16 / 16 - } - - /// @dev Compute the natural exponent for a fixed-point number EXP_MIN_VAL <= `x` <= 1 - function exp(int256 x) internal pure returns (int256 r) { - if (x < EXP_MIN_VAL) { - // Saturate to zero below EXP_MIN_VAL. - return 0; - } - if (x == 0) { - return FIXED_1; - } - if (x > EXP_MAX_VAL) { - LibRichErrors.rrevert(LibFixedMathRichErrors.SignedValueError( - LibFixedMathRichErrors.ValueErrorCodes.TOO_LARGE, - x - )); - } - - // Rewrite the input as a product of natural exponents and a - // single residual q, where q is a number of small magnitude. - // For example: e^-34.419 = e^(-32 - 2 - 0.25 - 0.125 - 0.044) - // = e^-32 * e^-2 * e^-0.25 * e^-0.125 * e^-0.044 - // -> q = -0.044 - - // Multiply with the taylor series for e^q - int256 y; - int256 z; - // q = x % 0.125 (the residual) - z = y = x % 0x0000000000000000000000000000000010000000000000000000000000000000; - z = z * y / FIXED_1; r += z * 0x10e1b3be415a0000; // add y^02 * (20! / 02!) - z = z * y / FIXED_1; r += z * 0x05a0913f6b1e0000; // add y^03 * (20! / 03!) - z = z * y / FIXED_1; r += z * 0x0168244fdac78000; // add y^04 * (20! / 04!) - z = z * y / FIXED_1; r += z * 0x004807432bc18000; // add y^05 * (20! / 05!) - z = z * y / FIXED_1; r += z * 0x000c0135dca04000; // add y^06 * (20! / 06!) - z = z * y / FIXED_1; r += z * 0x0001b707b1cdc000; // add y^07 * (20! / 07!) - z = z * y / FIXED_1; r += z * 0x000036e0f639b800; // add y^08 * (20! / 08!) - z = z * y / FIXED_1; r += z * 0x00000618fee9f800; // add y^09 * (20! / 09!) - z = z * y / FIXED_1; r += z * 0x0000009c197dcc00; // add y^10 * (20! / 10!) - z = z * y / FIXED_1; r += z * 0x0000000e30dce400; // add y^11 * (20! / 11!) - z = z * y / FIXED_1; r += z * 0x000000012ebd1300; // add y^12 * (20! / 12!) - z = z * y / FIXED_1; r += z * 0x0000000017499f00; // add y^13 * (20! / 13!) - z = z * y / FIXED_1; r += z * 0x0000000001a9d480; // add y^14 * (20! / 14!) - z = z * y / FIXED_1; r += z * 0x00000000001c6380; // add y^15 * (20! / 15!) - z = z * y / FIXED_1; r += z * 0x000000000001c638; // add y^16 * (20! / 16!) - z = z * y / FIXED_1; r += z * 0x0000000000001ab8; // add y^17 * (20! / 17!) - z = z * y / FIXED_1; r += z * 0x000000000000017c; // add y^18 * (20! / 18!) - z = z * y / FIXED_1; r += z * 0x0000000000000014; // add y^19 * (20! / 19!) - z = z * y / FIXED_1; r += z * 0x0000000000000001; // add y^20 * (20! / 20!) - r = r / 0x21c3677c82b40000 + y + FIXED_1; // divide by 20! and then add y^1 / 1! + y^0 / 0! - - // Multiply with the non-residual terms. - x = -x; - // e ^ -32 - if ((x & int256(0x0000000000000000000000000000001000000000000000000000000000000000)) != 0) { - r = r * int256(0x00000000000000000000000000000000000000f1aaddd7742e56d32fb9f99744) - / int256(0x0000000000000000000000000043cbaf42a000812488fc5c220ad7b97bf6e99e); // * e ^ -32 - } - // e ^ -16 - if ((x & int256(0x0000000000000000000000000000000800000000000000000000000000000000)) != 0) { - r = r * int256(0x00000000000000000000000000000000000afe10820813d65dfe6a33c07f738f) - / int256(0x000000000000000000000000000005d27a9f51c31b7c2f8038212a0574779991); // * e ^ -16 - } - // e ^ -8 - if ((x & int256(0x0000000000000000000000000000000400000000000000000000000000000000)) != 0) { - r = r * int256(0x0000000000000000000000000000000002582ab704279e8efd15e0265855c47a) - / int256(0x0000000000000000000000000000001b4c902e273a58678d6d3bfdb93db96d02); // * e ^ -8 - } - // e ^ -4 - if ((x & int256(0x0000000000000000000000000000000200000000000000000000000000000000)) != 0) { - r = r * int256(0x000000000000000000000000000000001152aaa3bf81cb9fdb76eae12d029571) - / int256(0x00000000000000000000000000000003b1cc971a9bb5b9867477440d6d157750); // * e ^ -4 - } - // e ^ -2 - if ((x & int256(0x0000000000000000000000000000000100000000000000000000000000000000)) != 0) { - r = r * int256(0x000000000000000000000000000000002f16ac6c59de6f8d5d6f63c1482a7c86) - / int256(0x000000000000000000000000000000015bf0a8b1457695355fb8ac404e7a79e3); // * e ^ -2 - } - // e ^ -1 - if ((x & int256(0x0000000000000000000000000000000080000000000000000000000000000000)) != 0) { - r = r * int256(0x000000000000000000000000000000004da2cbf1be5827f9eb3ad1aa9866ebb3) - / int256(0x00000000000000000000000000000000d3094c70f034de4b96ff7d5b6f99fcd8); // * e ^ -1 - } - // e ^ -0.5 - if ((x & int256(0x0000000000000000000000000000000040000000000000000000000000000000)) != 0) { - r = r * int256(0x0000000000000000000000000000000063afbe7ab2082ba1a0ae5e4eb1b479dc) - / int256(0x00000000000000000000000000000000a45af1e1f40c333b3de1db4dd55f29a7); // * e ^ -0.5 - } - // e ^ -0.25 - if ((x & int256(0x0000000000000000000000000000000020000000000000000000000000000000)) != 0) { - r = r * int256(0x0000000000000000000000000000000070f5a893b608861e1f58934f97aea57d) - / int256(0x00000000000000000000000000000000910b022db7ae67ce76b441c27035c6a1); // * e ^ -0.25 - } - // e ^ -0.125 - if ((x & int256(0x0000000000000000000000000000000010000000000000000000000000000000)) != 0) { - r = r * int256(0x00000000000000000000000000000000783eafef1c0a8f3978c7f81824d62ebf) - / int256(0x0000000000000000000000000000000088415abbe9a76bead8d00cf112e4d4a8); // * e ^ -0.125 - } - } - - /// @dev Returns the multiplication two numbers, reverting on overflow. - function _mul(int256 a, int256 b) private pure returns (int256 c) { - if (a == 0 || b == 0) { - return 0; - } - c = a * b; - if (c / a != b || c / b != a) { - LibRichErrors.rrevert(LibFixedMathRichErrors.BinOpError( - LibFixedMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW, - a, - b - )); - } - } - - /// @dev Returns the division of two numbers, reverting on division by zero. - function _div(int256 a, int256 b) private pure returns (int256 c) { - if (b == 0) { - LibRichErrors.rrevert(LibFixedMathRichErrors.BinOpError( - LibFixedMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO, - a, - b - )); - } - if (a == MIN_FIXED_VAL && b == -1) { - LibRichErrors.rrevert(LibFixedMathRichErrors.BinOpError( - LibFixedMathRichErrors.BinOpErrorCodes.DIVISION_OVERFLOW, - a, - b - )); - } - c = a / b; - } - - /// @dev Adds two numbers, reverting on overflow. - function _add(int256 a, int256 b) private pure returns (int256 c) { - c = a + b; - if ((a < 0 && b < 0 && c > a) || (a > 0 && b > 0 && c < a)) { - LibRichErrors.rrevert(LibFixedMathRichErrors.BinOpError( - LibFixedMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW, - a, - b - )); - } - } -} diff --git a/contracts/staking/contracts/src/libs/LibFixedMathRichErrors.sol b/contracts/staking/contracts/src/libs/LibFixedMathRichErrors.sol deleted file mode 100644 index 5b310150f4..0000000000 --- a/contracts/staking/contracts/src/libs/LibFixedMathRichErrors.sol +++ /dev/null @@ -1,97 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; - - -library LibFixedMathRichErrors { - - enum ValueErrorCodes { - TOO_SMALL, - TOO_LARGE - } - - enum BinOpErrorCodes { - ADDITION_OVERFLOW, - MULTIPLICATION_OVERFLOW, - DIVISION_BY_ZERO, - DIVISION_OVERFLOW - } - - // bytes4(keccak256("SignedValueError(uint8,int256)")) - bytes4 internal constant SIGNED_VALUE_ERROR_SELECTOR = - 0xed2f26a1; - - // bytes4(keccak256("UnsignedValueError(uint8,uint256)")) - bytes4 internal constant UNSIGNED_VALUE_ERROR_SELECTOR = - 0xbd79545f; - - // bytes4(keccak256("BinOpError(uint8,int256,int256)")) - bytes4 internal constant BIN_OP_ERROR_SELECTOR = - 0x8c12dfe7; - - // solhint-disable func-name-mixedcase - function SignedValueError( - ValueErrorCodes error, - int256 n - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - SIGNED_VALUE_ERROR_SELECTOR, - uint8(error), - n - ); - } - - function UnsignedValueError( - ValueErrorCodes error, - uint256 n - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - UNSIGNED_VALUE_ERROR_SELECTOR, - uint8(error), - n - ); - } - - function BinOpError( - BinOpErrorCodes error, - int256 a, - int256 b - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - BIN_OP_ERROR_SELECTOR, - uint8(error), - a, - b - ); - } -} diff --git a/contracts/staking/contracts/src/libs/LibSafeDowncast.sol b/contracts/staking/contracts/src/libs/LibSafeDowncast.sol deleted file mode 100644 index 145745ed27..0000000000 --- a/contracts/staking/contracts/src/libs/LibSafeDowncast.sol +++ /dev/null @@ -1,77 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMathRichErrors.sol"; - - -library LibSafeDowncast { - - /// @dev Safely downcasts to a uint96 - /// Note that this reverts if the input value is too large. - function downcastToUint96(uint256 a) - internal - pure - returns (uint96 b) - { - b = uint96(a); - if (uint256(b) != a) { - LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256DowncastError( - LibSafeMathRichErrors.DowncastErrorCodes.VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96, - a - )); - } - return b; - } - - /// @dev Safely downcasts to a uint64 - /// Note that this reverts if the input value is too large. - function downcastToUint64(uint256 a) - internal - pure - returns (uint64 b) - { - b = uint64(a); - if (uint256(b) != a) { - LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256DowncastError( - LibSafeMathRichErrors.DowncastErrorCodes.VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64, - a - )); - } - return b; - } - - /// @dev Safely downcasts to a uint32 - /// Note that this reverts if the input value is too large. - function downcastToUint32(uint256 a) - internal - pure - returns (uint32 b) - { - b = uint32(a); - if (uint256(b) != a) { - LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256DowncastError( - LibSafeMathRichErrors.DowncastErrorCodes.VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT32, - a - )); - } - return b; - } -} diff --git a/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol b/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol deleted file mode 100644 index 6acca6d6b7..0000000000 --- a/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol +++ /dev/null @@ -1,323 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "../interfaces/IStructs.sol"; - - -library LibStakingRichErrors { - - enum OperatorShareErrorCodes { - OperatorShareTooLarge, - CanOnlyDecreaseOperatorShare - } - - enum InitializationErrorCodes { - MixinSchedulerAlreadyInitialized, - MixinParamsAlreadyInitialized - } - - enum InvalidParamValueErrorCodes { - InvalidCobbDouglasAlpha, - InvalidRewardDelegatedStakeWeight, - InvalidMaximumMakersInPool, - InvalidMinimumPoolStake, - InvalidEpochDuration - } - - enum ExchangeManagerErrorCodes { - ExchangeAlreadyRegistered, - ExchangeNotRegistered - } - - // bytes4(keccak256("OnlyCallableByExchangeError(address)")) - bytes4 internal constant ONLY_CALLABLE_BY_EXCHANGE_ERROR_SELECTOR = - 0xb56d2df0; - - // bytes4(keccak256("ExchangeManagerError(uint8,address)")) - bytes4 internal constant EXCHANGE_MANAGER_ERROR_SELECTOR = - 0xb9588e43; - - // bytes4(keccak256("InsufficientBalanceError(uint256,uint256)")) - bytes4 internal constant INSUFFICIENT_BALANCE_ERROR_SELECTOR = - 0x84c8b7c9; - - // bytes4(keccak256("OnlyCallableByPoolOperatorError(address,bytes32)")) - bytes4 internal constant ONLY_CALLABLE_BY_POOL_OPERATOR_ERROR_SELECTOR = - 0x82ded785; - - // bytes4(keccak256("BlockTimestampTooLowError(uint256,uint256)")) - bytes4 internal constant BLOCK_TIMESTAMP_TOO_LOW_ERROR_SELECTOR = - 0xa6bcde47; - - // bytes4(keccak256("OnlyCallableByStakingContractError(address)")) - bytes4 internal constant ONLY_CALLABLE_BY_STAKING_CONTRACT_ERROR_SELECTOR = - 0xca1d07a2; - - // bytes4(keccak256("OnlyCallableIfInCatastrophicFailureError()")) - bytes internal constant ONLY_CALLABLE_IF_IN_CATASTROPHIC_FAILURE_ERROR = - hex"3ef081cc"; - - // bytes4(keccak256("OnlyCallableIfNotInCatastrophicFailureError()")) - bytes internal constant ONLY_CALLABLE_IF_NOT_IN_CATASTROPHIC_FAILURE_ERROR = - hex"7dd020ce"; - - // bytes4(keccak256("OperatorShareError(uint8,bytes32,uint32)")) - bytes4 internal constant OPERATOR_SHARE_ERROR_SELECTOR = - 0x22df9597; - - // bytes4(keccak256("PoolExistenceError(bytes32,bool)")) - bytes4 internal constant POOL_EXISTENCE_ERROR_SELECTOR = - 0x9ae94f01; - - // bytes4(keccak256("ProxyDestinationCannotBeNilError()")) - bytes internal constant PROXY_DESTINATION_CANNOT_BE_NIL_ERROR = - hex"6eff8285"; - - // bytes4(keccak256("InitializationError(uint8)")) - bytes4 internal constant INITIALIZATION_ERROR_SELECTOR = - 0x0b02d773; - - // bytes4(keccak256("InvalidParamValueError(uint8)")) - bytes4 internal constant INVALID_PARAM_VALUE_ERROR_SELECTOR = - 0xfc45bd11; - - // bytes4(keccak256("InvalidProtocolFeePaymentError(uint256,uint256)")) - bytes4 internal constant INVALID_PROTOCOL_FEE_PAYMENT_ERROR_SELECTOR = - 0x31d7a505; - - // bytes4(keccak256("PreviousEpochNotFinalizedError(uint256,uint256)")) - bytes4 internal constant PREVIOUS_EPOCH_NOT_FINALIZED_ERROR_SELECTOR = - 0x614b800a; - - // bytes4(keccak256("PoolNotFinalizedError(bytes32,uint256)")) - bytes4 internal constant POOL_NOT_FINALIZED_ERROR_SELECTOR = - 0x5caa0b05; - - // solhint-disable func-name-mixedcase - function OnlyCallableByExchangeError( - address senderAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ONLY_CALLABLE_BY_EXCHANGE_ERROR_SELECTOR, - senderAddress - ); - } - - function ExchangeManagerError( - ExchangeManagerErrorCodes errorCodes, - address exchangeAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - EXCHANGE_MANAGER_ERROR_SELECTOR, - errorCodes, - exchangeAddress - ); - } - - function InsufficientBalanceError( - uint256 amount, - uint256 balance - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INSUFFICIENT_BALANCE_ERROR_SELECTOR, - amount, - balance - ); - } - - function OnlyCallableByPoolOperatorError( - address senderAddress, - bytes32 poolId - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ONLY_CALLABLE_BY_POOL_OPERATOR_ERROR_SELECTOR, - senderAddress, - poolId - ); - } - - function BlockTimestampTooLowError( - uint256 epochEndTime, - uint256 currentBlockTimestamp - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - BLOCK_TIMESTAMP_TOO_LOW_ERROR_SELECTOR, - epochEndTime, - currentBlockTimestamp - ); - } - - function OnlyCallableByStakingContractError( - address senderAddress - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - ONLY_CALLABLE_BY_STAKING_CONTRACT_ERROR_SELECTOR, - senderAddress - ); - } - - function OnlyCallableIfInCatastrophicFailureError() - internal - pure - returns (bytes memory) - { - return ONLY_CALLABLE_IF_IN_CATASTROPHIC_FAILURE_ERROR; - } - - function OnlyCallableIfNotInCatastrophicFailureError() - internal - pure - returns (bytes memory) - { - return ONLY_CALLABLE_IF_NOT_IN_CATASTROPHIC_FAILURE_ERROR; - } - - function OperatorShareError( - OperatorShareErrorCodes errorCodes, - bytes32 poolId, - uint32 operatorShare - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - OPERATOR_SHARE_ERROR_SELECTOR, - errorCodes, - poolId, - operatorShare - ); - } - - function PoolExistenceError( - bytes32 poolId, - bool alreadyExists - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - POOL_EXISTENCE_ERROR_SELECTOR, - poolId, - alreadyExists - ); - } - - function InvalidProtocolFeePaymentError( - uint256 expectedProtocolFeePaid, - uint256 actualProtocolFeePaid - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INVALID_PROTOCOL_FEE_PAYMENT_ERROR_SELECTOR, - expectedProtocolFeePaid, - actualProtocolFeePaid - ); - } - - function InitializationError(InitializationErrorCodes code) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INITIALIZATION_ERROR_SELECTOR, - uint8(code) - ); - } - - function InvalidParamValueError(InvalidParamValueErrorCodes code) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - INVALID_PARAM_VALUE_ERROR_SELECTOR, - uint8(code) - ); - } - - function ProxyDestinationCannotBeNilError() - internal - pure - returns (bytes memory) - { - return PROXY_DESTINATION_CANNOT_BE_NIL_ERROR; - } - - function PreviousEpochNotFinalizedError( - uint256 unfinalizedEpoch, - uint256 unfinalizedPoolsRemaining - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - PREVIOUS_EPOCH_NOT_FINALIZED_ERROR_SELECTOR, - unfinalizedEpoch, - unfinalizedPoolsRemaining - ); - } - - function PoolNotFinalizedError( - bytes32 poolId, - uint256 epoch - ) - internal - pure - returns (bytes memory) - { - return abi.encodeWithSelector( - POOL_NOT_FINALIZED_ERROR_SELECTOR, - poolId, - epoch - ); - } -} diff --git a/contracts/staking/contracts/src/stake/MixinStake.sol b/contracts/staking/contracts/src/stake/MixinStake.sol deleted file mode 100644 index ad1ca1722c..0000000000 --- a/contracts/staking/contracts/src/stake/MixinStake.sol +++ /dev/null @@ -1,237 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../staking_pools/MixinStakingPool.sol"; -import "../libs/LibStakingRichErrors.sol"; - - -contract MixinStake is - MixinStakingPool -{ - using LibSafeMath for uint256; - - /// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault. - /// Unstake to retrieve the ZRX. Stake is in the 'Active' status. - /// @param amount Amount of ZRX to stake. - function stake(uint256 amount) - external - { - address staker = msg.sender; - - // deposit equivalent amount of ZRX into vault - getZrxVault().depositFrom(staker, amount); - - // mint stake - _increaseCurrentAndNextBalance( - _ownerStakeByStatus[uint8(IStructs.StakeStatus.UNDELEGATED)][staker], - amount - ); - - // notify - emit Stake( - staker, - amount - ); - } - - /// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to - /// the staker. Stake must be in the 'undelegated' status in both the - /// current and next epoch in order to be unstaked. - /// @param amount Amount of ZRX to unstake. - function unstake(uint256 amount) - external - { - address staker = msg.sender; - - IStructs.StoredBalance memory undelegatedBalance = - _loadCurrentBalance(_ownerStakeByStatus[uint8(IStructs.StakeStatus.UNDELEGATED)][staker]); - - // stake must be undelegated in current and next epoch to be withdrawn - uint256 currentWithdrawableStake = LibSafeMath.min256( - undelegatedBalance.currentEpochBalance, - undelegatedBalance.nextEpochBalance - ); - - if (amount > currentWithdrawableStake) { - LibRichErrors.rrevert( - LibStakingRichErrors.InsufficientBalanceError( - amount, - currentWithdrawableStake - ) - ); - } - - // burn undelegated stake - _decreaseCurrentAndNextBalance( - _ownerStakeByStatus[uint8(IStructs.StakeStatus.UNDELEGATED)][staker], - amount - ); - - // withdraw equivalent amount of ZRX from vault - getZrxVault().withdrawFrom(staker, amount); - - // emit stake event - emit Unstake( - staker, - amount - ); - } - - /// @dev Moves stake between statuses: 'undelegated' or 'delegated'. - /// Delegated stake can also be moved between pools. - /// This change comes into effect next epoch. - /// @param from Status to move stake out of. - /// @param to Status to move stake into. - /// @param amount Amount of stake to move. - function moveStake( - IStructs.StakeInfo calldata from, - IStructs.StakeInfo calldata to, - uint256 amount - ) - external - { - address staker = msg.sender; - - // Sanity check: no-op if no stake is being moved. - if (amount == 0) { - return; - } - - // Sanity check: no-op if moving stake from undelegated to undelegated. - if (from.status == IStructs.StakeStatus.UNDELEGATED && - to.status == IStructs.StakeStatus.UNDELEGATED) { - return; - } - - // handle delegation - if (from.status == IStructs.StakeStatus.DELEGATED) { - _undelegateStake( - from.poolId, - staker, - amount - ); - } - - if (to.status == IStructs.StakeStatus.DELEGATED) { - _delegateStake( - to.poolId, - staker, - amount - ); - } - - // execute move - IStructs.StoredBalance storage fromPtr = _ownerStakeByStatus[uint8(from.status)][staker]; - IStructs.StoredBalance storage toPtr = _ownerStakeByStatus[uint8(to.status)][staker]; - _moveStake( - fromPtr, - toPtr, - amount - ); - - // notify - emit MoveStake( - staker, - amount, - uint8(from.status), - from.poolId, - uint8(to.status), - to.poolId - ); - } - - /// @dev Delegates a owners stake to a staking pool. - /// @param poolId Id of pool to delegate to. - /// @param staker Owner who wants to delegate. - /// @param amount Amount of stake to delegate. - function _delegateStake( - bytes32 poolId, - address staker, - uint256 amount - ) - private - { - // Sanity check the pool we're delegating to exists. - _assertStakingPoolExists(poolId); - - _withdrawAndSyncDelegatorRewards( - poolId, - staker - ); - - // Increase how much stake the staker has delegated to the input pool. - _increaseNextBalance( - _delegatedStakeToPoolByOwner[staker][poolId], - amount - ); - - // Increase how much stake has been delegated to pool. - _increaseNextBalance( - _delegatedStakeByPoolId[poolId], - amount - ); - - // Increase next balance of global delegated stake. - _increaseNextBalance( - _globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)], - amount - ); - } - - /// @dev Un-Delegates a owners stake from a staking pool. - /// @param poolId Id of pool to un-delegate from. - /// @param staker Owner who wants to un-delegate. - /// @param amount Amount of stake to un-delegate. - function _undelegateStake( - bytes32 poolId, - address staker, - uint256 amount - ) - private - { - // sanity check the pool we're undelegating from exists - _assertStakingPoolExists(poolId); - - _withdrawAndSyncDelegatorRewards( - poolId, - staker - ); - - // Decrease how much stake the staker has delegated to the input pool. - _decreaseNextBalance( - _delegatedStakeToPoolByOwner[staker][poolId], - amount - ); - - // Decrease how much stake has been delegated to pool. - _decreaseNextBalance( - _delegatedStakeByPoolId[poolId], - amount - ); - - // Decrease next balance of global delegated stake (aggregated across all stakers). - _decreaseNextBalance( - _globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)], - amount - ); - } -} diff --git a/contracts/staking/contracts/src/stake/MixinStakeBalances.sol b/contracts/staking/contracts/src/stake/MixinStakeBalances.sol deleted file mode 100644 index 70a6fe515f..0000000000 --- a/contracts/staking/contracts/src/stake/MixinStakeBalances.sol +++ /dev/null @@ -1,109 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../interfaces/IStructs.sol"; -import "../immutable/MixinDeploymentConstants.sol"; -import "./MixinStakeStorage.sol"; - - -contract MixinStakeBalances is - MixinStakeStorage, - MixinDeploymentConstants -{ - using LibSafeMath for uint256; - - /// @dev Gets global stake for a given status. - /// @param stakeStatus UNDELEGATED or DELEGATED - /// @return Global stake for given status. - function getGlobalStakeByStatus(IStructs.StakeStatus stakeStatus) - external - view - returns (IStructs.StoredBalance memory balance) - { - balance = _loadCurrentBalance( - _globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)] - ); - if (stakeStatus == IStructs.StakeStatus.UNDELEGATED) { - // Undelegated stake is the difference between total stake and delegated stake - // Note that any ZRX erroneously sent to the vault will be counted as undelegated stake - uint256 totalStake = getZrxVault().balanceOfZrxVault(); - balance.currentEpochBalance = totalStake.safeSub(balance.currentEpochBalance).downcastToUint96(); - balance.nextEpochBalance = totalStake.safeSub(balance.nextEpochBalance).downcastToUint96(); - } - return balance; - } - - /// @dev Gets an owner's stake balances by status. - /// @param staker Owner of stake. - /// @param stakeStatus UNDELEGATED or DELEGATED - /// @return Owner's stake balances for given status. - function getOwnerStakeByStatus( - address staker, - IStructs.StakeStatus stakeStatus - ) - external - view - returns (IStructs.StoredBalance memory balance) - { - balance = _loadCurrentBalance( - _ownerStakeByStatus[uint8(stakeStatus)][staker] - ); - return balance; - } - - /// @dev Returns the total stake for a given staker. - /// @param staker of stake. - /// @return Total ZRX staked by `staker`. - function getTotalStake(address staker) - public - view - returns (uint256) - { - return getZrxVault().balanceOf(staker); - } - - /// @dev Returns the stake delegated to a specific staking pool, by a given staker. - /// @param staker of stake. - /// @param poolId Unique Id of pool. - /// @return Stake delegated to pool by staker. - function getStakeDelegatedToPoolByOwner(address staker, bytes32 poolId) - public - view - returns (IStructs.StoredBalance memory balance) - { - balance = _loadCurrentBalance(_delegatedStakeToPoolByOwner[staker][poolId]); - return balance; - } - - /// @dev Returns the total stake delegated to a specific staking pool, - /// across all members. - /// @param poolId Unique Id of pool. - /// @return Total stake delegated to pool. - function getTotalStakeDelegatedToPool(bytes32 poolId) - public - view - returns (IStructs.StoredBalance memory balance) - { - balance = _loadCurrentBalance(_delegatedStakeByPoolId[poolId]); - return balance; - } -} diff --git a/contracts/staking/contracts/src/stake/MixinStakeStorage.sol b/contracts/staking/contracts/src/stake/MixinStakeStorage.sol deleted file mode 100644 index 92d1a642ce..0000000000 --- a/contracts/staking/contracts/src/stake/MixinStakeStorage.sol +++ /dev/null @@ -1,187 +0,0 @@ -/* - - Copyright 2019 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/LICENSE2.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.5.9; - -import "../libs/LibSafeDowncast.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../interfaces/IStructs.sol"; -import "../sys/MixinScheduler.sol"; - - -/// @dev This mixin contains logic for managing stake storage. -contract MixinStakeStorage is - MixinScheduler -{ - using LibSafeMath for uint256; - using LibSafeDowncast for uint256; - - /// @dev Moves stake between states: 'undelegated' or 'delegated'. - /// This change comes into effect next epoch. - /// @param fromPtr pointer to storage location of `from` stake. - /// @param toPtr pointer to storage location of `to` stake. - /// @param amount of stake to move. - function _moveStake( - IStructs.StoredBalance storage fromPtr, - IStructs.StoredBalance storage toPtr, - uint256 amount - ) - internal - { - // do nothing if pointers are equal - if (_arePointersEqual(fromPtr, toPtr)) { - return; - } - - // load current balances from storage - IStructs.StoredBalance memory from = _loadCurrentBalance(fromPtr); - IStructs.StoredBalance memory to = _loadCurrentBalance(toPtr); - - // sanity check on balance - if (amount > from.nextEpochBalance) { - LibRichErrors.rrevert( - LibStakingRichErrors.InsufficientBalanceError( - amount, - from.nextEpochBalance - ) - ); - } - - // move stake for next epoch - from.nextEpochBalance = uint256(from.nextEpochBalance).safeSub(amount).downcastToUint96(); - to.nextEpochBalance = uint256(to.nextEpochBalance).safeAdd(amount).downcastToUint96(); - - // update state in storage - _storeBalance(fromPtr, from); - _storeBalance(toPtr, to); - } - - /// @dev Loads a balance from storage and updates its fields to reflect values for the current epoch. - /// @param balancePtr to load. - /// @return current balance. - function _loadCurrentBalance(IStructs.StoredBalance storage balancePtr) - internal - view - returns (IStructs.StoredBalance memory balance) - { - balance = balancePtr; - uint256 currentEpoch_ = currentEpoch; - if (currentEpoch_ > balance.currentEpoch) { - balance.currentEpoch = currentEpoch_.downcastToUint64(); - balance.currentEpochBalance = balance.nextEpochBalance; - } - return balance; - } - - /// @dev Increments both the `current` and `next` fields. - /// @param balancePtr storage pointer to balance. - /// @param amount to mint. - function _increaseCurrentAndNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount) - internal - { - // Remove stake from balance - IStructs.StoredBalance memory balance = _loadCurrentBalance(balancePtr); - balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeAdd(amount).downcastToUint96(); - balance.currentEpochBalance = uint256(balance.currentEpochBalance).safeAdd(amount).downcastToUint96(); - - // update state - _storeBalance(balancePtr, balance); - } - - /// @dev Decrements both the `current` and `next` fields. - /// @param balancePtr storage pointer to balance. - /// @param amount to mint. - function _decreaseCurrentAndNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount) - internal - { - // Remove stake from balance - IStructs.StoredBalance memory balance = _loadCurrentBalance(balancePtr); - balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeSub(amount).downcastToUint96(); - balance.currentEpochBalance = uint256(balance.currentEpochBalance).safeSub(amount).downcastToUint96(); - - // update state - _storeBalance(balancePtr, balance); - } - - /// @dev Increments the `next` field (but not the `current` field). - /// @param balancePtr storage pointer to balance. - /// @param amount to increment by. - function _increaseNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount) - internal - { - // Add stake to balance - IStructs.StoredBalance memory balance = _loadCurrentBalance(balancePtr); - balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeAdd(amount).downcastToUint96(); - - // update state - _storeBalance(balancePtr, balance); - } - - /// @dev Decrements the `next` field (but not the `current` field). - /// @param balancePtr storage pointer to balance. - /// @param amount to decrement by. - function _decreaseNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount) - internal - { - // Remove stake from balance - IStructs.StoredBalance memory balance = _loadCurrentBalance(balancePtr); - balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeSub(amount).downcastToUint96(); - - // update state - _storeBalance(balancePtr, balance); - } - - /// @dev Stores a balance in storage. - /// @param balancePtr points to where `balance` will be stored. - /// @param balance to save to storage. - function _storeBalance( - IStructs.StoredBalance storage balancePtr, - IStructs.StoredBalance memory balance - ) - private - { - // note - this compresses into a single `sstore` when optimizations are enabled, - // since the StoredBalance struct occupies a single word of storage. - balancePtr.currentEpoch = balance.currentEpoch; - balancePtr.nextEpochBalance = balance.nextEpochBalance; - balancePtr.currentEpochBalance = balance.currentEpochBalance; - } - - /// @dev Returns true iff storage pointers resolve to same storage location. - /// @param balancePtrA first storage pointer. - /// @param balancePtrB second storage pointer. - /// @return true iff pointers are equal. - function _arePointersEqual( - // solhint-disable-next-line no-unused-vars - IStructs.StoredBalance storage balancePtrA, - // solhint-disable-next-line no-unused-vars - IStructs.StoredBalance storage balancePtrB - ) - private - pure - returns (bool areEqual) - { - assembly { - areEqual := and( - eq(balancePtrA_slot, balancePtrB_slot), - eq(balancePtrA_offset, balancePtrB_offset) - ) - } - return areEqual; - } -} diff --git a/contracts/staking/contracts/src/staking_pools/MixinCumulativeRewards.sol b/contracts/staking/contracts/src/staking_pools/MixinCumulativeRewards.sol deleted file mode 100644 index 27b051c898..0000000000 --- a/contracts/staking/contracts/src/staking_pools/MixinCumulativeRewards.sol +++ /dev/null @@ -1,199 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibFractions.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../stake/MixinStakeBalances.sol"; -import "../immutable/MixinConstants.sol"; - - -contract MixinCumulativeRewards is - MixinStakeBalances, - MixinConstants -{ - using LibSafeMath for uint256; - - /// @dev returns true iff Cumulative Rewards are set - function _isCumulativeRewardSet(IStructs.Fraction memory cumulativeReward) - internal - pure - returns (bool) - { - // We use the denominator as a proxy for whether the cumulative - // reward is set, as setting the cumulative reward always sets this - // field to at least 1. - return cumulativeReward.denominator != 0; - } - - /// @dev Sets a pool's cumulative delegator rewards for the current epoch, - /// given the rewards earned and stake from the last epoch, which will - /// be summed with the previous cumulative rewards for this pool. - /// If the last cumulative reward epoch is the current epoch, this is a - /// no-op. - /// @param poolId The pool ID. - /// @param reward The total reward earned by pool delegators from the last epoch. - /// @param stake The total delegated stake in the pool in the last epoch. - function _addCumulativeReward( - bytes32 poolId, - uint256 reward, - uint256 stake - ) - internal - { - // Fetch the last epoch at which we stored an entry for this pool; - // this is the most up-to-date cumulative rewards for this pool. - uint256 lastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId]; - uint256 currentEpoch_ = currentEpoch; - - // If we already have a record for this epoch, don't overwrite it. - if (lastStoredEpoch == currentEpoch_) { - return; - } - - IStructs.Fraction memory mostRecentCumulativeReward = - _cumulativeRewardsByPool[poolId][lastStoredEpoch]; - - // Compute new cumulative reward - IStructs.Fraction memory cumulativeReward; - if (_isCumulativeRewardSet(mostRecentCumulativeReward)) { - // If we have a prior cumulative reward entry, we sum them as fractions. - (cumulativeReward.numerator, cumulativeReward.denominator) = LibFractions.add( - mostRecentCumulativeReward.numerator, - mostRecentCumulativeReward.denominator, - reward, - stake - ); - // Normalize to prevent overflows in future operations. - (cumulativeReward.numerator, cumulativeReward.denominator) = LibFractions.normalize( - cumulativeReward.numerator, - cumulativeReward.denominator - ); - } else { - (cumulativeReward.numerator, cumulativeReward.denominator) = (reward, stake); - } - - // Store cumulative rewards for this epoch. - _cumulativeRewardsByPool[poolId][currentEpoch_] = cumulativeReward; - _cumulativeRewardsByPoolLastStored[poolId] = currentEpoch_; - } - - /// @dev Sets a pool's cumulative delegator rewards for the current epoch, - /// using the last stored cumulative rewards. If we've already set - /// a CR for this epoch, this is a no-op. - /// @param poolId The pool ID. - function _updateCumulativeReward(bytes32 poolId) - internal - { - // Just add empty rewards for this epoch, which will be added to - // the previous CR, so we end up with the previous CR being set for - // this epoch. - _addCumulativeReward(poolId, 0, 1); - } - - /// @dev Computes a member's reward over a given epoch interval. - /// @param poolId Uniqud Id of pool. - /// @param memberStakeOverInterval Stake delegated to pool by member over - /// the interval. - /// @param beginEpoch Beginning of interval. - /// @param endEpoch End of interval. - /// @return rewards Reward accumulated over interval [beginEpoch, endEpoch] - function _computeMemberRewardOverInterval( - bytes32 poolId, - uint256 memberStakeOverInterval, - uint256 beginEpoch, - uint256 endEpoch - ) - internal - view - returns (uint256 reward) - { - // Sanity check if we can skip computation, as it will result in zero. - if (memberStakeOverInterval == 0 || beginEpoch == endEpoch) { - return 0; - } - - // Sanity check interval - require(beginEpoch < endEpoch, "CR_INTERVAL_INVALID"); - - // Sanity check begin reward - IStructs.Fraction memory beginReward = _getCumulativeRewardAtEpoch(poolId, beginEpoch); - IStructs.Fraction memory endReward = _getCumulativeRewardAtEpoch(poolId, endEpoch); - - // Compute reward - reward = LibFractions.scaleDifference( - endReward.numerator, - endReward.denominator, - beginReward.numerator, - beginReward.denominator, - memberStakeOverInterval - ); - } - - /// @dev Fetch the most recent cumulative reward entry for a pool. - /// @param poolId Unique ID of pool. - /// @return cumulativeReward The most recent cumulative reward `poolId`. - function _getMostRecentCumulativeReward(bytes32 poolId) - private - view - returns (IStructs.Fraction memory cumulativeReward) - { - uint256 lastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId]; - return _cumulativeRewardsByPool[poolId][lastStoredEpoch]; - } - - /// @dev Fetch the cumulative reward for a given epoch. - /// If the corresponding CR does not exist in state, then we backtrack - /// to find its value by querying `epoch-1` and then most recent CR. - /// @param poolId Unique ID of pool. - /// @param epoch The epoch to find the - /// @return cumulativeReward The cumulative reward for `poolId` at `epoch`. - /// @return cumulativeRewardStoredAt Epoch that the `cumulativeReward` is stored at. - function _getCumulativeRewardAtEpoch(bytes32 poolId, uint256 epoch) - private - view - returns (IStructs.Fraction memory cumulativeReward) - { - // Return CR at `epoch`, given it's set. - cumulativeReward = _cumulativeRewardsByPool[poolId][epoch]; - if (_isCumulativeRewardSet(cumulativeReward)) { - return cumulativeReward; - } - - // Return CR at `epoch-1`, given it's set. - uint256 lastEpoch = epoch.safeSub(1); - cumulativeReward = _cumulativeRewardsByPool[poolId][lastEpoch]; - if (_isCumulativeRewardSet(cumulativeReward)) { - return cumulativeReward; - } - - // Return the most recent CR, given it's less than `epoch`. - uint256 mostRecentEpoch = _cumulativeRewardsByPoolLastStored[poolId]; - if (mostRecentEpoch < epoch) { - cumulativeReward = _cumulativeRewardsByPool[poolId][mostRecentEpoch]; - if (_isCumulativeRewardSet(cumulativeReward)) { - return cumulativeReward; - } - } - - // Otherwise return an empty CR. - return IStructs.Fraction(0, 1); - } -} diff --git a/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol b/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol deleted file mode 100644 index 6365ea6bfe..0000000000 --- a/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol +++ /dev/null @@ -1,193 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../libs/LibStakingRichErrors.sol"; -import "../interfaces/IStructs.sol"; -import "../sys/MixinAbstract.sol"; -import "./MixinStakingPoolRewards.sol"; - - -contract MixinStakingPool is - MixinAbstract, - MixinStakingPoolRewards -{ - using LibSafeMath for uint256; - using LibSafeDowncast for uint256; - - /// @dev Asserts that the sender is the operator of the input pool. - /// @param poolId Pool sender must be operator of. - modifier onlyStakingPoolOperator(bytes32 poolId) { - _assertSenderIsPoolOperator(poolId); - _; - } - - /// @dev Create a new staking pool. The sender will be the operator of this pool. - /// Note that an operator must be payable. - /// @param operatorShare Portion of rewards owned by the operator, in ppm. - /// @param addOperatorAsMaker Adds operator to the created pool as a maker for convenience iff true. - /// @return poolId The unique pool id generated for this pool. - function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker) - external - returns (bytes32 poolId) - { - // note that an operator must be payable - address operator = msg.sender; - - // compute unique id for this pool - poolId = lastPoolId = bytes32(uint256(lastPoolId).safeAdd(1)); - - // sanity check on operator share - _assertNewOperatorShare( - poolId, - PPM_DENOMINATOR, // max operator share - operatorShare - ); - - // create and store pool - IStructs.Pool memory pool = IStructs.Pool({ - operator: operator, - operatorShare: operatorShare - }); - _poolById[poolId] = pool; - - // Staking pool has been created - emit StakingPoolCreated(poolId, operator, operatorShare); - - if (addOperatorAsMaker) { - joinStakingPoolAsMaker(poolId); - } - - return poolId; - } - - /// @dev Decreases the operator share for the given pool (i.e. increases pool rewards for members). - /// @param poolId Unique Id of pool. - /// @param newOperatorShare The newly decreased percentage of any rewards owned by the operator. - function decreaseStakingPoolOperatorShare(bytes32 poolId, uint32 newOperatorShare) - external - onlyStakingPoolOperator(poolId) - { - // load pool and assert that we can decrease - uint32 currentOperatorShare = _poolById[poolId].operatorShare; - _assertNewOperatorShare( - poolId, - currentOperatorShare, - newOperatorShare - ); - - // decrease operator share - _poolById[poolId].operatorShare = newOperatorShare; - emit OperatorShareDecreased( - poolId, - currentOperatorShare, - newOperatorShare - ); - } - - /// @dev Allows caller to join a staking pool as a maker. - /// @param poolId Unique id of pool. - function joinStakingPoolAsMaker(bytes32 poolId) - public - { - address maker = msg.sender; - poolIdByMaker[maker] = poolId; - emit MakerStakingPoolSet( - maker, - poolId - ); - } - - /// @dev Returns a staking pool - /// @param poolId Unique id of pool. - function getStakingPool(bytes32 poolId) - public - view - returns (IStructs.Pool memory) - { - return _poolById[poolId]; - } - - /// @dev Reverts iff a staking pool does not exist. - /// @param poolId Unique id of pool. - function _assertStakingPoolExists(bytes32 poolId) - internal - view - { - if (_poolById[poolId].operator == NIL_ADDRESS) { - // we use the pool's operator as a proxy for its existence - LibRichErrors.rrevert( - LibStakingRichErrors.PoolExistenceError( - poolId, - false - ) - ); - } - } - - /// @dev Reverts iff the new operator share is invalid. - /// @param poolId Unique id of pool. - /// @param currentOperatorShare Current operator share. - /// @param newOperatorShare New operator share. - function _assertNewOperatorShare( - bytes32 poolId, - uint32 currentOperatorShare, - uint32 newOperatorShare - ) - private - pure - { - // sanity checks - if (newOperatorShare > PPM_DENOMINATOR) { - // operator share must be a valid fraction - LibRichErrors.rrevert(LibStakingRichErrors.OperatorShareError( - LibStakingRichErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - poolId, - newOperatorShare - )); - } else if (newOperatorShare > currentOperatorShare) { - // new share must be less than or equal to the current share - LibRichErrors.rrevert(LibStakingRichErrors.OperatorShareError( - LibStakingRichErrors.OperatorShareErrorCodes.CanOnlyDecreaseOperatorShare, - poolId, - newOperatorShare - )); - } - } - - /// @dev Asserts that the sender is the operator of the input pool. - /// @param poolId Pool sender must be operator of. - function _assertSenderIsPoolOperator(bytes32 poolId) - private - view - { - address operator = _poolById[poolId].operator; - if (msg.sender != operator) { - LibRichErrors.rrevert( - LibStakingRichErrors.OnlyCallableByPoolOperatorError( - msg.sender, - poolId - ) - ); - } - } -} diff --git a/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol b/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol deleted file mode 100644 index 478113b9fb..0000000000 --- a/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol +++ /dev/null @@ -1,333 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "./MixinCumulativeRewards.sol"; -import "../sys/MixinAbstract.sol"; - - -contract MixinStakingPoolRewards is - MixinAbstract, - MixinCumulativeRewards -{ - using LibSafeMath for uint256; - - /// @dev Withdraws the caller's WETH rewards that have accumulated - /// until the last epoch. - /// @param poolId Unique id of pool. - function withdrawDelegatorRewards(bytes32 poolId) - external - { - _withdrawAndSyncDelegatorRewards(poolId, msg.sender); - } - - /// @dev Computes the reward balance in ETH of the operator of a pool. - /// @param poolId Unique id of pool. - /// @return totalReward Balance in ETH. - function computeRewardBalanceOfOperator(bytes32 poolId) - external - view - returns (uint256 reward) - { - // Because operator rewards are immediately withdrawn as WETH - // on finalization, the only factor in this function are unfinalized - // rewards. - IStructs.Pool memory pool = _poolById[poolId]; - // Get any unfinalized rewards. - (uint256 unfinalizedTotalRewards, uint256 unfinalizedMembersStake) = - _getUnfinalizedPoolRewards(poolId); - - // Get the operators' portion. - (reward,) = _computePoolRewardsSplit( - pool.operatorShare, - unfinalizedTotalRewards, - unfinalizedMembersStake - ); - return reward; - } - - /// @dev Computes the reward balance in ETH of a specific member of a pool. - /// @param poolId Unique id of pool. - /// @param member The member of the pool. - /// @return totalReward Balance in ETH. - function computeRewardBalanceOfDelegator(bytes32 poolId, address member) - external - view - returns (uint256 reward) - { - IStructs.Pool memory pool = _poolById[poolId]; - // Get any unfinalized rewards. - (uint256 unfinalizedTotalRewards, uint256 unfinalizedMembersStake) = - _getUnfinalizedPoolRewards(poolId); - - // Get the members' portion. - (, uint256 unfinalizedMembersReward) = _computePoolRewardsSplit( - pool.operatorShare, - unfinalizedTotalRewards, - unfinalizedMembersStake - ); - return _computeDelegatorReward( - poolId, - member, - unfinalizedMembersReward, - unfinalizedMembersStake - ); - } - - /// @dev Syncs rewards for a delegator. This includes withdrawing rewards - /// rewards and adding/removing dependencies on cumulative rewards. - /// @param poolId Unique id of pool. - /// @param member of the pool. - function _withdrawAndSyncDelegatorRewards( - bytes32 poolId, - address member - ) - internal - { - // Ensure the pool is finalized. - _assertPoolFinalizedLastEpoch(poolId); - - // Compute balance owed to delegator - uint256 balance = _computeDelegatorReward( - poolId, - member, - // No unfinalized values because we ensured the pool is already - // finalized. - 0, - 0 - ); - - // Sync the delegated stake balance. This will ensure future calls of - // `_computeDelegatorReward` during this epoch will return 0, - // preventing a delegator from withdrawing more than once an epoch. - _delegatedStakeToPoolByOwner[member][poolId] = - _loadCurrentBalance(_delegatedStakeToPoolByOwner[member][poolId]); - - // Withdraw non-0 balance - if (balance != 0) { - // Decrease the balance of the pool - _decreasePoolRewards(poolId, balance); - - // Withdraw the member's WETH balance - getWethContract().transfer(member, balance); - } - - // Ensure a cumulative reward entry exists for this epoch, - // copying the previous epoch's CR if one doesn't exist already. - _updateCumulativeReward(poolId); - } - - /// @dev Handles a pool's reward at the current epoch. - /// This will split the reward between the operator and members, - /// depositing them into their respective vaults, and update the - /// accounting needed to allow members to withdraw their individual - /// rewards. - /// @param poolId Unique Id of pool. - /// @param reward received by the pool. - /// @param membersStake the amount of non-operator delegated stake that - /// will split the reward. - /// @return operatorReward Portion of `reward` given to the pool operator. - /// @return membersReward Portion of `reward` given to the pool members. - function _syncPoolRewards( - bytes32 poolId, - uint256 reward, - uint256 membersStake - ) - internal - returns (uint256 operatorReward, uint256 membersReward) - { - IStructs.Pool memory pool = _poolById[poolId]; - - // Split the reward between operator and members - (operatorReward, membersReward) = _computePoolRewardsSplit( - pool.operatorShare, - reward, - membersStake - ); - - if (operatorReward > 0) { - // Transfer the operator's weth reward to the operator - getWethContract().transfer(pool.operator, operatorReward); - } - - if (membersReward > 0) { - // Increase the balance of the pool - _increasePoolRewards(poolId, membersReward); - // Create a cumulative reward entry at the current epoch. - _addCumulativeReward(poolId, membersReward, membersStake); - } - - return (operatorReward, membersReward); - } - - /// @dev Compute the split of a pool reward between the operator and members - /// based on the `operatorShare` and `membersStake`. - /// @param operatorShare The fraction of rewards owed to the operator, - /// in PPM. - /// @param totalReward The pool reward. - /// @param membersStake The amount of member (non-operator) stake delegated - /// to the pool in the epoch the rewards were earned. - /// @return operatorReward Portion of `totalReward` given to the pool operator. - /// @return membersReward Portion of `totalReward` given to the pool members. - function _computePoolRewardsSplit( - uint32 operatorShare, - uint256 totalReward, - uint256 membersStake - ) - internal - pure - returns (uint256 operatorReward, uint256 membersReward) - { - if (membersStake == 0) { - operatorReward = totalReward; - } else { - operatorReward = LibMath.getPartialAmountCeil( - uint256(operatorShare), - PPM_DENOMINATOR, - totalReward - ); - membersReward = totalReward.safeSub(operatorReward); - } - return (operatorReward, membersReward); - } - - /// @dev Computes the reward balance in ETH of a specific member of a pool. - /// @param poolId Unique id of pool. - /// @param member of the pool. - /// @param unfinalizedMembersReward Unfinalized total members reward (if any). - /// @param unfinalizedMembersStake Unfinalized total members stake (if any). - /// @return reward Balance in WETH. - function _computeDelegatorReward( - bytes32 poolId, - address member, - uint256 unfinalizedMembersReward, - uint256 unfinalizedMembersStake - ) - private - view - returns (uint256 reward) - { - uint256 currentEpoch_ = currentEpoch; - IStructs.StoredBalance memory delegatedStake = _delegatedStakeToPoolByOwner[member][poolId]; - - // There can be no rewards if the last epoch when stake was stored is - // equal to the current epoch, because all prior rewards, including - // rewards finalized this epoch have been claimed. - if (delegatedStake.currentEpoch == currentEpoch_) { - return 0; - } - - // We account for rewards over 3 intervals, below. - - // 1/3 Unfinalized rewards earned in `currentEpoch - 1`. - reward = _computeUnfinalizedDelegatorReward( - delegatedStake, - currentEpoch_, - unfinalizedMembersReward, - unfinalizedMembersStake - ); - - // 2/3 Finalized rewards earned in epochs [`delegatedStake.currentEpoch + 1` .. `currentEpoch - 1`] - uint256 delegatedStakeNextEpoch = uint256(delegatedStake.currentEpoch).safeAdd(1); - reward = reward.safeAdd( - _computeMemberRewardOverInterval( - poolId, - delegatedStake.currentEpochBalance, - delegatedStake.currentEpoch, - delegatedStakeNextEpoch - ) - ); - - // 3/3 Finalized rewards earned in epoch `delegatedStake.currentEpoch`. - reward = reward.safeAdd( - _computeMemberRewardOverInterval( - poolId, - delegatedStake.nextEpochBalance, - delegatedStakeNextEpoch, - currentEpoch_ - ) - ); - - return reward; - } - - /// @dev Computes the unfinalized rewards earned by a delegator in the last epoch. - /// @param delegatedStake Amount of stake delegated to pool by a specific staker - /// @param currentEpoch_ The epoch in which this call is executing - /// @param unfinalizedMembersReward Unfinalized total members reward (if any). - /// @param unfinalizedMembersStake Unfinalized total members stake (if any). - /// @return reward Balance in WETH. - function _computeUnfinalizedDelegatorReward( - IStructs.StoredBalance memory delegatedStake, - uint256 currentEpoch_, - uint256 unfinalizedMembersReward, - uint256 unfinalizedMembersStake - ) - private - pure - returns (uint256) - { - // If there are unfinalized rewards this epoch, compute the member's - // share. - if (unfinalizedMembersReward == 0 || unfinalizedMembersStake == 0) { - return 0; - } - - // Unfinalized rewards are always earned from stake in - // the prior epoch so we want the stake at `currentEpoch_-1`. - uint256 unfinalizedStakeBalance = delegatedStake.currentEpoch >= currentEpoch_.safeSub(1) ? - delegatedStake.currentEpochBalance : - delegatedStake.nextEpochBalance; - - // Sanity check to save gas on computation - if (unfinalizedStakeBalance == 0) { - return 0; - } - - // Compute unfinalized reward - return LibMath.getPartialAmountFloor( - unfinalizedMembersReward, - unfinalizedMembersStake, - unfinalizedStakeBalance - ); - } - - /// @dev Increases rewards for a pool. - /// @param poolId Unique id of pool. - /// @param amount Amount to increment rewards by. - function _increasePoolRewards(bytes32 poolId, uint256 amount) - private - { - rewardsByPoolId[poolId] = rewardsByPoolId[poolId].safeAdd(amount); - wethReservedForPoolRewards = wethReservedForPoolRewards.safeAdd(amount); - } - - /// @dev Decreases rewards for a pool. - /// @param poolId Unique id of pool. - /// @param amount Amount to decrement rewards by. - function _decreasePoolRewards(bytes32 poolId, uint256 amount) - private - { - rewardsByPoolId[poolId] = rewardsByPoolId[poolId].safeSub(amount); - wethReservedForPoolRewards = wethReservedForPoolRewards.safeSub(amount); - } -} diff --git a/contracts/staking/contracts/src/sys/MixinAbstract.sol b/contracts/staking/contracts/src/sys/MixinAbstract.sol deleted file mode 100644 index 9d2ad630eb..0000000000 --- a/contracts/staking/contracts/src/sys/MixinAbstract.sol +++ /dev/null @@ -1,46 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - - -/// @dev Exposes some internal functions from various contracts to avoid -/// cyclical dependencies. -contract MixinAbstract { - - /// @dev Computes the reward owed to a pool during finalization. - /// Does nothing if the pool is already finalized. - /// @param poolId The pool's ID. - /// @return totalReward The total reward owed to a pool. - /// @return membersStake The total stake for all non-operator members in - /// this pool. - function _getUnfinalizedPoolRewards(bytes32 poolId) - internal - view - returns ( - uint256 totalReward, - uint256 membersStake - ); - - /// @dev Asserts that a pool has been finalized last epoch. - /// @param poolId The id of the pool that should have been finalized. - function _assertPoolFinalizedLastEpoch(bytes32 poolId) - internal - view; -} diff --git a/contracts/staking/contracts/src/sys/MixinFinalizer.sol b/contracts/staking/contracts/src/sys/MixinFinalizer.sol deleted file mode 100644 index 8626b0d151..0000000000 --- a/contracts/staking/contracts/src/sys/MixinFinalizer.sol +++ /dev/null @@ -1,255 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../libs/LibCobbDouglas.sol"; -import "../libs/LibStakingRichErrors.sol"; -import "../interfaces/IStructs.sol"; -import "../staking_pools/MixinStakingPoolRewards.sol"; - - -contract MixinFinalizer is - MixinStakingPoolRewards -{ - using LibSafeMath for uint256; - - /// @dev Begins a new epoch, preparing the prior one for finalization. - /// Throws if not enough time has passed between epochs or if the - /// previous epoch was not fully finalized. - /// @return numPoolsToFinalize The number of unfinalized pools. - function endEpoch() - external - returns (uint256) - { - uint256 currentEpoch_ = currentEpoch; - uint256 prevEpoch = currentEpoch_.safeSub(1); - - // Make sure the previous epoch has been fully finalized. - uint256 numPoolsToFinalizeFromPrevEpoch = aggregatedStatsByEpoch[prevEpoch].numPoolsToFinalize; - if (numPoolsToFinalizeFromPrevEpoch != 0) { - LibRichErrors.rrevert( - LibStakingRichErrors.PreviousEpochNotFinalizedError( - prevEpoch, - numPoolsToFinalizeFromPrevEpoch - ) - ); - } - - // Convert all ETH to WETH; the WETH balance of this contract is the total rewards. - _wrapEth(); - - // Load aggregated stats for the epoch we're ending. - aggregatedStatsByEpoch[currentEpoch_].rewardsAvailable = _getAvailableWethBalance(); - IStructs.AggregatedStats memory aggregatedStats = aggregatedStatsByEpoch[currentEpoch_]; - - // Emit an event. - emit EpochEnded( - currentEpoch_, - aggregatedStats.numPoolsToFinalize, - aggregatedStats.rewardsAvailable, - aggregatedStats.totalFeesCollected, - aggregatedStats.totalWeightedStake - ); - - // Advance the epoch. This will revert if not enough time has passed. - _goToNextEpoch(); - - // If there are no pools to finalize then the epoch is finalized. - if (aggregatedStats.numPoolsToFinalize == 0) { - emit EpochFinalized(currentEpoch_, 0, aggregatedStats.rewardsAvailable); - } - - return aggregatedStats.numPoolsToFinalize; - } - - /// @dev Instantly finalizes a single pool that earned rewards in the previous - /// epoch, crediting it rewards for members and withdrawing operator's - /// rewards as WETH. This can be called by internal functions that need - /// to finalize a pool immediately. Does nothing if the pool is already - /// finalized or did not earn rewards in the previous epoch. - /// @param poolId The pool ID to finalize. - function finalizePool(bytes32 poolId) - external - { - // Compute relevant epochs - uint256 currentEpoch_ = currentEpoch; - uint256 prevEpoch = currentEpoch_.safeSub(1); - - // Load the aggregated stats into memory; noop if no pools to finalize. - IStructs.AggregatedStats memory aggregatedStats = aggregatedStatsByEpoch[prevEpoch]; - if (aggregatedStats.numPoolsToFinalize == 0) { - return; - } - - // Noop if the pool did not earn rewards or already finalized (has no fees). - IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][prevEpoch]; - if (poolStats.feesCollected == 0) { - return; - } - - // Clear the pool stats so we don't finalize it again, and to recoup - // some gas. - delete poolStatsByEpoch[poolId][prevEpoch]; - - // Compute the rewards. - uint256 rewards = _getUnfinalizedPoolRewardsFromPoolStats(poolStats, aggregatedStats); - - // Pay the operator and update rewards for the pool. - // Note that we credit at the CURRENT epoch even though these rewards - // were earned in the previous epoch. - (uint256 operatorReward, uint256 membersReward) = _syncPoolRewards( - poolId, - rewards, - poolStats.membersStake - ); - - // Emit an event. - emit RewardsPaid( - currentEpoch_, - poolId, - operatorReward, - membersReward - ); - - uint256 totalReward = operatorReward.safeAdd(membersReward); - - // Increase `totalRewardsFinalized`. - aggregatedStatsByEpoch[prevEpoch].totalRewardsFinalized = - aggregatedStats.totalRewardsFinalized = - aggregatedStats.totalRewardsFinalized.safeAdd(totalReward); - - // Decrease the number of unfinalized pools left. - aggregatedStatsByEpoch[prevEpoch].numPoolsToFinalize = - aggregatedStats.numPoolsToFinalize = - aggregatedStats.numPoolsToFinalize.safeSub(1); - - // If there are no more unfinalized pools remaining, the epoch is - // finalized. - if (aggregatedStats.numPoolsToFinalize == 0) { - emit EpochFinalized( - prevEpoch, - aggregatedStats.totalRewardsFinalized, - aggregatedStats.rewardsAvailable.safeSub(aggregatedStats.totalRewardsFinalized) - ); - } - } - - /// @dev Computes the reward owed to a pool during finalization. - /// Does nothing if the pool is already finalized. - /// @param poolId The pool's ID. - /// @return totalReward The total reward owed to a pool. - /// @return membersStake The total stake for all non-operator members in - /// this pool. - function _getUnfinalizedPoolRewards(bytes32 poolId) - internal - view - returns ( - uint256 reward, - uint256 membersStake - ) - { - uint256 prevEpoch = currentEpoch.safeSub(1); - IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][prevEpoch]; - reward = _getUnfinalizedPoolRewardsFromPoolStats(poolStats, aggregatedStatsByEpoch[prevEpoch]); - membersStake = poolStats.membersStake; - } - - /// @dev Converts the entire ETH balance of this contract into WETH. - function _wrapEth() - internal - { - uint256 ethBalance = address(this).balance; - if (ethBalance != 0) { - getWethContract().deposit.value(ethBalance)(); - } - } - - /// @dev Returns the WETH balance of this contract, minus - /// any WETH that has already been reserved for rewards. - function _getAvailableWethBalance() - internal - view - returns (uint256 wethBalance) - { - wethBalance = getWethContract().balanceOf(address(this)) - .safeSub(wethReservedForPoolRewards); - - return wethBalance; - } - - /// @dev Asserts that a pool has been finalized last epoch. - /// @param poolId The id of the pool that should have been finalized. - function _assertPoolFinalizedLastEpoch(bytes32 poolId) - internal - view - { - uint256 prevEpoch = currentEpoch.safeSub(1); - IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][prevEpoch]; - - // A pool that has any fees remaining has not been finalized - if (poolStats.feesCollected != 0) { - LibRichErrors.rrevert( - LibStakingRichErrors.PoolNotFinalizedError( - poolId, - prevEpoch - ) - ); - } - } - - /// @dev Computes the reward owed to a pool during finalization. - /// @param poolStats Stats for a specific pool. - /// @param aggregatedStats Stats aggregated across all pools. - /// @return rewards Unfinalized rewards for the input pool. - function _getUnfinalizedPoolRewardsFromPoolStats( - IStructs.PoolStats memory poolStats, - IStructs.AggregatedStats memory aggregatedStats - ) - private - view - returns (uint256 rewards) - { - // There can't be any rewards if the pool did not collect any fees. - if (poolStats.feesCollected == 0) { - return rewards; - } - - // Use the cobb-douglas function to compute the total reward. - rewards = LibCobbDouglas.cobbDouglas( - aggregatedStats.rewardsAvailable, - poolStats.feesCollected, - aggregatedStats.totalFeesCollected, - poolStats.weightedStake, - aggregatedStats.totalWeightedStake, - cobbDouglasAlphaNumerator, - cobbDouglasAlphaDenominator - ); - - // Clip the reward to always be under - // `rewardsAvailable - totalRewardsPaid`, - // in case cobb-douglas overflows, which should be unlikely. - uint256 rewardsRemaining = aggregatedStats.rewardsAvailable.safeSub(aggregatedStats.totalRewardsFinalized); - if (rewardsRemaining < rewards) { - rewards = rewardsRemaining; - } - } -} diff --git a/contracts/staking/contracts/src/sys/MixinParams.sol b/contracts/staking/contracts/src/sys/MixinParams.sol deleted file mode 100644 index 167c17a3a8..0000000000 --- a/contracts/staking/contracts/src/sys/MixinParams.sol +++ /dev/null @@ -1,158 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "../immutable/MixinStorage.sol"; -import "../immutable/MixinConstants.sol"; -import "../interfaces/IStakingEvents.sol"; -import "../interfaces/IStakingProxy.sol"; -import "../libs/LibStakingRichErrors.sol"; - - -contract MixinParams is - IStakingEvents, - MixinStorage, - MixinConstants -{ - /// @dev Set all configurable parameters at once. - /// @param _epochDurationInSeconds Minimum seconds between epochs. - /// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. - /// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. - /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. - /// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. - function setParams( - uint256 _epochDurationInSeconds, - uint32 _rewardDelegatedStakeWeight, - uint256 _minimumPoolStake, - uint32 _cobbDouglasAlphaNumerator, - uint32 _cobbDouglasAlphaDenominator - ) - external - onlyAuthorized - { - _setParams( - _epochDurationInSeconds, - _rewardDelegatedStakeWeight, - _minimumPoolStake, - _cobbDouglasAlphaNumerator, - _cobbDouglasAlphaDenominator - ); - - // Let the staking proxy enforce that these parameters are within - // acceptable ranges. - IStakingProxy(address(this)).assertValidStorageParams(); - } - - /// @dev Retrieves all configurable parameter values. - /// @return _epochDurationInSeconds Minimum seconds between epochs. - /// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. - /// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. - /// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. - /// @return _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. - function getParams() - external - view - returns ( - uint256 _epochDurationInSeconds, - uint32 _rewardDelegatedStakeWeight, - uint256 _minimumPoolStake, - uint32 _cobbDouglasAlphaNumerator, - uint32 _cobbDouglasAlphaDenominator - ) - { - _epochDurationInSeconds = epochDurationInSeconds; - _rewardDelegatedStakeWeight = rewardDelegatedStakeWeight; - _minimumPoolStake = minimumPoolStake; - _cobbDouglasAlphaNumerator = cobbDouglasAlphaNumerator; - _cobbDouglasAlphaDenominator = cobbDouglasAlphaDenominator; - } - - /// @dev Initialize storage belonging to this mixin. - function _initMixinParams() - internal - { - // Ensure state is uninitialized. - _assertParamsNotInitialized(); - - // Set up defaults. - uint256 _epochDurationInSeconds = 10 days; - uint32 _rewardDelegatedStakeWeight = (90 * PPM_DENOMINATOR) / 100; - uint256 _minimumPoolStake = 100 * MIN_TOKEN_VALUE; - uint32 _cobbDouglasAlphaNumerator = 2; - uint32 _cobbDouglasAlphaDenominator = 3; - - _setParams( - _epochDurationInSeconds, - _rewardDelegatedStakeWeight, - _minimumPoolStake, - _cobbDouglasAlphaNumerator, - _cobbDouglasAlphaDenominator - ); - } - - /// @dev Asserts that upgradable storage has not yet been initialized. - function _assertParamsNotInitialized() - internal - view - { - if (epochDurationInSeconds != 0 && - rewardDelegatedStakeWeight != 0 && - minimumPoolStake != 0 && - cobbDouglasAlphaNumerator != 0 && - cobbDouglasAlphaDenominator != 0 - ) { - LibRichErrors.rrevert( - LibStakingRichErrors.InitializationError( - LibStakingRichErrors.InitializationErrorCodes.MixinParamsAlreadyInitialized - ) - ); - } - } - - /// @dev Set all configurable parameters at once. - /// @param _epochDurationInSeconds Minimum seconds between epochs. - /// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. - /// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. - /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. - /// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. - function _setParams( - uint256 _epochDurationInSeconds, - uint32 _rewardDelegatedStakeWeight, - uint256 _minimumPoolStake, - uint32 _cobbDouglasAlphaNumerator, - uint32 _cobbDouglasAlphaDenominator - ) - private - { - epochDurationInSeconds = _epochDurationInSeconds; - rewardDelegatedStakeWeight = _rewardDelegatedStakeWeight; - minimumPoolStake = _minimumPoolStake; - cobbDouglasAlphaNumerator = _cobbDouglasAlphaNumerator; - cobbDouglasAlphaDenominator = _cobbDouglasAlphaDenominator; - - emit ParamsSet( - _epochDurationInSeconds, - _rewardDelegatedStakeWeight, - _minimumPoolStake, - _cobbDouglasAlphaNumerator, - _cobbDouglasAlphaDenominator - ); - } -} diff --git a/contracts/staking/contracts/src/sys/MixinScheduler.sol b/contracts/staking/contracts/src/sys/MixinScheduler.sol deleted file mode 100644 index 0c52978c03..0000000000 --- a/contracts/staking/contracts/src/sys/MixinScheduler.sol +++ /dev/null @@ -1,98 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "../libs/LibStakingRichErrors.sol"; -import "../immutable/MixinStorage.sol"; -import "../interfaces/IStakingEvents.sol"; - - -contract MixinScheduler is - IStakingEvents, - MixinStorage -{ - using LibSafeMath for uint256; - - /// @dev Returns the earliest end time in seconds of this epoch. - /// The next epoch can begin once this time is reached. - /// Epoch period = [startTimeInSeconds..endTimeInSeconds) - /// @return Time in seconds. - function getCurrentEpochEarliestEndTimeInSeconds() - public - view - returns (uint256) - { - return currentEpochStartTimeInSeconds.safeAdd(epochDurationInSeconds); - } - - /// @dev Initializes state owned by this mixin. - /// Fails if state was already initialized. - function _initMixinScheduler() - internal - { - // assert the current values before overwriting them. - _assertSchedulerNotInitialized(); - - // solhint-disable-next-line - currentEpochStartTimeInSeconds = block.timestamp; - currentEpoch = 1; - } - - /// @dev Moves to the next epoch, given the current epoch period has ended. - /// Time intervals that are measured in epochs (like timeLocks) are also incremented, given - /// their periods have ended. - function _goToNextEpoch() - internal - { - // get current timestamp - // solhint-disable-next-line not-rely-on-time - uint256 currentBlockTimestamp = block.timestamp; - - // validate that we can increment the current epoch - uint256 epochEndTime = getCurrentEpochEarliestEndTimeInSeconds(); - if (epochEndTime > currentBlockTimestamp) { - LibRichErrors.rrevert(LibStakingRichErrors.BlockTimestampTooLowError( - epochEndTime, - currentBlockTimestamp - )); - } - - // incremment epoch - uint256 nextEpoch = currentEpoch.safeAdd(1); - currentEpoch = nextEpoch; - currentEpochStartTimeInSeconds = currentBlockTimestamp; - } - - /// @dev Assert scheduler state before initializing it. - /// This must be updated for each migration. - function _assertSchedulerNotInitialized() - internal - view - { - if (currentEpochStartTimeInSeconds != 0) { - LibRichErrors.rrevert( - LibStakingRichErrors.InitializationError( - LibStakingRichErrors.InitializationErrorCodes.MixinSchedulerAlreadyInitialized - ) - ); - } - } -} diff --git a/contracts/staking/contracts/test/TestAssertStorageParams.sol b/contracts/staking/contracts/test/TestAssertStorageParams.sol deleted file mode 100644 index 6482b3b892..0000000000 --- a/contracts/staking/contracts/test/TestAssertStorageParams.sol +++ /dev/null @@ -1,55 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/StakingProxy.sol"; - - -// solhint-disable no-empty-blocks -contract TestAssertStorageParams is - StakingProxy -{ - struct StorageParams { - uint256 epochDurationInSeconds; - uint32 rewardDelegatedStakeWeight; - uint256 minimumPoolStake; - uint32 cobbDouglasAlphaNumerator; - uint32 cobbDouglasAlphaDenominator; - } - - constructor() - public - StakingProxy(NIL_ADDRESS) - {} - - function setAndAssertParams(StorageParams memory params) - public - { - epochDurationInSeconds = params.epochDurationInSeconds; - rewardDelegatedStakeWeight = params.rewardDelegatedStakeWeight; - minimumPoolStake = params.minimumPoolStake; - cobbDouglasAlphaNumerator = params.cobbDouglasAlphaNumerator; - cobbDouglasAlphaDenominator = params.cobbDouglasAlphaDenominator; - assertValidStorageParams(); - } - - function _attachStakingContract(address) - internal - {} -} diff --git a/contracts/staking/contracts/test/TestCobbDouglas.sol b/contracts/staking/contracts/test/TestCobbDouglas.sol deleted file mode 100644 index cb8982afc9..0000000000 --- a/contracts/staking/contracts/test/TestCobbDouglas.sol +++ /dev/null @@ -1,49 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/libs/LibCobbDouglas.sol"; - - -contract TestCobbDouglas { - - function cobbDouglas( - uint256 totalRewards, - uint256 fees, - uint256 totalFees, - uint256 stake, - uint256 totalStake, - uint32 alphaNumerator, - uint32 alphaDenominator - ) - external - pure - returns (uint256 rewards) - { - rewards = LibCobbDouglas.cobbDouglas( - totalRewards, - fees, - totalFees, - stake, - totalStake, - alphaNumerator, - alphaDenominator - ); - } -} diff --git a/contracts/staking/contracts/test/TestCumulativeRewardTracking.sol b/contracts/staking/contracts/test/TestCumulativeRewardTracking.sol deleted file mode 100644 index 94c254e7d3..0000000000 --- a/contracts/staking/contracts/test/TestCumulativeRewardTracking.sol +++ /dev/null @@ -1,64 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./TestStaking.sol"; - - -// solhint-disable no-empty-blocks -contract TestCumulativeRewardTracking is - TestStaking -{ - event SetCumulativeReward( - bytes32 poolId, - uint256 epoch - ); - - constructor( - address wethAddress, - address zrxVaultAddress - ) - public - TestStaking( - wethAddress, - zrxVaultAddress - ) - {} - - function init() public {} - - function _addCumulativeReward( - bytes32 poolId, - uint256 reward, - uint256 stake - ) - internal - { - uint256 lastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId]; - MixinCumulativeRewards._addCumulativeReward( - poolId, - reward, - stake - ); - uint256 newLastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId]; - if (newLastStoredEpoch != lastStoredEpoch) { - emit SetCumulativeReward(poolId, currentEpoch); - } - } -} diff --git a/contracts/staking/contracts/test/TestDelegatorRewards.sol b/contracts/staking/contracts/test/TestDelegatorRewards.sol deleted file mode 100644 index 814b054808..0000000000 --- a/contracts/staking/contracts/test/TestDelegatorRewards.sol +++ /dev/null @@ -1,215 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestDelegatorRewards is - TestStakingNoWETH -{ - event FinalizePool( - bytes32 poolId, - uint256 operatorReward, - uint256 membersReward, - uint256 membersStake - ); - - struct UnfinalizedPoolReward { - uint256 operatorReward; - uint256 membersReward; - uint256 membersStake; - } - - constructor() public { - _addAuthorizedAddress(msg.sender); - init(); - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - mapping (uint256 => mapping (bytes32 => UnfinalizedPoolReward)) private - unfinalizedPoolRewardsByEpoch; - - /// @dev Set unfinalized rewards for a pool in the current epoch. - function setUnfinalizedPoolReward( - bytes32 poolId, - address payable operatorAddress, - uint256 operatorReward, - uint256 membersReward, - uint256 membersStake - ) - external - { - unfinalizedPoolRewardsByEpoch[currentEpoch][poolId] = UnfinalizedPoolReward({ - operatorReward: operatorReward, - membersReward: membersReward, - membersStake: membersStake - }); - // Lazily initialize this pool. - _poolById[poolId].operator = operatorAddress; - _setOperatorShare(poolId, operatorReward, membersReward); - } - - /// @dev Expose/wrap `_syncPoolRewards`. - function syncPoolRewards( - bytes32 poolId, - address payable operatorAddress, - uint256 operatorReward, - uint256 membersReward, - uint256 membersStake - ) - external - { - // Lazily initialize this pool. - _poolById[poolId].operator = operatorAddress; - _setOperatorShare(poolId, operatorReward, membersReward); - - _syncPoolRewards( - poolId, - operatorReward + membersReward, - membersStake - ); - } - - /// @dev Advance the epoch. - function advanceEpoch() external { - currentEpoch += 1; - } - - /// @dev Create and delegate stake to the current epoch. - /// Only used to test purportedly unreachable states. - /// Also withdraws pending rewards. - function delegateStakeNow( - address delegator, - bytes32 poolId, - uint256 stake - ) - external - { - _withdrawAndSyncDelegatorRewards( - poolId, - delegator - ); - IStructs.StoredBalance storage _stake = _delegatedStakeToPoolByOwner[delegator][poolId]; - _stake.currentEpochBalance += uint96(stake); - _stake.nextEpochBalance += uint96(stake); - _stake.currentEpoch = uint32(currentEpoch); - _withdrawAndSyncDelegatorRewards( - poolId, - delegator - ); - } - - /// @dev Create and delegate stake that will occur in the next epoch - /// (normal behavior). - /// Also withdraws pending rewards. - function delegateStake( - address delegator, - bytes32 poolId, - uint256 stake - ) - external - { - _withdrawAndSyncDelegatorRewards( - poolId, - delegator - ); - IStructs.StoredBalance storage _stake = _delegatedStakeToPoolByOwner[delegator][poolId]; - if (_stake.currentEpoch < currentEpoch) { - _stake.currentEpochBalance = _stake.nextEpochBalance; - } - _stake.nextEpochBalance += uint96(stake); - _stake.currentEpoch = uint32(currentEpoch); - } - - /// @dev Clear stake that will occur in the next epoch - /// (normal behavior). - /// Also withdraws pending rewards. - function undelegateStake( - address delegator, - bytes32 poolId, - uint256 stake - ) - external - { - _withdrawAndSyncDelegatorRewards( - poolId, - delegator - ); - IStructs.StoredBalance storage _stake = _delegatedStakeToPoolByOwner[delegator][poolId]; - if (_stake.currentEpoch < currentEpoch) { - _stake.currentEpochBalance = _stake.nextEpochBalance; - } - _stake.nextEpochBalance -= uint96(stake); - _stake.currentEpoch = uint32(currentEpoch); - } - - // solhint-disable no-simple-event-func-name - /// @dev Overridden to realize `unfinalizedPoolRewardsByEpoch` in - /// the current epoch and emit a event, - function finalizePool(bytes32 poolId) - external - { - UnfinalizedPoolReward memory reward = unfinalizedPoolRewardsByEpoch[currentEpoch][poolId]; - delete unfinalizedPoolRewardsByEpoch[currentEpoch][poolId]; - - _setOperatorShare(poolId, reward.operatorReward, reward.membersReward); - - uint256 totalRewards = reward.operatorReward + reward.membersReward; - uint256 membersStake = reward.membersStake; - (uint256 operatorReward, uint256 membersReward) = - _syncPoolRewards(poolId, totalRewards, membersStake); - emit FinalizePool(poolId, operatorReward, membersReward, membersStake); - } - - /// @dev Overridden to use unfinalizedPoolRewardsByEpoch. - function _getUnfinalizedPoolRewards(bytes32 poolId) - internal - view - returns ( - uint256 totalReward, - uint256 membersStake - ) - { - UnfinalizedPoolReward storage reward = unfinalizedPoolRewardsByEpoch[currentEpoch][poolId]; - totalReward = reward.operatorReward + reward.membersReward; - membersStake = reward.membersStake; - } - - /// @dev Set the operator share of a pool based on reward ratios. - function _setOperatorShare( - bytes32 poolId, - uint256 operatorReward, - uint256 membersReward - ) - private - { - uint32 operatorShare = 0; - uint256 totalReward = operatorReward + membersReward; - if (totalReward != 0) { - operatorShare = uint32( - operatorReward * PPM_DENOMINATOR / totalReward - ); - } - _poolById[poolId].operatorShare = operatorShare; - } - -} diff --git a/contracts/staking/contracts/test/TestExchangeManager.sol b/contracts/staking/contracts/test/TestExchangeManager.sol deleted file mode 100644 index 5a47aae84b..0000000000 --- a/contracts/staking/contracts/test/TestExchangeManager.sol +++ /dev/null @@ -1,42 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/Staking.sol"; - - -contract TestExchangeManager is - Staking -{ - function setValidExchange(address exchange) - external - { - validExchanges[exchange] = true; - } - - function onlyExchangeFunction() - external - view - onlyExchange - returns (bool) - { - return true; - } -} diff --git a/contracts/staking/contracts/test/TestFinalizer.sol b/contracts/staking/contracts/test/TestFinalizer.sol deleted file mode 100644 index 23dbfc342b..0000000000 --- a/contracts/staking/contracts/test/TestFinalizer.sol +++ /dev/null @@ -1,181 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "../src/libs/LibCobbDouglas.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestFinalizer is - TestStakingNoWETH -{ - event DepositStakingPoolRewards( - bytes32 poolId, - uint256 reward, - uint256 membersStake - ); - - struct UnfinalizedPoolReward { - uint256 totalReward; - uint256 membersStake; - } - - struct FinalizedPoolRewards { - uint256 operatorReward; - uint256 membersReward; - uint256 membersStake; - } - - address payable private _operatorRewardsReceiver; - address payable private _membersRewardsReceiver; - mapping (bytes32 => uint32) private _operatorSharesByPool; - - /// @param operatorRewardsReceiver The address to transfer rewards into when - /// a pool is finalized. - constructor( - address payable operatorRewardsReceiver, - address payable membersRewardsReceiver - ) - public - { - _addAuthorizedAddress(msg.sender); - init(); - _operatorRewardsReceiver = operatorRewardsReceiver; - _membersRewardsReceiver = membersRewardsReceiver; - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - // this contract can receive ETH - // solhint-disable no-empty-blocks - function () - external - payable - {} - - /// @dev Activate a pool in the current epoch. - function addActivePool( - bytes32 poolId, - uint32 operatorShare, - uint256 feesCollected, - uint256 membersStake, - uint256 weightedStake - ) - external - { - require(feesCollected > 0, "FEES_MUST_BE_NONZERO"); - uint256 currentEpoch_ = currentEpoch; - IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][currentEpoch_]; - require(poolStats.feesCollected == 0, "POOL_ALREADY_ADDED"); - _operatorSharesByPool[poolId] = operatorShare; - poolStatsByEpoch[poolId][currentEpoch_] = IStructs.PoolStats({ - feesCollected: feesCollected, - membersStake: membersStake, - weightedStake: weightedStake - }); - - aggregatedStatsByEpoch[currentEpoch_].totalFeesCollected += feesCollected; - aggregatedStatsByEpoch[currentEpoch_].totalWeightedStake += weightedStake; - aggregatedStatsByEpoch[currentEpoch_].numPoolsToFinalize += 1; - } - - /// @dev Drain the balance of this contract. - function drainBalance() - external - { - address(0).transfer(address(this).balance); - } - - /// @dev Compute Cobb-Douglas. - function cobbDouglas( - uint256 totalRewards, - uint256 ownerFees, - uint256 totalFees, - uint256 ownerStake, - uint256 totalStake - ) - external - view - returns (uint256 ownerRewards) - { - ownerRewards = LibCobbDouglas.cobbDouglas( - totalRewards, - ownerFees, - totalFees, - ownerStake, - totalStake, - cobbDouglasAlphaNumerator, - cobbDouglasAlphaDenominator - ); - } - - /// @dev Expose `_getUnfinalizedPoolReward()` - function getUnfinalizedPoolRewards(bytes32 poolId) - external - view - returns (UnfinalizedPoolReward memory reward) - { - (reward.totalReward, reward.membersStake) = _getUnfinalizedPoolRewards( - poolId - ); - } - - /// @dev Expose pool stats for the input epoch. - function getPoolStatsFromEpoch(uint256 epoch, bytes32 poolId) - external - view - returns (IStructs.PoolStats memory) - { - return poolStatsByEpoch[poolId][epoch]; - } - - function getAggregatedStatsForPreviousEpoch() - external - view - returns (IStructs.AggregatedStats memory) - { - return aggregatedStatsByEpoch[currentEpoch - 1]; - } - - /// @dev Overridden to log and transfer to receivers. - function _syncPoolRewards( - bytes32 poolId, - uint256 reward, - uint256 membersStake - ) - internal - returns (uint256 operatorReward, uint256 membersReward) - { - uint32 operatorShare = _operatorSharesByPool[poolId]; - (operatorReward, membersReward) = _computePoolRewardsSplit( - operatorShare, - reward, - membersStake - ); - address(_operatorRewardsReceiver).transfer(operatorReward); - address(_membersRewardsReceiver).transfer(membersReward); - emit DepositStakingPoolRewards(poolId, reward, membersStake); - } - - /// @dev Overriden to just increase the epoch counter. - function _goToNextEpoch() internal { - currentEpoch += 1; - } -} diff --git a/contracts/staking/contracts/test/TestInitTarget.sol b/contracts/staking/contracts/test/TestInitTarget.sol deleted file mode 100644 index c2aab82762..0000000000 --- a/contracts/staking/contracts/test/TestInitTarget.sol +++ /dev/null @@ -1,64 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/immutable/MixinStorage.sol"; - - -contract TestInitTarget is - MixinStorage -{ - // We can't store state in this contract before it is attached, so - // we will grant this predefined address a balance to indicate that - // `init()` should revert. - address public constant SHOULD_REVERT_ADDRESS = 0x5ed6A38c6bEcEd15b0AB58566b6fD7A00463d2F7; - // Counter that is incremented with every call to `init()`. - uint256 private _initCounter = 0; - // `msg.sender` of the last `init()` call. - address private _initSender = address(0); - // `address(this)` of the last `init()` call. - address private _initThisAddress = address(0); - - function init() - external - { - if (SHOULD_REVERT_ADDRESS.balance != 0) { - revert("FORCED_INIT_REVERT"); - } - _initCounter += 1; - _initSender = msg.sender; - _initThisAddress = address(this); - } - - function getInitState() - external - view - returns ( - address initSender, - address initThisAddress - ) - { - initSender = _initSender; - initThisAddress = _initThisAddress; - } - - function getInitCounter() external view returns (uint256) { - return _initCounter; - } -} diff --git a/contracts/staking/contracts/test/TestLibFixedMath.sol b/contracts/staking/contracts/test/TestLibFixedMath.sol deleted file mode 100644 index a9e0fa58d2..0000000000 --- a/contracts/staking/contracts/test/TestLibFixedMath.sol +++ /dev/null @@ -1,88 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../src/libs/LibFixedMath.sol"; - - -contract TestLibFixedMath { - - function one() external pure returns (int256) { - return LibFixedMath.one(); - } - - function mulDiv(int256 a, int256 n, int256 d) external pure returns (int256) { - return LibFixedMath.mulDiv(a, n, d); - } - - function mul(int256 a, int256 b) external pure returns (int256) { - return LibFixedMath.mul(a, b); - } - - function div(int256 a, int256 b) external pure returns (int256) { - return LibFixedMath.div(a, b); - } - - function add(int256 a, int256 b) external pure returns (int256) { - return LibFixedMath.add(a, b); - } - - function sub(int256 a, int256 b) external pure returns (int256) { - return LibFixedMath.sub(a, b); - } - - function uintMul(int256 f, uint256 u) external pure returns (uint256) { - return LibFixedMath.uintMul(f, u); - } - - function abs(int256 a) external pure returns (int256) { - return LibFixedMath.abs(a); - } - - function invert(int256 a) external pure returns (int256) { - return LibFixedMath.invert(a); - } - - function toFixedSigned(int256 n, int256 d) external pure returns (int256) { - return LibFixedMath.toFixed(n, d); - } - - function toFixedSigned(int256 n) external pure returns (int256) { - return LibFixedMath.toFixed(n); - } - - function toFixedUnsigned(uint256 n, uint256 d) external pure returns (int256) { - return LibFixedMath.toFixed(n, d); - } - - function toFixedUnsigned(uint256 n) external pure returns (int256) { - return LibFixedMath.toFixed(n); - } - - function toInteger(int256 f) external pure returns (int256) { - return LibFixedMath.toInteger(f); - } - - function ln(int256 x) external pure returns (int256 r) { - return LibFixedMath.ln(x); - } - - function exp(int256 x) external pure returns (int256 r) { - return LibFixedMath.exp(x); - } -} diff --git a/contracts/staking/contracts/test/TestLibSafeDowncast.sol b/contracts/staking/contracts/test/TestLibSafeDowncast.sol deleted file mode 100644 index 43d1bc8fce..0000000000 --- a/contracts/staking/contracts/test/TestLibSafeDowncast.sol +++ /dev/null @@ -1,41 +0,0 @@ -/* - - Copyright 2019 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.5.9; - -import "../src/libs/LibSafeDowncast.sol"; - - -contract TestLibSafeDowncast { - - function downcastToUint96(uint256 a) - external - pure - returns (uint96) - { - return LibSafeDowncast.downcastToUint96(a); - } - - function downcastToUint64(uint256 a) - external - pure - returns (uint64) - { - return LibSafeDowncast.downcastToUint64(a); - } -} diff --git a/contracts/staking/contracts/test/TestMixinCumulativeRewards.sol b/contracts/staking/contracts/test/TestMixinCumulativeRewards.sol deleted file mode 100644 index abd9445d34..0000000000 --- a/contracts/staking/contracts/test/TestMixinCumulativeRewards.sol +++ /dev/null @@ -1,115 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./TestStaking.sol"; - - -contract TestMixinCumulativeRewards is - TestStaking -{ - - constructor( - address wethAddress, - address zrxVaultAddress - ) - public - TestStaking( - wethAddress, - zrxVaultAddress - ) - { - _addAuthorizedAddress(msg.sender); - init(); - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - /// @dev Exposes `_isCumulativeRewardSet` - function isCumulativeRewardSet(IStructs.Fraction memory cumulativeReward) - public - pure - returns (bool) - { - return _isCumulativeRewardSet(cumulativeReward); - } - - /// @dev Exposes `_addCumulativeReward` - function addCumulativeReward( - bytes32 poolId, - uint256 reward, - uint256 stake - ) - public - { - _addCumulativeReward(poolId, reward, stake); - } - - /// @dev Exposes `_updateCumulativeReward` - function updateCumulativeReward(bytes32 poolId) - public - { - _updateCumulativeReward(poolId); - } - - /// @dev Exposes _computeMemberRewardOverInterval - function computeMemberRewardOverInterval( - bytes32 poolId, - uint256 memberStakeOverInterval, - uint256 beginEpoch, - uint256 endEpoch - ) - public - view - returns (uint256 reward) - { - return _computeMemberRewardOverInterval(poolId, memberStakeOverInterval, beginEpoch, endEpoch); - } - - /// @dev Increments current epoch by 1 - function incrementEpoch() - public - { - currentEpoch += 1; - } - - /// @dev Stores an arbitrary cumulative reward for a given epoch. - /// Also sets the `_cumulativeRewardsByPoolLastStored` to the input epoch. - function storeCumulativeReward( - bytes32 poolId, - IStructs.Fraction memory cumulativeReward, - uint256 epoch - ) - public - { - _cumulativeRewardsByPool[poolId][epoch] = cumulativeReward; - _cumulativeRewardsByPoolLastStored[poolId] = epoch; - } - - /// @dev Returns the raw cumulative reward for a given pool in an epoch. - /// This is considered "raw" because the internal implementation - /// (_getCumulativeRewardAtEpochRaw) will query other state variables - /// to determine the most accurate cumulative reward for a given epoch. - function getCumulativeRewardAtEpochRaw(bytes32 poolId, uint256 epoch) - public - returns (IStructs.Fraction memory) - { - return _cumulativeRewardsByPool[poolId][epoch]; - } -} diff --git a/contracts/staking/contracts/test/TestMixinParams.sol b/contracts/staking/contracts/test/TestMixinParams.sol deleted file mode 100644 index 6c51c584a7..0000000000 --- a/contracts/staking/contracts/test/TestMixinParams.sol +++ /dev/null @@ -1,47 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/sys/MixinParams.sol"; - - -contract TestMixinParams is - MixinParams -{ - bool public shouldFailAssertValidStorageParams; - - /// @dev Set `shouldFailAssertValidStorageParams` - function setShouldFailAssertValidStorageParams(bool shouldFail) - external - { - shouldFailAssertValidStorageParams = shouldFail; - } - - /// @dev `IStakingProxy.assertValidStorageParams()` that reverts if - /// `shouldFailAssertValidStorageParams` is true. - function assertValidStorageParams() - public - view - { - if (shouldFailAssertValidStorageParams) { - revert("ASSERT_VALID_STORAGE_PARAMS_FAILED"); - } - } -} diff --git a/contracts/staking/contracts/test/TestMixinScheduler.sol b/contracts/staking/contracts/test/TestMixinScheduler.sol deleted file mode 100644 index ac5d545be3..0000000000 --- a/contracts/staking/contracts/test/TestMixinScheduler.sol +++ /dev/null @@ -1,96 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "./TestStaking.sol"; - - -contract TestMixinScheduler is - TestStaking -{ - uint256 public testDeployedTimestamp; - - event GoToNextEpochTestInfo( - uint256 oldEpoch, - uint256 blockTimestamp - ); - - constructor( - address wethAddress, - address zrxVaultAddress - ) - public - TestStaking( - wethAddress, - zrxVaultAddress - ) - { - _addAuthorizedAddress(msg.sender); - init(); - _removeAuthorizedAddressAtIndex(msg.sender, 0); - - // Record time of deployment - // solhint-disable-next-line not-rely-on-time - testDeployedTimestamp = block.timestamp; - } - - /// @dev Tests `_goToNextEpoch`. - /// Configures internal variables such taht `epochEndTime` will be - /// less-than, equal-to, or greater-than the block timestamp. - /// @param epochEndTimeDelta Set to desired `epochEndTime - block.timestamp` - function goToNextEpochTest(int256 epochEndTimeDelta) - public - { - // solhint-disable-next-line not-rely-on-time - uint256 blockTimestamp = block.timestamp; - - // Emit info used by client-side test code - emit GoToNextEpochTestInfo( - currentEpoch, - blockTimestamp - ); - - // (i) In `_goToNextEpoch` we compute: - // `epochEndTime = currentEpochStartTimeInSeconds + epochDurationInSeconds` - // (ii) We want adjust internal state such that: - // `epochEndTime - block.timestamp = epochEndTimeDelta`, or - // `currentEpochStartTimeInSeconds + epochDurationInSeconds - block.timestamp = epochEndTimeDelta` - // - // To do this, we: - // (i) Set `epochDurationInSeconds` to a constant value of 1, and - // (ii) Rearrange the eqn above to get: - // `currentEpochStartTimeInSeconds = epochEndTimeDelta + block.timestamp - epochDurationInSeconds` - epochDurationInSeconds = 1; - currentEpochStartTimeInSeconds = - uint256(epochEndTimeDelta + int256(blockTimestamp) - int256(epochDurationInSeconds)); - - // Test internal function - _goToNextEpoch(); - } - - /// @dev Tests `_initMixinScheduler` - /// @param _currentEpochStartTimeInSeconds Sets `currentEpochStartTimeInSeconds` to this value before test. - function initMixinSchedulerTest(uint256 _currentEpochStartTimeInSeconds) - public - { - currentEpochStartTimeInSeconds = _currentEpochStartTimeInSeconds; - _initMixinScheduler(); - } -} \ No newline at end of file diff --git a/contracts/staking/contracts/test/TestMixinStake.sol b/contracts/staking/contracts/test/TestMixinStake.sol deleted file mode 100644 index 382f17f8e9..0000000000 --- a/contracts/staking/contracts/test/TestMixinStake.sol +++ /dev/null @@ -1,241 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestMixinStake is - TestStakingNoWETH -{ - event ZrxVaultDepositFrom( - address staker, - uint256 amount - ); - - event ZrxVaultWithdrawFrom( - address staker, - uint256 amount - ); - - event MoveStakeStorage( - bytes32 fromBalanceSlot, - bytes32 toBalanceSlot, - uint256 amount - ); - - event IncreaseCurrentAndNextBalance( - bytes32 balanceSlot, - uint256 amount - ); - - event DecreaseCurrentAndNextBalance( - bytes32 balanceSlot, - uint256 amount - ); - - event IncreaseNextBalance( - bytes32 balanceSlot, - uint256 amount - ); - - event DecreaseNextBalance( - bytes32 balanceSlot, - uint256 amount - ); - - event WithdrawAndSyncDelegatorRewards( - bytes32 poolId, - address delegator - ); - - /// @dev Advance the epoch counter. - function advanceEpoch() external { - currentEpoch += 1; - } - - /// @dev `IZrxVault.depositFrom` - function depositFrom(address staker, uint256 amount) external { - emit ZrxVaultDepositFrom(staker, amount); - } - - /// @dev `IZrxVault.withdrawFrom` - function withdrawFrom(address staker, uint256 amount) external { - emit ZrxVaultWithdrawFrom(staker, amount); - } - - function getDelegatedStakeByPoolIdSlot(bytes32 poolId) - external - view - returns (bytes32 slot) - { - return _getPtrSlot(_delegatedStakeByPoolId[poolId]); - } - - function getDelegatedStakeToPoolByOwnerSlot(bytes32 poolId, address staker) - external - view - returns (bytes32 slot) - { - return _getPtrSlot(_delegatedStakeToPoolByOwner[staker][poolId]); - } - - function getGlobalStakeByStatusSlot(IStructs.StakeStatus status) - external - view - returns (bytes32 slot) - { - return _getPtrSlot(_globalStakeByStatus[uint8(status)]); - } - - function getOwnerStakeByStatusSlot(address owner, IStructs.StakeStatus status) - external - view - returns (bytes32 slot) - { - return _getPtrSlot(_ownerStakeByStatus[uint8(status)][owner]); - } - - /// @dev Set `_ownerStakeByStatus` - function setOwnerStakeByStatus( - address owner, - IStructs.StakeStatus status, - IStructs.StoredBalance memory stake - ) - public - { - _ownerStakeByStatus[uint8(status)][owner] = stake; - } - - /// @dev Overridden to use this contract as the ZRX vault. - function getZrxVault() - public - view - returns (IZrxVault zrxVault) - { - return IZrxVault(address(this)); - } - - /// @dev Overridden to only emit an event. - function _withdrawAndSyncDelegatorRewards( - bytes32 poolId, - address member - ) - internal - { - emit WithdrawAndSyncDelegatorRewards(poolId, member); - } - - /// @dev Overridden to only emit an event. - function _moveStake( - IStructs.StoredBalance storage fromPtr, - IStructs.StoredBalance storage toPtr, - uint256 amount - ) - internal - { - emit MoveStakeStorage( - _getPtrSlot(fromPtr), - _getPtrSlot(toPtr), - amount - ); - } - - /// @dev Overridden to only emit an event. - function _increaseCurrentAndNextBalance( - IStructs.StoredBalance storage balancePtr, - uint256 amount - ) - internal - { - emit IncreaseCurrentAndNextBalance( - _getPtrSlot(balancePtr), - amount - ); - } - - /// @dev Overridden to only emit an event. - function _decreaseCurrentAndNextBalance( - IStructs.StoredBalance storage balancePtr, - uint256 amount - ) - internal - { - emit DecreaseCurrentAndNextBalance( - _getPtrSlot(balancePtr), - amount - ); - } - - /// @dev Overridden to only emit an event. - function _increaseNextBalance( - IStructs.StoredBalance storage balancePtr, - uint256 amount - ) - internal - { - emit IncreaseNextBalance( - _getPtrSlot(balancePtr), - amount - ); - } - - /// @dev Overridden to only emit an event. - function _decreaseNextBalance( - IStructs.StoredBalance storage balancePtr, - uint256 amount - ) - internal - { - emit DecreaseNextBalance( - _getPtrSlot(balancePtr), - amount - ); - } - - /// @dev Overridden to just return the input. - function _loadCurrentBalance(IStructs.StoredBalance storage balancePtr) - internal - view - returns (IStructs.StoredBalance memory balance) - { - balance = balancePtr; - } - - /// @dev Throws if poolId == 0x0 - function _assertStakingPoolExists(bytes32 poolId) - internal - view - { - require(poolId != bytes32(0), "INVALID_POOL"); - } - - // solhint-disable-next-line - function _getPtrSlot(IStructs.StoredBalance storage ptr) - private - pure - returns (bytes32 offset) - { - assembly { - offset := ptr_slot - } - } -} diff --git a/contracts/staking/contracts/test/TestMixinStakeBalances.sol b/contracts/staking/contracts/test/TestMixinStakeBalances.sol deleted file mode 100644 index 7ef21888d4..0000000000 --- a/contracts/staking/contracts/test/TestMixinStakeBalances.sol +++ /dev/null @@ -1,122 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestMixinStakeBalances is - TestStakingNoWETH -{ - uint256 private _balanceOfZrxVault; - mapping (address => uint256) private _zrxBalanceOf; - - function setBalanceOfZrxVault(uint256 balance) - external - { - _balanceOfZrxVault = balance; - } - - function setZrxBalanceOf(address staker, uint256 balance) - external - { - _zrxBalanceOf[staker] = balance; - } - - /// @dev `IZrxVault.balanceOfZrxVault` - function balanceOfZrxVault() - external - view - returns (uint256) - { - return _balanceOfZrxVault; - } - - /// @dev `IZrxVault.balanceOf` - function balanceOf(address staker) - external - view - returns (uint256) - { - return _zrxBalanceOf[staker]; - } - - /// @dev Set `_ownerStakeByStatus` - function setOwnerStakeByStatus( - address owner, - IStructs.StakeStatus status, - IStructs.StoredBalance memory stake - ) - public - { - _ownerStakeByStatus[uint8(status)][owner] = stake; - } - - /// @dev Set `_delegatedStakeToPoolByOwner` - function setDelegatedStakeToPoolByOwner( - address owner, - bytes32 poolId, - IStructs.StoredBalance memory stake - ) - public - { - _delegatedStakeToPoolByOwner[owner][poolId] = stake; - } - - /// @dev Set `_delegatedStakeByPoolId` - function setDelegatedStakeByPoolId( - bytes32 poolId, - IStructs.StoredBalance memory stake - ) - public - { - _delegatedStakeByPoolId[poolId] = stake; - } - - /// @dev Set `_globalStakeByStatus` - function setGlobalStakeByStatus( - IStructs.StakeStatus status, - IStructs.StoredBalance memory stake - ) - public - { - _globalStakeByStatus[uint8(status)] = stake; - } - - /// @dev Overridden to use this contract as the ZRX vault. - function getZrxVault() - public - view - returns (IZrxVault zrxVault) - { - return IZrxVault(address(this)); - } - - /// @dev Overridden to just return the input with the epoch incremented. - function _loadCurrentBalance(IStructs.StoredBalance storage balancePtr) - internal - view - returns (IStructs.StoredBalance memory balance) - { - balance = balancePtr; - balance.currentEpoch += 1; - } -} diff --git a/contracts/staking/contracts/test/TestMixinStakeStorage.sol b/contracts/staking/contracts/test/TestMixinStakeStorage.sol deleted file mode 100644 index 82882130f6..0000000000 --- a/contracts/staking/contracts/test/TestMixinStakeStorage.sol +++ /dev/null @@ -1,98 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "../src/stake/MixinStakeStorage.sol"; - - -contract TestMixinStakeStorage is - MixinStakeStorage -{ - mapping (uint256 => IStructs.StoredBalance) public testBalances; - - function setCurrentEpoch(uint256 newEpoch) - external - { - currentEpoch = newEpoch; - } - - function moveStake( - uint256 fromIndex, - uint256 toIndex, - uint256 amount - ) - external - { - return _moveStake( - testBalances[fromIndex], - testBalances[toIndex], - amount - ); - } - - function increaseCurrentAndNextBalance(uint256 index, uint256 amount) - external - { - return _increaseCurrentAndNextBalance(testBalances[index], amount); - } - - function decreaseCurrentAndNextBalance(uint256 index, uint256 amount) - external - { - _decreaseCurrentAndNextBalance(testBalances[index], amount); - } - - function increaseNextBalance(uint256 index, uint256 amount) - external - { - _increaseNextBalance(testBalances[index], amount); - } - - function decreaseNextBalance(uint256 index, uint256 amount) - external - { - _decreaseNextBalance(testBalances[index], amount); - } - - function loadCurrentBalance(uint256 index) - external - returns (IStructs.StoredBalance memory balance) - { - return _loadCurrentBalance(testBalances[index]); - } - - function loadStaleBalance(uint256 index) - external - view - returns (IStructs.StoredBalance memory balance) - { - return testBalances[index]; - } - - function setStoredBalance( - IStructs.StoredBalance memory balance, - uint256 index - ) - public - { - testBalances[index] = balance; - } -} diff --git a/contracts/staking/contracts/test/TestMixinStakingPool.sol b/contracts/staking/contracts/test/TestMixinStakingPool.sol deleted file mode 100644 index 02e370b014..0000000000 --- a/contracts/staking/contracts/test/TestMixinStakingPool.sol +++ /dev/null @@ -1,53 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestMixinStakingPool is - TestStakingNoWETH -{ - function setLastPoolId(bytes32 poolId) - external - { - lastPoolId = poolId; - } - - function setPoolIdByMaker(bytes32 poolId, address maker) - external - { - poolIdByMaker[maker] = poolId; - } - - // solhint-disable no-empty-blocks - function testOnlyStakingPoolOperatorModifier(bytes32 poolId) - external - view - onlyStakingPoolOperator(poolId) - {} - - function setPoolById(bytes32 poolId, IStructs.Pool memory pool) - public - { - _poolById[poolId] = pool; - } -} diff --git a/contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol b/contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol deleted file mode 100644 index 3bda161aac..0000000000 --- a/contracts/staking/contracts/test/TestMixinStakingPoolRewards.sol +++ /dev/null @@ -1,281 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestMixinStakingPoolRewards is - TestStakingNoWETH -{ - // solhint-disable no-simple-event-func-name - event UpdateCumulativeReward( - bytes32 poolId - ); - - event WithdrawAndSyncDelegatorRewards( - bytes32 poolId, - address delegator - ); - - struct UnfinalizedPoolReward { - uint256 reward; - uint256 membersStake; - } - - constructor() public { - _addAuthorizedAddress(msg.sender); - init(); - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - // Rewards returned by `_computeMemberRewardOverInterval()`, indexed - // by `_getMemberRewardOverIntervalHash()`. - mapping (bytes32 => uint256) private _memberRewardsOverInterval; - // Rewards returned by `_getUnfinalizedPoolRewards()`, indexed by pool ID. - mapping (bytes32 => UnfinalizedPoolReward) private _unfinalizedPoolRewards; - - // Set pool `rewardsByPoolId`. - function setPoolRewards( - bytes32 poolId, - uint256 _rewardsByPoolId - ) - external - { - rewardsByPoolId[poolId] = _rewardsByPoolId; - } - - // Set `wethReservedForPoolRewards`. - function setWethReservedForPoolRewards( - uint256 _wethReservedForPoolRewards - ) - external - { - wethReservedForPoolRewards = _wethReservedForPoolRewards; - } - - // Set the rewards returned by a call to `_computeMemberRewardOverInterval()`. - function setMemberRewardsOverInterval( - bytes32 poolId, - uint256 memberStakeOverInterval, - uint256 beginEpoch, - uint256 endEpoch, - uint256 reward - ) - external - { - bytes32 rewardHash = _getMemberRewardOverIntervalHash( - poolId, - memberStakeOverInterval, - beginEpoch, - endEpoch - ); - _memberRewardsOverInterval[rewardHash] = reward; - } - - // Set the rewards returned by `_getUnfinalizedPoolRewards()`. - function setUnfinalizedPoolRewards( - bytes32 poolId, - uint256 reward, - uint256 membersStake - ) - external - { - _unfinalizedPoolRewards[poolId] = UnfinalizedPoolReward( - reward, - membersStake - ); - } - - // Set `currentEpoch`. - function setCurrentEpoch(uint256 epoch) external { - currentEpoch = epoch; - } - - // Expose `_syncPoolRewards()` for testing. - function syncPoolRewards( - bytes32 poolId, - uint256 reward, - uint256 membersStake - ) - external - returns (uint256 operatorReward, uint256 membersReward) - { - return _syncPoolRewards(poolId, reward, membersStake); - } - - // Expose `_withdrawAndSyncDelegatorRewards()` for testing. - function withdrawAndSyncDelegatorRewards( - bytes32 poolId, - address member - ) - external - { - return _withdrawAndSyncDelegatorRewards( - poolId, - member - ); - } - - // Expose `_computePoolRewardsSplit()` for testing. - function computePoolRewardsSplit( - uint32 operatorShare, - uint256 totalReward, - uint256 membersStake - ) - external - pure - returns (uint256 operatorReward, uint256 membersReward) - { - return _computePoolRewardsSplit( - operatorShare, - totalReward, - membersStake - ); - } - - // Access `_delegatedStakeToPoolByOwner` - function delegatedStakeToPoolByOwner(address member, bytes32 poolId) - external - view - returns (IStructs.StoredBalance memory balance) - { - return _delegatedStakeToPoolByOwner[member][poolId]; - } - - // Set `_delegatedStakeToPoolByOwner` - function setDelegatedStakeToPoolByOwner( - address member, - bytes32 poolId, - IStructs.StoredBalance memory balance - ) - public - { - _delegatedStakeToPoolByOwner[member][poolId] = balance; - } - - // Set `_poolById`. - function setPool( - bytes32 poolId, - IStructs.Pool memory pool - ) - public - { - _poolById[poolId] = pool; - } - - // Overridden to emit an event. - function _withdrawAndSyncDelegatorRewards( - bytes32 poolId, - address member - ) - internal - { - emit WithdrawAndSyncDelegatorRewards(poolId, member); - return MixinStakingPoolRewards._withdrawAndSyncDelegatorRewards( - poolId, - member - ); - } - - // Overridden to use `_memberRewardsOverInterval` - function _computeMemberRewardOverInterval( - bytes32 poolId, - uint256 memberStakeOverInterval, - uint256 beginEpoch, - uint256 endEpoch - ) - internal - view - returns (uint256 reward) - { - bytes32 rewardHash = _getMemberRewardOverIntervalHash( - poolId, - memberStakeOverInterval, - beginEpoch, - endEpoch - ); - return _memberRewardsOverInterval[rewardHash]; - } - - // Overridden to use `_unfinalizedPoolRewards` - function _getUnfinalizedPoolRewards( - bytes32 poolId - ) - internal - view - returns (uint256 reward, uint256 membersStake) - { - (reward, membersStake) = ( - _unfinalizedPoolRewards[poolId].reward, - _unfinalizedPoolRewards[poolId].membersStake - ); - } - - // Overridden to just increase `currentEpoch`. - function _loadCurrentBalance(IStructs.StoredBalance storage balancePtr) - internal - view - returns (IStructs.StoredBalance memory balance) - { - balance = balancePtr; - balance.currentEpoch += 1; - } - - // Overridden to revert if a pool has unfinalized rewards. - function _assertPoolFinalizedLastEpoch(bytes32 poolId) - internal - view - { - require( - _unfinalizedPoolRewards[poolId].membersStake == 0, - "POOL_NOT_FINALIZED" - ); - } - - // Overridden to just emit an event. - function _updateCumulativeReward(bytes32 poolId) - internal - { - emit UpdateCumulativeReward(poolId); - } - - // Compute a hash to index `_memberRewardsOverInterval` - function _getMemberRewardOverIntervalHash( - bytes32 poolId, - uint256 memberStakeOverInterval, - uint256 beginEpoch, - uint256 endEpoch - ) - private - pure - returns (bytes32 rewardHash) - { - return keccak256( - abi.encode( - poolId, - memberStakeOverInterval, - beginEpoch, - endEpoch - ) - ); - } -} diff --git a/contracts/staking/contracts/test/TestProtocolFees.sol b/contracts/staking/contracts/test/TestProtocolFees.sol deleted file mode 100644 index b9b93944e6..0000000000 --- a/contracts/staking/contracts/test/TestProtocolFees.sol +++ /dev/null @@ -1,142 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/interfaces/IStructs.sol"; -import "./TestStakingNoWETH.sol"; - - -contract TestProtocolFees is - TestStakingNoWETH -{ - struct TestPool { - uint96 operatorStake; - uint96 membersStake; - mapping(address => bool) isMaker; - } - - event ERC20ProxyTransferFrom( - address from, - address to, - uint256 amount - ); - - mapping(bytes32 => TestPool) private _testPools; - mapping(address => bytes32) private _makersToTestPoolIds; - - constructor(address exchangeAddress) public { - _addAuthorizedAddress(msg.sender); - init(); - validExchanges[exchangeAddress] = true; - _removeAuthorizedAddressAtIndex(msg.sender, 0); - } - - function advanceEpoch() - external - { - currentEpoch += 1; - } - - /// @dev Create a test pool. - function createTestPool( - bytes32 poolId, - uint96 operatorStake, - uint96 membersStake, - address[] calldata makerAddresses - ) - external - { - TestPool storage pool = _testPools[poolId]; - pool.operatorStake = operatorStake; - pool.membersStake = membersStake; - for (uint256 i = 0; i < makerAddresses.length; ++i) { - pool.isMaker[makerAddresses[i]] = true; - _makersToTestPoolIds[makerAddresses[i]] = poolId; - poolIdByMaker[makerAddresses[i]] = poolId; - } - } - - /// @dev The ERC20Proxy `transferFrom()` function. - function transferFrom( - address from, - address to, - uint256 amount - ) - external - returns (bool) - { - emit ERC20ProxyTransferFrom(from, to, amount); - return true; - } - - function getAggregatedStatsForCurrentEpoch() - external - view - returns (IStructs.AggregatedStats memory) - { - return aggregatedStatsByEpoch[currentEpoch]; - } - - /// @dev Overridden to use test pools. - function getStakingPoolIdOfMaker(address makerAddress) - public - view - returns (bytes32) - { - return _makersToTestPoolIds[makerAddress]; - } - - /// @dev Overridden to use test pools. - function getTotalStakeDelegatedToPool(bytes32 poolId) - public - view - returns (IStructs.StoredBalance memory balance) - { - TestPool memory pool = _testPools[poolId]; - uint96 stake = pool.operatorStake + pool.membersStake; - return IStructs.StoredBalance({ - currentEpoch: currentEpoch.downcastToUint64(), - currentEpochBalance: stake, - nextEpochBalance: stake - }); - } - - /// @dev Overridden to use test pools. - function getStakeDelegatedToPoolByOwner(address, bytes32 poolId) - public - view - returns (IStructs.StoredBalance memory balance) - { - TestPool memory pool = _testPools[poolId]; - return IStructs.StoredBalance({ - currentEpoch: currentEpoch.downcastToUint64(), - currentEpochBalance: pool.operatorStake, - nextEpochBalance: pool.operatorStake - }); - } - - function getWethContract() - public - view - returns (IEtherToken wethContract) - { - return IEtherToken(address(this)); - } -} diff --git a/contracts/staking/contracts/test/TestProxyDestination.sol b/contracts/staking/contracts/test/TestProxyDestination.sol deleted file mode 100644 index 11dc41714b..0000000000 --- a/contracts/staking/contracts/test/TestProxyDestination.sol +++ /dev/null @@ -1,82 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/Staking.sol"; - - -contract TestProxyDestination is - Staking -{ - // Init will revert if this flag is set to `true` - bool public initFailFlag; - - /// @dev Emitted when `init` is called - event InitCalled( - bool initCalled - ); - - /// @dev returns the input string - function echo(string calldata val) - external - returns (string memory) - { - return val; - } - - /// @dev Just a function that'll do some math on input - function doMath(uint256 a, uint256 b) - external - returns (uint256 sum, uint256 difference) - { - return ( - a + b, - a - b - ); - } - - /// @dev reverts with "Goodbye, World!" - function die() - external - { - revert("Goodbye, World!"); - } - - /// @dev Called when attached to the StakingProxy. - /// Reverts if `initFailFlag` is set, otherwise - /// sets storage params and emits `InitCalled`. - function init() - public - { - if (initFailFlag) { - revert("INIT_FAIL_FLAG_SET"); - } - - // Set params such that they'll pass `StakingProxy.assertValidStorageParams` - epochDurationInSeconds = 5 days; - cobbDouglasAlphaNumerator = 1; - cobbDouglasAlphaDenominator = 1; - rewardDelegatedStakeWeight = PPM_DENOMINATOR; - minimumPoolStake = 100; - - // Emit event to notify that `init` was called - emit InitCalled(true); - } -} \ No newline at end of file diff --git a/contracts/staking/contracts/test/TestStaking.sol b/contracts/staking/contracts/test/TestStaking.sol deleted file mode 100644 index ac6cd979f1..0000000000 --- a/contracts/staking/contracts/test/TestStaking.sol +++ /dev/null @@ -1,93 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; -import "@0x/contracts-utils/contracts/src/LibFractions.sol"; -import "../src/Staking.sol"; -import "../src/interfaces/IStructs.sol"; - - -contract TestStaking is - Staking -{ - address public testWethAddress; - address public testZrxVaultAddress; - - constructor( - address wethAddress, - address zrxVaultAddress - ) - public - { - testWethAddress = wethAddress; - testZrxVaultAddress = zrxVaultAddress; - } - - /// @dev Sets the weth contract address. - /// @param wethAddress The address of the weth contract. - function setWethContract(address wethAddress) - external - { - testWethAddress = wethAddress; - } - - /// @dev Sets the zrx vault address. - /// @param zrxVaultAddress The address of a zrx vault. - function setZrxVault(address zrxVaultAddress) - external - { - testZrxVaultAddress = zrxVaultAddress; - } - - // @dev Gets the most recent cumulative reward for a pool, and the epoch it was stored. - function getMostRecentCumulativeReward(bytes32 poolId) - external - view - returns (IStructs.Fraction memory cumulativeRewards, uint256 lastStoredEpoch) - { - lastStoredEpoch = _cumulativeRewardsByPoolLastStored[poolId]; - cumulativeRewards = _cumulativeRewardsByPool[poolId][lastStoredEpoch]; - } - - /// @dev Overridden to use testWethAddress; - function getWethContract() - public - view - returns (IEtherToken) - { - // `testWethAddress` will not be set on the proxy this contract is - // attached to, so we need to access the storage of the deployed - // instance of this contract. - address wethAddress = TestStaking(address(uint160(stakingContract))).testWethAddress(); - return IEtherToken(wethAddress); - } - - function getZrxVault() - public - view - returns (IZrxVault zrxVault) - { - address zrxVaultAddress = TestStaking(address(uint160(stakingContract))).testZrxVaultAddress(); - zrxVault = IZrxVault(zrxVaultAddress); - return zrxVault; - } -} diff --git a/contracts/staking/contracts/test/TestStakingNoWETH.sol b/contracts/staking/contracts/test/TestStakingNoWETH.sol deleted file mode 100644 index e176f326aa..0000000000 --- a/contracts/staking/contracts/test/TestStakingNoWETH.sol +++ /dev/null @@ -1,64 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/Staking.sol"; - - -// solhint-disable no-empty-blocks,no-simple-event-func-name -/// @dev A version of the staking contract with WETH-related functions -/// overridden to do nothing. -contract TestStakingNoWETH is - Staking -{ - event Transfer( - address indexed _from, - address indexed _to, - uint256 _value - ); - - function transfer(address to, uint256 amount) - external - returns (bool) - { - emit Transfer(address(this), to, amount); - return true; - } - - function getWethContract() - public - view - returns (IEtherToken) - { - return IEtherToken(address(this)); - } - - function _wrapEth() - internal - {} - - function _getAvailableWethBalance() - internal - view - returns (uint256) - { - return address(this).balance; - } -} diff --git a/contracts/staking/contracts/test/TestStakingProxy.sol b/contracts/staking/contracts/test/TestStakingProxy.sol deleted file mode 100644 index 70d55c286b..0000000000 --- a/contracts/staking/contracts/test/TestStakingProxy.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/StakingProxy.sol"; - - -contract TestStakingProxy is - StakingProxy -{ - address public constant SHOULD_REVERT_STAKING_ADDRESS = 0x5ed6A38c6bEcEd15b0AB58566b6fD7A00463d2F7; - - // solhint-disable no-empty-blocks - constructor(address _stakingContract) - public - StakingProxy( _stakingContract) - {} - - function assertValidStorageParams() - public - view - { - require( - stakingContract != SHOULD_REVERT_STAKING_ADDRESS, - "FORCED_STORAGE_PARAMS_REVERT" - ); - } -} diff --git a/contracts/staking/contracts/test/TestStakingProxyUnit.sol b/contracts/staking/contracts/test/TestStakingProxyUnit.sol deleted file mode 100644 index 523ddc544b..0000000000 --- a/contracts/staking/contracts/test/TestStakingProxyUnit.sol +++ /dev/null @@ -1,62 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "../src/StakingProxy.sol"; - - -contract TestStakingProxyUnit is - StakingProxy -{ - // Storage Params - these are tested by StakingProxy.assertValidStorageParams. - struct TestStorageParams { - uint256 epochDurationInSeconds; - uint32 cobbDouglasAlphaNumerator; - uint32 cobbDouglasAlphaDenominator; - uint32 rewardDelegatedStakeWeight; - uint256 minimumPoolStake; - } - - // If this is set then the `init` call will revert in the `TestProxyDestination` contract - bool public initFailFlag; - - // solhint-disable no-empty-blocks - constructor(address _stakingContract) - public - StakingProxy( _stakingContract) - {} - - // Setters to modify the - function setInitFailFlag() - external - { - initFailFlag = true; - } - - /// @dev Sets storage params with test values - function setTestStorageParams(TestStorageParams calldata params) - external - { - epochDurationInSeconds = params.epochDurationInSeconds; - cobbDouglasAlphaNumerator = params.cobbDouglasAlphaNumerator; - cobbDouglasAlphaDenominator = params.cobbDouglasAlphaDenominator; - rewardDelegatedStakeWeight = params.rewardDelegatedStakeWeight; - minimumPoolStake = params.minimumPoolStake; - } -} diff --git a/contracts/staking/contracts/test/TestStorageLayoutAndConstants.sol b/contracts/staking/contracts/test/TestStorageLayoutAndConstants.sol deleted file mode 100644 index 374a1c796f..0000000000 --- a/contracts/staking/contracts/test/TestStorageLayoutAndConstants.sol +++ /dev/null @@ -1,304 +0,0 @@ -/* - - Copyright 2019 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.5.9; -pragma experimental ABIEncoderV2; - -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol"; -import "@0x/contracts-utils/contracts/src/LibBytes.sol"; -import "../src/Staking.sol"; - - -contract TestStorageLayoutAndConstants is - Staking -{ - using LibBytes for bytes; - - /// @dev Construction will fail if the storage layout or the deployment constants are incompatible - /// with the V1 staking proxy. - constructor() public { - _assertDeploymentConstants(); - _assertStorageLayout(); - } - - /// @dev This function will fail if the deployment constants change to the point where they - /// are considered "invalid". - function _assertDeploymentConstants() - internal - view - { - require( - address(getWethContract()) != address(0), - "WETH_MUST_BE_SET" - ); - - require( - address(getZrxVault()) != address(0), - "ZRX_VAULT_MUST_BE_SET" - ); - } - - /// @dev This function will fail if the storage layout of this contract deviates from - /// the original staking contract's storage. The use of this function provides assurance - /// that regressions from the original storage layout will not occur. - function _assertStorageLayout() - internal - pure - { - assembly { - let slot := 0x0 - let offset := 0x0 - - /// Ownable - - assertSlotAndOffset( - owner_slot, - owner_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - /// Authorizable - - assertSlotAndOffset( - authorized_slot, - authorized_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - authorities_slot, - authorities_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - /// MixinStorage - - assertSlotAndOffset( - stakingContract_slot, - stakingContract_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _globalStakeByStatus_slot, - _globalStakeByStatus_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _ownerStakeByStatus_slot, - _ownerStakeByStatus_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _delegatedStakeToPoolByOwner_slot, - _delegatedStakeToPoolByOwner_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _delegatedStakeByPoolId_slot, - _delegatedStakeByPoolId_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - lastPoolId_slot, - lastPoolId_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - poolIdByMaker_slot, - poolIdByMaker_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _poolById_slot, - _poolById_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - rewardsByPoolId_slot, - rewardsByPoolId_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - currentEpoch_slot, - currentEpoch_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - currentEpochStartTimeInSeconds_slot, - currentEpochStartTimeInSeconds_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _cumulativeRewardsByPool_slot, - _cumulativeRewardsByPool_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - _cumulativeRewardsByPoolLastStored_slot, - _cumulativeRewardsByPoolLastStored_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - validExchanges_slot, - validExchanges_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - epochDurationInSeconds_slot, - epochDurationInSeconds_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - rewardDelegatedStakeWeight_slot, - rewardDelegatedStakeWeight_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - minimumPoolStake_slot, - minimumPoolStake_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - cobbDouglasAlphaNumerator_slot, - cobbDouglasAlphaNumerator_offset, - slot, - offset - ) - offset := add(offset, 0x4) - - // This number will be tightly packed into the previous values storage slot since - // they are both `uint32`. Because of this tight packing, the offset of this value - // must be 4, since the previous value is a 4 byte number. - assertSlotAndOffset( - cobbDouglasAlphaDenominator_slot, - cobbDouglasAlphaDenominator_offset, - slot, - offset - ) - slot := add(slot, 0x1) - offset := 0x0 - - assertSlotAndOffset( - poolStatsByEpoch_slot, - poolStatsByEpoch_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - aggregatedStatsByEpoch_slot, - aggregatedStatsByEpoch_offset, - slot, - offset - ) - slot := add(slot, 0x1) - - assertSlotAndOffset( - wethReservedForPoolRewards_slot, - wethReservedForPoolRewards_offset, - slot, - offset - ) - - // This assembly function will assert that the actual values for `_slot` and `_offset` are - // correct and will revert with a rich error if they are different than the expected values. - function assertSlotAndOffset( - actual_slot, - actual_offset, - expected_slot, - expected_offset - ) { - // If expected_slot is not equal to actual_slot, revert with a rich error. - if iszero(eq(expected_slot, actual_slot)) { - mstore(0x0, 0x213eb13400000000000000000000000000000000000000000000000000000000) // Rich error selector - mstore(0x4, 0x0) // Unexpected slot error code - mstore(0x24, expected_slot) // Expected slot - mstore(0x44, actual_slot) // Actual slot - revert(0x0, 0x64) - } - - // If expected_offset is not equal to actual_offset, revert with a rich error. - if iszero(eq(expected_offset, actual_offset)) { - mstore(0x0, 0x213eb13400000000000000000000000000000000000000000000000000000000) // Rich error selector - mstore(0x4, 0x1) // Unexpected offset error code - mstore(0x24, expected_offset) // Expected offset - mstore(0x44, actual_offset) // Actual offset - revert(0x0, 0x64) - } - } - } - } -} diff --git a/contracts/staking/package.json b/contracts/staking/package.json deleted file mode 100644 index 9ee52f0859..0000000000 --- a/contracts/staking/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "@0x/contracts-staking", - "version": "2.0.45", - "engines": { - "node": ">=6.12" - }, - "description": "Staking contracts used by 0x protocol", - "main": "lib/src/index.js", - "directories": { - "test": "test" - }, - "scripts": { - "build2": "tsc -b", - "build": "yarn pre_build && tsc -b", - "build:ci": "yarn build", - "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy", - "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", - "watch": "sol-compiler -w", - "clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers", - "generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", - "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", - "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/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", - "contracts:gen": "contracts-gen generate", - "contracts:copy": "contracts-gen copy", - "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", - "compile:truffle": "truffle compile", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "publicInterfaceContracts": "IStaking,IStakingEvents,IStakingProxy,IZrxVault,LibStakingRichErrors,Staking,StakingProxy,ZrxVault,TestStaking", - "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingPatch|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinCumulativeRewards|TestMixinParams|TestMixinScheduler|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", - "devDependencies": { - "@0x/abi-gen": "^5.6.0", - "@0x/contracts-asset-proxy": "^3.7.19", - "@0x/contracts-dev-utils": "^1.3.36", - "@0x/contracts-erc20": "^3.3.16", - "@0x/contracts-exchange-libs": "^4.3.37", - "@0x/contracts-gen": "^2.0.38", - "@0x/contracts-utils": "^4.7.16", - "@0x/dev-utils": "^4.2.7", - "@0x/order-utils": "^10.4.28", - "@0x/sol-compiler": "^4.7.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/lodash": "4.14.104", - "@types/node": "12.12.54", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "decimal.js": "^10.2.0", - "dirty-chai": "^2.0.1", - "js-combinatorics": "^0.5.3", - "lodash": "^4.17.11", - "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "solhint": "^1.4.1", - "truffle": "^5.0.32", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2" - }, - "dependencies": { - "@0x/base-contract": "^6.4.0", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/typescript-typings": "^5.2.0", - "@0x/utils": "^6.4.3", - "ethereum-types": "^3.5.0", - "ethereumjs-util": "^7.0.10" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/contracts/staking/src/artifacts.ts b/contracts/staking/src/artifacts.ts deleted file mode 100644 index 857f91a64b..0000000000 --- a/contracts/staking/src/artifacts.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as IStaking from '../generated-artifacts/IStaking.json'; -import * as IStakingEvents from '../generated-artifacts/IStakingEvents.json'; -import * as IStakingProxy from '../generated-artifacts/IStakingProxy.json'; -import * as IZrxVault from '../generated-artifacts/IZrxVault.json'; -import * as LibStakingRichErrors from '../generated-artifacts/LibStakingRichErrors.json'; -import * as Staking from '../generated-artifacts/Staking.json'; -import * as StakingProxy from '../generated-artifacts/StakingProxy.json'; -import * as TestStaking from '../generated-artifacts/TestStaking.json'; -import * as ZrxVault from '../generated-artifacts/ZrxVault.json'; -export const artifacts = { - IStaking: IStaking as ContractArtifact, - IStakingEvents: IStakingEvents as ContractArtifact, - IStakingProxy: IStakingProxy as ContractArtifact, - IZrxVault: IZrxVault as ContractArtifact, - LibStakingRichErrors: LibStakingRichErrors as ContractArtifact, - Staking: Staking as ContractArtifact, - StakingProxy: StakingProxy as ContractArtifact, - ZrxVault: ZrxVault as ContractArtifact, - TestStaking: TestStaking as ContractArtifact, -}; diff --git a/contracts/staking/src/constants.ts b/contracts/staking/src/constants.ts deleted file mode 100644 index 36a11e3230..0000000000 --- a/contracts/staking/src/constants.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { constants as testConstants } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -const TEN_DAYS = 10 * 24 * 60 * 60; -const PPM = 10 ** 6; -export const constants = { - TOKEN_MULTIPLIER: testConstants.DUMMY_TOKEN_DECIMALS, - INITIAL_POOL_ID: '0x0000000000000000000000000000000000000000000000000000000000000001', - SECOND_POOL_ID: '0x0000000000000000000000000000000000000000000000000000000000000002', - NIL_POOL_ID: '0x0000000000000000000000000000000000000000000000000000000000000000', - NIL_ADDRESS: '0x0000000000000000000000000000000000000000', - INITIAL_EPOCH: new BigNumber(1), - DEFAULT_PARAMS: { - epochDurationInSeconds: new BigNumber(TEN_DAYS), - rewardDelegatedStakeWeight: new BigNumber(PPM * 0.9), - minimumPoolStake: new BigNumber(10).pow(testConstants.DUMMY_TOKEN_DECIMALS).times(100), - cobbDouglasAlphaNumerator: new BigNumber(2), - cobbDouglasAlphaDenominator: new BigNumber(3), - }, - PPM, - ONE_DAY_IN_SECONDS: 24 * 60 * 60, -}; diff --git a/contracts/staking/src/index.ts b/contracts/staking/src/index.ts deleted file mode 100644 index f0ad2cf8bc..0000000000 --- a/contracts/staking/src/index.ts +++ /dev/null @@ -1,91 +0,0 @@ -export { - IStakingContract, - IStakingEventsContract, - IStakingProxyContract, - IZrxVaultContract, - LibStakingRichErrorsContract, - TestStakingContract, - ZrxVaultContract, - StakingAuthorizedAddressAddedEventArgs, - StakingAuthorizedAddressRemovedEventArgs, - StakingContract, - StakingEpochEndedEventArgs, - StakingEpochFinalizedEventArgs, - StakingEventArgs, - StakingEvents, - StakingExchangeAddedEventArgs, - StakingExchangeRemovedEventArgs, - StakingMakerStakingPoolSetEventArgs, - StakingMoveStakeEventArgs, - StakingOperatorShareDecreasedEventArgs, - StakingOwnershipTransferredEventArgs, - StakingParamsSetEventArgs, - StakingRewardsPaidEventArgs, - StakingStakeEventArgs, - StakingStakingPoolCreatedEventArgs, - StakingStakingPoolEarnedRewardsInEpochEventArgs, - StakingUnstakeEventArgs, - StakingProxyAuthorizedAddressAddedEventArgs, - StakingProxyAuthorizedAddressRemovedEventArgs, - StakingProxyContract, - StakingProxyEventArgs, - StakingProxyEvents, - StakingProxyOwnershipTransferredEventArgs, - StakingProxyStakingContractAttachedToProxyEventArgs, - StakingProxyStakingContractDetachedFromProxyEventArgs, - IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs, - TestStakingEvents, - IStakingEventsEpochEndedEventArgs, - IStakingEventsEpochFinalizedEventArgs, - IStakingEventsEvents, - IStakingEventsRewardsPaidEventArgs, -} from './wrappers'; -export { artifacts } from './artifacts'; -export { StakingRevertErrors, FixedMathRevertErrors } from '@0x/utils'; -export { constants } from './constants'; -export { - AggregatedStats, - StakeInfo, - StakeStatus, - StoredBalance, - loadCurrentBalance, - increaseNextBalance, - decreaseNextBalance, - increaseCurrentAndNextBalance, - decreaseCurrentAndNextBalance, - StakingPoolById, - OwnerStakeByStatus, - GlobalStakeByStatus, - StakingPool, - PoolStats, - Numberish, -} from './types'; -export { - ContractArtifact, - ContractChains, - CompilerOpts, - StandardContractOutput, - CompilerSettings, - ContractChainData, - ContractAbi, - DevdocOutput, - EvmOutput, - CompilerSettingsMetadata, - OptimizerSettings, - OutputField, - ParamDescription, - EvmBytecodeOutput, - EvmBytecodeOutputLinkReferences, - AbiDefinition, - FunctionAbi, - EventAbi, - RevertErrorAbi, - EventParameter, - DataItem, - MethodAbi, - ConstructorAbi, - FallbackAbi, - ConstructorStateMutability, - TupleDataItem, - StateMutability, -} from 'ethereum-types'; diff --git a/contracts/staking/src/types.ts b/contracts/staking/src/types.ts deleted file mode 100644 index 5955646639..0000000000 --- a/contracts/staking/src/types.ts +++ /dev/null @@ -1,262 +0,0 @@ -import { constants, Numberish } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types'; - -import { constants as stakingConstants } from './constants'; - -export { Numberish } from '@0x/contracts-test-utils'; -// tslint:disable:max-classes-per-file - -export interface StakingParams { - epochDurationInSeconds: Numberish; - rewardDelegatedStakeWeight: Numberish; - minimumPoolStake: Numberish; - cobbDouglasAlphaNumerator: Numberish; - cobbDouglasAlphaDenominator: Numberish; -} - -export interface StakerBalances { - zrxBalance: BigNumber; - stakeBalance: BigNumber; - stakeBalanceInVault: BigNumber; - activatableStakeBalance: BigNumber; - activatedStakeBalance: BigNumber; - deactivatedStakeBalance: BigNumber; - timeLockedStakeBalance: BigNumber; -} - -export interface DelegatorBalances extends StakerBalances { - delegatedStakeBalance: BigNumber; - stakeDelegatedToPoolByOwner: BigNumber[]; - stakeDelegatedToPool: BigNumber[]; -} - -export interface SimulationParams { - users: string[]; - numberOfPools: number; - poolOperatorShares: number[]; - stakeByPoolOperator: BigNumber[]; - numberOfMakers: number; - numberOfMakersPerPool: number[]; - protocolFeesByMaker: BigNumber[]; - numberOfDelegators: number; - numberOfDelegatorsPerPool: number[]; - stakeByDelegator: BigNumber[]; - expectedFeesByPool: BigNumber[]; - expectedPayoutByPool: BigNumber[]; - expectedPayoutByPoolOperator: BigNumber[]; - expectedMembersPayoutByPool: BigNumber[]; - expectedPayoutByDelegator: BigNumber[]; - exchangeAddress: string; - delegateInNextEpoch: boolean; - withdrawByUndelegating: boolean; -} - -export interface EndOfEpochInfo { - closingEpoch: BigNumber; - activePoolIds: string[]; - rewardsAvailable: BigNumber; - totalFeesCollected: BigNumber; - totalWeightedStake: BigNumber; -} - -export class StoredBalance { - constructor( - public currentEpoch: BigNumber = stakingConstants.INITIAL_EPOCH, - public currentEpochBalance: BigNumber = constants.ZERO_AMOUNT, - public nextEpochBalance: BigNumber = constants.ZERO_AMOUNT, - ) {} -} - -/** - * Simulates _loadCurrentBalance. `shouldMutate` flag specifies whether or not to update the given - * StoredBalance instance. - */ -export function loadCurrentBalance(balance: StoredBalance, epoch: BigNumber): StoredBalance { - return new StoredBalance( - epoch, - epoch.isGreaterThan(balance.currentEpoch) ? balance.nextEpochBalance : balance.currentEpochBalance, - balance.nextEpochBalance, - ); -} - -/** - * Simulates _increaseNextBalance - */ -export function increaseNextBalance(balance: StoredBalance, amount: Numberish, epoch: BigNumber): StoredBalance { - const newBalance = loadCurrentBalance(balance, epoch); - return { - ...newBalance, - nextEpochBalance: newBalance.nextEpochBalance.plus(amount), - }; -} - -/** - * Simulates _decreaseNextBalance - */ -export function decreaseNextBalance(balance: StoredBalance, amount: Numberish, epoch: BigNumber): StoredBalance { - const newBalance = loadCurrentBalance(balance, epoch); - return { - ...newBalance, - nextEpochBalance: newBalance.nextEpochBalance.minus(amount), - }; -} - -/** - * Simulates _increaseCurrentAndNextBalance - */ -export function increaseCurrentAndNextBalance( - balance: StoredBalance, - amount: Numberish, - epoch: BigNumber, -): StoredBalance { - const newBalance = loadCurrentBalance(balance, epoch); - return { - ...newBalance, - currentEpochBalance: newBalance.currentEpochBalance.plus(amount), - nextEpochBalance: newBalance.nextEpochBalance.plus(amount), - }; -} - -/** - * Simulates _decreaseCurrentAndNextBalance - */ -export function decreaseCurrentAndNextBalance( - balance: StoredBalance, - amount: Numberish, - epoch: BigNumber, -): StoredBalance { - const newBalance = loadCurrentBalance(balance, epoch); - return { - ...newBalance, - currentEpochBalance: newBalance.currentEpochBalance.minus(amount), - nextEpochBalance: newBalance.nextEpochBalance.minus(amount), - }; -} - -export interface StakeBalanceByPool { - [key: string]: StoredBalance; -} - -export enum StakeStatus { - Undelegated, - Delegated, -} - -export class StakeInfo { - constructor(public status: StakeStatus, public poolId: string = stakingConstants.NIL_POOL_ID) {} -} - -export interface StakeBalances { - currentEpoch: BigNumber; - zrxBalance: BigNumber; - stakeBalance: BigNumber; - stakeBalanceInVault: BigNumber; - undelegatedStakeBalance: StoredBalance; - delegatedStakeBalance: StoredBalance; - globalUndelegatedStakeBalance: StoredBalance; - globalDelegatedStakeBalance: StoredBalance; - delegatedStakeByPool: StakeBalanceByPool; - totalDelegatedStakeByPool: StakeBalanceByPool; -} - -export interface RewardBalanceByPoolId { - [key: string]: BigNumber; -} - -export interface OperatorShareByPoolId { - [key: string]: BigNumber; -} - -export interface OperatorBalanceByPoolId { - [key: string]: BigNumber; -} - -export interface BalanceByOwner { - [key: string]: BigNumber; -} - -export interface RewardByPoolId { - [key: string]: BigNumber; -} - -export interface DelegatorBalancesByPoolId { - [key: string]: BalanceByOwner; -} - -export interface OperatorByPoolId { - [key: string]: string; -} - -export interface DelegatorsByPoolId { - [key: string]: string[]; -} - -export type DecodedLogs = Array>; - -// mapping (uint8 => IStructs.StoredBalance) internal _globalStakeByStatus; -export interface GlobalStakeByStatus { - [StakeStatus.Undelegated]: StoredBalance; - [StakeStatus.Delegated]: StoredBalance; -} - -/* - * A combination of: - * mapping (uint8 => mapping (address => IStructs.StoredBalance)) internal _ownerStakeByStatus; - * and - * mapping (address => mapping (bytes32 => IStructs.StoredBalance)) internal _delegatedStakeToPoolByOwner; - */ -export interface OwnerStakeByStatus { - [StakeStatus.Undelegated]: StoredBalance; - [StakeStatus.Delegated]: { - total: StoredBalance; - [poolId: string]: StoredBalance; - }; -} - -export interface StakingPool { - operator: string; - operatorShare: number; - delegatedStake: StoredBalance; - lastFinalized: BigNumber; // Epoch during which the pool was most recently finalized -} - -export interface StakingPoolById { - [poolId: string]: StakingPool; -} - -export class PoolStats { - public feesCollected: BigNumber = constants.ZERO_AMOUNT; - public weightedStake: BigNumber = constants.ZERO_AMOUNT; - public membersStake: BigNumber = constants.ZERO_AMOUNT; - - public static fromArray(arr: [BigNumber, BigNumber, BigNumber]): PoolStats { - const poolStats = new PoolStats(); - [poolStats.feesCollected, poolStats.weightedStake, poolStats.membersStake] = arr; - return poolStats; - } -} - -export class AggregatedStats { - public rewardsAvailable: BigNumber = constants.ZERO_AMOUNT; - public numPoolsToFinalize: BigNumber = constants.ZERO_AMOUNT; - public totalFeesCollected: BigNumber = constants.ZERO_AMOUNT; - public totalWeightedStake: BigNumber = constants.ZERO_AMOUNT; - public totalRewardsFinalized: BigNumber = constants.ZERO_AMOUNT; - - public static fromArray(arr: [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber]): AggregatedStats { - const aggregatedStats = new AggregatedStats(); - [ - aggregatedStats.rewardsAvailable, - aggregatedStats.numPoolsToFinalize, - aggregatedStats.totalFeesCollected, - aggregatedStats.totalWeightedStake, - aggregatedStats.totalRewardsFinalized, - ] = arr; - return aggregatedStats; - } -} - -export interface AggregatedStatsByEpoch { - [epoch: string]: AggregatedStats; -} diff --git a/contracts/staking/src/wrappers.ts b/contracts/staking/src/wrappers.ts deleted file mode 100644 index f331c5466c..0000000000 --- a/contracts/staking/src/wrappers.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../generated-wrappers/i_staking'; -export * from '../generated-wrappers/i_staking_events'; -export * from '../generated-wrappers/i_staking_proxy'; -export * from '../generated-wrappers/i_zrx_vault'; -export * from '../generated-wrappers/lib_staking_rich_errors'; -export * from '../generated-wrappers/staking'; -export * from '../generated-wrappers/staking_proxy'; -export * from '../generated-wrappers/test_staking'; -export * from '../generated-wrappers/zrx_vault'; diff --git a/contracts/staking/test/actors/base_actor.ts b/contracts/staking/test/actors/base_actor.ts deleted file mode 100644 index 82be26100d..0000000000 --- a/contracts/staking/test/actors/base_actor.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { StakingApiWrapper } from '../utils/api_wrapper'; - -export class BaseActor { - protected readonly _owner: string; - protected readonly _stakingApiWrapper: StakingApiWrapper; - - constructor(owner: string, stakingApiWrapper: StakingApiWrapper) { - this._owner = owner; - this._stakingApiWrapper = stakingApiWrapper; - } - public getOwner(): string { - return this._owner; - } - public getStakingApiWrapper(): StakingApiWrapper { - return this._stakingApiWrapper; - } -} diff --git a/contracts/staking/test/actors/finalizer_actor.ts b/contracts/staking/test/actors/finalizer_actor.ts deleted file mode 100644 index f7e80004bd..0000000000 --- a/contracts/staking/test/actors/finalizer_actor.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { constants, expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { - BalanceByOwner, - DelegatorBalancesByPoolId, - DelegatorsByPoolId, - OperatorBalanceByPoolId, - OperatorByPoolId, - OperatorShareByPoolId, - RewardBalanceByPoolId, - RewardByPoolId, -} from '../../src/types'; -import { StakingApiWrapper } from '../utils/api_wrapper'; - -import { BaseActor } from './base_actor'; - -const { PPM_100_PERCENT } = constants; - -// tslint:disable: prefer-conditional-expression -export class FinalizerActor extends BaseActor { - private readonly _poolIds: string[]; - private readonly _operatorByPoolId: OperatorByPoolId; - private readonly _delegatorsByPoolId: DelegatorsByPoolId; - - constructor( - owner: string, - stakingApiWrapper: StakingApiWrapper, - poolIds: string[], - operatorByPoolId: OperatorByPoolId, - delegatorsByPoolId: DelegatorsByPoolId, - ) { - super(owner, stakingApiWrapper); - this._poolIds = _.cloneDeep(poolIds); - this._operatorByPoolId = _.cloneDeep(operatorByPoolId); - this._delegatorsByPoolId = _.cloneDeep(delegatorsByPoolId); - } - - public async finalizeAsync(): Promise { - // cache initial info and balances - const operatorShareByPoolId = await this._getOperatorShareByPoolIdAsync(this._poolIds); - const rewardBalanceByPoolId = await this._getRewardBalanceByPoolIdAsync(this._poolIds); - const delegatorBalancesByPoolId = await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId); - const delegatorStakesByPoolId = await this._getDelegatorStakesByPoolIdAsync(this._delegatorsByPoolId); - const operatorBalanceByPoolId = await this._getOperatorBalanceByPoolIdAsync(this._operatorByPoolId); - const rewardByPoolId = await this._getRewardByPoolIdAsync(this._poolIds); - // compute expected changes - const [ - expectedOperatorBalanceByPoolId, - expectedRewardBalanceByPoolId, - ] = this._computeExpectedRewardBalanceByPoolId( - rewardByPoolId, - operatorBalanceByPoolId, - rewardBalanceByPoolId, - delegatorStakesByPoolId, - operatorShareByPoolId, - ); - const expectedDelegatorBalancesByPoolId = await this._computeExpectedDelegatorBalancesByPoolIdAsync( - this._delegatorsByPoolId, - delegatorBalancesByPoolId, - delegatorStakesByPoolId, - operatorShareByPoolId, - rewardByPoolId, - ); - // finalize - await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync(); - // assert reward changes - const finalRewardBalanceByPoolId = await this._getRewardBalanceByPoolIdAsync(this._poolIds); - expect(finalRewardBalanceByPoolId, 'final pool reward balances').to.be.deep.equal( - expectedRewardBalanceByPoolId, - ); - // assert delegator balances - const finalDelegatorBalancesByPoolId = await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId); - expect(finalDelegatorBalancesByPoolId, 'final delegator reward balances').to.be.deep.equal( - expectedDelegatorBalancesByPoolId, - ); - // assert operator balances - const finalOperatorBalanceByPoolId = await this._getOperatorBalanceByPoolIdAsync(this._operatorByPoolId); - expect(finalOperatorBalanceByPoolId, 'final operator weth balance').to.be.deep.equal( - expectedOperatorBalanceByPoolId, - ); - } - - private async _computeExpectedDelegatorBalancesByPoolIdAsync( - delegatorsByPoolId: DelegatorsByPoolId, - delegatorBalancesByPoolId: DelegatorBalancesByPoolId, - delegatorStakesByPoolId: DelegatorBalancesByPoolId, - operatorShareByPoolId: OperatorShareByPoolId, - rewardByPoolId: RewardByPoolId, - ): Promise { - const expectedDelegatorBalancesByPoolId = _.cloneDeep(delegatorBalancesByPoolId); - for (const poolId of Object.keys(delegatorsByPoolId)) { - const operator = this._operatorByPoolId[poolId]; - const totalStakeInPool = BigNumber.sum(...Object.values(delegatorStakesByPoolId[poolId])); - const operatorStakeInPool = delegatorStakesByPoolId[poolId][operator]; - const membersStakeInPool = totalStakeInPool.minus(operatorStakeInPool); - const operatorShare = operatorShareByPoolId[poolId]; - const totalReward = rewardByPoolId[poolId]; - const operatorReward = membersStakeInPool.eq(0) - ? totalReward - : totalReward.times(operatorShare).dividedToIntegerBy(PPM_100_PERCENT); - const membersTotalReward = totalReward.minus(operatorReward); - - for (const delegator of delegatorsByPoolId[poolId]) { - let delegatorReward = new BigNumber(0); - if (delegator !== operator && membersStakeInPool.gt(0)) { - const delegatorStake = delegatorStakesByPoolId[poolId][delegator]; - delegatorReward = delegatorStake.times(membersTotalReward).dividedToIntegerBy(membersStakeInPool); - } - const currentBalance = expectedDelegatorBalancesByPoolId[poolId][delegator] || 0; - expectedDelegatorBalancesByPoolId[poolId][delegator] = delegatorReward.plus(currentBalance); - } - } - return expectedDelegatorBalancesByPoolId; - } - - private async _getDelegatorBalancesByPoolIdAsync( - delegatorsByPoolId: DelegatorsByPoolId, - ): Promise { - const { - computeRewardBalanceOfDelegator, - computeRewardBalanceOfOperator, - } = this._stakingApiWrapper.stakingContract; - const delegatorBalancesByPoolId: DelegatorBalancesByPoolId = {}; - - for (const poolId of Object.keys(delegatorsByPoolId)) { - const operator = this._operatorByPoolId[poolId]; - const delegators = delegatorsByPoolId[poolId]; - delegatorBalancesByPoolId[poolId] = {}; - for (const delegator of delegators) { - let balance = new BigNumber(delegatorBalancesByPoolId[poolId][delegator] || 0); - if (delegator === operator) { - balance = balance.plus( - await computeRewardBalanceOfOperator - .bind(this._stakingApiWrapper.stakingContract)(poolId) - .callAsync(), - ); - } else { - balance = balance.plus( - await computeRewardBalanceOfDelegator - .bind(this._stakingApiWrapper.stakingContract)(poolId, delegator) - .callAsync(), - ); - } - delegatorBalancesByPoolId[poolId][delegator] = balance; - } - } - return delegatorBalancesByPoolId; - } - - private async _getDelegatorStakesByPoolIdAsync( - delegatorsByPoolId: DelegatorsByPoolId, - ): Promise { - const delegatorBalancesByPoolId: DelegatorBalancesByPoolId = {}; - for (const poolId of Object.keys(delegatorsByPoolId)) { - const delegators = delegatorsByPoolId[poolId]; - delegatorBalancesByPoolId[poolId] = {}; - for (const delegator of delegators) { - delegatorBalancesByPoolId[poolId][delegator] = ( - await this._stakingApiWrapper.stakingContract - .getStakeDelegatedToPoolByOwner(delegator, poolId) - .callAsync() - ).currentEpochBalance; - } - } - return delegatorBalancesByPoolId; - } - - private _computeExpectedRewardBalanceByPoolId( - rewardByPoolId: RewardByPoolId, - operatorBalanceByPoolId: OperatorBalanceByPoolId, - rewardBalanceByPoolId: RewardBalanceByPoolId, - delegatorStakesByPoolId: DelegatorBalancesByPoolId, - operatorShareByPoolId: OperatorShareByPoolId, - ): [RewardBalanceByPoolId, OperatorBalanceByPoolId] { - const expectedOperatorBalanceByPoolId = _.cloneDeep(operatorBalanceByPoolId); - const expectedRewardBalanceByPoolId = _.cloneDeep(rewardBalanceByPoolId); - for (const poolId of Object.keys(rewardByPoolId)) { - const operatorShare = operatorShareByPoolId[poolId]; - [ - expectedOperatorBalanceByPoolId[poolId], - expectedRewardBalanceByPoolId[poolId], - ] = this._computeExpectedRewardBalance( - poolId, - rewardByPoolId[poolId], - expectedOperatorBalanceByPoolId[poolId], - expectedRewardBalanceByPoolId[poolId], - delegatorStakesByPoolId[poolId], - operatorShare, - ); - } - return [expectedOperatorBalanceByPoolId, expectedRewardBalanceByPoolId]; - } - - private _computeExpectedRewardBalance( - poolId: string, - reward: BigNumber, - operatorBalance: BigNumber, - rewardBalance: BigNumber, - stakeBalances: BalanceByOwner, - operatorShare: BigNumber, - ): [BigNumber, BigNumber] { - const totalStakeDelegatedToPool = BigNumber.sum(...Object.values(stakeBalances)); - const stakeDelegatedToPoolByOperator = stakeBalances[this._operatorByPoolId[poolId]]; - const membersStakeDelegatedToPool = totalStakeDelegatedToPool.minus(stakeDelegatedToPoolByOperator); - const operatorPortion = membersStakeDelegatedToPool.eq(0) - ? reward - : reward.times(operatorShare).dividedToIntegerBy(PPM_100_PERCENT); - const membersPortion = reward.minus(operatorPortion); - return [operatorBalance.plus(operatorPortion), rewardBalance.plus(membersPortion)]; - } - - private async _getOperatorBalanceByPoolIdAsync( - operatorByPoolId: OperatorByPoolId, - ): Promise { - const operatorBalanceByPoolId: OperatorBalanceByPoolId = {}; - for (const poolId of Object.keys(operatorByPoolId)) { - operatorBalanceByPoolId[poolId] = await this._stakingApiWrapper.wethContract - .balanceOf(operatorByPoolId[poolId]) - .callAsync(); - } - return operatorBalanceByPoolId; - } - - private async _getOperatorShareByPoolIdAsync(poolIds: string[]): Promise { - const operatorShareByPoolId: OperatorShareByPoolId = {}; - for (const poolId of poolIds) { - operatorShareByPoolId[poolId] = new BigNumber( - (await this._stakingApiWrapper.stakingContract.getStakingPool(poolId).callAsync()).operatorShare, - ); - } - return operatorShareByPoolId; - } - - private async _getRewardBalanceByPoolIdAsync(poolIds: string[]): Promise { - const rewardBalanceByPoolId: RewardBalanceByPoolId = {}; - for (const poolId of poolIds) { - rewardBalanceByPoolId[poolId] = await this._stakingApiWrapper.stakingContract - .rewardsByPoolId(poolId) - .callAsync(); - } - return rewardBalanceByPoolId; - } - - private async _getRewardByPoolIdAsync(poolIds: string[]): Promise { - const activePools = await Promise.all( - poolIds.map(async poolId => - this._stakingApiWrapper.stakingContract.getStakingPoolStatsThisEpoch(poolId).callAsync(), - ), - ); - const totalRewards = await this._stakingApiWrapper.utils.getAvailableRewardsBalanceAsync(); - const totalFeesCollected = BigNumber.sum(...activePools.map(p => p.feesCollected)); - const totalWeightedStake = BigNumber.sum(...activePools.map(p => p.weightedStake)); - if (totalRewards.eq(0) || totalFeesCollected.eq(0) || totalWeightedStake.eq(0)) { - return _.zipObject( - poolIds, - _.times(poolIds.length, () => new BigNumber(0)), - ); - } - const rewards = await Promise.all( - activePools.map(async pool => - this._stakingApiWrapper.utils.cobbDouglasAsync( - totalRewards, - pool.feesCollected, - totalFeesCollected, - pool.weightedStake, - totalWeightedStake, - ), - ), - ); - return _.zipObject(poolIds, rewards); - } -} diff --git a/contracts/staking/test/actors/maker_actor.ts b/contracts/staking/test/actors/maker_actor.ts deleted file mode 100644 index f5331ae473..0000000000 --- a/contracts/staking/test/actors/maker_actor.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from '@0x/contracts-test-utils'; -import { RevertError } from '@0x/utils'; -import * as _ from 'lodash'; - -import { PoolOperatorActor } from './pool_operator_actor'; - -export class MakerActor extends PoolOperatorActor { - public async joinStakingPoolAsMakerAsync(poolId: string, revertError?: RevertError): Promise { - // add maker - const txReceiptPromise = this._stakingApiWrapper.stakingContract - .joinStakingPoolAsMaker(poolId) - .awaitTransactionSuccessAsync({ from: this.getOwner() }); - if (revertError !== undefined) { - await expect(txReceiptPromise).to.revertWith(revertError); - return; - } - await txReceiptPromise; - // check the pool id of the maker - const poolIdOfMaker = await this._stakingApiWrapper.stakingContract.poolIdByMaker(this.getOwner()).callAsync(); - expect(poolIdOfMaker, 'pool id of maker').to.be.equal(poolId); - } -} diff --git a/contracts/staking/test/actors/pool_operator_actor.ts b/contracts/staking/test/actors/pool_operator_actor.ts deleted file mode 100644 index 2bc1e124bc..0000000000 --- a/contracts/staking/test/actors/pool_operator_actor.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { expect } from '@0x/contracts-test-utils'; -import { RevertError } from '@0x/utils'; -import * as _ from 'lodash'; - -import { BaseActor } from './base_actor'; - -export class PoolOperatorActor extends BaseActor { - public async createStakingPoolAsync( - operatorShare: number, - addOperatorAsMaker: boolean, - revertError?: RevertError, - ): Promise { - // create pool - const poolIdPromise = this._stakingApiWrapper.utils.createStakingPoolAsync( - this._owner, - operatorShare, - addOperatorAsMaker, - ); - if (revertError !== undefined) { - await expect(poolIdPromise).to.revertWith(revertError); - return ''; - } - const poolId = await poolIdPromise; - // validate pool id - const lastPoolId = await this._stakingApiWrapper.stakingContract.lastPoolId().callAsync(); - expect(poolId, 'pool id').to.be.bignumber.equal(lastPoolId); - - if (addOperatorAsMaker) { - // check the pool id of the operator - const poolIdOfMaker = await this._stakingApiWrapper.stakingContract.poolIdByMaker(this._owner).callAsync(); - expect(poolIdOfMaker, 'pool id of maker').to.be.equal(poolId); - } - return poolId; - } - public async decreaseStakingPoolOperatorShareAsync( - poolId: string, - newOperatorShare: number, - revertError?: RevertError, - ): Promise { - // decrease operator share - const txReceiptPromise = this._stakingApiWrapper.stakingContract - .decreaseStakingPoolOperatorShare(poolId, newOperatorShare) - .awaitTransactionSuccessAsync({ from: this._owner }); - if (revertError !== undefined) { - await expect(txReceiptPromise).to.revertWith(revertError); - return; - } - await txReceiptPromise; - // Check operator share - const pool = await this._stakingApiWrapper.stakingContract.getStakingPool(poolId).callAsync(); - expect(pool.operatorShare, 'updated operator share').to.be.bignumber.equal(newOperatorShare); - } -} diff --git a/contracts/staking/test/actors/staker_actor.ts b/contracts/staking/test/actors/staker_actor.ts deleted file mode 100644 index 6603d85774..0000000000 --- a/contracts/staking/test/actors/staker_actor.ts +++ /dev/null @@ -1,320 +0,0 @@ -import { expect } from '@0x/contracts-test-utils'; -import { BigNumber, RevertError } from '@0x/utils'; -import * as _ from 'lodash'; - -import { StakeBalances, StakeInfo, StakeStatus, StoredBalance } from '../../src/types'; -import { StakingApiWrapper } from '../utils/api_wrapper'; - -import { BaseActor } from './base_actor'; - -export class StakerActor extends BaseActor { - private readonly _poolIds: string[]; - - private static _incrementNextBalance(balance: StoredBalance, amount: BigNumber): void { - balance.nextEpochBalance = balance.nextEpochBalance.plus(amount); - } - private static _decrementNextBalance(balance: StoredBalance, amount: BigNumber): void { - balance.nextEpochBalance = balance.nextEpochBalance.minus(amount); - } - private static _incrementCurrentAndNextBalance(balance: StoredBalance, amount: BigNumber): void { - balance.currentEpochBalance = balance.currentEpochBalance.plus(amount); - balance.nextEpochBalance = balance.nextEpochBalance.plus(amount); - } - private static _decrementCurrentAndNextBalance(balance: StoredBalance, amount: BigNumber): void { - balance.currentEpochBalance = balance.currentEpochBalance.minus(amount); - balance.nextEpochBalance = balance.nextEpochBalance.minus(amount); - } - - constructor(owner: string, stakingApiWrapper: StakingApiWrapper) { - super(owner, stakingApiWrapper); - this._poolIds = []; - } - - public async stakeAndMoveAsync( - from: StakeInfo, - to: StakeInfo, - amount: BigNumber, - revertError?: RevertError, - ): Promise { - const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - const initBalances = await this._getBalancesAsync(); - // move stake - const txReceiptPromise = this._stakingApiWrapper.stakingProxyContract - .batchExecute([ - this._stakingApiWrapper.stakingContract.stake(amount).getABIEncodedTransactionData(), - this._stakingApiWrapper.stakingContract.moveStake(from, to, amount).getABIEncodedTransactionData(), - ]) - .awaitTransactionSuccessAsync({ from: this._owner }); - if (revertError !== undefined) { - await expect(txReceiptPromise, 'expected revert error').to.revertWith(revertError); - return; - } - await txReceiptPromise; - // Calculate the expected stake amount. - const expectedBalances = await this._calculateExpectedBalancesAfterMoveAsync( - from, - to, - amount, - await this._calculateExpectedBalancesAfterStakeAsync(amount, initBalances), - ); - await this._assertBalancesAsync(expectedBalances); - // check zrx balance of vault - const finalZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - expect(finalZrxBalanceOfVault, 'final balance of zrx vault').to.be.bignumber.equal( - initZrxBalanceOfVault.plus(amount), - ); - } - - public async stakeAsync(amount: BigNumber, revertError?: RevertError): Promise { - const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - const initBalances = await this._getBalancesAsync(); - // deposit stake - const txReceiptPromise = this._stakingApiWrapper.stakingContract.stake(amount).awaitTransactionSuccessAsync({ - from: this._owner, - }); - if (revertError !== undefined) { - await expect(txReceiptPromise, 'expected revert error').to.revertWith(revertError); - return; - } - await txReceiptPromise; - // @TODO check receipt logs and return value via eth_call - // check balances - const expectedBalances = await this._calculateExpectedBalancesAfterStakeAsync(amount, initBalances); - await this._assertBalancesAsync(expectedBalances); - // check zrx balance of vault - const finalZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - expect(finalZrxBalanceOfVault, 'final balance of zrx vault').to.be.bignumber.equal( - initZrxBalanceOfVault.plus(amount), - ); - } - - public async unstakeAsync(amount: BigNumber, revertError?: RevertError): Promise { - const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - const initBalances = await this._getBalancesAsync(); - // deposit stake - const txReceiptPromise = this._stakingApiWrapper.stakingContract.unstake(amount).awaitTransactionSuccessAsync({ - from: this._owner, - }); - if (revertError !== undefined) { - await expect(txReceiptPromise, 'expected revert error').to.revertWith(revertError); - return; - } - await txReceiptPromise; - // @TODO check receipt logs and return value via eth_call - // check balances - const expectedBalances = initBalances; - expectedBalances.zrxBalance = initBalances.zrxBalance.plus(amount); - expectedBalances.stakeBalanceInVault = initBalances.stakeBalanceInVault.minus(amount); - StakerActor._decrementCurrentAndNextBalance(expectedBalances.undelegatedStakeBalance, amount); - StakerActor._decrementCurrentAndNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount); - await this._assertBalancesAsync(expectedBalances); - // check zrx balance of vault - const finalZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - expect(finalZrxBalanceOfVault, 'final balance of zrx vault').to.be.bignumber.equal( - initZrxBalanceOfVault.minus(amount), - ); - } - - public async moveStakeAsync( - from: StakeInfo, - to: StakeInfo, - amount: BigNumber, - revertError?: RevertError, - ): Promise { - // Cache Initial Balances. - const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - // Calculate the expected outcome after the move. - const expectedBalances = await this._calculateExpectedBalancesAfterMoveAsync(from, to, amount); - // move stake - const txReceiptPromise = this._stakingApiWrapper.stakingContract - .moveStake(from, to, amount) - .awaitTransactionSuccessAsync({ from: this._owner }); - if (revertError !== undefined) { - await expect(txReceiptPromise).to.revertWith(revertError); - return; - } - await txReceiptPromise; - // check balances - await this._assertBalancesAsync(expectedBalances); - // check zrx balance of vault - const finalZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - expect(finalZrxBalanceOfVault, 'final balance of zrx vault').to.be.bignumber.equal(initZrxBalanceOfVault); - } - - public async stakeWithPoolAsync(poolId: string, amount: BigNumber): Promise { - await this.stakeAsync(amount); - await this.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - amount, - ); - } - - public async withdrawDelegatorRewardsAsync(poolId: string, revertError?: RevertError): Promise { - const txReceiptPromise = this._stakingApiWrapper.stakingContract - .withdrawDelegatorRewards(poolId) - .awaitTransactionSuccessAsync({ from: this._owner }); - if (revertError !== undefined) { - await expect(txReceiptPromise, 'expected revert error').to.revertWith(revertError); - return; - } - await txReceiptPromise; - } - - public async goToNextEpochAsync(): Promise { - // cache balances - const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - const initBalances = await this._getBalancesAsync(); - // go to next epoch - await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync(); - // check balances - const expectedBalances = this._getNextEpochBalances(initBalances); - await this._assertBalancesAsync(expectedBalances); - // check zrx balance of vault - const finalZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync(); - expect(finalZrxBalanceOfVault, 'final balance of zrx vault').to.be.bignumber.equal(initZrxBalanceOfVault); - } - private _getNextEpochBalances(balances: StakeBalances): StakeBalances { - const nextBalances = _.cloneDeep(balances); - for (const balance of [ - nextBalances.undelegatedStakeBalance, - nextBalances.delegatedStakeBalance, - nextBalances.globalUndelegatedStakeBalance, - nextBalances.globalDelegatedStakeBalance, - ...this._poolIds.map(poolId => nextBalances.delegatedStakeByPool[poolId]), - ...this._poolIds.map(poolId => nextBalances.totalDelegatedStakeByPool[poolId]), - ]) { - balance.currentEpoch = balances.currentEpoch.plus(1); - balance.currentEpochBalance = balance.nextEpochBalance; - } - return nextBalances; - } - private async _getBalancesAsync(): Promise { - const balances: StakeBalances = { - currentEpoch: await this._stakingApiWrapper.stakingContract.currentEpoch().callAsync(), - zrxBalance: await this._stakingApiWrapper.zrxTokenContract.balanceOf(this._owner).callAsync(), - stakeBalance: await this._stakingApiWrapper.stakingContract.getTotalStake(this._owner).callAsync(), - stakeBalanceInVault: await this._stakingApiWrapper.zrxVaultContract.balanceOf(this._owner).callAsync(), - undelegatedStakeBalance: await this._stakingApiWrapper.stakingContract - .getOwnerStakeByStatus(this._owner, StakeStatus.Undelegated) - .callAsync(), - delegatedStakeBalance: await this._stakingApiWrapper.stakingContract - .getOwnerStakeByStatus(this._owner, StakeStatus.Delegated) - .callAsync(), - globalUndelegatedStakeBalance: await this._stakingApiWrapper.stakingContract - .getGlobalStakeByStatus(StakeStatus.Undelegated) - .callAsync(), - globalDelegatedStakeBalance: await this._stakingApiWrapper.stakingContract - .getGlobalStakeByStatus(StakeStatus.Delegated) - .callAsync(), - delegatedStakeByPool: {}, - totalDelegatedStakeByPool: {}, - }; - // lookup for each pool - for (const poolId of this._poolIds) { - const delegatedStakeBalanceByPool = await this._stakingApiWrapper.stakingContract - .getStakeDelegatedToPoolByOwner(this._owner, poolId) - .callAsync(); - const totalDelegatedStakeBalanceByPool = await this._stakingApiWrapper.stakingContract - .getTotalStakeDelegatedToPool(poolId) - .callAsync(); - balances.delegatedStakeByPool[poolId] = delegatedStakeBalanceByPool; - balances.totalDelegatedStakeByPool[poolId] = totalDelegatedStakeBalanceByPool; - } - return balances; - } - private async _assertBalancesAsync(expectedBalances: StakeBalances): Promise { - const balances = await this._getBalancesAsync(); - expect(balances.zrxBalance, 'zrx balance').to.be.bignumber.equal(expectedBalances.zrxBalance); - expect(balances.stakeBalanceInVault, 'stake balance, recorded in vault').to.be.bignumber.equal( - expectedBalances.stakeBalanceInVault, - ); - expect( - balances.undelegatedStakeBalance.currentEpochBalance, - 'undelegated stake balance (current)', - ).to.be.bignumber.equal(expectedBalances.undelegatedStakeBalance.currentEpochBalance); - expect( - balances.undelegatedStakeBalance.nextEpochBalance, - 'undelegated stake balance (next)', - ).to.be.bignumber.equal(expectedBalances.undelegatedStakeBalance.nextEpochBalance); - expect( - balances.delegatedStakeBalance.currentEpochBalance, - 'delegated stake balance (current)', - ).to.be.bignumber.equal(expectedBalances.delegatedStakeBalance.currentEpochBalance); - expect(balances.delegatedStakeBalance.nextEpochBalance, 'delegated stake balance (next)').to.be.bignumber.equal( - expectedBalances.delegatedStakeBalance.nextEpochBalance, - ); - expect( - balances.globalUndelegatedStakeBalance.currentEpochBalance, - 'global undelegated stake (current)', - ).to.bignumber.equal(expectedBalances.globalUndelegatedStakeBalance.currentEpochBalance); - expect( - balances.globalDelegatedStakeBalance.currentEpochBalance, - 'global delegated stake (current)', - ).to.bignumber.equal(expectedBalances.globalDelegatedStakeBalance.currentEpochBalance); - expect( - balances.globalUndelegatedStakeBalance.nextEpochBalance, - 'global undelegated stake (next)', - ).to.bignumber.equal(expectedBalances.globalUndelegatedStakeBalance.nextEpochBalance); - expect( - balances.globalDelegatedStakeBalance.nextEpochBalance, - 'global delegated stake (next)', - ).to.bignumber.equal(expectedBalances.globalDelegatedStakeBalance.nextEpochBalance); - expect(balances.delegatedStakeByPool, 'delegated stake by pool').to.be.deep.equal( - expectedBalances.delegatedStakeByPool, - ); - expect(balances.totalDelegatedStakeByPool, 'total delegated stake by pool').to.be.deep.equal( - expectedBalances.totalDelegatedStakeByPool, - ); - } - - private async _calculateExpectedBalancesAfterMoveAsync( - from: StakeInfo, - to: StakeInfo, - amount: BigNumber, - initBalances?: StakeBalances, - ): Promise { - // check if we're moving stake into a new pool - if (to.status === StakeStatus.Delegated && to.poolId !== undefined && !_.includes(this._poolIds, to.poolId)) { - this._poolIds.push(to.poolId); - } - // cache balances - const expectedBalances = initBalances || (await this._getBalancesAsync()); - // @TODO check receipt logs and return value via eth_call - // check balances - // from - if (from.status === StakeStatus.Undelegated) { - StakerActor._decrementNextBalance(expectedBalances.undelegatedStakeBalance, amount); - StakerActor._decrementNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount); - } else if (from.status === StakeStatus.Delegated && from.poolId !== undefined) { - StakerActor._decrementNextBalance(expectedBalances.delegatedStakeBalance, amount); - StakerActor._decrementNextBalance(expectedBalances.globalDelegatedStakeBalance, amount); - StakerActor._decrementNextBalance(expectedBalances.delegatedStakeByPool[from.poolId], amount); - StakerActor._decrementNextBalance(expectedBalances.totalDelegatedStakeByPool[from.poolId], amount); - } - // to - if (to.status === StakeStatus.Undelegated) { - StakerActor._incrementNextBalance(expectedBalances.undelegatedStakeBalance, amount); - StakerActor._incrementNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount); - } else if (to.status === StakeStatus.Delegated && to.poolId !== undefined) { - StakerActor._incrementNextBalance(expectedBalances.delegatedStakeBalance, amount); - StakerActor._incrementNextBalance(expectedBalances.globalDelegatedStakeBalance, amount); - StakerActor._incrementNextBalance(expectedBalances.delegatedStakeByPool[to.poolId], amount); - StakerActor._incrementNextBalance(expectedBalances.totalDelegatedStakeByPool[to.poolId], amount); - } - return expectedBalances; - } - - private async _calculateExpectedBalancesAfterStakeAsync( - amount: BigNumber, - initBalances?: StakeBalances, - ): Promise { - const expectedBalances = initBalances || (await this._getBalancesAsync()); - // check balances - expectedBalances.zrxBalance = expectedBalances.zrxBalance.minus(amount); - expectedBalances.stakeBalanceInVault = expectedBalances.stakeBalanceInVault.plus(amount); - StakerActor._incrementCurrentAndNextBalance(expectedBalances.undelegatedStakeBalance, amount); - StakerActor._incrementCurrentAndNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount); - return expectedBalances; - } -} diff --git a/contracts/staking/test/artifacts.ts b/contracts/staking/test/artifacts.ts deleted file mode 100644 index 3cfedb0547..0000000000 --- a/contracts/staking/test/artifacts.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -import { ContractArtifact } from 'ethereum-types'; - -import * as IStaking from '../test/generated-artifacts/IStaking.json'; -import * as IStakingEvents from '../test/generated-artifacts/IStakingEvents.json'; -import * as IStakingProxy from '../test/generated-artifacts/IStakingProxy.json'; -import * as IStorage from '../test/generated-artifacts/IStorage.json'; -import * as IStorageInit from '../test/generated-artifacts/IStorageInit.json'; -import * as IStructs from '../test/generated-artifacts/IStructs.json'; -import * as IZrxVault from '../test/generated-artifacts/IZrxVault.json'; -import * as LibCobbDouglas from '../test/generated-artifacts/LibCobbDouglas.json'; -import * as LibFixedMath from '../test/generated-artifacts/LibFixedMath.json'; -import * as LibFixedMathRichErrors from '../test/generated-artifacts/LibFixedMathRichErrors.json'; -import * as LibSafeDowncast from '../test/generated-artifacts/LibSafeDowncast.json'; -import * as LibStakingRichErrors from '../test/generated-artifacts/LibStakingRichErrors.json'; -import * as MixinAbstract from '../test/generated-artifacts/MixinAbstract.json'; -import * as MixinConstants from '../test/generated-artifacts/MixinConstants.json'; -import * as MixinCumulativeRewards from '../test/generated-artifacts/MixinCumulativeRewards.json'; -import * as MixinDeploymentConstants from '../test/generated-artifacts/MixinDeploymentConstants.json'; -import * as MixinExchangeFees from '../test/generated-artifacts/MixinExchangeFees.json'; -import * as MixinExchangeManager from '../test/generated-artifacts/MixinExchangeManager.json'; -import * as MixinFinalizer from '../test/generated-artifacts/MixinFinalizer.json'; -import * as MixinParams from '../test/generated-artifacts/MixinParams.json'; -import * as MixinScheduler from '../test/generated-artifacts/MixinScheduler.json'; -import * as MixinStake from '../test/generated-artifacts/MixinStake.json'; -import * as MixinStakeBalances from '../test/generated-artifacts/MixinStakeBalances.json'; -import * as MixinStakeStorage from '../test/generated-artifacts/MixinStakeStorage.json'; -import * as MixinStakingPool from '../test/generated-artifacts/MixinStakingPool.json'; -import * as MixinStakingPoolRewards from '../test/generated-artifacts/MixinStakingPoolRewards.json'; -import * as MixinStorage from '../test/generated-artifacts/MixinStorage.json'; -import * as Staking from '../test/generated-artifacts/Staking.json'; -import * as StakingPatch from '../test/generated-artifacts/StakingPatch.json'; -import * as StakingProxy from '../test/generated-artifacts/StakingProxy.json'; -import * as TestAssertStorageParams from '../test/generated-artifacts/TestAssertStorageParams.json'; -import * as TestCobbDouglas from '../test/generated-artifacts/TestCobbDouglas.json'; -import * as TestCumulativeRewardTracking from '../test/generated-artifacts/TestCumulativeRewardTracking.json'; -import * as TestDelegatorRewards from '../test/generated-artifacts/TestDelegatorRewards.json'; -import * as TestExchangeManager from '../test/generated-artifacts/TestExchangeManager.json'; -import * as TestFinalizer from '../test/generated-artifacts/TestFinalizer.json'; -import * as TestInitTarget from '../test/generated-artifacts/TestInitTarget.json'; -import * as TestLibFixedMath from '../test/generated-artifacts/TestLibFixedMath.json'; -import * as TestLibSafeDowncast from '../test/generated-artifacts/TestLibSafeDowncast.json'; -import * as TestMixinCumulativeRewards from '../test/generated-artifacts/TestMixinCumulativeRewards.json'; -import * as TestMixinParams from '../test/generated-artifacts/TestMixinParams.json'; -import * as TestMixinScheduler from '../test/generated-artifacts/TestMixinScheduler.json'; -import * as TestMixinStake from '../test/generated-artifacts/TestMixinStake.json'; -import * as TestMixinStakeBalances from '../test/generated-artifacts/TestMixinStakeBalances.json'; -import * as TestMixinStakeStorage from '../test/generated-artifacts/TestMixinStakeStorage.json'; -import * as TestMixinStakingPool from '../test/generated-artifacts/TestMixinStakingPool.json'; -import * as TestMixinStakingPoolRewards from '../test/generated-artifacts/TestMixinStakingPoolRewards.json'; -import * as TestProtocolFees from '../test/generated-artifacts/TestProtocolFees.json'; -import * as TestProxyDestination from '../test/generated-artifacts/TestProxyDestination.json'; -import * as TestStaking from '../test/generated-artifacts/TestStaking.json'; -import * as TestStakingNoWETH from '../test/generated-artifacts/TestStakingNoWETH.json'; -import * as TestStakingProxy from '../test/generated-artifacts/TestStakingProxy.json'; -import * as TestStakingProxyUnit from '../test/generated-artifacts/TestStakingProxyUnit.json'; -import * as TestStorageLayoutAndConstants from '../test/generated-artifacts/TestStorageLayoutAndConstants.json'; -import * as ZrxVault from '../test/generated-artifacts/ZrxVault.json'; -export const artifacts = { - Staking: Staking as ContractArtifact, - StakingPatch: StakingPatch as ContractArtifact, - StakingProxy: StakingProxy as ContractArtifact, - ZrxVault: ZrxVault as ContractArtifact, - MixinExchangeFees: MixinExchangeFees as ContractArtifact, - MixinExchangeManager: MixinExchangeManager as ContractArtifact, - MixinConstants: MixinConstants as ContractArtifact, - MixinDeploymentConstants: MixinDeploymentConstants as ContractArtifact, - MixinStorage: MixinStorage as ContractArtifact, - IStaking: IStaking as ContractArtifact, - IStakingEvents: IStakingEvents as ContractArtifact, - IStakingProxy: IStakingProxy as ContractArtifact, - IStorage: IStorage as ContractArtifact, - IStorageInit: IStorageInit as ContractArtifact, - IStructs: IStructs as ContractArtifact, - IZrxVault: IZrxVault as ContractArtifact, - LibCobbDouglas: LibCobbDouglas as ContractArtifact, - LibFixedMath: LibFixedMath as ContractArtifact, - LibFixedMathRichErrors: LibFixedMathRichErrors as ContractArtifact, - LibSafeDowncast: LibSafeDowncast as ContractArtifact, - LibStakingRichErrors: LibStakingRichErrors as ContractArtifact, - MixinStake: MixinStake as ContractArtifact, - MixinStakeBalances: MixinStakeBalances as ContractArtifact, - MixinStakeStorage: MixinStakeStorage as ContractArtifact, - MixinCumulativeRewards: MixinCumulativeRewards as ContractArtifact, - MixinStakingPool: MixinStakingPool as ContractArtifact, - MixinStakingPoolRewards: MixinStakingPoolRewards as ContractArtifact, - MixinAbstract: MixinAbstract as ContractArtifact, - MixinFinalizer: MixinFinalizer as ContractArtifact, - MixinParams: MixinParams as ContractArtifact, - MixinScheduler: MixinScheduler as ContractArtifact, - TestAssertStorageParams: TestAssertStorageParams as ContractArtifact, - TestCobbDouglas: TestCobbDouglas as ContractArtifact, - TestCumulativeRewardTracking: TestCumulativeRewardTracking as ContractArtifact, - TestDelegatorRewards: TestDelegatorRewards as ContractArtifact, - TestExchangeManager: TestExchangeManager as ContractArtifact, - TestFinalizer: TestFinalizer as ContractArtifact, - TestInitTarget: TestInitTarget as ContractArtifact, - TestLibFixedMath: TestLibFixedMath as ContractArtifact, - TestLibSafeDowncast: TestLibSafeDowncast as ContractArtifact, - TestMixinCumulativeRewards: TestMixinCumulativeRewards as ContractArtifact, - TestMixinParams: TestMixinParams as ContractArtifact, - TestMixinScheduler: TestMixinScheduler as ContractArtifact, - TestMixinStake: TestMixinStake as ContractArtifact, - TestMixinStakeBalances: TestMixinStakeBalances as ContractArtifact, - TestMixinStakeStorage: TestMixinStakeStorage as ContractArtifact, - TestMixinStakingPool: TestMixinStakingPool as ContractArtifact, - TestMixinStakingPoolRewards: TestMixinStakingPoolRewards as ContractArtifact, - TestProtocolFees: TestProtocolFees as ContractArtifact, - TestProxyDestination: TestProxyDestination as ContractArtifact, - TestStaking: TestStaking as ContractArtifact, - TestStakingNoWETH: TestStakingNoWETH as ContractArtifact, - TestStakingProxy: TestStakingProxy as ContractArtifact, - TestStakingProxyUnit: TestStakingProxyUnit as ContractArtifact, - TestStorageLayoutAndConstants: TestStorageLayoutAndConstants as ContractArtifact, -}; diff --git a/contracts/staking/test/codesize_test.ts b/contracts/staking/test/codesize_test.ts deleted file mode 100644 index 21557401ea..0000000000 --- a/contracts/staking/test/codesize_test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { constants, expect, getCodesizeFromArtifact } from '@0x/contracts-test-utils'; - -import { artifacts } from './artifacts'; - -describe('Contract Size Checks', () => { - describe('Staking', () => { - it('should have a codesize less than the maximum', async () => { - const actualSize = getCodesizeFromArtifact(artifacts.Staking); - expect(actualSize).to.be.lt(constants.MAX_CODE_SIZE); - }); - }); - describe('StakingProxy', () => { - it('should have a codesize less than the maximum', async () => { - const actualSize = getCodesizeFromArtifact(artifacts.StakingProxy); - expect(actualSize).to.be.lt(constants.MAX_CODE_SIZE); - }); - }); -}); diff --git a/contracts/staking/test/cumulative_reward_tracking_test.ts b/contracts/staking/test/cumulative_reward_tracking_test.ts deleted file mode 100644 index 3930dee05b..0000000000 --- a/contracts/staking/test/cumulative_reward_tracking_test.ts +++ /dev/null @@ -1,429 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { blockchainTests, describe } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper'; -import { CumulativeRewardTrackingSimulation, TestAction } from './utils/cumulative_reward_tracking_simulation'; - -// tslint:disable:no-unnecessary-type-assertion -// tslint:disable:max-file-line-count -blockchainTests.resets('Cumulative Reward Tracking', env => { - // tokens & addresses - let accounts: string[]; - let owner: string; - // wrappers - let stakingApiWrapper: StakingApiWrapper; - let simulation: CumulativeRewardTrackingSimulation; - // let testWrapper: TestRewardBalancesContract; - let erc20Wrapper: ERC20Wrapper; - - // tests - before(async () => { - // create accounts - accounts = await env.getAccountAddressesAsync(); - owner = accounts[0]; - const actors = accounts.slice(1); - // set up ERC20Wrapper - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - // deploy staking contracts - stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper); - simulation = new CumulativeRewardTrackingSimulation(stakingApiWrapper, actors); - await simulation.deployAndConfigureTestContractsAsync(env); - }); - - describe('Tracking Cumulative Rewards (CR)', () => { - it('pool created at epoch 1', async () => { - await simulation.runTestAsync([], [TestAction.CreatePool], []); - }); - it('pool created in epoch >1', async () => { - await simulation.runTestAsync([TestAction.Finalize], [TestAction.CreatePool], []); - }); - it('delegating in the same epoch pool is created', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - ], - [ - // Updates CR for epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 1 }], - ); - }); - it('re-delegating in the same epoch', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - ], - [ - // Updates CR for epoch 1 - TestAction.Delegate, - // Updates CR for epoch 1 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 1 }], - ); - }); - it('delegating in new epoch', async () => { - // since there was no delegation in epoch 1 there is no longer a dependency on the CR for epoch 1 - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Moves to epoch 2 - TestAction.Finalize, - ], - [ - // Creates a CR for epoch 2 - // Sets MRCR to epoch 2 - // Unsets the CR for epoch 1 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 2 }], - ); - }); - it('re-delegating in a new epoch', async () => { - await simulation.runTestAsync( - [ - // Creates CR in epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 2 - // Sets MRCR to epoch 2 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 2 }], - ); - }); - it('delegating in epoch 2 then again in epoch 3', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Moves to epoch 2 - TestAction.Finalize, - // Creates CR for epoch 2 - // Sets MRCR to epoch 2 - TestAction.Delegate, - // Move to epoch 3 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 3 - // Sets MRCR to epoch 3 - // Creates CR for epoch 4 - // Clears CR for epoch 2 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 3 }], - ); - }); - it('delegate in epoch 2 then undelegate in epoch 3', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Moves to epoch 2 - TestAction.Finalize, - // Creates CR for epoch 2 - // Sets MRCR to epoch 1 - // Clears CR for epoch 1 - // Creates CR for epoch 3 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - ], - [ - // Update CR for epoch 3 - // Set MRCR to epoch 3 - // Clear CR for epoch 2 - TestAction.Undelegate, - ], - [{ event: 'SetCumulativeReward', epoch: 3 }], - ); - }); - it('delegate in epoch 1 and epoch 2, then undelegate half in epoch 3', async () => { - await simulation.runTestAsync( - [ - // Create CR for epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Sets MRCR to epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - // Updates CR for epoch 2 - // Sets MRCR to epoch 2 - // Creates CR for epoch 3 - // Clears CR for epoch 1 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 3 - // Sets MRCR to epoch 3 - // Creates CR for epoch 4 (because there will still be stake) - // Clears CR for epoch 2 - TestAction.Undelegate, - ], - [{ event: 'SetCumulativeReward', epoch: 3 }], - ); - }); - it('delegate in epoch 2 and 3 then again in 3', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Sets MRCR to epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - // Updates CR for epoch 2 - // Sets MRCR to epoch 2 - // Creates CR for epoch 3 - // Clears CR for epoch 1 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 3 - // Sets MRCR to epoch 3 - // Creates CR for epoch 4 - // Clears CR for epoch 2 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 3 }], - ); - }); - it('delegate in epoch 1, earn reward in epoch 2', async () => { - await simulation.runTestAsync( - [ - // Create CR for epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Sets MRCR to epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - // Credits pool with rewards - TestAction.PayProtocolFee, - ], - [ - // Moves to epoch 3 - // Creates CR for epoch 3 - // Sets MRCR to epoch 3 - TestAction.Finalize, - ], - [{ event: 'SetCumulativeReward', epoch: 3 }], - ); - }); - it('delegate in epoch 1, epoch 3, earn reward in epoch 4, then delegate', async () => { - await simulation.runTestAsync( - [ - // Create CR for epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Sets MRCR to epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - // Updates CR for epoch 2 - // Sets MRCR to epoch 2 - // Creates CR for epoch 3 - // Clears CR for epoch 1 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - // Credits pool with rewards - TestAction.PayProtocolFee, - // Moves to epoch 4 - // Creates CR for epoch 4 - // Sets MRCR to epoch 4 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 4 - // Creates CR for epoch 5 - // Clears CR for epoch 2 - // Clears CR for epoch 3 - TestAction.Delegate, - ], - [], - ); - }); - it('delegate in epoch 1 and 2, earn reward in epoch 4, then undelegate half', async () => { - await simulation.runTestAsync( - [ - // Create CR for epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Sets MRCR to epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - // Updates CR for epoch 2 - // Sets MRCR to epoch 2 - // Creates CR for epoch 3 - // Clears CR for epoch 1 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - // Credits pool with rewards - TestAction.PayProtocolFee, - // Moves to epoch 4 - // Creates CR for epoch 4 - // Sets MRCR to epoch 4 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 4 - // Creates CR for epoch 5 (because there is still stake remaming) - // Clears CR for epoch 2 - // Clears CR for epoch 3 - TestAction.Undelegate, - ], - [], - ); - }); - it('delegate in epoch 2, 3, earn rewards in epoch 4, skip to epoch 5, then delegate', async () => { - await simulation.runTestAsync( - [ - // Create CR for epoch 1 - TestAction.CreatePool, - // Updates CR for epoch 1 - // Sets MRCR to epoch 1 - // Creates CR for epoch 2 - TestAction.Delegate, - // Moves to epoch 2 - TestAction.Finalize, - // Updates CR for epoch 2 - // Sets MRCR to epoch 2 - // Creates CR for epoch 3 - // Clears CR for epoch 1 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - // Credits pool with rewards - TestAction.PayProtocolFee, - // Moves to epoch 4 - // Creates CR for epoch 4 - // Sets MRCR to epoch 4 - TestAction.Finalize, - // Moves to epoch 5 - TestAction.Finalize, - ], - [ - // Creates CR for epoch 5 - // Sets MRCR to epoch 5 - // Clears CR for epoch 4 - // Creates CR for epoch 6 - // Clears CR for epoch 2 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 5 }], - ); - }); - it('earn reward in epoch 2 with no stake, then delegate', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Credit pool with rewards - TestAction.PayProtocolFee, - // Moves to epoch 2 - // That's it, because there's no active pools. - TestAction.Finalize, - ], - [ - // Updates CR to epoch 2 - // Sets MRCR to epoch 2 - // Clears CR for epoch 1 - // Creates CR for epoch 3 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 2 }], - ); - }); - it('delegate in epoch 2, 4, then delegate in epoch 5', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Moves to epoch 2 - TestAction.Finalize, - // Creates CR for epoch 2 - // Sets MRCR to epoch 1 - // Clears CR for epoch 1 - // Creates CR for epoch 3 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - // Moves to epoch 4 - TestAction.Finalize, - // Creates CR for epoch 4 - // Sets MRCR to epoch 4 - // Clears CR for epoch 2 - // Creates CR for epoch 5 - // Clears CR for epoch 3 - TestAction.Delegate, - // Moves to epoch 5 - TestAction.Finalize, - ], - [ - // Updates CR for epoch 5 - // Sets MRCR to epoch 5 - // Clears CR for epoch 4 - // Creates CR for epoch 6 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 5 }], - ); - }); - it('delegate in epoch 2, then epoch 4', async () => { - await simulation.runTestAsync( - [ - // Creates CR for epoch 1 - TestAction.CreatePool, - // Moves to epoch 2 - TestAction.Finalize, - // Creates CR for epoch 2 - // Sets MRCR to epoch 1 - // Clears CR for epoch 1 - // Creates CR for epoch 3 - TestAction.Delegate, - // Moves to epoch 3 - TestAction.Finalize, - // Moves to epoch 4 - TestAction.Finalize, - ], - [ - // Creates CR for epoch 4 - // Sets MRCR to epoch 4 - // Clears CR for epoch 2 - // Creates CR for epoch 5 - // Clears CR for epoch 3 - TestAction.Delegate, - ], - [{ event: 'SetCumulativeReward', epoch: 4 }], - ); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/epoch_test.ts b/contracts/staking/test/epoch_test.ts deleted file mode 100644 index 36515cb166..0000000000 --- a/contracts/staking/test/epoch_test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { blockchainTests, expect } from '@0x/contracts-test-utils'; -import * as _ from 'lodash'; - -import { constants as stakingConstants } from '../src/constants'; - -import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests('Epochs', env => { - // tokens & addresses - let accounts: string[]; - let owner: string; - // wrappers - let stakingApiWrapper: StakingApiWrapper; - let erc20Wrapper: ERC20Wrapper; - // tests - before(async () => { - // create accounts - accounts = await env.getAccountAddressesAsync(); - owner = accounts[0]; - // set up ERC20Wrapper - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - // deploy staking contracts - stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper); - }); - describe('Epochs & TimeLocks', () => { - it('basic epochs & timeLock periods', async () => { - ///// 1/3 Validate Assumptions ///// - expect((await stakingApiWrapper.utils.getParamsAsync()).epochDurationInSeconds).to.be.bignumber.equal( - stakingConstants.DEFAULT_PARAMS.epochDurationInSeconds, - ); - ///// 2/3 Validate Initial Epoch & TimeLock Period ///// - { - // epoch - const currentEpoch = await stakingApiWrapper.stakingContract.currentEpoch().callAsync(); - expect(currentEpoch).to.be.bignumber.equal(stakingConstants.INITIAL_EPOCH); - } - ///// 3/3 Increment Epoch (TimeLock Should Not Increment) ///// - await stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync(); - { - // epoch - const currentEpoch = await stakingApiWrapper.stakingContract.currentEpoch().callAsync(); - expect(currentEpoch).to.be.bignumber.equal(stakingConstants.INITIAL_EPOCH.plus(1)); - } - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/global_hooks.ts b/contracts/staking/test/global_hooks.ts deleted file mode 100644 index 2ca47d433b..0000000000 --- a/contracts/staking/test/global_hooks.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { env, EnvVars } from '@0x/dev-utils'; - -import { coverage, profiler, provider } from '@0x/contracts-test-utils'; -import { providerUtils } from '@0x/utils'; - -before('start web3 provider', () => { - providerUtils.startProviderEngine(provider); -}); -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(); - } - provider.stop(); -}); diff --git a/contracts/staking/test/layout_and_constant_regression_test.ts b/contracts/staking/test/layout_and_constant_regression_test.ts deleted file mode 100644 index 4a74d5eacf..0000000000 --- a/contracts/staking/test/layout_and_constant_regression_test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; - -import { artifacts } from './artifacts'; -import { TestStorageLayoutAndConstantsContract } from './wrappers'; - -blockchainTests('Storage Layout and Deployment Constants Regression Tests', env => { - it('Should successfully deploy the staking contract after running the layout and regression test', async () => { - await TestStorageLayoutAndConstantsContract.deployFrom0xArtifactAsync( - artifacts.TestStorageLayoutAndConstants, - env.provider, - env.txDefaults, - artifacts, - ); - }); -}); diff --git a/contracts/staking/test/migration_test.ts b/contracts/staking/test/migration_test.ts deleted file mode 100644 index 6c6b963e46..0000000000 --- a/contracts/staking/test/migration_test.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { AuthorizableRevertErrors } from '@0x/contracts-utils'; -import { BigNumber, StakingRevertErrors, StringRevertError } from '@0x/utils'; - -import { constants as stakingConstants } from '../src/constants'; - -import { artifacts } from './artifacts'; -import { - StakingContract, - StakingProxyContract, - TestAssertStorageParamsContract, - TestInitTargetContract, - TestStakingProxyContract, - TestStakingProxyStakingContractAttachedToProxyEventArgs, -} from './wrappers'; - -blockchainTests('Migration tests', env => { - let authorizedAddress: string; - let notAuthorizedAddress: string; - - let stakingContract: StakingContract; - - before(async () => { - [authorizedAddress, notAuthorizedAddress] = await env.getAccountAddressesAsync(); - stakingContract = await StakingContract.deployFrom0xArtifactAsync( - artifacts.TestStakingNoWETH, - env.provider, - env.txDefaults, - artifacts, - ); - await stakingContract.addAuthorizedAddress(authorizedAddress).awaitTransactionSuccessAsync(); - }); - - describe('StakingProxy', () => { - const INIT_REVERT_ERROR = new StringRevertError('FORCED_INIT_REVERT'); - const STORAGE_PARAMS_REVERT_ERROR = new StringRevertError('FORCED_STORAGE_PARAMS_REVERT'); - let initTargetContract: TestInitTargetContract; - let revertAddress: string; - - async function deployStakingProxyAsync(stakingContractAddress?: string): Promise { - const proxyContract = await TestStakingProxyContract.deployFrom0xArtifactAsync( - artifacts.TestStakingProxy, - env.provider, - env.txDefaults, - artifacts, - stakingContractAddress || constants.NULL_ADDRESS, - ); - await proxyContract.addAuthorizedAddress(authorizedAddress).awaitTransactionSuccessAsync(); - return proxyContract; - } - - before(async () => { - [authorizedAddress, notAuthorizedAddress] = await env.getAccountAddressesAsync(); - initTargetContract = await TestInitTargetContract.deployFrom0xArtifactAsync( - artifacts.TestInitTarget, - env.provider, - env.txDefaults, - artifacts, - ); - revertAddress = await initTargetContract.SHOULD_REVERT_ADDRESS().callAsync(); - }); - - async function enableInitRevertsAsync(): Promise { - // Deposit some ether into `revertAddress` to signal `initTargetContract` - // to fail. - await env.web3Wrapper.awaitTransactionMinedAsync( - await env.web3Wrapper.sendTransactionAsync({ - ...env.txDefaults, - from: authorizedAddress, - to: revertAddress, - data: constants.NULL_BYTES, - value: new BigNumber(1), - }), - ); - } - - async function assertInitStateAsync(proxyContract: TestStakingProxyContract): Promise { - const [senderAddress, thisAddress] = await initTargetContract.getInitState().callAsync({ - to: proxyContract.address, - }); - expect(senderAddress).to.eq(authorizedAddress); - expect(thisAddress).to.eq(proxyContract.address); - const attachedAddress = await proxyContract.stakingContract().callAsync(); - expect(attachedAddress).to.eq(initTargetContract.address); - } - - blockchainTests.resets('StakingProxy constructor', async () => { - it('calls init() and attaches the contract', async () => { - const proxyContract = await deployStakingProxyAsync(initTargetContract.address); - await assertInitStateAsync(proxyContract); - }); - - it('reverts if init() reverts', async () => { - await enableInitRevertsAsync(); - const tx = deployStakingProxyAsync(initTargetContract.address); - return expect(tx).to.revertWith(INIT_REVERT_ERROR); - }); - - it('reverts if assertValidStorageParams() fails', async () => { - const tx = deployStakingProxyAsync(revertAddress); - return expect(tx).to.revertWith(STORAGE_PARAMS_REVERT_ERROR); - }); - - it('should set the correct initial params', async () => { - const stakingProxyContractAddress = ( - await StakingProxyContract.deployFrom0xArtifactAsync( - artifacts.StakingProxy, - env.provider, - env.txDefaults, - artifacts, - stakingContract.address, - ) - ).address; - - const stakingProxyContract = new StakingContract( - stakingProxyContractAddress, - env.provider, - env.txDefaults, - ); - const params = await stakingProxyContract.getParams().callAsync(); - expect(params[0]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.epochDurationInSeconds); - expect(params[1]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.rewardDelegatedStakeWeight); - expect(params[2]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.minimumPoolStake); - expect(params[3]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaNumerator); - expect(params[4]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaDenominator); - }); - }); - - blockchainTests.resets('attachStakingContract()', async () => { - let proxyContract: TestStakingProxyContract; - - before(async () => { - proxyContract = await deployStakingProxyAsync(); - }); - - it('throws if not called by an authorized address', async () => { - const tx = proxyContract - .attachStakingContract(initTargetContract.address) - .awaitTransactionSuccessAsync({ - from: notAuthorizedAddress, - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddress); - return expect(tx).to.revertWith(expectedError); - }); - - it('calls init() and attaches the contract', async () => { - await proxyContract.attachStakingContract(initTargetContract.address).awaitTransactionSuccessAsync(); - await assertInitStateAsync(proxyContract); - }); - - it('emits a `StakingContractAttachedToProxy` event', async () => { - const receipt = await proxyContract - .attachStakingContract(initTargetContract.address) - .awaitTransactionSuccessAsync(); - const logsArgs = filterLogsToArguments( - receipt.logs, - 'StakingContractAttachedToProxy', - ); - expect(logsArgs.length).to.eq(1); - for (const args of logsArgs) { - expect(args.newStakingContractAddress).to.eq(initTargetContract.address); - } - await assertInitStateAsync(proxyContract); - }); - - it('reverts if init() reverts', async () => { - await enableInitRevertsAsync(); - const tx = proxyContract - .attachStakingContract(initTargetContract.address) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(INIT_REVERT_ERROR); - }); - - it('reverts if assertValidStorageParams() fails', async () => { - const tx = proxyContract.attachStakingContract(revertAddress).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(STORAGE_PARAMS_REVERT_ERROR); - }); - }); - - blockchainTests.resets('upgrades', async () => { - it('modifies prior state', async () => { - const proxyContract = await deployStakingProxyAsync(initTargetContract.address); - await proxyContract.attachStakingContract(initTargetContract.address).awaitTransactionSuccessAsync(); - const initCounter = await initTargetContract.getInitCounter().callAsync({ to: proxyContract.address }); - expect(initCounter).to.bignumber.eq(2); - }); - }); - }); - - blockchainTests.resets('Staking.init()', async () => { - it('throws if not called by an authorized address', async () => { - const tx = stakingContract.init().awaitTransactionSuccessAsync({ - from: notAuthorizedAddress, - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddress); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if already intitialized', async () => { - await stakingContract.init().awaitTransactionSuccessAsync(); - const tx = stakingContract.init().awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InitializationError(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - blockchainTests.resets('assertValidStorageParams', async () => { - let proxyContract: TestAssertStorageParamsContract; - const fiveDays = new BigNumber(5 * 24 * 60 * 60); - const thirtyDays = new BigNumber(30 * 24 * 60 * 60); - before(async () => { - proxyContract = await TestAssertStorageParamsContract.deployFrom0xArtifactAsync( - artifacts.TestAssertStorageParams, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - it('succeeds if all params are valid', async () => { - const tx = proxyContract.setAndAssertParams(stakingConstants.DEFAULT_PARAMS).awaitTransactionSuccessAsync(); - expect(tx).to.be.fulfilled(''); - }); - - it('reverts if epoch duration is < 5 days', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - epochDurationInSeconds: fiveDays.minus(1), - }) - .awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidEpochDuration, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('reverts if epoch duration is > 30 days', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - epochDurationInSeconds: thirtyDays.plus(1), - }) - .awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidEpochDuration, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('succeeds if epoch duration is 5 days', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - epochDurationInSeconds: fiveDays, - }) - .awaitTransactionSuccessAsync(); - return expect(tx).to.be.fulfilled(''); - }); - it('succeeds if epoch duration is 30 days', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - epochDurationInSeconds: thirtyDays, - }) - .awaitTransactionSuccessAsync(); - return expect(tx).to.be.fulfilled(''); - }); - it('reverts if alpha denominator is 0', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - cobbDouglasAlphaDenominator: constants.ZERO_AMOUNT, - }) - .awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('reverts if alpha > 1', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - cobbDouglasAlphaNumerator: new BigNumber(101), - cobbDouglasAlphaDenominator: new BigNumber(100), - }) - .awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('succeeds if alpha == 1', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - cobbDouglasAlphaNumerator: new BigNumber(1), - cobbDouglasAlphaDenominator: new BigNumber(1), - }) - .awaitTransactionSuccessAsync(); - return expect(tx).to.be.fulfilled(''); - }); - it('succeeds if alpha == 0', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - cobbDouglasAlphaNumerator: constants.ZERO_AMOUNT, - cobbDouglasAlphaDenominator: new BigNumber(1), - }) - .awaitTransactionSuccessAsync(); - return expect(tx).to.be.fulfilled(''); - }); - it('reverts if delegation weight is > 100%', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - rewardDelegatedStakeWeight: new BigNumber(stakingConstants.PPM).plus(1), - }) - .awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidRewardDelegatedStakeWeight, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('succeeds if delegation weight is 100%', async () => { - const tx = proxyContract - .setAndAssertParams({ - ...stakingConstants.DEFAULT_PARAMS, - rewardDelegatedStakeWeight: new BigNumber(stakingConstants.PPM), - }) - .awaitTransactionSuccessAsync(); - return expect(tx).to.be.fulfilled(''); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/patch_mainnet_test.ts b/contracts/staking/test/patch_mainnet_test.ts deleted file mode 100644 index 4f4e31ae51..0000000000 --- a/contracts/staking/test/patch_mainnet_test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { BigNumber, logUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { artifacts } from './artifacts'; -import { StakingEvents, StakingPatchContract, StakingProxyContract, StakingProxyEvents } from './wrappers'; - -const abis = _.mapValues(artifacts, v => v.compilerOutput.abi); -const STAKING_PROXY = '0xa26e80e7dea86279c6d778d702cc413e6cffa777'; -const STAKING_OWNER = '0x7d3455421bbc5ed534a83c88fd80387dc8271392'; -const EXCHANGE_PROXY = '0xdef1c0ded9bec7f1a1670819833240f027b25eff'; -blockchainTests.configure({ - fork: { - unlockedAccounts: [STAKING_OWNER, EXCHANGE_PROXY], - }, -}); - -blockchainTests.fork('Staking patch mainnet fork tests', env => { - let stakingProxyContract: StakingProxyContract; - let patchedStakingPatchContract: StakingPatchContract; - - before(async () => { - stakingProxyContract = new StakingProxyContract(STAKING_PROXY, env.provider, undefined, abis); - patchedStakingPatchContract = await StakingPatchContract.deployFrom0xArtifactAsync( - artifacts.Staking, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - it('Staking proxy successfully attaches to patched logic', async () => { - const tx = await stakingProxyContract - .attachStakingContract(patchedStakingPatchContract.address) - .awaitTransactionSuccessAsync({ from: STAKING_OWNER, gasPrice: 0 }, { shouldValidate: false }); - expect(filterLogsToArguments(tx.logs, StakingProxyEvents.StakingContractAttachedToProxy)).to.deep.equal([ - { - newStakingPatchContractAddress: patchedStakingPatchContract.address, - }, - ]); - expect(filterLogsToArguments(tx.logs, StakingEvents.EpochEnded).length).to.equal(1); - expect(filterLogsToArguments(tx.logs, StakingEvents.EpochFinalized).length).to.equal(1); - logUtils.log(`${tx.gasUsed} gas used`); - }); - - it('Patched staking handles 0 gas protocol fees', async () => { - const staking = new StakingPatchContract(STAKING_PROXY, env.provider, undefined, abis); - const maker = '0x7b1886e49ab5433bb46f7258548092dc8cdca28b'; - const zeroFeeTx = await staking - .payProtocolFee(maker, constants.NULL_ADDRESS, constants.ZERO_AMOUNT) - .awaitTransactionSuccessAsync({ from: EXCHANGE_PROXY, gasPrice: 0 }, { shouldValidate: false }); - // StakingPoolEarnedRewardsInEpoch should _not_ be emitted for a zero protocol fee. - // tslint:disable-next-line:no-unused-expression - expect(filterLogsToArguments(zeroFeeTx.logs, StakingEvents.StakingPoolEarnedRewardsInEpoch)).to.be.empty; - - // Coincidentally there's some ETH in the ExchangeProxy - const nonZeroFeeTx = await staking - .payProtocolFee(maker, constants.NULL_ADDRESS, new BigNumber(1)) - .awaitTransactionSuccessAsync({ from: EXCHANGE_PROXY, gasPrice: 0, value: 1 }, { shouldValidate: false }); - // StakingPoolEarnedRewardsInEpoch _should_ be emitted for a non-zero protocol fee. - expect( - filterLogsToArguments(nonZeroFeeTx.logs, StakingEvents.StakingPoolEarnedRewardsInEpoch), - ).to.have.lengthOf(1); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/pools_test.ts b/contracts/staking/test/pools_test.ts deleted file mode 100644 index 9581fcec20..0000000000 --- a/contracts/staking/test/pools_test.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; -import { StakingRevertErrors } from '@0x/utils'; -import * as _ from 'lodash'; - -import { constants as stakingConstants } from '../src/constants'; - -import { MakerActor } from './actors/maker_actor'; -import { PoolOperatorActor } from './actors/pool_operator_actor'; -import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper'; - -// tslint:disable:no-unnecessary-type-assertion -// tslint:disable:max-file-line-count -blockchainTests('Staking Pool Management', env => { - // constants - const { PPM_100_PERCENT, PPM_DENOMINATOR } = constants; - // tokens & addresses - let accounts: string[]; - let owner: string; - let users: string[]; - // wrappers - let stakingApiWrapper: StakingApiWrapper; - let erc20Wrapper: ERC20Wrapper; - // tests - before(async () => { - // create accounts - accounts = await env.getAccountAddressesAsync(); - [owner, ...users] = accounts; - // set up ERC20Wrapper - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - // deploy staking contracts - stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper); - }); - blockchainTests.resets('Staking Pool Management', () => { - it('Should successfully create a pool', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - // check that the next pool id was incremented - const lastPoolId = await stakingApiWrapper.stakingContract.lastPoolId().callAsync(); - expect(lastPoolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - }); - it('Should successfully create several staking pools, as long as the operator is only a maker in one', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - // create pool - const poolId1 = await poolOperator.createStakingPoolAsync(operatorShare, true); - expect(poolId1).to.be.equal(stakingConstants.INITIAL_POOL_ID); - const poolId2 = await poolOperator.createStakingPoolAsync(operatorShare, false); - expect(poolId2).to.be.equal(stakingConstants.SECOND_POOL_ID); - }); - it('Should fail to create a pool with operator share > 100', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (101 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - - const revertError = new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - stakingConstants.INITIAL_POOL_ID, - operatorShare, - ); - // create pool - await poolOperator.createStakingPoolAsync(operatorShare, false, revertError); - }); - it('Should successfully create a pool and add owner as a maker', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - // check that the next pool id was incremented - const lastPoolId = await stakingApiWrapper.stakingContract.lastPoolId().callAsync(); - expect(lastPoolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - }); - it('Should throw if operatorShare is > PPM_DENOMINATOR', async () => { - // test parameters - const operatorAddress = users[0]; - // tslint:disable-next-line - const operatorShare = PPM_100_PERCENT + 1; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - // create pool - const tx = poolOperator.createStakingPoolAsync(operatorShare, true); - const expectedPoolId = stakingConstants.INITIAL_POOL_ID; - const expectedError = new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - expectedPoolId, - operatorShare, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('Should successfully add a maker to a pool', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - const makerAddress = users[1]; - const maker = new MakerActor(makerAddress, stakingApiWrapper); - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - // maker joins pool - await maker.joinStakingPoolAsMakerAsync(poolId); - }); - it('Maker should successfully remove themselves from a pool', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - const makerAddress = users[1]; - const maker = new MakerActor(makerAddress, stakingApiWrapper); - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - // maker joins pool - await maker.joinStakingPoolAsMakerAsync(poolId); - // maker removes themselves from pool - await maker.joinStakingPoolAsMakerAsync(stakingConstants.NIL_POOL_ID); - }); - it('Should successfully add/remove multiple makers to the same pool', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - const makerAddresses = users.slice(1, 4); - const makers = makerAddresses.map(makerAddress => new MakerActor(makerAddress, stakingApiWrapper)); - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - // add makers to pool - await Promise.all(makers.map(async maker => maker.joinStakingPoolAsMakerAsync(poolId))); - // remove makers to pool - await Promise.all( - makers.map(async maker => maker.joinStakingPoolAsMakerAsync(stakingConstants.NIL_POOL_ID)), - ); - }); - it('Operator should successfully decrease their share of rewards', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - - // decrease operator share - await poolOperator.decreaseStakingPoolOperatorShareAsync(poolId, operatorShare - 1); - }); - it('Should fail if operator tries to increase their share of rewards', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - - const increasedOperatorShare = operatorShare + 1; - const revertError = new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.CanOnlyDecreaseOperatorShare, - poolId, - increasedOperatorShare, - ); - // decrease operator share - await poolOperator.decreaseStakingPoolOperatorShareAsync(poolId, increasedOperatorShare, revertError); - }); - it('Should be successful if operator calls decreaseStakingPoolOperatorShare and newOperatorShare == oldOperatorShare', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - - // decrease operator share - await poolOperator.decreaseStakingPoolOperatorShareAsync(poolId, operatorShare); - }); - it('should fail to decrease operator share if not called by operator', async () => { - // test parameters - const operatorAddress = users[0]; - const operatorShare = (39 / 100) * PPM_DENOMINATOR; - const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper); - const makerAddress = users[1]; - const maker = new MakerActor(makerAddress, stakingApiWrapper); - // create pool - const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true); - expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID); - await maker.decreaseStakingPoolOperatorShareAsync( - poolId, - operatorShare - 1, - new StakingRevertErrors.OnlyCallableByPoolOperatorError(makerAddress, poolId), - ); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/rewards_test.ts b/contracts/staking/test/rewards_test.ts deleted file mode 100644 index e7fe02279c..0000000000 --- a/contracts/staking/test/rewards_test.ts +++ /dev/null @@ -1,700 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { blockchainTests, constants, describe, expect, shortZip, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { BigNumber, StakingRevertErrors } from '@0x/utils'; -import * as _ from 'lodash'; - -import { DelegatorsByPoolId, OperatorByPoolId, StakeInfo, StakeStatus } from '../src/types'; - -import { FinalizerActor } from './actors/finalizer_actor'; -import { PoolOperatorActor } from './actors/pool_operator_actor'; -import { StakerActor } from './actors/staker_actor'; -import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper'; - -// tslint:disable:no-unnecessary-type-assertion -// tslint:disable:max-file-line-count -blockchainTests.resets('Testing Rewards', env => { - // tokens & addresses - let accounts: string[]; - let owner: string; - let actors: string[]; - let exchangeAddress: string; - let takerAddress: string; - // wrappers - let stakingApiWrapper: StakingApiWrapper; - // let testWrapper: TestRewardBalancesContract; - let erc20Wrapper: ERC20Wrapper; - // test parameters - let stakers: StakerActor[]; - let poolOperatorStaker: StakerActor; - let poolId: string; - let poolOperator: PoolOperatorActor; - let finalizer: FinalizerActor; - // tests - before(async () => { - // create accounts - accounts = await env.getAccountAddressesAsync(); - owner = accounts[0]; - exchangeAddress = accounts[1]; - takerAddress = accounts[2]; - actors = accounts.slice(3); - // set up ERC20Wrapper - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - // deploy staking contracts - stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper); - // set up staking parameters - await stakingApiWrapper.utils.setParamsAsync({ - minimumPoolStake: new BigNumber(2), - cobbDouglasAlphaNumerator: new BigNumber(1), - cobbDouglasAlphaDenominator: new BigNumber(6), - }); - // setup stakers - stakers = actors.slice(0, 2).map(a => new StakerActor(a, stakingApiWrapper)); - // setup pools - poolOperator = new PoolOperatorActor(actors[2], stakingApiWrapper); - // Create a pool where all rewards go to members. - poolId = await poolOperator.createStakingPoolAsync(0, true); - // Stake something in the pool or else it won't get any rewards. - poolOperatorStaker = new StakerActor(poolOperator.getOwner(), stakingApiWrapper); - await poolOperatorStaker.stakeWithPoolAsync(poolId, new BigNumber(2)); - // set exchange address - await stakingApiWrapper.stakingContract.addExchangeAddress(exchangeAddress).awaitTransactionSuccessAsync(); - // associate operators for tracking in Finalizer - const operatorByPoolId: OperatorByPoolId = {}; - operatorByPoolId[poolId] = poolOperator.getOwner(); - // associate actors with pools for tracking in Finalizer - const stakersByPoolId: DelegatorsByPoolId = {}; - stakersByPoolId[poolId] = actors.slice(0, 3); - // create Finalizer actor - finalizer = new FinalizerActor(actors[3], stakingApiWrapper, [poolId], operatorByPoolId, stakersByPoolId); - // Skip to next epoch so operator stake is realized. - await stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync(); - }); - describe('Reward Simulation', () => { - interface EndBalances { - // staker 1 - stakerRewardBalance_1?: BigNumber; - stakerWethBalance_1?: BigNumber; - // staker 2 - stakerRewardBalance_2?: BigNumber; - stakerWethBalance_2?: BigNumber; - // operator - operatorWethBalance?: BigNumber; - // undivided balance in reward pool - poolRewardBalance?: BigNumber; - membersRewardBalance?: BigNumber; - } - const validateEndBalances = async (_expectedEndBalances: EndBalances): Promise => { - const expectedEndBalances = { - // staker 1 - stakerRewardBalance_1: - _expectedEndBalances.stakerRewardBalance_1 !== undefined - ? _expectedEndBalances.stakerRewardBalance_1 - : constants.ZERO_AMOUNT, - stakerWethBalance_1: - _expectedEndBalances.stakerWethBalance_1 !== undefined - ? _expectedEndBalances.stakerWethBalance_1 - : constants.ZERO_AMOUNT, - // staker 2 - stakerRewardBalance_2: - _expectedEndBalances.stakerRewardBalance_2 !== undefined - ? _expectedEndBalances.stakerRewardBalance_2 - : constants.ZERO_AMOUNT, - stakerWethBalance_2: - _expectedEndBalances.stakerWethBalance_2 !== undefined - ? _expectedEndBalances.stakerWethBalance_2 - : constants.ZERO_AMOUNT, - // operator - operatorWethBalance: - _expectedEndBalances.operatorWethBalance !== undefined - ? _expectedEndBalances.operatorWethBalance - : constants.ZERO_AMOUNT, - // undivided balance in reward pool - poolRewardBalance: - _expectedEndBalances.poolRewardBalance !== undefined - ? _expectedEndBalances.poolRewardBalance - : constants.ZERO_AMOUNT, - }; - const finalEndBalancesAsArray = await Promise.all([ - // staker 1 - stakingApiWrapper.stakingContract - .computeRewardBalanceOfDelegator(poolId, stakers[0].getOwner()) - .callAsync(), - stakingApiWrapper.wethContract.balanceOf(stakers[0].getOwner()).callAsync(), - // staker 2 - stakingApiWrapper.stakingContract - .computeRewardBalanceOfDelegator(poolId, stakers[1].getOwner()) - .callAsync(), - stakingApiWrapper.wethContract.balanceOf(stakers[1].getOwner()).callAsync(), - // operator - stakingApiWrapper.wethContract.balanceOf(poolOperator.getOwner()).callAsync(), - // undivided balance in reward pool - stakingApiWrapper.stakingContract.rewardsByPoolId(poolId).callAsync(), - ]); - expect(finalEndBalancesAsArray[0], 'stakerRewardBalance_1').to.be.bignumber.equal( - expectedEndBalances.stakerRewardBalance_1, - ); - expect(finalEndBalancesAsArray[1], 'stakerWethBalance_1').to.be.bignumber.equal( - expectedEndBalances.stakerWethBalance_1, - ); - expect(finalEndBalancesAsArray[2], 'stakerRewardBalance_2').to.be.bignumber.equal( - expectedEndBalances.stakerRewardBalance_2, - ); - expect(finalEndBalancesAsArray[3], 'stakerWethBalance_2').to.be.bignumber.equal( - expectedEndBalances.stakerWethBalance_2, - ); - expect(finalEndBalancesAsArray[4], 'operatorWethBalance').to.be.bignumber.equal( - expectedEndBalances.operatorWethBalance, - ); - expect(finalEndBalancesAsArray[5], 'poolRewardBalance').to.be.bignumber.equal( - expectedEndBalances.poolRewardBalance, - ); - }; - const payProtocolFeeAndFinalize = async (_fee?: BigNumber) => { - const fee = _fee !== undefined ? _fee : constants.ZERO_AMOUNT; - if (!fee.eq(constants.ZERO_AMOUNT)) { - await stakingApiWrapper.stakingContract - .payProtocolFee(poolOperator.getOwner(), takerAddress, fee) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: fee }); - } - await finalizer.finalizeAsync(); - }; - it('Reward balance should be zero if not delegated', async () => { - // sanity balances - all zero - await validateEndBalances({}); - }); - it('Reward balance should be zero if not delegated, when epoch is greater than 0', async () => { - await payProtocolFeeAndFinalize(); - // sanity balances - all zero - await validateEndBalances({}); - }); - it('Reward balance should be zero in same epoch as delegation', async () => { - const amount = toBaseUnitAmount(4); - await stakers[0].stakeAsync(amount); - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - amount, - ); - await payProtocolFeeAndFinalize(); - // sanit check final balances - all zero - await validateEndBalances({}); - }); - it('Operator should receive entire reward if no delegators in their pool', async () => { - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // sanity check final balances - all zero - await validateEndBalances({ - operatorWethBalance: reward, - }); - }); - it(`Operator should receive entire reward if no delegators in their pool - (staker joins this epoch but is active next epoch)`, async () => { - // delegate - const amount = toBaseUnitAmount(4); - await stakers[0].stakeWithPoolAsync(poolId, amount); - // finalize - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // sanity check final balances - await validateEndBalances({ - operatorWethBalance: reward, - }); - }); - it('Should give pool reward to delegator', async () => { - // delegate - const amount = toBaseUnitAmount(4); - await stakers[0].stakeWithPoolAsync(poolId, amount); - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // finalize - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: reward, - poolRewardBalance: reward, - membersRewardBalance: reward, - }); - }); - it('Should split pool reward between delegators', async () => { - const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)]; - const totalStakeAmount = toBaseUnitAmount(10); - // first staker delegates - await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]); - // second staker delegates - await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]); - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // finalize - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: reward.times(stakeAmounts[0]).dividedToIntegerBy(totalStakeAmount), - stakerRewardBalance_2: reward.times(stakeAmounts[1]).dividedToIntegerBy(totalStakeAmount), - poolRewardBalance: reward, - membersRewardBalance: reward, - }); - }); - it('Should split pool reward between delegators, when they join in different epochs', async () => { - // first staker delegates (epoch 1) - - const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)]; - const totalStakeAmount = toBaseUnitAmount(10); - await stakers[0].stakeAsync(stakeAmounts[0]); - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmounts[0], - ); - - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - - // second staker delegates (epoch 2) - await stakers[1].stakeAsync(stakeAmounts[1]); - await stakers[1].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmounts[1], - ); - - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // finalize - - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: reward.times(stakeAmounts[0]).dividedToIntegerBy(totalStakeAmount), - stakerRewardBalance_2: reward.times(stakeAmounts[1]).dividedToIntegerBy(totalStakeAmount), - poolRewardBalance: reward, - membersRewardBalance: reward, - }); - }); - it('Should give pool reward to delegators only for the epoch during which they delegated', async () => { - const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)]; - const totalStakeAmount = toBaseUnitAmount(10); - // first staker delegates (epoch 1) - await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // second staker delegates (epoch 2) - await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]); - // only the first staker will get this reward - const rewardForOnlyFirstDelegator = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(rewardForOnlyFirstDelegator); - // finalize - const rewardForBothDelegators = toBaseUnitAmount(20); - await payProtocolFeeAndFinalize(rewardForBothDelegators); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: rewardForOnlyFirstDelegator.plus( - rewardForBothDelegators.times(stakeAmounts[0]).dividedToIntegerBy(totalStakeAmount), - ), - stakerRewardBalance_2: rewardForBothDelegators - .times(stakeAmounts[1]) - .dividedToIntegerBy(totalStakeAmount), - poolRewardBalance: rewardForOnlyFirstDelegator.plus(rewardForBothDelegators), - membersRewardBalance: rewardForOnlyFirstDelegator.plus(rewardForBothDelegators), - }); - }); - it('Should split pool reward between delegators, over several consecutive epochs', async () => { - const rewardForOnlyFirstDelegator = toBaseUnitAmount(10); - const sharedRewards = [ - toBaseUnitAmount(20), - toBaseUnitAmount(16), - toBaseUnitAmount(24), - toBaseUnitAmount(5), - toBaseUnitAmount(0), - toBaseUnitAmount(17), - ]; - const totalSharedRewardsAsNumber = _.sumBy(sharedRewards, v => { - return v.toNumber(); - }); - const totalSharedRewards = new BigNumber(totalSharedRewardsAsNumber); - const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)]; - const totalStakeAmount = toBaseUnitAmount(10); - // first staker delegates (epoch 1) - await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // second staker delegates (epoch 2) - await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]); - // only the first staker will get this reward - await payProtocolFeeAndFinalize(rewardForOnlyFirstDelegator); - // earn a bunch of rewards - for (const reward of sharedRewards) { - await payProtocolFeeAndFinalize(reward); - } - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: rewardForOnlyFirstDelegator.plus( - totalSharedRewards.times(stakeAmounts[0]).dividedToIntegerBy(totalStakeAmount), - ), - stakerRewardBalance_2: totalSharedRewards.times(stakeAmounts[1]).dividedToIntegerBy(totalStakeAmount), - poolRewardBalance: rewardForOnlyFirstDelegator.plus(totalSharedRewards), - membersRewardBalance: rewardForOnlyFirstDelegator.plus(totalSharedRewards), - }); - }); - it('Should withdraw existing rewards when undelegating stake', async () => { - const stakeAmount = toBaseUnitAmount(4); - // first staker delegates (epoch 1) - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // earn reward - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // undelegate (withdraws delegator's rewards) - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolId), - new StakeInfo(StakeStatus.Undelegated), - stakeAmount, - ); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: constants.ZERO_AMOUNT, - stakerWethBalance_1: reward, - }); - }); - it('Should withdraw existing rewards correctly when delegating more stake', async () => { - const stakeAmount = toBaseUnitAmount(4); - // first staker delegates (epoch 1) - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // earn reward - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // add more stake - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: constants.ZERO_AMOUNT, - stakerWethBalance_1: reward, - }); - }); - it('Should continue earning rewards after adding more stake and progressing several epochs', async () => { - const rewardBeforeAddingMoreStake = toBaseUnitAmount(10); - const rewardsAfterAddingMoreStake = [ - toBaseUnitAmount(20), - toBaseUnitAmount(16), - toBaseUnitAmount(24), - toBaseUnitAmount(5), - toBaseUnitAmount(0), - toBaseUnitAmount(17), - ]; - const totalRewardsAfterAddingMoreStake = BigNumber.sum(...rewardsAfterAddingMoreStake); - const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)]; - const totalStake = BigNumber.sum(...stakeAmounts); - // first staker delegates (epoch 1) - await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // second staker delegates (epoch 2) - await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]); - // only the first staker will get this reward - await payProtocolFeeAndFinalize(rewardBeforeAddingMoreStake); - // earn a bunch of rewards - for (const reward of rewardsAfterAddingMoreStake) { - await payProtocolFeeAndFinalize(reward); - } - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: rewardBeforeAddingMoreStake.plus( - totalRewardsAfterAddingMoreStake - .times(stakeAmounts[0]) - .dividedBy(totalStake) - .integerValue(BigNumber.ROUND_DOWN), - ), - stakerRewardBalance_2: totalRewardsAfterAddingMoreStake - .times(stakeAmounts[1]) - .dividedBy(totalStake) - .integerValue(BigNumber.ROUND_DOWN), - poolRewardBalance: rewardBeforeAddingMoreStake.plus(totalRewardsAfterAddingMoreStake), - membersRewardBalance: rewardBeforeAddingMoreStake.plus(totalRewardsAfterAddingMoreStake), - }); - }); - it('Should stop collecting rewards after undelegating', async () => { - // first staker delegates (epoch 1) - const rewardForDelegator = toBaseUnitAmount(10); - const rewardNotForDelegator = toBaseUnitAmount(7); - const stakeAmount = toBaseUnitAmount(4); - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // earn reward - await payProtocolFeeAndFinalize(rewardForDelegator); - - // undelegate stake and finalize epoch - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolId), - new StakeInfo(StakeStatus.Undelegated), - stakeAmount, - ); - - await payProtocolFeeAndFinalize(); - - // this should not go do the delegator - await payProtocolFeeAndFinalize(rewardNotForDelegator); - - // sanity check final balances - await validateEndBalances({ - stakerWethBalance_1: rewardForDelegator, - operatorWethBalance: rewardNotForDelegator, - }); - }); - it('Should stop collecting rewards after undelegating, after several epochs', async () => { - // first staker delegates (epoch 1) - const rewardForDelegator = toBaseUnitAmount(10); - const rewardsNotForDelegator = [ - toBaseUnitAmount(20), - toBaseUnitAmount(16), - toBaseUnitAmount(24), - toBaseUnitAmount(5), - toBaseUnitAmount(0), - toBaseUnitAmount(17), - ]; - const totalRewardsNotForDelegator = BigNumber.sum(...rewardsNotForDelegator); - const stakeAmount = toBaseUnitAmount(4); - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // earn reward - await payProtocolFeeAndFinalize(rewardForDelegator); - // undelegate stake and finalize epoch - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolId), - new StakeInfo(StakeStatus.Undelegated), - stakeAmount, - ); - await payProtocolFeeAndFinalize(); - // this should not go do the delegator - for (const reward of rewardsNotForDelegator) { - await payProtocolFeeAndFinalize(reward); - } - // sanity check final balances - await validateEndBalances({ - stakerWethBalance_1: rewardForDelegator, - operatorWethBalance: totalRewardsNotForDelegator, - }); - }); - it('Should collect fees correctly when leaving and returning to a pool', async () => { - // first staker delegates (epoch 1) - const rewardsForDelegator = [toBaseUnitAmount(10), toBaseUnitAmount(15)]; - const rewardNotForDelegator = toBaseUnitAmount(7); - const stakeAmount = toBaseUnitAmount(4); - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // skip epoch, so first staker can start earning rewards - await payProtocolFeeAndFinalize(); - // earn reward - await payProtocolFeeAndFinalize(rewardsForDelegator[0]); - // undelegate stake and finalize epoch - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolId), - new StakeInfo(StakeStatus.Undelegated), - stakeAmount, - ); - await payProtocolFeeAndFinalize(); - // this should not go do the delegator - await payProtocolFeeAndFinalize(rewardNotForDelegator); - // delegate stake and go to next epoch - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmount, - ); - await payProtocolFeeAndFinalize(); - // this reward should go to delegator - await payProtocolFeeAndFinalize(rewardsForDelegator[1]); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: rewardsForDelegator[1], - stakerWethBalance_1: rewardsForDelegator[0], - operatorWethBalance: rewardNotForDelegator, - poolRewardBalance: rewardsForDelegator[1], - }); - }); - it('Should collect fees correctly when re-delegating after un-delegating', async () => { - // Note - there are two ranges over which payouts are computed (see _computeRewardBalanceOfDelegator). - // This triggers the first range (rewards for `delegatedStake.currentEpoch`), but not the second. - // first staker delegates (epoch 1) - const rewardForDelegator = toBaseUnitAmount(10); - const stakeAmount = toBaseUnitAmount(4); - await stakers[0].stakeAsync(stakeAmount); - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmount, - ); - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // undelegate stake and finalize epoch - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolId), - new StakeInfo(StakeStatus.Undelegated), - stakeAmount, - ); - // this should go to the delegator - await payProtocolFeeAndFinalize(rewardForDelegator); - // delegate stake ~ this will result in a payout where rewards are computed on - // the balance's `currentEpochBalance` field but not the `nextEpochBalance` field. - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmount, - ); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: constants.ZERO_AMOUNT, - stakerWethBalance_1: rewardForDelegator, - operatorWethBalance: constants.ZERO_AMOUNT, - poolRewardBalance: constants.ZERO_AMOUNT, - }); - }); - it('Should withdraw delegator rewards when calling `withdrawDelegatorRewards`', async () => { - // first staker delegates (epoch 1) - const rewardForDelegator = toBaseUnitAmount(10); - const stakeAmount = toBaseUnitAmount(4); - await stakers[0].stakeAsync(stakeAmount); - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmount, - ); - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // this should go to the delegator - await payProtocolFeeAndFinalize(rewardForDelegator); - await stakingApiWrapper.stakingContract.withdrawDelegatorRewards(poolId).awaitTransactionSuccessAsync({ - from: stakers[0].getOwner(), - }); - // sanity check final balances - await validateEndBalances({ - stakerRewardBalance_1: constants.ZERO_AMOUNT, - stakerWethBalance_1: rewardForDelegator, - operatorWethBalance: constants.ZERO_AMOUNT, - poolRewardBalance: constants.ZERO_AMOUNT, - }); - }); - it('should fail to withdraw delegator rewards if the pool has not been finalized for the previous epoch', async () => { - const rewardForDelegator = toBaseUnitAmount(10); - const stakeAmount = toBaseUnitAmount(4); - await stakers[0].stakeAsync(stakeAmount); - await stakers[0].moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolId), - stakeAmount, - ); - await stakingApiWrapper.stakingContract - .payProtocolFee(poolOperator.getOwner(), takerAddress, rewardForDelegator) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: rewardForDelegator }); - const currentEpoch = await stakingApiWrapper.stakingContract.currentEpoch().callAsync(); - await stakingApiWrapper.utils.fastForwardToNextEpochAsync(); - await stakingApiWrapper.utils.endEpochAsync(); - const expectedError = new StakingRevertErrors.PoolNotFinalizedError(poolId, currentEpoch); - expect( - stakingApiWrapper.stakingContract.withdrawDelegatorRewards(poolId).awaitTransactionSuccessAsync({ - from: stakers[0].getOwner(), - }), - ).to.revertWith(expectedError); - }); - it(`payout should be based on stake at the time of rewards`, async () => { - const staker = stakers[0]; - const stakeAmount = toBaseUnitAmount(5); - // stake and delegate - await stakers[0].stakeWithPoolAsync(poolId, stakeAmount); - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // undelegate some stake - const undelegateAmount = toBaseUnitAmount(2.5); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolId), - new StakeInfo(StakeStatus.Undelegated), - undelegateAmount, - ); - // finalize - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // withdraw rewards - await staker.withdrawDelegatorRewardsAsync(poolId); - await validateEndBalances({ - stakerRewardBalance_1: toBaseUnitAmount(0), - stakerWethBalance_1: reward, - }); - }); - it(`should split payout between two delegators when syncing rewards`, async () => { - const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)]; - const totalStakeAmount = BigNumber.sum(...stakeAmounts); - // stake and delegate both - const stakersAndStake = shortZip(stakers, stakeAmounts); - for (const [staker, stakeAmount] of stakersAndStake) { - await staker.stakeWithPoolAsync(poolId, stakeAmount); - } - // skip epoch, so stakers can start earning rewards - await payProtocolFeeAndFinalize(); - // finalize - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - // withdraw rewards - for (const [staker] of _.reverse(stakersAndStake)) { - await staker.withdrawDelegatorRewardsAsync(poolId); - } - const expectedStakerRewards = stakeAmounts.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount)); - await validateEndBalances({ - stakerRewardBalance_1: toBaseUnitAmount(0), - stakerRewardBalance_2: toBaseUnitAmount(0), - stakerWethBalance_1: expectedStakerRewards[0], - stakerWethBalance_2: expectedStakerRewards[1], - poolRewardBalance: new BigNumber(1), // Rounding error - membersRewardBalance: new BigNumber(1), // Rounding error - }); - }); - it(`delegator should not be credited payout twice by syncing rewards twice`, async () => { - const stakeAmounts = [toBaseUnitAmount(5), toBaseUnitAmount(10)]; - const totalStakeAmount = BigNumber.sum(...stakeAmounts); - // stake and delegate both - const stakersAndStake = shortZip(stakers, stakeAmounts); - for (const [staker, stakeAmount] of stakersAndStake) { - await staker.stakeWithPoolAsync(poolId, stakeAmount); - } - // skip epoch, so staker can start earning rewards - await payProtocolFeeAndFinalize(); - // finalize - const reward = toBaseUnitAmount(10); - await payProtocolFeeAndFinalize(reward); - const expectedStakerRewards = stakeAmounts.map(n => reward.times(n).dividedToIntegerBy(totalStakeAmount)); - await validateEndBalances({ - stakerRewardBalance_1: expectedStakerRewards[0], - stakerRewardBalance_2: expectedStakerRewards[1], - stakerWethBalance_1: toBaseUnitAmount(0), - stakerWethBalance_2: toBaseUnitAmount(0), - poolRewardBalance: reward, - membersRewardBalance: reward, - }); - // First staker will withdraw rewards. - const sneakyStaker = stakers[0]; - const sneakyStakerExpectedWethBalance = expectedStakerRewards[0]; - await sneakyStaker.withdrawDelegatorRewardsAsync(poolId); - // Should have been credited the correct amount of rewards. - let sneakyStakerWethBalance = await stakingApiWrapper.wethContract - .balanceOf(sneakyStaker.getOwner()) - .callAsync(); - expect(sneakyStakerWethBalance, 'WETH balance after first undelegate').to.bignumber.eq( - sneakyStakerExpectedWethBalance, - ); - // Now he'll try to do it again to see if he gets credited twice. - await sneakyStaker.withdrawDelegatorRewardsAsync(poolId); - /// The total amount credited should remain the same. - sneakyStakerWethBalance = await stakingApiWrapper.wethContract - .balanceOf(sneakyStaker.getOwner()) - .callAsync(); - expect(sneakyStakerWethBalance, 'WETH balance after second undelegate').to.bignumber.eq( - sneakyStakerExpectedWethBalance, - ); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/stake_test.ts b/contracts/staking/test/stake_test.ts deleted file mode 100644 index eaf3d8a911..0000000000 --- a/contracts/staking/test/stake_test.ts +++ /dev/null @@ -1,391 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { blockchainTests, describe, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { BigNumber, StakingRevertErrors } from '@0x/utils'; -import * as _ from 'lodash'; - -import { StakeInfo, StakeStatus } from '../src/types'; - -import { StakerActor } from './actors/staker_actor'; -import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper'; - -// tslint:disable:no-unnecessary-type-assertion -blockchainTests.resets('Stake Statuses', env => { - // constants - const ZERO = new BigNumber(0); - // tokens & addresses - let accounts: string[]; - let owner: string; - let actors: string[]; - // wrappers - let stakingApiWrapper: StakingApiWrapper; - let erc20Wrapper: ERC20Wrapper; - // stake actor - let staker: StakerActor; - let poolIds: string[]; - let unusedPoolId: string; - let poolOperator: string; - // tests - before(async () => { - // create accounts - accounts = await env.getAccountAddressesAsync(); - owner = accounts[0]; - actors = accounts.slice(2, 5); - // set up ERC20Wrapper - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - // deploy staking contracts - stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper); - - // setup new staker - staker = new StakerActor(actors[0], stakingApiWrapper); - // setup pools - poolOperator = actors[1]; - poolIds = await Promise.all([ - await stakingApiWrapper.utils.createStakingPoolAsync(poolOperator, 4, false), - await stakingApiWrapper.utils.createStakingPoolAsync(poolOperator, 5, false), - ]); - const lastPoolId = await stakingApiWrapper.stakingContract.lastPoolId().callAsync(); - unusedPoolId = `0x${new BigNumber(lastPoolId) - .plus(1) - .toString(16) - .padStart(64, '0')}`; - }); - describe('Stake', () => { - it('should successfully stake zero ZRX', async () => { - const amount = toBaseUnitAmount(0); - await staker.stakeAsync(amount); - }); - it('should successfully stake non-zero ZRX', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - }); - it('should retain stake balance across 1 epoch', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.goToNextEpochAsync(); - }); - it('should retain stake balance across 2 epochs', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.goToNextEpochAsync(); - await staker.goToNextEpochAsync(); - }); - }); - describe('Move Stake', () => { - it("should be able to rebalance next epoch's stake", async () => { - // epoch 2 - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - // still epoch 2 ~ should be able to move stake again - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Undelegated), - amount, - ); - }); - it("should be able to reassign next epoch's stake", async () => { - // epoch 2 - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - // still epoch 2 ~ should be able to move stake again - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Delegated, poolIds[1]), - amount, - ); - }); - it('should fail to move the same stake more than once', async () => { - // epoch 2 - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - // stake is now undelegated, should not be able to move it out of active status again - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[1]), - amount, - new StakingRevertErrors.InsufficientBalanceError(amount, ZERO), - ); - }); - }); - describe('Stake and Move', () => { - it("should be able to rebalance next epoch's stake", async () => { - // epoch 2 - const amount = toBaseUnitAmount(10); - await staker.stakeAndMoveAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - // still epoch 2 ~ should be able to move stake again - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Undelegated), - amount, - ); - }); - it('should fail to move the same stake more than once', async () => { - // epoch 2 - const amount = toBaseUnitAmount(10); - await staker.stakeAndMoveAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - // stake is now undelegated, should not be able to move it out of active status again - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[1]), - amount, - new StakingRevertErrors.InsufficientBalanceError(amount, ZERO), - ); - }); - }); - describe('Move Zero Stake', () => { - it('undelegated -> undelegated', async () => { - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Undelegated), - ZERO, - ); - }); - it('undelegated -> delegated', async () => { - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - ZERO, - ); - }); - it('delegated -> undelegated', async () => { - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Undelegated), - ZERO, - ); - }); - it('delegated -> delegated (same pool)', async () => { - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - ZERO, - ); - }); - it('delegated -> delegated (other pool)', async () => { - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Delegated, poolIds[1]), - ZERO, - ); - }); - }); - describe('Move Non-Zero Stake', () => { - const testMovePartialStake = async (from: StakeInfo, to: StakeInfo) => { - // setup - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - if (from.status !== StakeStatus.Undelegated) { - await staker.moveStakeAsync(new StakeInfo(StakeStatus.Undelegated), from, amount); - } - // run test, checking balances in epochs [n .. n + 2] - // in epoch `n` - `next` is set - // in epoch `n+1` - `current` is set - await staker.moveStakeAsync(from, to, amount.div(2)); - await staker.goToNextEpochAsync(); - }; - it('undelegated -> undelegated', async () => { - await testMovePartialStake(new StakeInfo(StakeStatus.Undelegated), new StakeInfo(StakeStatus.Undelegated)); - }); - it('undelegated -> delegated', async () => { - await testMovePartialStake( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - ); - }); - it('delegated -> undelegated', async () => { - await testMovePartialStake( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Undelegated), - ); - }); - it('delegated -> delegated (same pool)', async () => { - await testMovePartialStake( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - ); - }); - it('delegated -> delegated (other pool)', async () => { - await testMovePartialStake( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Delegated, poolIds[1]), - ); - }); - it('undelegated -> delegated (non-existent pool)', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, unusedPoolId), - amount, - new StakingRevertErrors.PoolExistenceError(unusedPoolId, false), - ); - }); - it('delegated -> delegated (non-existent pool)', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Delegated, unusedPoolId), - amount, - new StakingRevertErrors.PoolExistenceError(unusedPoolId, false), - ); - }); - }); - describe('Unstake', () => { - it('should successfully unstake zero ZRX', async () => { - const amount = toBaseUnitAmount(0); - await staker.unstakeAsync(amount); - }); - it('should successfully unstake after becoming undelegated', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Undelegated), - amount, - ); - await staker.goToNextEpochAsync(); // stake is now undelegated - await staker.unstakeAsync(amount); - }); - it('should fail to unstake in the same epoch as stake was undelegated', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - await staker.goToNextEpochAsync(); // stake is now delegated - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - new StakeInfo(StakeStatus.Undelegated), - amount, - ); - await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO)); - }); - it('should fail to unstake in same epoch that undelegated stake has been delegated', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO)); - }); - it('should fail to unstake one epoch after undelegated stake has been delegated', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - await staker.goToNextEpochAsync(); // stake is now undelegated - await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO)); - }); - it('should fail to unstake >1 epoch after undelegated stake has been delegated', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.moveStakeAsync( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, poolIds[0]), - amount, - ); - await staker.goToNextEpochAsync(); // stake is now undelegated - await staker.goToNextEpochAsync(); // stake is now withdrawable - await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO)); - }); - it('should successfuly unstake freshly deposited stake', async () => { - const amount = toBaseUnitAmount(10); - await staker.stakeAsync(amount); - await staker.unstakeAsync(amount); - }); - }); - describe('Simulations', () => { - // it('Simulation from Staking Spec', async () => { - // // Epoch 1: Stake some ZRX - // await staker.stakeAsync(toBaseUnitAmount(4)); - // // Later in Epoch 1: User delegates and deactivates some stake - // await staker.moveStakeAsync( - // new StakeInfo(StakeStatus.Active), - // new StakeInfo(StakeStatus.Undelegated), - // toBaseUnitAmount(1), - // ); - // await staker.moveStakeAsync( - // new StakeInfo(StakeStatus.Active), - // new StakeInfo(StakeStatus.Delegated, poolIds[0]), - // toBaseUnitAmount(2), - // ); - // // Epoch 2: Status updates (no user intervention required) - // await staker.goToNextEpochAsync(); - // // Epoch 3: Stake that has been undelegated for an epoch can be withdrawn (no user intervention required) - // await staker.goToNextEpochAsync(); - // // Later in Epoch 3: User reactivates half of their undelegated stake; this becomes Active next epoch - // await staker.moveStakeAsync( - // new StakeInfo(StakeStatus.Undelegated), - // new StakeInfo(StakeStatus.Active), - // toBaseUnitAmount(0.5), - // ); - // // Later in Epoch 3: User re-delegates half of their stake from Pool 1 to Pool 2 - // await staker.moveStakeAsync( - // new StakeInfo(StakeStatus.Delegated, poolIds[0]), - // new StakeInfo(StakeStatus.Delegated, poolIds[1]), - // toBaseUnitAmount(1), - // ); - // // Epoch 4: Status updates (no user intervention required) - // await staker.goToNextEpochAsync(); - // // Later in Epoch 4: User deactivates all active stake - // await staker.moveStakeAsync( - // new StakeInfo(StakeStatus.Active), - // new StakeInfo(StakeStatus.Undelegated), - // toBaseUnitAmount(1.5), - // ); - // // Later in Epoch 4: User withdraws all available undelegated stake - // await staker.unstakeAsync(toBaseUnitAmount(0.5)); - // // Epoch 5: Status updates (no user intervention required) - // await staker.goToNextEpochAsync(); - // // Later in Epoch 5: User reactivates a portion of their stake - // await staker.moveStakeAsync( - // new StakeInfo(StakeStatus.Undelegated), - // new StakeInfo(StakeStatus.Active), - // toBaseUnitAmount(1), - // ); - // // Epoch 6: Status updates (no user intervention required) - // await staker.goToNextEpochAsync(); - // }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/unit_tests/authorizable.ts b/contracts/staking/test/unit_tests/authorizable.ts deleted file mode 100644 index 3c99acec50..0000000000 --- a/contracts/staking/test/unit_tests/authorizable.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { - AuthorizableAuthorizedAddressAddedEventArgs, - AuthorizableAuthorizedAddressRemovedEventArgs, - OwnableRevertErrors, -} from '@0x/contracts-utils'; - -import { artifacts, TestStakingContract, TestStakingEvents } from '../../src'; - -blockchainTests.resets('Staking Authorization Tests', env => { - let testContract: TestStakingContract; - - let owner: string; - let nonOwner: string; - - before(async () => { - [owner, nonOwner] = await env.getAccountAddressesAsync(); - - testContract = await TestStakingContract.deployFrom0xArtifactAsync( - artifacts.TestStaking, - env.provider, - { - ...env.txDefaults, - from: owner, - }, - artifacts, - constants.NULL_ADDRESS, - constants.NULL_ADDRESS, - ); - }); - - it("shouldn't have any authorized addresses initially", async () => { - const authorities = await testContract.getAuthorizedAddresses().callAsync(); - expect(authorities).to.be.deep.eq([]); - }); - - describe('addAuthorizedAddress', () => { - it('should allow owner to add authorized address', async () => { - const receipt = await testContract - .addAuthorizedAddress(nonOwner) - .awaitTransactionSuccessAsync({ from: owner }); - - const args = filterLogsToArguments( - receipt.logs, - TestStakingEvents.AuthorizedAddressAdded, - ); - expect(args).to.be.deep.eq([{ target: nonOwner, caller: owner }]); - - const authorities = await testContract.getAuthorizedAddresses().callAsync(); - expect(authorities).to.be.deep.eq([nonOwner]); - }); - - it('should throw if non-owner adds authorized address', async () => { - const tx = testContract.addAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: nonOwner }); - const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('removeAuthorizedAddress', () => { - before(async () => { - await testContract.addAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner }); - const authorities = await testContract.getAuthorizedAddresses().callAsync(); - expect(authorities).to.be.deep.eq([owner]); - }); - - it('should allow owner to remove authorized address', async () => { - const receipt = await testContract - .removeAuthorizedAddress(owner) - .awaitTransactionSuccessAsync({ from: owner }); - - const args = filterLogsToArguments( - receipt.logs, - TestStakingEvents.AuthorizedAddressRemoved, - ); - expect(args).to.be.deep.eq([{ target: owner, caller: owner }]); - - const authorities = await testContract.getAuthorizedAddresses().callAsync(); - expect(authorities).to.be.deep.eq([]); - }); - - it('should throw if non-owner removes authorized address', async () => { - const tx = testContract.removeAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: nonOwner }); - const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/delegator_reward_test.ts b/contracts/staking/test/unit_tests/delegator_reward_test.ts deleted file mode 100644 index 0d459b051b..0000000000 --- a/contracts/staking/test/unit_tests/delegator_reward_test.ts +++ /dev/null @@ -1,789 +0,0 @@ -import { - assertIntegerRoughlyEquals as assertRoughlyEquals, - blockchainTests, - constants, - expect, - filterLogsToArguments, - getRandomInteger, - Numberish, - randomAddress, - toBaseUnitAmount, -} from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { LogEntry } from 'ethereum-types'; - -import { artifacts } from '../artifacts'; - -import { - TestDelegatorRewardsContract, - TestDelegatorRewardsEvents, - TestDelegatorRewardsTransferEventArgs, -} from '../wrappers'; - -blockchainTests.resets('Delegator rewards unit tests', env => { - let testContract: TestDelegatorRewardsContract; - - before(async () => { - testContract = await TestDelegatorRewardsContract.deployFrom0xArtifactAsync( - artifacts.TestDelegatorRewards, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - interface RewardPoolOpts { - poolId: string; - operator: string; - membersReward: Numberish; - operatorReward: Numberish; - membersStake: Numberish; - } - - async function rewardPoolAsync(opts?: Partial): Promise { - const _opts = { - poolId: hexUtils.random(), - operator: constants.NULL_ADDRESS, - membersReward: getRandomInteger(1, toBaseUnitAmount(100)), - operatorReward: getRandomInteger(1, toBaseUnitAmount(100)), - membersStake: getRandomInteger(1, toBaseUnitAmount(10)), - ...opts, - }; - // Generate a deterministic operator address based on the poolId. - _opts.operator = poolIdToOperator(_opts.poolId); - await testContract - .syncPoolRewards( - _opts.poolId, - _opts.operator, - new BigNumber(_opts.operatorReward), - new BigNumber(_opts.membersReward), - new BigNumber(_opts.membersStake), - ) - .awaitTransactionSuccessAsync(); - // Because the operator share is implicitly defined by the member and - // operator reward, and is stored as a uint32, there will be precision - // loss when the reward is combined then split again in the contracts. - // So we perform this transformation on the values and return them. - [_opts.operatorReward, _opts.membersReward] = toActualRewards(_opts.operatorReward, _opts.membersReward); - return _opts; - } - - interface SetUnfinalizedMembersRewardsOpts extends RewardPoolOpts {} - - async function setUnfinalizedPoolRewardAsync( - opts?: Partial, - ): Promise { - const _opts = { - poolId: hexUtils.random(), - operator: constants.NULL_ADDRESS, - membersReward: getRandomInteger(1, toBaseUnitAmount(100)), - operatorReward: getRandomInteger(1, toBaseUnitAmount(100)), - membersStake: getRandomInteger(1, toBaseUnitAmount(10)), - ...opts, - }; - // Generate a deterministic operator address based on the poolId. - _opts.operator = poolIdToOperator(_opts.poolId); - await testContract - .setUnfinalizedPoolReward( - _opts.poolId, - _opts.operator, - new BigNumber(_opts.operatorReward), - new BigNumber(_opts.membersReward), - new BigNumber(_opts.membersStake), - ) - .awaitTransactionSuccessAsync(); - // Because the operator share is implicitly defined by the member and - // operator reward, and is stored as a uint32, there will be precision - // loss when the reward is combined then split again in the contracts. - // So we perform this transformation on the values and return them. - [_opts.operatorReward, _opts.membersReward] = toActualRewards(_opts.operatorReward, _opts.membersReward); - return _opts; - } - - // Generates a deterministic operator address given a pool ID. - function poolIdToOperator(poolId: string): string { - return hexUtils.slice(hexUtils.hash(poolId), -20); - } - - // Converts pre-split rewards to the amounts the contracts will calculate - // after suffering precision loss from the low-precision `operatorShare`. - function toActualRewards(operatorReward: Numberish, membersReward: Numberish): [BigNumber, BigNumber] { - const totalReward = BigNumber.sum(operatorReward, membersReward); - const operatorSharePPM = new BigNumber(operatorReward) - .times(constants.PPM_100_PERCENT) - .dividedBy(totalReward) - .integerValue(BigNumber.ROUND_DOWN); - const _operatorReward = totalReward - .times(operatorSharePPM) - .dividedBy(constants.PPM_100_PERCENT) - .integerValue(BigNumber.ROUND_UP); - const _membersReward = totalReward.minus(_operatorReward); - return [_operatorReward, _membersReward]; - } - - type ResultWithTransfers = T & { - delegatorTransfers: BigNumber; - }; - - interface DelegateStakeOpts { - delegator: string; - stake: Numberish; - } - - async function delegateStakeNowAsync( - poolId: string, - opts?: Partial, - ): Promise> { - return delegateStakeAsync(poolId, opts, true); - } - - async function delegateStakeAsync( - poolId: string, - opts?: Partial, - now?: boolean, - ): Promise> { - const _opts = { - delegator: randomAddress(), - stake: getRandomInteger(1, toBaseUnitAmount(10)), - ...opts, - }; - const fn = now - ? testContract.delegateStakeNow.bind(testContract) - : testContract.delegateStake.bind(testContract); - const receipt = await fn(_opts.delegator, poolId, new BigNumber(_opts.stake)).awaitTransactionSuccessAsync(); - const delegatorTransfers = getTransfersFromLogs(receipt.logs, _opts.delegator); - return { - ..._opts, - delegatorTransfers, - }; - } - - async function undelegateStakeAsync( - poolId: string, - delegator: string, - stake?: Numberish, - ): Promise> { - const _stake = new BigNumber( - stake || - (await testContract.getStakeDelegatedToPoolByOwner(delegator, poolId).callAsync()).currentEpochBalance, - ); - const receipt = await testContract.undelegateStake(delegator, poolId, _stake).awaitTransactionSuccessAsync(); - const delegatorTransfers = getTransfersFromLogs(receipt.logs, delegator); - return { - stake: _stake, - delegatorTransfers, - }; - } - - function getTransfersFromLogs(logs: LogEntry[], delegator?: string): BigNumber { - let delegatorTransfers = constants.ZERO_AMOUNT; - const transferArgs = filterLogsToArguments( - logs, - TestDelegatorRewardsEvents.Transfer, - ); - for (const event of transferArgs) { - if (event._to === delegator) { - delegatorTransfers = delegatorTransfers.plus(event._value); - } - } - return delegatorTransfers; - } - - async function advanceEpochAsync(): Promise { - await testContract.advanceEpoch().awaitTransactionSuccessAsync(); - const epoch = await testContract.currentEpoch().callAsync(); - return epoch.toNumber(); - } - - async function getDelegatorRewardBalanceAsync(poolId: string, delegator: string): Promise { - return testContract.computeRewardBalanceOfDelegator(poolId, delegator).callAsync(); - } - - async function getOperatorRewardBalanceAsync(poolId: string): Promise { - return testContract.computeRewardBalanceOfOperator(poolId).callAsync(); - } - - async function touchStakeAsync(poolId: string, delegator: string): Promise> { - return undelegateStakeAsync(poolId, delegator, 0); - } - - async function finalizePoolAsync(poolId: string): Promise> { - const receipt = await testContract.finalizePool(poolId).awaitTransactionSuccessAsync(); - const delegatorTransfers = getTransfersFromLogs(receipt.logs, poolId); - return { - delegatorTransfers, - }; - } - - function computeDelegatorRewards( - totalRewards: Numberish, - delegatorStake: Numberish, - totalDelegatorStake: Numberish, - ): BigNumber { - return new BigNumber(totalRewards) - .times(delegatorStake) - .dividedBy(new BigNumber(totalDelegatorStake)) - .integerValue(BigNumber.ROUND_DOWN); - } - - describe('computeRewardBalanceOfOperator()', () => { - it('nothing in epoch 1', async () => { - const { poolId } = await rewardPoolAsync(); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - expect(operatorReward).to.bignumber.eq(0); - }); - - it('nothing in epoch 2', async () => { - await advanceEpochAsync(); - const { poolId } = await rewardPoolAsync(); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - expect(operatorReward).to.bignumber.eq(0); - }); - - it('nothing one epoch after rewards', async () => { - const { poolId } = await rewardPoolAsync(); - await advanceEpochAsync(); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - expect(operatorReward).to.bignumber.eq(0); - }); - - describe('with unfinalized rewards', () => { - it('something with unfinalized rewards', async () => { - const { poolId, operatorReward: expectedOperatorReward } = await setUnfinalizedPoolRewardAsync(); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - assertRoughlyEquals(operatorReward, expectedOperatorReward); - }); - - it('nothing for operator with 0% share', async () => { - // We define operator shares implicitly, so we set the operator - // reward to 0, which kind of makes this silly. - const { poolId } = await setUnfinalizedPoolRewardAsync({ operatorReward: 0 }); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - expect(operatorReward).to.bignumber.eq(0); - }); - - it('everything for operator with 100% share', async () => { - // We define operator shares implicitly, so we set the members - // reward to 0. - const { poolId, operatorReward: expectedOperatorReward } = await setUnfinalizedPoolRewardAsync({ - membersReward: 0, - }); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - assertRoughlyEquals(operatorReward, expectedOperatorReward); - }); - - it('nothing once rewards are finalized', async () => { - const { poolId } = await setUnfinalizedPoolRewardAsync(); - await finalizePoolAsync(poolId); - const operatorReward = await getOperatorRewardBalanceAsync(poolId); - expect(operatorReward).to.bignumber.eq(0); - }); - }); - }); - - describe('computeRewardBalanceOfDelegator()', () => { - it('nothing in epoch 1 for delegator with no stake', async () => { - const { poolId } = await rewardPoolAsync(); - const delegator = randomAddress(); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('nothing in epoch 2 for delegator with no stake', async () => { - await advanceEpochAsync(); // epoch 2 - const { poolId } = await rewardPoolAsync(); - const delegator = randomAddress(); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('nothing in epoch 1 for delegator staked in epoch 1', async () => { - const { poolId } = await rewardPoolAsync(); - // Assign active stake to pool in epoch 1, which is usuaslly not - // possible due to delegating delays. - const { delegator } = await delegateStakeNowAsync(poolId); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('nothing in epoch 2 for delegator delegating in epoch 2', async () => { - await advanceEpochAsync(); // epoch 2 - const { poolId } = await rewardPoolAsync(); - const { delegator } = await delegateStakeAsync(poolId); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('nothing in epoch 2 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - // rewards paid for stake in epoch 1. - await rewardPoolAsync({ poolId, membersStake: stake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('all rewards from epoch 3 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2. - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(reward); - }); - - it('all rewards from epoch 3 and 3 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: stake }); - await advanceEpochAsync(); // epoch 4 - const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: stake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - assertRoughlyEquals(delegatorReward, BigNumber.sum(reward1, reward2)); - }); - - it('partial rewards from epoch 3 and 3 for delegator partially delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake: delegatorStake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2. - const { membersReward: reward, membersStake: rewardStake } = await rewardPoolAsync({ - poolId, - membersStake: new BigNumber(delegatorStake).times(2), - }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedDelegatorRewards = computeDelegatorRewards(reward, delegatorStake, rewardStake); - assertRoughlyEquals(delegatorReward, expectedDelegatorRewards); - }); - - it('has correct reward immediately after undelegating', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2. - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake }); - const { delegatorTransfers: withdrawal } = await undelegateStakeAsync(poolId, delegator); - assertRoughlyEquals(withdrawal, reward); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('has correct reward immediately after undelegating and redelegating', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2. - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake }); - const { delegatorTransfers: withdrawal } = await undelegateStakeAsync(poolId, delegator); - assertRoughlyEquals(withdrawal, reward); - await delegateStakeAsync(poolId, { delegator, stake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(0); - }); - - it('has correct reward immediately after undelegating, redelegating, and rewarding fees', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2. - await rewardPoolAsync({ poolId, membersStake: stake }); - await undelegateStakeAsync(poolId, delegator); - await delegateStakeAsync(poolId, { delegator, stake }); - await advanceEpochAsync(); // epoch 4 - await advanceEpochAsync(); // epoch 5 - // rewards paid for stake in epoch 4. - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - assertRoughlyEquals(delegatorReward, reward); - }); - - it('ignores rewards paid in the same epoch the stake was first active in', async () => { - const poolId = hexUtils.random(); - // stake at 0 - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - // Pay rewards for epoch 1. - await advanceEpochAsync(); // epoch 3 - // Pay rewards for epoch 2. - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(delegatorReward).to.bignumber.eq(reward); - }); - - it('uses old stake for rewards paid in the same epoch extra stake is added', async () => { - const poolId = hexUtils.random(); - // stake at 0 - const { delegator, stake: stake1 } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake1 now active) - await advanceEpochAsync(); // epoch 3 - const stake2 = getRandomInteger(0, stake1); - const totalStake = BigNumber.sum(stake1, stake2); - // Make the total stake in rewards > totalStake so delegator never - // receives 100% of rewards. - const rewardStake = totalStake.times(2); - // Pay rewards for epoch 2. - const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - // add extra stake - const { delegatorTransfers: withdrawal } = await delegateStakeAsync(poolId, { delegator, stake: stake2 }); - await advanceEpochAsync(); // epoch 4 (stake2 now active) - // Pay rewards for epoch 3. - await advanceEpochAsync(); // epoch 5 - // Pay rewards for epoch 4. - const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedDelegatorReward = BigNumber.sum( - computeDelegatorRewards(reward1, stake1, rewardStake), - computeDelegatorRewards(reward2, totalStake, rewardStake), - ); - assertRoughlyEquals(BigNumber.sum(withdrawal, delegatorReward), expectedDelegatorReward); - }); - - it('uses old stake for rewards paid in the epoch right after extra stake is added', async () => { - const poolId = hexUtils.random(); - // stake at 0 - const { delegator, stake: stake1 } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake1 now active) - // add extra stake - const { stake: stake2 } = await delegateStakeAsync(poolId, { delegator }); - const totalStake = BigNumber.sum(stake1, stake2); - await advanceEpochAsync(); // epoch 3 (stake2 now active) - // Make the total stake in rewards > totalStake so delegator never - // receives 100% of rewards. - const rewardStake = totalStake.times(2); - // Pay rewards for epoch 2. - const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - await advanceEpochAsync(); // epoch 4 - // Pay rewards for epoch 3. - const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedDelegatorReward = BigNumber.sum( - computeDelegatorRewards(reward1, stake1, rewardStake), - computeDelegatorRewards(reward2, totalStake, rewardStake), - ); - assertRoughlyEquals(delegatorReward, expectedDelegatorReward); - }); - - it('computes correct rewards for 2 staggered delegators', async () => { - const poolId = hexUtils.random(); - const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake A now active) - const { delegator: delegatorB, stake: stakeB } = await delegateStakeAsync(poolId); - const totalStake = BigNumber.sum(stakeA, stakeB); - await advanceEpochAsync(); // epoch 3 (stake B now active) - // rewards paid for stake in epoch 2 (delegator A only) - const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: stakeA }); - await advanceEpochAsync(); // epoch 4 - // rewards paid for stake in epoch 3 (delegator A and B) - const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: totalStake }); - const delegatorRewardA = await getDelegatorRewardBalanceAsync(poolId, delegatorA); - const expectedDelegatorRewardA = BigNumber.sum( - computeDelegatorRewards(reward1, stakeA, stakeA), - computeDelegatorRewards(reward2, stakeA, totalStake), - ); - assertRoughlyEquals(delegatorRewardA, expectedDelegatorRewardA); - const delegatorRewardB = await getDelegatorRewardBalanceAsync(poolId, delegatorB); - const expectedDelegatorRewardB = BigNumber.sum(computeDelegatorRewards(reward2, stakeB, totalStake)); - assertRoughlyEquals(delegatorRewardB, expectedDelegatorRewardB); - }); - - it('computes correct rewards for 2 staggered delegators with a 2 epoch gap between payments', async () => { - const poolId = hexUtils.random(); - const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake A now active) - const { delegator: delegatorB, stake: stakeB } = await delegateStakeAsync(poolId); - const totalStake = BigNumber.sum(stakeA, stakeB); - await advanceEpochAsync(); // epoch 3 (stake B now active) - // rewards paid for stake in epoch 2 (delegator A only) - const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: stakeA }); - await advanceEpochAsync(); // epoch 4 - await advanceEpochAsync(); // epoch 5 - // rewards paid for stake in epoch 4 (delegator A and B) - const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: totalStake }); - const delegatorRewardA = await getDelegatorRewardBalanceAsync(poolId, delegatorA); - const expectedDelegatorRewardA = BigNumber.sum( - computeDelegatorRewards(reward1, stakeA, stakeA), - computeDelegatorRewards(reward2, stakeA, totalStake), - ); - assertRoughlyEquals(delegatorRewardA, expectedDelegatorRewardA); - const delegatorRewardB = await getDelegatorRewardBalanceAsync(poolId, delegatorB); - const expectedDelegatorRewardB = BigNumber.sum(computeDelegatorRewards(reward2, stakeB, totalStake)); - assertRoughlyEquals(delegatorRewardB, expectedDelegatorRewardB); - }); - - it('correct rewards for rewards with different stakes', async () => { - const poolId = hexUtils.random(); - const { delegator, stake: delegatorStake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2. - const { membersReward: reward1, membersStake: rewardStake1 } = await rewardPoolAsync({ - poolId, - membersStake: new BigNumber(delegatorStake).times(2), - }); - await advanceEpochAsync(); // epoch 4 - // rewards paid for stake in epoch 3 - const { membersReward: reward2, membersStake: rewardStake2 } = await rewardPoolAsync({ - poolId, - membersStake: new BigNumber(delegatorStake).times(3), - }); - const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedDelegatorReward = BigNumber.sum( - computeDelegatorRewards(reward1, delegatorStake, rewardStake1), - computeDelegatorRewards(reward2, delegatorStake, rewardStake2), - ); - assertRoughlyEquals(delegatorReward, expectedDelegatorReward); - }); - - describe('with unfinalized rewards', async () => { - it('nothing with only unfinalized rewards from epoch 2 for delegator with nothing delegated', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId, { stake: 0 }); - await advanceEpochAsync(); // epoch 2 - await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(reward).to.bignumber.eq(0); - }); - - it('nothing with only unfinalized rewards from epoch 2 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 - await setUnfinalizedPoolRewardAsync({ poolId, membersStake: stake }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(reward).to.bignumber.eq(0); - }); - - it('returns unfinalized rewards from epoch 3 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 - await advanceEpochAsync(); // epoch 3 - const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: stake, - }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - assertRoughlyEquals(reward, unfinalizedReward); - }); - - it('returns unfinalized rewards from epoch 4 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 - await advanceEpochAsync(); // epoch 3 - await advanceEpochAsync(); // epoch 4 - const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: stake, - }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - assertRoughlyEquals(reward, unfinalizedReward); - }); - - it('returns unfinalized rewards from epoch 4 + rewards from epoch 3 for delegator delegating in epoch 1', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 - await advanceEpochAsync(); // epoch 3 - const { membersReward: prevReward } = await rewardPoolAsync({ poolId, membersStake: stake }); - await advanceEpochAsync(); // epoch 4 - const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: stake, - }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedReward = BigNumber.sum(prevReward, unfinalizedReward); - assertRoughlyEquals(reward, expectedReward); - }); - - it('returns unfinalized rewards from epoch 5 + rewards from epoch 3 for delegator delegating in epoch 2', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 - await advanceEpochAsync(); // epoch 3 - const { membersReward: prevReward } = await rewardPoolAsync({ poolId, membersStake: stake }); - await advanceEpochAsync(); // epoch 4 - await advanceEpochAsync(); // epoch 5 - const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: stake, - }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedReward = BigNumber.sum(prevReward, unfinalizedReward); - assertRoughlyEquals(reward, expectedReward); - }); - - it('returns correct rewards if unfinalized stake is different from previous rewards', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 - await advanceEpochAsync(); // epoch 3 - const { membersReward: prevReward, membersStake: prevStake } = await rewardPoolAsync({ - poolId, - membersStake: new BigNumber(stake).times(2), - }); - await advanceEpochAsync(); // epoch 4 - await advanceEpochAsync(); // epoch 5 - const { - membersReward: unfinalizedReward, - membersStake: unfinalizedStake, - } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: new BigNumber(stake).times(5), - }); - const reward = await getDelegatorRewardBalanceAsync(poolId, delegator); - const expectedReward = BigNumber.sum( - computeDelegatorRewards(prevReward, stake, prevStake), - computeDelegatorRewards(unfinalizedReward, stake, unfinalizedStake), - ); - assertRoughlyEquals(reward, expectedReward); - }); - }); - }); - - describe('reward transfers', async () => { - it('transfers all rewards to delegator when touching stake', async () => { - const poolId = hexUtils.random(); - const { delegator, stake } = await delegateStakeAsync(poolId); - await advanceEpochAsync(); // epoch 2 (stake now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2 - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: stake }); - const { delegatorTransfers: withdrawal } = await touchStakeAsync(poolId, delegator); - const finalRewardBalance = await getDelegatorRewardBalanceAsync(poolId, delegator); - expect(withdrawal).to.bignumber.eq(reward); - expect(finalRewardBalance).to.bignumber.eq(0); - }); - - it('does not collect extra rewards from delegating more stake in the reward epoch', async () => { - const poolId = hexUtils.random(); - const stakeResults = []; - // stake - stakeResults.push(await delegateStakeAsync(poolId)); - const { delegator, stake } = stakeResults[0]; - const rewardStake = new BigNumber(stake).times(2); - await advanceEpochAsync(); // epoch 2 (stake now active) - // add more stake. - stakeResults.push(await delegateStakeAsync(poolId, { delegator, stake })); - await advanceEpochAsync(); // epoch 2 (2 * stake now active) - // reward for epoch 2, using 2 * stake so delegator should - // only be entitled to a fraction of the rewards. - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - await advanceEpochAsync(); // epoch 3 - // touch the stake one last time - stakeResults.push(await touchStakeAsync(poolId, delegator)); - // Should only see deposits for epoch 3. - const allDeposits = stakeResults.map(r => r.delegatorTransfers); - const expectedReward = computeDelegatorRewards(reward, stake, rewardStake); - assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedReward); - }); - - it('only collects rewards from staked epochs', async () => { - const poolId = hexUtils.random(); - const stakeResults = []; - // stake - stakeResults.push(await delegateStakeAsync(poolId)); - const { delegator, stake } = stakeResults[0]; - const rewardStake = new BigNumber(stake).times(2); - await advanceEpochAsync(); // epoch 2 (full stake now active) - // reward for epoch 1 - await rewardPoolAsync({ poolId, membersStake: rewardStake }); - // unstake some - const unstake = new BigNumber(stake).dividedToIntegerBy(2); - stakeResults.push(await undelegateStakeAsync(poolId, delegator, unstake)); - await advanceEpochAsync(); // epoch 3 (half active stake) - // reward for epoch 2 - const { membersReward: reward1 } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - // re-stake - stakeResults.push(await delegateStakeAsync(poolId, { delegator, stake: unstake })); - await advanceEpochAsync(); // epoch 4 (full stake now active) - // reward for epoch 3 - const { membersReward: reward2 } = await rewardPoolAsync({ poolId, membersStake: rewardStake }); - // touch the stake to claim rewards - stakeResults.push(await touchStakeAsync(poolId, delegator)); - const allDeposits = stakeResults.map(r => r.delegatorTransfers); - const expectedReward = BigNumber.sum( - computeDelegatorRewards(reward1, stake, rewardStake), - computeDelegatorRewards(reward2, new BigNumber(stake).minus(unstake), rewardStake), - ); - assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedReward); - }); - - it('two delegators can collect split rewards as soon as available', async () => { - const poolId = hexUtils.random(); - const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId); - const { delegator: delegatorB, stake: stakeB } = await delegateStakeAsync(poolId); - const totalStake = BigNumber.sum(stakeA, stakeB); - await advanceEpochAsync(); // epoch 2 (stakes now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2 - const { membersReward: reward } = await rewardPoolAsync({ poolId, membersStake: totalStake }); - // delegator A will finalize and collect rewards by touching stake. - const { delegatorTransfers: withdrawalA } = await touchStakeAsync(poolId, delegatorA); - assertRoughlyEquals(withdrawalA, computeDelegatorRewards(reward, stakeA, totalStake)); - // delegator B will collect rewards by touching stake - const { delegatorTransfers: withdrawalB } = await touchStakeAsync(poolId, delegatorB); - assertRoughlyEquals(withdrawalB, computeDelegatorRewards(reward, stakeB, totalStake)); - }); - - it('delegator B collects correct rewards after delegator A finalizes', async () => { - const poolId = hexUtils.random(); - const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId); - const { delegator: delegatorB, stake: stakeB } = await delegateStakeAsync(poolId); - const totalStake = BigNumber.sum(stakeA, stakeB); - await advanceEpochAsync(); // epoch 2 (stakes now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2 - const { membersReward: prevReward } = await rewardPoolAsync({ poolId, membersStake: totalStake }); - await advanceEpochAsync(); // epoch 4 - // unfinalized rewards for stake in epoch 3 - const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: totalStake, - }); - const totalRewards = BigNumber.sum(prevReward, unfinalizedReward); - await finalizePoolAsync(poolId); - const { delegatorTransfers: withdrawalA } = await touchStakeAsync(poolId, delegatorA); - assertRoughlyEquals(withdrawalA, computeDelegatorRewards(totalRewards, stakeA, totalStake)); - // delegator B will collect rewards by touching stake - const { delegatorTransfers: withdrawalB } = await touchStakeAsync(poolId, delegatorB); - assertRoughlyEquals(withdrawalB, computeDelegatorRewards(totalRewards, stakeB, totalStake)); - }); - - it('delegator A and B collect correct rewards after external finalization', async () => { - const poolId = hexUtils.random(); - const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId); - const { delegator: delegatorB, stake: stakeB } = await delegateStakeAsync(poolId); - const totalStake = BigNumber.sum(stakeA, stakeB); - await advanceEpochAsync(); // epoch 2 (stakes now active) - await advanceEpochAsync(); // epoch 3 - // rewards paid for stake in epoch 2 - const { membersReward: prevReward } = await rewardPoolAsync({ poolId, membersStake: totalStake }); - await advanceEpochAsync(); // epoch 4 - // unfinalized rewards for stake in epoch 3 - const { membersReward: unfinalizedReward } = await setUnfinalizedPoolRewardAsync({ - poolId, - membersStake: totalStake, - }); - const totalRewards = BigNumber.sum(prevReward, unfinalizedReward); - // finalize - await finalizePoolAsync(poolId); - // delegator A will collect rewards by touching stake. - const { delegatorTransfers: withdrawalA } = await touchStakeAsync(poolId, delegatorA); - assertRoughlyEquals(withdrawalA, computeDelegatorRewards(totalRewards, stakeA, totalStake)); - // delegator B will collect rewards by touching stake - const { delegatorTransfers: withdrawalB } = await touchStakeAsync(poolId, delegatorB); - assertRoughlyEquals(withdrawalB, computeDelegatorRewards(totalRewards, stakeB, totalStake)); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/exchange_test.ts b/contracts/staking/test/unit_tests/exchange_test.ts deleted file mode 100644 index 5e7631ecd3..0000000000 --- a/contracts/staking/test/unit_tests/exchange_test.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { blockchainTests, expect } from '@0x/contracts-test-utils'; -import { AuthorizableRevertErrors } from '@0x/contracts-utils'; -import { StakingRevertErrors } from '@0x/utils'; -import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { artifacts } from '../artifacts'; -import { - TestExchangeManagerContract, - TestExchangeManagerExchangeAddedEventArgs, - TestExchangeManagerExchangeRemovedEventArgs, -} from '../wrappers'; - -blockchainTests.resets('Exchange Unit Tests', env => { - // Addresses - let owner: string; - let nonExchange: string; - let exchange: string; - let nonAuthority: string; - let authority: string; - - // Exchange Manager - let exchangeManager: TestExchangeManagerContract; - - before(async () => { - // Set up addresses for testing. - [, owner, nonExchange, exchange, nonAuthority, authority] = await env.getAccountAddressesAsync(); - - // Deploy the Exchange Manager contract. - exchangeManager = await TestExchangeManagerContract.deployFrom0xArtifactAsync( - artifacts.TestExchangeManager, - env.provider, - { - ...env.txDefaults, - from: owner, - }, - artifacts, - ); - - // Register the exchange. - await exchangeManager.setValidExchange(exchange).awaitTransactionSuccessAsync(); - - // Register an authority. - await exchangeManager.addAuthorizedAddress(authority).awaitTransactionSuccessAsync({ from: owner }); - }); - - describe('onlyExchange', () => { - it('should revert if called by an unregistered exchange', async () => { - const expectedError = new StakingRevertErrors.OnlyCallableByExchangeError(nonExchange); - return expect(exchangeManager.onlyExchangeFunction().callAsync({ from: nonExchange })).to.revertWith( - expectedError, - ); - }); - - it('should succeed if called by a registered exchange', async () => { - const didSucceed = await exchangeManager.onlyExchangeFunction().callAsync({ from: exchange }); - expect(didSucceed).to.be.true(); - }); - }); - - enum ExchangeManagerEventType { - ExchangeAdded, - ExchangeRemoved, - } - - // Verify the logs emitted by `addExchangeAddress` and `removeExchangeAddress` - function verifyExchangeManagerEvent( - eventType: ExchangeManagerEventType, - exchangeAddress: string, - receipt: TransactionReceiptWithDecodedLogs, - ): void { - // Ensure that the length of the logs is correct. - expect(receipt.logs.length).to.be.eq(1); - - // Ensure that the event emitted was correct. - let log; - // tslint:disable:no-unnecessary-type-assertion - if (eventType === ExchangeManagerEventType.ExchangeAdded) { - log = receipt.logs[0] as LogWithDecodedArgs; - expect(log.event).to.be.eq('ExchangeAdded'); - } else { - log = receipt.logs[0] as LogWithDecodedArgs; - expect(log.event).to.be.eq('ExchangeRemoved'); - } - // tslint:enable:no-unnecessary-type-assertion - expect(log.args.exchangeAddress).to.be.eq(exchangeAddress); - } - - describe('addExchangeAddress', () => { - it('should revert if called by an unauthorized address', async () => { - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(nonAuthority); - const tx = exchangeManager.addExchangeAddress(nonExchange).awaitTransactionSuccessAsync({ - from: nonAuthority, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when adding an exchange if called by the (non-authorized) owner', async () => { - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(owner); - const tx = exchangeManager.addExchangeAddress(nonExchange).awaitTransactionSuccessAsync({ - from: owner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should successfully add an exchange if called by an authorized address', async () => { - // Register a new exchange. - const receipt = await exchangeManager.addExchangeAddress(nonExchange).awaitTransactionSuccessAsync({ - from: authority, - }); - - // Ensure that the logged event was correct. - verifyExchangeManagerEvent(ExchangeManagerEventType.ExchangeAdded, nonExchange, receipt); - - // Ensure that the exchange was successfully registered. - const isValidExchange = await exchangeManager.validExchanges(nonExchange).callAsync(); - expect(isValidExchange).to.be.true(); - }); - - it('should fail to add an exchange redundantly', async () => { - const expectedError = new StakingRevertErrors.ExchangeManagerError( - StakingRevertErrors.ExchangeManagerErrorCodes.ExchangeAlreadyRegistered, - exchange, - ); - const tx = exchangeManager.addExchangeAddress(exchange).awaitTransactionSuccessAsync({ from: authority }); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('removeExchangeAddress', () => { - it('should revert if called by an unauthorized address', async () => { - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(nonAuthority); - const tx = exchangeManager.removeExchangeAddress(exchange).awaitTransactionSuccessAsync({ - from: nonAuthority, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert when removing an exchange if called by the (non-authorized) owner', async () => { - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(owner); - const tx = exchangeManager.removeExchangeAddress(nonExchange).awaitTransactionSuccessAsync({ - from: owner, - }); - return expect(tx).to.revertWith(expectedError); - }); - - it('should successfully remove a registered exchange if called by an authorized address', async () => { - // Remove the registered exchange. - const receipt = await exchangeManager.removeExchangeAddress(exchange).awaitTransactionSuccessAsync({ - from: authority, - }); - - // Ensure that the logged event was correct. - verifyExchangeManagerEvent(ExchangeManagerEventType.ExchangeRemoved, exchange, receipt); - - // Ensure that the exchange was removed. - const isValidExchange = await exchangeManager.validExchanges(exchange).callAsync(); - expect(isValidExchange).to.be.false(); - }); - - it('should fail to remove an exchange redundantly', async () => { - const expectedError = new StakingRevertErrors.ExchangeManagerError( - StakingRevertErrors.ExchangeManagerErrorCodes.ExchangeNotRegistered, - nonExchange, - ); - const tx = exchangeManager.removeExchangeAddress(nonExchange).awaitTransactionSuccessAsync({ - from: authority, - }); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/finalizer_test.ts b/contracts/staking/test/unit_tests/finalizer_test.ts deleted file mode 100644 index 1c873f3a1c..0000000000 --- a/contracts/staking/test/unit_tests/finalizer_test.ts +++ /dev/null @@ -1,579 +0,0 @@ -import { - assertIntegerRoughlyEquals, - blockchainTests, - constants, - expect, - filterLogsToArguments, - getRandomInteger, - Numberish, - shortZip, - toBaseUnitAmount, -} from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils, StakingRevertErrors } from '@0x/utils'; -import { LogEntry } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { constants as stakingConstants } from '../../src/constants'; - -import { artifacts } from '../artifacts'; - -import { - IStakingEventsEpochEndedEventArgs, - IStakingEventsEpochFinalizedEventArgs, - IStakingEventsEvents, - IStakingEventsRewardsPaidEventArgs, - TestFinalizerContract, - TestFinalizerDepositStakingPoolRewardsEventArgs as DepositStakingPoolRewardsEventArgs, - TestFinalizerEvents, -} from '../wrappers'; - -blockchainTests.resets('Finalizer unit tests', env => { - const { ZERO_AMOUNT } = constants; - const INITIAL_BALANCE = toBaseUnitAmount(32); - let operatorRewardsReceiver: string; - let membersRewardsReceiver: string; - let testContract: TestFinalizerContract; - - before(async () => { - operatorRewardsReceiver = hexUtils.random(constants.ADDRESS_LENGTH); - membersRewardsReceiver = hexUtils.random(constants.ADDRESS_LENGTH); - testContract = await TestFinalizerContract.deployFrom0xArtifactAsync( - artifacts.TestFinalizer, - env.provider, - env.txDefaults, - artifacts, - operatorRewardsReceiver, - membersRewardsReceiver, - ); - // Give the contract a balance. - await sendEtherAsync(testContract.address, INITIAL_BALANCE); - }); - - async function sendEtherAsync(to: string, amount: Numberish): Promise { - await env.web3Wrapper.awaitTransactionSuccessAsync( - await env.web3Wrapper.sendTransactionAsync({ - from: (await env.getAccountAddressesAsync())[0], - to, - value: new BigNumber(amount), - }), - ); - } - - interface ActivePoolOpts { - poolId: string; - operatorShare: number; - feesCollected: Numberish; - membersStake: Numberish; - weightedStake: Numberish; - } - - async function addActivePoolAsync(opts?: Partial): Promise { - const maxAmount = toBaseUnitAmount(1e9); - const _opts = { - poolId: hexUtils.random(), - operatorShare: Math.floor(Math.random() * constants.PPM_DENOMINATOR) / constants.PPM_DENOMINATOR, - feesCollected: getRandomInteger(0, maxAmount), - membersStake: getRandomInteger(0, maxAmount), - weightedStake: getRandomInteger(0, maxAmount), - ...opts, - }; - await testContract - .addActivePool( - _opts.poolId, - new BigNumber(_opts.operatorShare * constants.PPM_DENOMINATOR).integerValue(), - new BigNumber(_opts.feesCollected), - new BigNumber(_opts.membersStake), - new BigNumber(_opts.weightedStake), - ) - .awaitTransactionSuccessAsync(); - return _opts; - } - - interface UnfinalizedState { - rewardsAvailable: Numberish; - numPoolsToFinalize: Numberish; - totalFeesCollected: Numberish; - totalWeightedStake: Numberish; - totalRewardsFinalized: Numberish; - } - - async function getUnfinalizedStateAsync(): Promise { - return testContract.getAggregatedStatsForPreviousEpoch().callAsync(); - } - - async function finalizePoolsAsync(poolIds: string[]): Promise { - const logs = [] as LogEntry[]; - for (const poolId of poolIds) { - const receipt = await testContract.finalizePool(poolId).awaitTransactionSuccessAsync(); - logs.splice(logs.length, 0, ...receipt.logs); - } - return logs; - } - - async function assertUnfinalizedStateAsync(expected: Partial): Promise { - const actual = await getUnfinalizedStateAsync(); - assertEqualNumberFields(actual, expected); - } - - function assertEpochEndedEvent(logs: LogEntry[], args: Partial): void { - const events = getEpochEndedEvents(logs); - expect(events.length).to.eq(1); - assertEqualNumberFields(events[0], args); - } - - function assertEpochFinalizedEvent(logs: LogEntry[], args: Partial): void { - const events = getEpochFinalizedEvents(logs); - expect(events.length).to.eq(1); - assertEqualNumberFields(events[0], args); - } - - function assertEqualNumberFields(actual: T, expected: Partial): void { - for (const key of Object.keys(actual)) { - const a = (actual as any)[key] as BigNumber; - const e = (expected as any)[key] as Numberish; - if (e !== undefined) { - expect(a, key).to.bignumber.eq(e); - } - } - } - - async function assertFinalizationLogsAndBalancesAsync( - rewardsAvailable: Numberish, - poolsToFinalize: ActivePoolOpts[], - finalizationLogs: LogEntry[], - ): Promise { - const currentEpoch = await getCurrentEpochAsync(); - // Compute the expected rewards for each pool. - const poolsWithStake = poolsToFinalize.filter(p => !new BigNumber(p.weightedStake).isZero()); - const poolRewards = await calculatePoolRewardsAsync(rewardsAvailable, poolsWithStake); - const totalRewards = BigNumber.sum(...poolRewards); - const rewardsRemaining = new BigNumber(rewardsAvailable).minus(totalRewards); - const [totalOperatorRewards, totalMembersRewards] = getTotalSplitRewards(poolsToFinalize, poolRewards); - - // Assert the `RewardsPaid` logs. - const rewardsPaidEvents = getRewardsPaidEvents(finalizationLogs); - expect(rewardsPaidEvents.length).to.eq(poolsWithStake.length); - for (const i of _.times(rewardsPaidEvents.length)) { - const event = rewardsPaidEvents[i]; - const pool = poolsWithStake[i]; - const reward = poolRewards[i]; - const [operatorReward, membersReward] = splitRewards(pool, reward); - expect(event.epoch).to.bignumber.eq(currentEpoch); - assertIntegerRoughlyEquals(event.operatorReward, operatorReward); - assertIntegerRoughlyEquals(event.membersReward, membersReward); - } - - // Assert the `DepositStakingPoolRewards` logs. - const depositStakingPoolRewardsEvents = getDepositStakingPoolRewardsEvents(finalizationLogs); - expect(depositStakingPoolRewardsEvents.length).to.eq(poolsWithStake.length); - for (const i of _.times(depositStakingPoolRewardsEvents.length)) { - const event = depositStakingPoolRewardsEvents[i]; - const pool = poolsWithStake[i]; - const reward = poolRewards[i]; - expect(event.poolId).to.eq(pool.poolId); - assertIntegerRoughlyEquals(event.reward, reward); - assertIntegerRoughlyEquals(event.membersStake, pool.membersStake); - } - // Make sure they all sum up to the totals. - if (depositStakingPoolRewardsEvents.length > 0) { - const totalDepositRewards = BigNumber.sum(...depositStakingPoolRewardsEvents.map(e => e.reward)); - assertIntegerRoughlyEquals(totalDepositRewards, totalRewards); - } - - // Assert the `EpochFinalized` logs. - const epochFinalizedEvents = getEpochFinalizedEvents(finalizationLogs); - expect(epochFinalizedEvents.length).to.eq(1); - expect(epochFinalizedEvents[0].epoch).to.bignumber.eq(currentEpoch.minus(1)); - assertIntegerRoughlyEquals(epochFinalizedEvents[0].rewardsPaid, totalRewards); - assertIntegerRoughlyEquals(epochFinalizedEvents[0].rewardsRemaining, rewardsRemaining); - - // Assert the receiver balances. - await assertReceiverBalancesAsync(totalOperatorRewards, totalMembersRewards); - } - - async function assertReceiverBalancesAsync(operatorRewards: Numberish, membersRewards: Numberish): Promise { - const operatorRewardsBalance = await getBalanceOfAsync(operatorRewardsReceiver); - assertIntegerRoughlyEquals(operatorRewardsBalance, operatorRewards); - const membersRewardsBalance = await getBalanceOfAsync(membersRewardsReceiver); - assertIntegerRoughlyEquals(membersRewardsBalance, membersRewards); - } - - async function calculatePoolRewardsAsync( - rewardsAvailable: Numberish, - poolsToFinalize: ActivePoolOpts[], - ): Promise { - const totalFees = BigNumber.sum(...poolsToFinalize.map(p => p.feesCollected)); - const totalStake = BigNumber.sum(...poolsToFinalize.map(p => p.weightedStake)); - const poolRewards = _.times(poolsToFinalize.length, () => constants.ZERO_AMOUNT); - for (const i of _.times(poolsToFinalize.length)) { - const pool = poolsToFinalize[i]; - const feesCollected = new BigNumber(pool.feesCollected); - if (feesCollected.isZero()) { - continue; - } - poolRewards[i] = await testContract - .cobbDouglas( - new BigNumber(rewardsAvailable), - new BigNumber(feesCollected), - new BigNumber(totalFees), - new BigNumber(pool.weightedStake), - new BigNumber(totalStake), - ) - .callAsync(); - } - return poolRewards; - } - - function splitRewards(pool: ActivePoolOpts, totalReward: Numberish): [BigNumber, BigNumber] { - if (new BigNumber(pool.membersStake).isZero()) { - return [new BigNumber(totalReward), ZERO_AMOUNT]; - } - const operatorShare = new BigNumber(totalReward).times(pool.operatorShare).integerValue(BigNumber.ROUND_UP); - const membersShare = new BigNumber(totalReward).minus(operatorShare); - return [operatorShare, membersShare]; - } - - // Calculates the split rewards for every pool and returns the operator - // and member sums. - function getTotalSplitRewards(pools: ActivePoolOpts[], rewards: Numberish[]): [BigNumber, BigNumber] { - const _rewards = _.times(pools.length).map(i => splitRewards(pools[i], rewards[i])); - const totalOperatorRewards = BigNumber.sum(..._rewards.map(([o]) => o)); - const totalMembersRewards = BigNumber.sum(..._rewards.map(([, m]) => m)); - return [totalOperatorRewards, totalMembersRewards]; - } - - function getEpochEndedEvents(logs: LogEntry[]): IStakingEventsEpochEndedEventArgs[] { - return filterLogsToArguments(logs, IStakingEventsEvents.EpochEnded); - } - - function getEpochFinalizedEvents(logs: LogEntry[]): IStakingEventsEpochFinalizedEventArgs[] { - return filterLogsToArguments(logs, IStakingEventsEvents.EpochFinalized); - } - - function getDepositStakingPoolRewardsEvents(logs: LogEntry[]): DepositStakingPoolRewardsEventArgs[] { - return filterLogsToArguments( - logs, - TestFinalizerEvents.DepositStakingPoolRewards, - ); - } - - function getRewardsPaidEvents(logs: LogEntry[]): IStakingEventsRewardsPaidEventArgs[] { - return filterLogsToArguments(logs, IStakingEventsEvents.RewardsPaid); - } - - async function getCurrentEpochAsync(): Promise { - return testContract.currentEpoch().callAsync(); - } - - async function getBalanceOfAsync(whom: string): Promise { - return env.web3Wrapper.getBalanceInWeiAsync(whom); - } - - describe('endEpoch()', () => { - it('advances the epoch', async () => { - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const currentEpoch = await testContract.currentEpoch().callAsync(); - expect(currentEpoch).to.bignumber.eq(stakingConstants.INITIAL_EPOCH.plus(1)); - }); - - it('emits an `EpochEnded` event', async () => { - const receipt = await testContract.endEpoch().awaitTransactionSuccessAsync(); - assertEpochEndedEvent(receipt.logs, { - epoch: stakingConstants.INITIAL_EPOCH, - numActivePools: ZERO_AMOUNT, - rewardsAvailable: INITIAL_BALANCE, - totalFeesCollected: ZERO_AMOUNT, - totalWeightedStake: ZERO_AMOUNT, - }); - }); - - it('immediately finalizes if there are no pools to finalize', async () => { - const receipt = await testContract.endEpoch().awaitTransactionSuccessAsync(); - assertEpochFinalizedEvent(receipt.logs, { - epoch: stakingConstants.INITIAL_EPOCH, - rewardsPaid: ZERO_AMOUNT, - rewardsRemaining: INITIAL_BALANCE, - }); - }); - - it('does not immediately finalize if there is a pool to finalize', async () => { - await addActivePoolAsync(); - const receipt = await testContract.endEpoch().awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - receipt.logs, - IStakingEventsEvents.EpochFinalized, - ); - expect(events).to.deep.eq([]); - }); - - it('prepares unfinalized state', async () => { - // Add a pool so there is state to clear. - const pool = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - return assertUnfinalizedStateAsync({ - numPoolsToFinalize: 1, - rewardsAvailable: INITIAL_BALANCE, - totalFeesCollected: pool.feesCollected, - totalWeightedStake: pool.weightedStake, - }); - }); - - it("correctly stores the epoch's aggregated stats after ending the epoch", async () => { - const pool = await addActivePoolAsync(); - const epoch = await testContract.currentEpoch().callAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const aggregatedStats = await testContract.aggregatedStatsByEpoch(epoch).callAsync(); - expect(aggregatedStats).to.be.deep.equal([ - INITIAL_BALANCE, - new BigNumber(1), // pools to finalize - pool.feesCollected, - pool.weightedStake, - new BigNumber(0), // rewards finalized - ]); - }); - - it('reverts if the prior epoch is unfinalized', async () => { - await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const tx = testContract.endEpoch().awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.PreviousEpochNotFinalizedError( - stakingConstants.INITIAL_EPOCH, - 1, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('_finalizePool()', () => { - it('does nothing if there were no pools to finalize', async () => { - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const poolId = hexUtils.random(); - const logs = await finalizePoolsAsync([poolId]); - expect(logs).to.deep.eq([]); - }); - - it('can finalize a pool', async () => { - const pool = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const logs = await finalizePoolsAsync([pool.poolId]); - return assertFinalizationLogsAndBalancesAsync(INITIAL_BALANCE, [pool], logs); - }); - - it('can finalize multiple pools over multiple transactions', async () => { - const pools = await Promise.all(_.times(2, async () => addActivePoolAsync())); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const logs = await finalizePoolsAsync(pools.map(p => p.poolId)); - return assertFinalizationLogsAndBalancesAsync(INITIAL_BALANCE, pools, logs); - }); - - it('ignores a finalized pool', async () => { - const pools = await Promise.all(_.times(3, async () => addActivePoolAsync())); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const [finalizedPool] = _.sampleSize(pools, 1); - await finalizePoolsAsync([finalizedPool.poolId]); - const logs = await finalizePoolsAsync([finalizedPool.poolId]); - const rewardsPaidEvents = getRewardsPaidEvents(logs); - expect(rewardsPaidEvents).to.deep.eq([]); - }); - - it('resets pool state after finalizing it', async () => { - const pools = await Promise.all(_.times(3, async () => addActivePoolAsync())); - const pool = _.sample(pools) as ActivePoolOpts; - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await finalizePoolsAsync([pool.poolId]); - const poolState = await testContract - .getPoolStatsFromEpoch(stakingConstants.INITIAL_EPOCH, pool.poolId) - .callAsync(); - expect(poolState.feesCollected).to.bignumber.eq(0); - expect(poolState.weightedStake).to.bignumber.eq(0); - expect(poolState.membersStake).to.bignumber.eq(0); - }); - - it('`rewardsPaid` <= `rewardsAvailable` <= contract balance at the end of the epoch', async () => { - const pools = await Promise.all(_.times(3, async () => addActivePoolAsync())); - const receipt = await testContract.endEpoch().awaitTransactionSuccessAsync(); - const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0]; - expect(rewardsAvailable).to.bignumber.lte(INITIAL_BALANCE); - const logs = await finalizePoolsAsync(pools.map(r => r.poolId)); - const { rewardsPaid } = getEpochFinalizedEvents(logs)[0]; - expect(rewardsPaid).to.bignumber.lte(rewardsAvailable); - }); - - it('`rewardsPaid` <= `rewardsAvailable` with two equal pools', async () => { - const pool1 = await addActivePoolAsync(); - const pool2 = await addActivePoolAsync(_.omit(pool1, 'poolId')); - const receipt = await testContract.endEpoch().awaitTransactionSuccessAsync(); - const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0]; - const logs = await finalizePoolsAsync([pool1, pool2].map(r => r.poolId)); - const { rewardsPaid } = getEpochFinalizedEvents(logs)[0]; - expect(rewardsPaid).to.bignumber.lte(rewardsAvailable); - }); - - blockchainTests.optional('`rewardsPaid` fuzzing', async () => { - const numTests = 32; - for (const i of _.times(numTests)) { - const numPools = _.random(1, 32); - it(`${i + 1}/${numTests} \`rewardsPaid\` <= \`rewardsAvailable\` (${numPools} pools)`, async () => { - const pools = await Promise.all(_.times(numPools, async () => addActivePoolAsync())); - const receipt = await testContract.endEpoch().awaitTransactionSuccessAsync(); - const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0]; - const logs = await finalizePoolsAsync(pools.map(r => r.poolId)); - const { rewardsPaid } = getEpochFinalizedEvents(logs)[0]; - expect(rewardsPaid).to.bignumber.lte(rewardsAvailable); - }); - } - }); - }); - - describe('lifecycle', () => { - it('can advance the epoch after the prior epoch is finalized', async () => { - const pool = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await finalizePoolsAsync([pool.poolId]); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - return expect(getCurrentEpochAsync()).to.become(stakingConstants.INITIAL_EPOCH.plus(2)); - }); - - it('does not reward a pool that only earned rewards 2 epochs ago', async () => { - const pool1 = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await finalizePoolsAsync([pool1.poolId]); - await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - expect(getCurrentEpochAsync()).to.become(stakingConstants.INITIAL_EPOCH.plus(2)); - const logs = await finalizePoolsAsync([pool1.poolId]); - const rewardsPaidEvents = getRewardsPaidEvents(logs); - expect(rewardsPaidEvents).to.deep.eq([]); - }); - - it('does not reward a pool that only earned rewards 3 epochs ago', async () => { - const pool1 = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await finalizePoolsAsync([pool1.poolId]); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - expect(getCurrentEpochAsync()).to.become(stakingConstants.INITIAL_EPOCH.plus(3)); - const logs = await finalizePoolsAsync([pool1.poolId]); - const rewardsPaidEvents = getRewardsPaidEvents(logs); - expect(rewardsPaidEvents).to.deep.eq([]); - }); - - it('rolls over leftover rewards into the next epoch', async () => { - const poolIds = _.times(3, () => hexUtils.random()); - await Promise.all(poolIds.map(async id => addActivePoolAsync({ poolId: id }))); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const finalizeLogs = await finalizePoolsAsync(poolIds); - const { rewardsRemaining: rolledOverRewards } = getEpochFinalizedEvents(finalizeLogs)[0]; - await Promise.all(poolIds.map(async id => addActivePoolAsync({ poolId: id }))); - const { logs: endEpochLogs } = await testContract.endEpoch().awaitTransactionSuccessAsync(); - const { rewardsAvailable } = getEpochEndedEvents(endEpochLogs)[0]; - expect(rewardsAvailable).to.bignumber.eq(rolledOverRewards); - }); - }); - - interface FinalizedPoolRewards { - totalReward: Numberish; - membersStake: Numberish; - } - - async function assertUnfinalizedPoolRewardsAsync( - poolId: string, - expected: Partial, - ): Promise { - const actual = await testContract.getUnfinalizedPoolRewards(poolId).callAsync(); - if (expected.totalReward !== undefined) { - expect(actual.totalReward).to.bignumber.eq(expected.totalReward); - } - if (expected.membersStake !== undefined) { - expect(actual.membersStake).to.bignumber.eq(expected.membersStake); - } - } - - describe('_getUnfinalizedPoolReward()', () => { - const ZERO_REWARDS = { - totalReward: 0, - membersStake: 0, - }; - - it('returns empty if epoch is 1', async () => { - const poolId = hexUtils.random(); - return assertUnfinalizedPoolRewardsAsync(poolId, ZERO_REWARDS); - }); - - it('returns empty if pool did not earn rewards', async () => { - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const poolId = hexUtils.random(); - return assertUnfinalizedPoolRewardsAsync(poolId, ZERO_REWARDS); - }); - - it('returns empty if pool is earned rewards only in the current epoch', async () => { - const pool = await addActivePoolAsync(); - return assertUnfinalizedPoolRewardsAsync(pool.poolId, ZERO_REWARDS); - }); - - it('returns empty if pool only earned rewards in the 2 epochs ago', async () => { - const pool = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await finalizePoolsAsync([pool.poolId]); - return assertUnfinalizedPoolRewardsAsync(pool.poolId, ZERO_REWARDS); - }); - - it('returns empty if pool was already finalized', async () => { - const pools = await Promise.all(_.times(3, async () => addActivePoolAsync())); - const [pool] = _.sampleSize(pools, 1); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - await finalizePoolsAsync([pool.poolId]); - return assertUnfinalizedPoolRewardsAsync(pool.poolId, ZERO_REWARDS); - }); - - it('computes one reward among one pool', async () => { - const pool = await addActivePoolAsync(); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const expectedTotalRewards = INITIAL_BALANCE; - return assertUnfinalizedPoolRewardsAsync(pool.poolId, { - totalReward: expectedTotalRewards, - membersStake: pool.membersStake, - }); - }); - - it('computes one reward among multiple pools', async () => { - const pools = await Promise.all(_.times(3, async () => addActivePoolAsync())); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - const expectedPoolRewards = await calculatePoolRewardsAsync(INITIAL_BALANCE, pools); - const [pool, reward] = _.sampleSize(shortZip(pools, expectedPoolRewards), 1)[0]; - return assertUnfinalizedPoolRewardsAsync(pool.poolId, { - totalReward: reward, - membersStake: pool.membersStake, - }); - }); - - it('computes a reward with 0% operatorShare', async () => { - const pool = await addActivePoolAsync({ operatorShare: 0 }); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - return assertUnfinalizedPoolRewardsAsync(pool.poolId, { - totalReward: INITIAL_BALANCE, - membersStake: pool.membersStake, - }); - }); - - it('computes a reward with 0% < operatorShare < 100%', async () => { - const pool = await addActivePoolAsync({ operatorShare: Math.random() }); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - return assertUnfinalizedPoolRewardsAsync(pool.poolId, { - totalReward: INITIAL_BALANCE, - membersStake: pool.membersStake, - }); - }); - - it('computes a reward with 100% operatorShare', async () => { - const pool = await addActivePoolAsync({ operatorShare: 1 }); - await testContract.endEpoch().awaitTransactionSuccessAsync(); - return assertUnfinalizedPoolRewardsAsync(pool.poolId, { - totalReward: INITIAL_BALANCE, - membersStake: pool.membersStake, - }); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/lib_cobb_douglas_test.ts b/contracts/staking/test/unit_tests/lib_cobb_douglas_test.ts deleted file mode 100644 index 58d1fa5af1..0000000000 --- a/contracts/staking/test/unit_tests/lib_cobb_douglas_test.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { - assertRoughlyEquals, - blockchainTests, - getRandomInteger, - getRandomPortion, - Numberish, - toDecimal, -} from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { TestCobbDouglasContract } from '../wrappers'; - -blockchainTests('LibCobbDouglas unit tests', env => { - const FUZZ_COUNT = 1024; - const PRECISION = 15; - - let testContract: TestCobbDouglasContract; - - before(async () => { - testContract = await TestCobbDouglasContract.deployFrom0xArtifactAsync( - artifacts.TestCobbDouglas, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('cobbDouglas()', () => { - interface CobbDouglasParams { - totalRewards: Numberish; - ownerFees: Numberish; - totalFees: Numberish; - ownerStake: Numberish; - totalStake: Numberish; - alphaNumerator: Numberish; - alphaDenominator: Numberish; - gas?: number; - } - - const MAX_COBB_DOUGLAS_GAS = 11e3; - const TX_GAS_FEE = 21e3; - const DEFAULT_COBB_DOUGLAS_PARAMS: CobbDouglasParams = { - totalRewards: 100e18, - ownerFees: 10e18, - totalFees: 500e18, - ownerStake: 1.1e21, - totalStake: 3e27, - alphaNumerator: 1, - alphaDenominator: 3, - gas: MAX_COBB_DOUGLAS_GAS, - }; - - async function callCobbDouglasAsync(params?: Partial): Promise { - const _params = { - ...DEFAULT_COBB_DOUGLAS_PARAMS, - ...params, - }; - return testContract - .cobbDouglas( - new BigNumber(_params.totalRewards), - new BigNumber(_params.ownerFees), - new BigNumber(_params.totalFees), - new BigNumber(_params.ownerStake), - new BigNumber(_params.totalStake), - new BigNumber(_params.alphaNumerator), - new BigNumber(_params.alphaDenominator), - ) - .callAsync({ - gas: TX_GAS_FEE + (_params.gas === undefined ? MAX_COBB_DOUGLAS_GAS : _params.gas), - }); - } - - function cobbDouglas(params?: Partial): BigNumber { - const { totalRewards, ownerFees, totalFees, ownerStake, totalStake, alphaNumerator, alphaDenominator } = { - ...DEFAULT_COBB_DOUGLAS_PARAMS, - ...params, - }; - const feeRatio = toDecimal(ownerFees).dividedBy(toDecimal(totalFees)); - const stakeRatio = toDecimal(ownerStake).dividedBy(toDecimal(totalStake)); - const alpha = toDecimal(alphaNumerator).dividedBy(toDecimal(alphaDenominator)); - // totalRewards * feeRatio ^ alpha * stakeRatio ^ (1-alpha) - return new BigNumber( - feeRatio - .pow(alpha) - .times(stakeRatio.pow(toDecimal(1).minus(alpha))) - .times(toDecimal(totalRewards)) - .toFixed(0, BigNumber.ROUND_FLOOR), - ); - } - - function getRandomParams(overrides?: Partial): CobbDouglasParams { - const totalRewards = _.get(overrides, 'totalRewards', getRandomInteger(0, 1e27)) as Numberish; - const totalFees = _.get(overrides, 'totalFees', getRandomInteger(1, 1e27)) as Numberish; - const ownerFees = _.get(overrides, 'ownerFees', getRandomPortion(totalFees)) as Numberish; - const totalStake = _.get(overrides, 'totalStake', getRandomInteger(1, 1e27)) as Numberish; - const ownerStake = _.get(overrides, 'ownerStake', getRandomPortion(totalStake)) as Numberish; - const alphaDenominator = _.get(overrides, 'alphaDenominator', getRandomInteger(1, 1e6)) as Numberish; - const alphaNumerator = _.get(overrides, 'alphaNumerator', getRandomPortion(alphaDenominator)) as Numberish; - return { - totalRewards, - ownerFees, - totalFees, - ownerStake, - totalStake, - alphaNumerator, - alphaDenominator, - }; - } - - it('computes the correct reward', async () => { - const expected = cobbDouglas(); - const r = await callCobbDouglasAsync(); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with zero stake ratio', async () => { - const ownerStake = 0; - const expected = cobbDouglas({ ownerStake }); - const r = await callCobbDouglasAsync({ ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with full stake ratio', async () => { - const ownerStake = DEFAULT_COBB_DOUGLAS_PARAMS.totalStake; - const expected = cobbDouglas({ ownerStake }); - const r = await callCobbDouglasAsync({ ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with a very low stake ratio', async () => { - const ownerStake = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalStake).times(1e-18); - const expected = cobbDouglas({ ownerStake }); - const r = await callCobbDouglasAsync({ ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with a very high stake ratio', async () => { - const ownerStake = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalStake).times(1 - 1e-18); - const expected = cobbDouglas({ ownerStake }); - const r = await callCobbDouglasAsync({ ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with zero fee ratio', async () => { - const ownerFees = 0; - const expected = cobbDouglas({ ownerFees }); - const r = await callCobbDouglasAsync({ ownerFees }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with full fee ratio', async () => { - const ownerFees = DEFAULT_COBB_DOUGLAS_PARAMS.totalFees; - const expected = cobbDouglas({ ownerFees }); - const r = await callCobbDouglasAsync({ ownerFees }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with a very low fee ratio', async () => { - const ownerFees = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalFees).times(1e-18); - const expected = cobbDouglas({ ownerFees }); - const r = await callCobbDouglasAsync({ ownerFees }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with a very high fee ratio', async () => { - const ownerFees = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalFees).times(1 - 1e-18); - const expected = cobbDouglas({ ownerFees }); - const r = await callCobbDouglasAsync({ ownerFees }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with equal fee and stake ratios', async () => { - const ownerFees = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalFees).times(0.5); - const ownerStake = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalStake).times(0.5); - const expected = cobbDouglas({ ownerFees, ownerStake }); - const r = await callCobbDouglasAsync({ ownerFees, ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with full fee and stake ratios', async () => { - const ownerFees = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalFees); - const ownerStake = new BigNumber(DEFAULT_COBB_DOUGLAS_PARAMS.totalStake); - const expected = cobbDouglas({ ownerFees, ownerStake }); - const r = await callCobbDouglasAsync({ ownerFees, ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - it('computes the correct reward with zero fee and stake ratios', async () => { - const ownerFees = 0; - const ownerStake = 0; - const expected = cobbDouglas({ ownerFees, ownerStake }); - const r = await callCobbDouglasAsync({ ownerFees, ownerStake }); - assertRoughlyEquals(r, expected, PRECISION); - }); - - blockchainTests.optional('fuzzing', () => { - const inputs = _.times(FUZZ_COUNT, () => getRandomParams()); - for (const params of inputs) { - it(`cobbDouglas(${JSON.stringify(params)})`, async () => { - const expected = cobbDouglas(params); - const r = await callCobbDouglasAsync(params); - assertRoughlyEquals(r, expected, PRECISION); - }); - } - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/lib_fixed_math_test.ts b/contracts/staking/test/unit_tests/lib_fixed_math_test.ts deleted file mode 100644 index e2f07d41bb..0000000000 --- a/contracts/staking/test/unit_tests/lib_fixed_math_test.ts +++ /dev/null @@ -1,960 +0,0 @@ -import { - assertRoughlyEquals, - blockchainTests, - expect, - fromFixed, - Numberish, - toDecimal, - toFixed, -} from '@0x/contracts-test-utils'; -import { BigNumber, FixedMathRevertErrors, hexUtils } from '@0x/utils'; -import { Decimal } from 'decimal.js'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { TestLibFixedMathContract } from '../wrappers'; - -blockchainTests('LibFixedMath unit tests', env => { - let testContract: TestLibFixedMathContract; - - before(async () => { - testContract = await TestLibFixedMathContract.deployFrom0xArtifactAsync( - artifacts.TestLibFixedMath, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - const BITS_OF_PRECISION = 127; - const FIXED_POINT_DIVISOR = new BigNumber(2).pow(BITS_OF_PRECISION); - const FIXED_1 = FIXED_POINT_DIVISOR; - const MAX_FIXED_VALUE = new BigNumber(2).pow(255).minus(1); - const MIN_FIXED_VALUE = new BigNumber(2).pow(255).times(-1); - const MIN_EXP_NUMBER = new BigNumber('-63.875'); - const MAX_EXP_NUMBER = new BigNumber(0); - // e ^ MIN_EXP_NUMBER - const MIN_LN_NUMBER = new BigNumber(new Decimal(MIN_EXP_NUMBER.toFixed(128)).exp().toFixed(128)); - const FUZZ_COUNT = 1024; - - function assertFixedEquals(actualFixed: Numberish, expected: Numberish): void { - expect(fromFixed(actualFixed)).to.bignumber.eq(fromFixed(toFixed(expected))); - } - - function assertFixedRoughlyEquals(actualFixed: Numberish, expected: Numberish, precision: number = 18): void { - assertRoughlyEquals(fromFixed(actualFixed), expected, precision); - } - - describe('one()', () => { - it('equals 1', async () => { - const r = await testContract.one().callAsync(); - assertFixedEquals(r, 1); - }); - }); - - describe('abs()', () => { - it('abs(n) == n', async () => { - const n = 1337.5912; - const r = await testContract.abs(toFixed(n)).callAsync(); - assertFixedEquals(r, n); - }); - - it('abs(-n) == n', async () => { - const n = -1337.5912; - const r = await testContract.abs(toFixed(n)).callAsync(); - assertFixedEquals(r, -n); - }); - - it('abs(0) == 0', async () => { - const n = 0; - const r = await testContract.abs(toFixed(n)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('abs(MAX_FIXED) == MAX_FIXED', async () => { - const n = MAX_FIXED_VALUE; - const r = await testContract.abs(n).callAsync(); - expect(r).to.bignumber.eq(n); - }); - - it('abs(MIN_FIXED) throws', async () => { - const n = MIN_FIXED_VALUE; - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooSmall, - n, - ); - const tx = testContract.abs(n).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('abs(int(-1)) == int(1)', async () => { - const n = -1; - const r = await testContract.abs(new BigNumber(n)).callAsync(); - expect(r).to.bignumber.eq(1); - }); - - it('abs(int(1)) == int(1)', async () => { - const n = 1; - const r = await testContract.abs(new BigNumber(n)).callAsync(); - expect(r).to.bignumber.eq(1); - }); - }); - - describe('invert()', () => { - it('invert(1) == 1', async () => { - const n = 1; - const r = await testContract.invert(toFixed(n)).callAsync(); - assertFixedEquals(r, n); - }); - - it('invert(n) == 1 / n', async () => { - const n = 1337.5912; - const r = await testContract.invert(toFixed(n)).callAsync(); - assertFixedRoughlyEquals(r, 1 / n); - }); - - it('invert(-n) == -1 / n', async () => { - const n = -1337.5912; - const r = await testContract.invert(toFixed(n)).callAsync(); - assertFixedRoughlyEquals(r, 1 / n); - }); - - it('invert(0) throws', async () => { - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.DivisionByZero, - ); - const tx = testContract.invert(toFixed(0)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('mulDiv()', () => { - it('mulDiv(0, 0, 1) == 0', async () => { - const [a, n, d] = [0, 0, 1]; - const r = await testContract.mulDiv(toFixed(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, 0); - }); - - it('mulDiv(0, x, y) == 0', async () => { - const [a, n, d] = [0, 13, 300]; - const r = await testContract.mulDiv(toFixed(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, 0); - }); - - it('mulDiv(x, y, y) == x', async () => { - const [a, n, d] = [1.2345, 149, 149]; - const r = await testContract.mulDiv(toFixed(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, a); - }); - - it('mulDiv(x, -y, y) == -x', async () => { - const [a, n, d] = [1.2345, -149, 149]; - const r = await testContract.mulDiv(toFixed(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, -a); - }); - - it('mulDiv(-x, -y, y) == x', async () => { - const [a, n, d] = [-1.2345, -149, 149]; - const r = await testContract.mulDiv(toFixed(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, -a); - }); - - it('mulDiv(x, y, 0) throws', async () => { - const [a, n, d] = [1.2345, 149, 0]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.DivisionByZero, - ); - const tx = testContract.mulDiv(toFixed(a), new BigNumber(n), new BigNumber(d)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('mulDiv(int(-1), int(1), int(-1)) == int(1)', async () => { - const [a, n, d] = [-1, 1, -1]; - const r = await testContract.mulDiv(new BigNumber(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, fromFixed(1)); - }); - - it('mulDiv(int(1), int(-1), int(-1)) == int(1)', async () => { - const [a, n, d] = [1, -1, -1]; - const r = await testContract.mulDiv(new BigNumber(a), new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, fromFixed(1)); - }); - - it('mulDiv(MIN_FIXED, int(-1), int(1)) throws', async () => { - const [a, n, d] = [MIN_FIXED_VALUE, -1, 1]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - n, - ); - const tx = testContract.mulDiv(a, new BigNumber(n), new BigNumber(d)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('mulDiv(int(-1), MIN_FIXED, int(1)) throws', async () => { - const [a, n, d] = [-1, MIN_FIXED_VALUE, 1]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - n, - ); - const tx = testContract.mulDiv(new BigNumber(a), n, new BigNumber(d)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('mulDiv(MIN_FIXED, int(1), int(-1)) throws', async () => { - const [a, n, d] = [MIN_FIXED_VALUE, 1, -1]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.DivisionOverflow, - a, - d, - ); - const tx = testContract.mulDiv(a, new BigNumber(n), new BigNumber(d)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('mulDiv(MAX_FIXED, int(-1), int(1)) == -MAX_FIXED', async () => { - const [a, n, d] = [MAX_FIXED_VALUE, -1, 1]; - const r = await testContract.mulDiv(a, new BigNumber(n), new BigNumber(d)).callAsync(); - expect(r).to.bignumber.eq(MAX_FIXED_VALUE.negated()); - }); - - it('mulDiv(MAX_FIXED, int(1), int(-1)) == -MAX_FIXED', async () => { - const [a, n, d] = [MAX_FIXED_VALUE, 1, -1]; - const r = await testContract.mulDiv(a, new BigNumber(n), new BigNumber(d)).callAsync(); - expect(r).to.bignumber.eq(MAX_FIXED_VALUE.negated()); - }); - }); - - describe('add()', () => { - function add(a: Numberish, b: Numberish): BigNumber { - return fromFixed(toFixed(a).plus(toFixed(b))); - } - - it('0 + 0 == 0', async () => { - const [a, b] = [0, 0]; - const r = await testContract.add(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, 0); - }); - - it('adds two positive decimals', async () => { - const [a, b] = ['9310841.31841', '491021921.318948193']; - const r = await testContract.add(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, add(a, b)); - }); - - it('adds two mixed decimals', async () => { - const [a, b] = ['9310841.31841', '-491021921.318948193']; - const r = await testContract.add(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, add(a, b)); - }); - - it('throws on overflow', async () => { - const [a, b] = [MAX_FIXED_VALUE, new BigNumber(1)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b, - ); - const tx = testContract.add(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws on underflow', async () => { - const [a, b] = [MIN_FIXED_VALUE, new BigNumber(-1)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b, - ); - const tx = testContract.add(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MIN_FIXED + MIN_FIXED throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, MIN_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b, - ); - const tx = testContract.add(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED + MAX_FIXED throws', async () => { - const [a, b] = [MAX_FIXED_VALUE, MAX_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b, - ); - const tx = testContract.add(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MIN_FIXED + MAX_FIXED == int(-1)', async () => { - const [a, b] = [MIN_FIXED_VALUE, MAX_FIXED_VALUE]; - const r = await testContract.add(a, b).callAsync(); - expect(r).to.bignumber.eq(-1); - }); - - it('MAX_FIXED + (MIN_FIXED + int(1)) == 0', async () => { - const [a, b] = [MAX_FIXED_VALUE, MIN_FIXED_VALUE.plus(1)]; - const r = await testContract.add(a, b).callAsync(); - expect(r).to.bignumber.eq(0); - }); - }); - - describe('sub()', () => { - function sub(a: Numberish, b: Numberish): BigNumber { - return fromFixed(toFixed(a).minus(toFixed(b))); - } - - it('0 - 0 == 0', async () => { - const [a, b] = [0, 0]; - const r = await testContract.sub(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, 0); - }); - - it('subtracts two positive decimals', async () => { - const [a, b] = ['9310841.31841', '491021921.318948193']; - const r = await testContract.sub(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, sub(a, b)); - }); - - it('subtracts two mixed decimals', async () => { - const [a, b] = ['9310841.31841', '-491021921.318948193']; - const r = await testContract.sub(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, sub(a, b)); - }); - - it('throws on underflow', async () => { - const [a, b] = [MIN_FIXED_VALUE, new BigNumber(1)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b.negated(), - ); - const tx = testContract.sub(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws on overflow', async () => { - const [a, b] = [MAX_FIXED_VALUE, new BigNumber(-1)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b.negated(), - ); - const tx = testContract.sub(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MIN_FIXED - MIN_FIXED throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, MIN_FIXED_VALUE]; - // This fails because `-MIN_FIXED_VALUE == MIN_FIXED_VALUE` because of - // twos-complement. - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooSmall, - b, - ); - const tx = testContract.sub(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED - MAX_FIXED == 0', async () => { - const [a, b] = [MAX_FIXED_VALUE, MAX_FIXED_VALUE]; - const r = await testContract.sub(a, b).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('MIN_FIXED - MAX_FIXED throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, MAX_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - a, - b.negated(), - ); - const tx = testContract.sub(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED - MIN_FIXED throws', async () => { - const [a, b] = [MAX_FIXED_VALUE, MIN_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooSmall, - b, - ); - const tx = testContract.sub(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('mul()', () => { - function mul(a: Numberish, b: Numberish): BigNumber { - return fromFixed( - toFixed(a) - .times(toFixed(b)) - .dividedToIntegerBy(FIXED_POINT_DIVISOR), - ); - } - - it('x * 0 == 0', async () => { - const [a, b] = [1337, 0]; - const r = await testContract.mul(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, b); - }); - - it('x * 1 == x', async () => { - const [a, b] = [0.5, 1]; - const r = await testContract.mul(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, a); - }); - - it('x * -1 == -x', async () => { - const [a, b] = [0.5, -1]; - const r = await testContract.mul(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, -a); - }); - - it('multiplies two positive decimals', async () => { - const [a, b] = ['1.25394912112', '0.03413318948193']; - const r = await testContract.mul(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, mul(a, b)); - }); - - it('multiplies two mixed decimals', async () => { - const [a, b] = ['1.25394912112', '-0.03413318948193']; - const r = await testContract.mul(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, mul(a, b)); - }); - - it('throws on underflow', async () => { - const [a, b] = [MIN_FIXED_VALUE, new BigNumber(2)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws on overflow', async () => { - const [a, b] = [MAX_FIXED_VALUE, new BigNumber(2)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED * int(1) == MAX_FIXED / FIXED_1', async () => { - const [a, b] = [MAX_FIXED_VALUE, 1]; - const r = await testContract.mul(a, new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(MAX_FIXED_VALUE.dividedToIntegerBy(FIXED_1)); - }); - - it('MAX_FIXED * int(2) throws', async () => { - const [a, b] = [MAX_FIXED_VALUE, 2]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, new BigNumber(b)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED * MAX_FIXED throws', async () => { - const [a, b] = [MAX_FIXED_VALUE, MAX_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MIN_FIXED * MIN_FIXED throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, MIN_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED * MIN_FIXED throws', async () => { - const [a, b] = [MAX_FIXED_VALUE, MIN_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MIN_FIXED * int(-1) throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, -1]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(a, new BigNumber(b)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('int(-1) * MIN_FIXED throws', async () => { - const [a, b] = [-1, MIN_FIXED_VALUE]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.mul(new BigNumber(a), b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED * int(-1) == -MAX_FIXED / FIXED_1', async () => { - const [a, b] = [MAX_FIXED_VALUE, -1]; - const r = await testContract.mul(a, new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(MAX_FIXED_VALUE.negated().dividedToIntegerBy(FIXED_1)); - }); - }); - - describe('div()', () => { - function div(a: Numberish, b: Numberish): BigNumber { - return fromFixed( - toFixed(a) - .times(FIXED_POINT_DIVISOR) - .dividedBy(toFixed(b)), - ); - } - - it('x / 0 throws', async () => { - const [a, b] = [1, 0]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.DivisionByZero, - toFixed(a).times(FIXED_POINT_DIVISOR), - toFixed(b), - ); - const tx = testContract.div(toFixed(a), toFixed(b)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('x / 1 == x', async () => { - const [a, b] = [1.41214552, 1]; - const r = await testContract.div(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, a); - }); - - it('x / -1 == -x', async () => { - const [a, b] = [1.109312, -1]; - const r = await testContract.div(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, -a); - }); - - it('divides two positive decimals', async () => { - const [a, b] = ['1.25394912112', '0.03413318948193']; - const r = await testContract.div(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, div(a, b)); - }); - - it('divides two mixed decimals', async () => { - const [a, b] = ['1.25394912112', '-0.03413318948193']; - const r = await testContract.div(toFixed(a), toFixed(b)).callAsync(); - assertFixedEquals(r, div(a, b)); - }); - - it('MIN_FIXED / int(-1) throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, -1]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - FIXED_1, - ); - const tx = testContract.div(a, new BigNumber(b)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('MAX_FIXED / int(-1) throws', async () => { - const [a, b] = [MIN_FIXED_VALUE, -1]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - FIXED_1, - ); - const tx = testContract.div(a, new BigNumber(b)).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('int(-1) / MIN_FIXED == 0', async () => { - const [a, b] = [-1, MIN_FIXED_VALUE]; - const r = await testContract.div(new BigNumber(a), b).callAsync(); - expect(r).to.bignumber.eq(0); - }); - }); - - describe('uintMul()', () => { - it('0 * x == 0', async () => { - const [a, b] = [0, 1234]; - const r = await testContract.uintMul(toFixed(a), new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('1 * x == int(x)', async () => { - const [a, b] = [1, 1234]; - const r = await testContract.uintMul(toFixed(a), new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(Math.trunc(b)); - }); - - it('-1 * x == 0', async () => { - const [a, b] = [-1, 1234]; - const r = await testContract.uintMul(toFixed(a), new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('0.5 * x == x/2', async () => { - const [a, b] = [0.5, 1234]; - const r = await testContract.uintMul(toFixed(a), new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(b / 2); - }); - - it('0.5 * x == 0 if x = 1', async () => { - const [a, b] = [0.5, 1]; - const r = await testContract.uintMul(toFixed(a), new BigNumber(b)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('throws if rhs is too large', async () => { - const [a, b] = [toFixed(1), MAX_FIXED_VALUE.plus(1)]; - const expectedError = new FixedMathRevertErrors.UnsignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooLarge, - b, - ); - const tx = testContract.uintMul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if lhs is too large', async () => { - const [a, b] = [MAX_FIXED_VALUE, new BigNumber(2)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - a, - b, - ); - const tx = testContract.uintMul(a, b).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('toInteger()', () => { - it('toInteger(n) == int(n)', async () => { - const n = 1337.5912; - const r = await testContract.toInteger(toFixed(n)).callAsync(); - expect(r).to.bignumber.eq(Math.trunc(n)); - }); - - it('toInteger(-n) == -int(n)', async () => { - const n = -1337.5912; - const r = await testContract.toInteger(toFixed(n)).callAsync(); - expect(r).to.bignumber.eq(Math.trunc(n)); - }); - - it('toInteger(n) == 0, when 0 < n < 1', async () => { - const n = 0.9995; - const r = await testContract.toInteger(toFixed(n)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('toInteger(-n) == 0, when -1 < n < 0', async () => { - const n = -0.9995; - const r = await testContract.toInteger(toFixed(n)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - - it('toInteger(0) == 0', async () => { - const n = 0; - const r = await testContract.toInteger(toFixed(n)).callAsync(); - expect(r).to.bignumber.eq(0); - }); - }); - - describe('toFixed()', () => { - describe('signed', () => { - it('converts a positive integer', async () => { - const n = 1337; - const r = await testContract.toFixedSigned1(new BigNumber(n)).callAsync(); - assertFixedEquals(r, n); - }); - - it('converts a negative integer', async () => { - const n = -1337; - const r = await testContract.toFixedSigned1(new BigNumber(n)).callAsync(); - assertFixedEquals(r, n); - }); - - it('converts a fraction with a positive numerator and denominator', async () => { - const [n, d] = [1337, 1000]; - const r = await testContract.toFixedSigned2(new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, n / d); - }); - - it('converts a fraction with a negative numerator and positive denominator', async () => { - const [n, d] = [-1337, 1000]; - const r = await testContract.toFixedSigned2(new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, n / d); - }); - - it('converts a fraction with a negative numerator and denominator', async () => { - const [n, d] = [-1337, -1000]; - const r = await testContract.toFixedSigned2(new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, n / d); - }); - - it('converts a fraction with a negative numerator and negative denominator', async () => { - const [n, d] = [-1337, -1000]; - const r = await testContract.toFixedSigned2(new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, n / d); - }); - - it('throws if the numerator is too large to convert', async () => { - const [n, d] = [MAX_FIXED_VALUE.dividedToIntegerBy(FIXED_POINT_DIVISOR).plus(1), new BigNumber(1000)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - n, - FIXED_POINT_DIVISOR, - ); - const tx = testContract.toFixedSigned2(n, d).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if the denominator is zero', async () => { - const [n, d] = [new BigNumber(1), new BigNumber(0)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.DivisionByZero, - n.times(FIXED_POINT_DIVISOR), - d, - ); - const tx = testContract.toFixedSigned2(n, d).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('unsigned', () => { - it('converts an integer', async () => { - const n = 1337; - const r = await testContract.toFixedUnsigned1(new BigNumber(n)).callAsync(); - assertFixedEquals(r, n); - }); - - it('converts a fraction', async () => { - const [n, d] = [1337, 1000]; - const r = await testContract.toFixedUnsigned2(new BigNumber(n), new BigNumber(d)).callAsync(); - assertFixedEquals(r, n / d); - }); - - it('throws if the numerator is too large', async () => { - const [n, d] = [MAX_FIXED_VALUE.plus(1), new BigNumber(1000)]; - const expectedError = new FixedMathRevertErrors.UnsignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooLarge, - n, - ); - const tx = testContract.toFixedUnsigned2(n, d).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if the denominator is too large', async () => { - const [n, d] = [new BigNumber(1000), MAX_FIXED_VALUE.plus(1)]; - const expectedError = new FixedMathRevertErrors.UnsignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooLarge, - d, - ); - const tx = testContract.toFixedUnsigned2(n, d).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if the numerator is too large to convert', async () => { - const [n, d] = [MAX_FIXED_VALUE.dividedToIntegerBy(FIXED_POINT_DIVISOR).plus(1), new BigNumber(1000)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow, - n, - FIXED_POINT_DIVISOR, - ); - const tx = testContract.toFixedUnsigned2(n, d).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if the denominator is zero', async () => { - const [n, d] = [new BigNumber(1), new BigNumber(0)]; - const expectedError = new FixedMathRevertErrors.BinOpError( - FixedMathRevertErrors.BinOpErrorCodes.DivisionByZero, - n.times(FIXED_POINT_DIVISOR), - d, - ); - const tx = testContract.toFixedUnsigned2(n, d).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - }); - - function getRandomDecimal(min: Numberish, max: Numberish): BigNumber { - const range = new BigNumber(max).minus(min); - const random = fromFixed(new BigNumber(hexUtils.random().substr(2), 16)); - return random.mod(range).plus(min); - } - - describe('ln()', () => { - const LN_PRECISION = 16; - - function ln(x: Numberish): BigNumber { - return new BigNumber( - toDecimal(x) - .ln() - .toFixed(128), - ); - } - - it('ln(x = 0) throws', async () => { - const x = toFixed(0); - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooSmall, - x, - ); - const tx = testContract.ln(x).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('ln(x > 1) throws', async () => { - const x = toFixed(1.000001); - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooLarge, - x, - ); - const tx = testContract.ln(x).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('ln(x < 0) throws', async () => { - const x = toFixed(-0.000001); - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooSmall, - x, - ); - const tx = testContract.ln(x).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('ln(x = 1) == 0', async () => { - const x = toFixed(1); - const r = await testContract.ln(x).callAsync(); - assertFixedEquals(r, 0); - }); - - it('ln(x < LN_MIN_VAL) == EXP_MIN_VAL', async () => { - const x = toFixed(MIN_LN_NUMBER).minus(1); - const r = await testContract.ln(x).callAsync(); - assertFixedEquals(r, MIN_EXP_NUMBER); - }); - - it('ln(x), where x is close to 0', async () => { - const x = new BigNumber('1e-27'); - const r = await testContract.ln(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, ln(x), 12); - }); - - it('ln(x), where x is close to 1', async () => { - const x = new BigNumber(1).minus('1e-27'); - const r = await testContract.ln(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, ln(x), LN_PRECISION); - }); - - it('ln(x = 0.85)', async () => { - const x = 0.85; - const r = await testContract.ln(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, ln(x), LN_PRECISION); - }); - - blockchainTests.optional('fuzzing', () => { - const inputs = _.times(FUZZ_COUNT, () => getRandomDecimal(0, 1)); - for (const x of inputs) { - it(`ln(${x.toString(10)})`, async () => { - const r = await testContract.ln(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, ln(x), LN_PRECISION); - }); - } - }); - }); - - describe('exp()', () => { - const EXP_PRECISION = 18; - - function exp(x: Numberish): BigNumber { - return new BigNumber( - toDecimal(x) - .exp() - .toFixed(128), - ); - } - - it('exp(x = 0) == 1', async () => { - const x = toFixed(0); - const r = await testContract.exp(x).callAsync(); - assertFixedEquals(r, 1); - }); - - it('exp(x > EXP_MAX_VAL) throws', async () => { - const x = toFixed(MAX_EXP_NUMBER).plus(1); - const expectedError = new FixedMathRevertErrors.SignedValueError( - FixedMathRevertErrors.ValueErrorCodes.TooLarge, - x, - ); - const tx = testContract.exp(x).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - - it('exp(x < EXP_MIN_VAL) == 0', async () => { - const x = toFixed(MIN_EXP_NUMBER).minus(1); - const r = await testContract.exp(x).callAsync(); - assertFixedEquals(r, 0); - }); - - it('exp(x < 0), where x is close to 0', async () => { - const x = new BigNumber('-1e-18'); - const r = await testContract.exp(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, exp(x), EXP_PRECISION); - }); - - it('exp(x), where x is close to EXP_MIN_VAL', async () => { - const x = MIN_EXP_NUMBER.plus('1e-18'); - const r = await testContract.exp(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, exp(x), EXP_PRECISION); - }); - - it('exp(x = -0.85)', async () => { - const x = -0.85; - const r = await testContract.exp(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, exp(x), EXP_PRECISION); - }); - - blockchainTests.optional('fuzzing', () => { - const inputs = _.times(FUZZ_COUNT, () => getRandomDecimal(MIN_EXP_NUMBER, MAX_EXP_NUMBER)); - for (const x of inputs) { - it(`exp(${x.toString(10)})`, async () => { - const r = await testContract.exp(toFixed(x)).callAsync(); - assertFixedRoughlyEquals(r, exp(x), EXP_PRECISION); - }); - } - }); - }); -}); -// tslint:disable-next-line: max-file-line-count diff --git a/contracts/staking/test/unit_tests/lib_safe_downcast_test.ts b/contracts/staking/test/unit_tests/lib_safe_downcast_test.ts deleted file mode 100644 index a5e56c924a..0000000000 --- a/contracts/staking/test/unit_tests/lib_safe_downcast_test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { BigNumber } from '@0x/utils'; - -import { artifacts } from '../artifacts'; -import { TestLibSafeDowncastContract } from '../wrappers'; - -blockchainTests('LibSafeDowncast unit tests', env => { - let testContract: TestLibSafeDowncastContract; - - before(async () => { - testContract = await TestLibSafeDowncastContract.deployFrom0xArtifactAsync( - artifacts.TestLibSafeDowncast, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - const MAX_UINT_64 = new BigNumber(2).pow(64).minus(1); - const MAX_UINT_96 = new BigNumber(2).pow(96).minus(1); - const MAX_UINT_256 = new BigNumber(2).pow(256).minus(1); - - describe('downcastToUint96', () => { - async function verifyCorrectDowncastAsync(n: Numberish): Promise { - const actual = await testContract.downcastToUint96(new BigNumber(n)).callAsync(); - expect(actual).to.bignumber.eq(n); - } - function toDowncastError(n: Numberish): SafeMathRevertErrors.Uint256DowncastError { - return new SafeMathRevertErrors.Uint256DowncastError( - SafeMathRevertErrors.DowncastErrorCodes.ValueTooLargeToDowncastToUint96, - new BigNumber(n), - ); - } - - it('correctly downcasts 0', async () => { - return verifyCorrectDowncastAsync(0); - }); - it('correctly downcasts 1337', async () => { - return verifyCorrectDowncastAsync(1337); - }); - it('correctly downcasts MAX_UINT_96', async () => { - return verifyCorrectDowncastAsync(MAX_UINT_96); - }); - it('reverts on MAX_UINT_96 + 1', async () => { - const n = MAX_UINT_96.plus(1); - return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); - }); - it('reverts on MAX_UINT_256', async () => { - const n = MAX_UINT_256; - return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); - }); - }); - - describe('downcastToUint64', () => { - async function verifyCorrectDowncastAsync(n: Numberish): Promise { - const actual = await testContract.downcastToUint64(new BigNumber(n)).callAsync(); - expect(actual).to.bignumber.eq(n); - } - function toDowncastError(n: Numberish): SafeMathRevertErrors.Uint256DowncastError { - return new SafeMathRevertErrors.Uint256DowncastError( - SafeMathRevertErrors.DowncastErrorCodes.ValueTooLargeToDowncastToUint64, - new BigNumber(n), - ); - } - - it('correctly downcasts 0', async () => { - return verifyCorrectDowncastAsync(0); - }); - it('correctly downcasts 1337', async () => { - return verifyCorrectDowncastAsync(1337); - }); - it('correctly downcasts MAX_UINT_64', async () => { - return verifyCorrectDowncastAsync(MAX_UINT_64); - }); - it('reverts on MAX_UINT_64 + 1', async () => { - const n = MAX_UINT_64.plus(1); - return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); - }); - it('reverts on MAX_UINT_256', async () => { - const n = MAX_UINT_256; - return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/mixin_cumulative_rewards_test.ts b/contracts/staking/test/unit_tests/mixin_cumulative_rewards_test.ts deleted file mode 100644 index 187859f518..0000000000 --- a/contracts/staking/test/unit_tests/mixin_cumulative_rewards_test.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { blockchainTests, expect, toBaseUnitAmount } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { constants as stakingConstants } from '../../src/constants'; - -import { artifacts } from '../artifacts'; -import { TestMixinCumulativeRewardsContract } from '../wrappers'; - -blockchainTests.resets('MixinCumulativeRewards unit tests', env => { - const ZERO = new BigNumber(0); - const testRewards = [ - { - numerator: new BigNumber(1), - denominator: new BigNumber(2), - }, - { - numerator: new BigNumber(3), - denominator: new BigNumber(4), - }, - ]; - const sumOfTestRewardsNormalized = { - numerator: new BigNumber(10), - denominator: new BigNumber(8), - }; - let testPoolId: string; - let testContract: TestMixinCumulativeRewardsContract; - - before(async () => { - // Deploy contracts - testContract = await TestMixinCumulativeRewardsContract.deployFrom0xArtifactAsync( - artifacts.TestMixinCumulativeRewards, - env.provider, - env.txDefaults, - artifacts, - stakingConstants.NIL_ADDRESS, - stakingConstants.NIL_ADDRESS, - ); - - // Create a test pool - const operatorShare = new BigNumber(1); - const addOperatorAsMaker = true; - const txReceipt = await testContract - .createStakingPool(operatorShare, addOperatorAsMaker) - .awaitTransactionSuccessAsync(); - const createStakingPoolLog = txReceipt.logs[0]; - testPoolId = (createStakingPoolLog as any).args.poolId; - }); - - describe('_isCumulativeRewardSet', () => { - it('Should return true iff denominator is non-zero', async () => { - const isSet = await testContract - .isCumulativeRewardSet({ - numerator: ZERO, - denominator: new BigNumber(1), - }) - .callAsync(); - expect(isSet).to.be.true(); - }); - it('Should return false iff denominator is zero', async () => { - const isSet = await testContract - .isCumulativeRewardSet({ - numerator: new BigNumber(1), - denominator: ZERO, - }) - .callAsync(); - expect(isSet).to.be.false(); - }); - }); - - describe('_addCumulativeReward', () => { - it('Should set value to `reward/stake` if this is the first cumulative reward', async () => { - await testContract - .addCumulativeReward(testPoolId, testRewards[0].numerator, testRewards[0].denominator) - .awaitTransactionSuccessAsync(); - const [mostRecentCumulativeReward] = await testContract - .getMostRecentCumulativeReward(testPoolId) - .callAsync(); - expect(mostRecentCumulativeReward).to.deep.equal(testRewards[0]); - }); - - it('Should do nothing if a cumulative reward has already been recorded in the current epoch (`lastStoredEpoch == currentEpoch_`)', async () => { - await testContract - .addCumulativeReward(testPoolId, testRewards[0].numerator, testRewards[0].denominator) - .awaitTransactionSuccessAsync(); - // this call should not overwrite existing value (testRewards[0]) - await testContract - .addCumulativeReward(testPoolId, testRewards[1].numerator, testRewards[1].denominator) - .awaitTransactionSuccessAsync(); - const [mostRecentCumulativeReward] = await testContract - .getMostRecentCumulativeReward(testPoolId) - .callAsync(); - expect(mostRecentCumulativeReward).to.deep.equal(testRewards[0]); - }); - - it('Should set value to normalized sum of `reward/stake` plus most recent cumulative reward, given one exists', async () => { - await testContract - .addCumulativeReward(testPoolId, testRewards[0].numerator, testRewards[0].denominator) - .awaitTransactionSuccessAsync(); - await testContract.incrementEpoch().awaitTransactionSuccessAsync(); - await testContract - .addCumulativeReward(testPoolId, testRewards[1].numerator, testRewards[1].denominator) - .awaitTransactionSuccessAsync(); - const [mostRecentCumulativeReward] = await testContract - .getMostRecentCumulativeReward(testPoolId) - .callAsync(); - expect(mostRecentCumulativeReward).to.deep.equal(sumOfTestRewardsNormalized); - }); - }); - - describe('_updateCumulativeReward', () => { - it('Should set current cumulative reward to most recent cumulative reward', async () => { - await testContract - .addCumulativeReward(testPoolId, testRewards[0].numerator, testRewards[0].denominator) - .awaitTransactionSuccessAsync(); - await testContract.incrementEpoch().awaitTransactionSuccessAsync(); - await testContract.updateCumulativeReward(testPoolId).awaitTransactionSuccessAsync(); - const epoch = new BigNumber(2); - const mostRecentCumulativeReward = await testContract - .getCumulativeRewardAtEpochRaw(testPoolId, epoch) - .callAsync(); - expect(mostRecentCumulativeReward).to.deep.equal(testRewards[0]); - }); - }); - - describe('_computeMemberRewardOverInterval', () => { - const runTest = async ( - amountToStake: BigNumber, - epochOfFirstReward: BigNumber, - epochOfSecondReward: BigNumber, - epochOfIntervalStart: BigNumber, - epochOfIntervalEnd: BigNumber, - ): Promise => { - // Simulate earning reward - await testContract - .storeCumulativeReward(testPoolId, testRewards[0], epochOfFirstReward) - .awaitTransactionSuccessAsync(); - await testContract - .storeCumulativeReward(testPoolId, sumOfTestRewardsNormalized, epochOfSecondReward) - .awaitTransactionSuccessAsync(); - const reward = await testContract - .computeMemberRewardOverInterval(testPoolId, amountToStake, epochOfIntervalStart, epochOfIntervalEnd) - .callAsync(); - // Compute expected reward - const lhs = sumOfTestRewardsNormalized.numerator.dividedBy(sumOfTestRewardsNormalized.denominator); - const rhs = testRewards[0].numerator.dividedBy(testRewards[0].denominator); - const expectedReward = lhs.minus(rhs).multipliedBy(amountToStake); - // Assert correctness - expect(reward).to.bignumber.equal(expectedReward); - }; - - it('Should successfully compute reward over a valid interval when staking non-zero ZRX', async () => { - const amountToStake = toBaseUnitAmount(1); - const epochOfFirstReward = new BigNumber(1); - const epochOfSecondReward = new BigNumber(2); - const epochOfIntervalStart = new BigNumber(1); - const epochOfIntervalEnd = new BigNumber(2); - await runTest( - amountToStake, - epochOfFirstReward, - epochOfSecondReward, - epochOfIntervalStart, - epochOfIntervalEnd, - ); - }); - - it('Should successfully compute reward if no entry for current epoch, but there is an entry for epoch n-1', async () => { - // End epoch = n-1 forces the code to query the previous epoch's cumulative reward - const amountToStake = toBaseUnitAmount(1); - const epochOfFirstReward = new BigNumber(1); - const epochOfSecondReward = new BigNumber(2); - const epochOfIntervalStart = new BigNumber(1); - const epochOfIntervalEnd = new BigNumber(3); - await runTest( - amountToStake, - epochOfFirstReward, - epochOfSecondReward, - epochOfIntervalStart, - epochOfIntervalEnd, - ); - }); - - it('Should successfully compute reward if no entry for current epoch, but there is an entry for epoch n-2', async () => { - // End epoch = n-2 forces the code to query the most recent cumulative reward - const amountToStake = toBaseUnitAmount(1); - const epochOfFirstReward = new BigNumber(1); - const epochOfSecondReward = new BigNumber(2); - const epochOfIntervalStart = new BigNumber(1); - const epochOfIntervalEnd = new BigNumber(4); - await runTest( - amountToStake, - epochOfFirstReward, - epochOfSecondReward, - epochOfIntervalStart, - epochOfIntervalEnd, - ); - }); - - it('Should successfully compute reward are no cumulative reward entries', async () => { - // No entries forces the default cumulatie reward to be used in computations - const stake = toBaseUnitAmount(1); - const beginEpoch = new BigNumber(1); - const endEpoch = new BigNumber(2); - const reward = await testContract - .computeMemberRewardOverInterval(testPoolId, stake, beginEpoch, endEpoch) - .callAsync(); - expect(reward).to.bignumber.equal(ZERO); - }); - - it('Should return zero if no stake was delegated', async () => { - const stake = toBaseUnitAmount(0); - const beginEpoch = new BigNumber(1); - const endEpoch = new BigNumber(2); - const reward = await testContract - .computeMemberRewardOverInterval(testPoolId, stake, beginEpoch, endEpoch) - .callAsync(); - expect(reward).to.bignumber.equal(ZERO); - }); - - it('Should return zero if the start/end of the interval are the same epoch', async () => { - const stake = toBaseUnitAmount(1); - const beginEpoch = new BigNumber(1); - const endEpoch = new BigNumber(1); - const reward = await testContract - .computeMemberRewardOverInterval(testPoolId, stake, beginEpoch, endEpoch) - .callAsync(); - expect(reward).to.bignumber.equal(ZERO); - }); - - it('Should revert if start is greater than the end of the interval', async () => { - const stake = toBaseUnitAmount(1); - const beginEpoch = new BigNumber(2); - const endEpoch = new BigNumber(1); - const tx = testContract - .computeMemberRewardOverInterval(testPoolId, stake, beginEpoch, endEpoch) - .callAsync(); - return expect(tx).to.revertWith('CR_INTERVAL_INVALID'); - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/mixin_scheduler_test.ts b/contracts/staking/test/unit_tests/mixin_scheduler_test.ts deleted file mode 100644 index c588472410..0000000000 --- a/contracts/staking/test/unit_tests/mixin_scheduler_test.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; -import { BigNumber, StakingRevertErrors } from '@0x/utils'; -import { LogWithDecodedArgs } from 'ethereum-types'; - -import { constants as stakingConstants } from '../../src/constants'; - -import { artifacts } from '../artifacts'; -import { - TestMixinSchedulerContract, - TestMixinSchedulerEvents, - TestMixinSchedulerGoToNextEpochTestInfoEventArgs, -} from '../wrappers'; - -blockchainTests.resets('MixinScheduler unit tests', env => { - let testContract: TestMixinSchedulerContract; - - before(async () => { - // Deploy contracts - testContract = await TestMixinSchedulerContract.deployFrom0xArtifactAsync( - artifacts.TestMixinScheduler, - env.provider, - env.txDefaults, - artifacts, - stakingConstants.NIL_ADDRESS, - stakingConstants.NIL_ADDRESS, - ); - }); - - describe('getCurrentEpochEarliestEndTimeInSeconds', () => { - it('Should return the sum of `epoch start time + epoch duration`', async () => { - const testDeployedTimestamp = await testContract.testDeployedTimestamp().callAsync(); - const epochDurationInSeconds = await testContract.epochDurationInSeconds().callAsync(); - const expectedCurrentEpochEarliestEndTimeInSeconds = testDeployedTimestamp.plus(epochDurationInSeconds); - const currentEpochEarliestEndTimeInSeconds = await testContract - .getCurrentEpochEarliestEndTimeInSeconds() - .callAsync(); - expect(currentEpochEarliestEndTimeInSeconds).to.bignumber.equal( - expectedCurrentEpochEarliestEndTimeInSeconds, - ); - }); - }); - - describe('_initMixinScheduler', () => { - it('Should succeed if scheduler is not yet initialized (`currentEpochStartTimeInSeconds == 0`)', async () => { - const initCurrentEpochStartTimeInSeconds = constants.ZERO_AMOUNT; - const txReceipt = await testContract - .initMixinSchedulerTest(initCurrentEpochStartTimeInSeconds) - .awaitTransactionSuccessAsync(); - // Assert `currentEpochStartTimeInSeconds` was properly initialized - const blockTimestamp = await env.web3Wrapper.getBlockTimestampAsync(txReceipt.blockNumber); - const currentEpochStartTimeInSeconds = await testContract.currentEpochStartTimeInSeconds().callAsync(); - expect(currentEpochStartTimeInSeconds).to.bignumber.equal(blockTimestamp); - // Assert `currentEpoch` was properly initialized - const currentEpoch = await testContract.currentEpoch().callAsync(); - expect(currentEpoch).to.bignumber.equal(1); - }); - - it('Should revert if scheduler is already initialized (`currentEpochStartTimeInSeconds != 0`)', async () => { - const initCurrentEpochStartTimeInSeconds = new BigNumber(10); - const tx = testContract - .initMixinSchedulerTest(initCurrentEpochStartTimeInSeconds) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith( - new StakingRevertErrors.InitializationError( - StakingRevertErrors.InitializationErrorCodes.MixinSchedulerAlreadyInitialized, - ), - ); - }); - }); - - describe('_goToNextEpoch', () => { - it('Should succeed if epoch end time is strictly less than to block timestamp', async () => { - const epochEndTimeDelta = new BigNumber(-10); - const txReceipt = await testContract.goToNextEpochTest(epochEndTimeDelta).awaitTransactionSuccessAsync(); - const currentEpoch = await testContract.currentEpoch().callAsync(); - const currentEpochStartTimeInSeconds = await testContract.currentEpochStartTimeInSeconds().callAsync(); - verifyEventsFromLogs( - txReceipt.logs, - [ - { - oldEpoch: currentEpoch.minus(1), - blockTimestamp: currentEpochStartTimeInSeconds, - }, - ], - TestMixinSchedulerEvents.GoToNextEpochTestInfo, - ); - }); - - it('Should succeed if epoch end time is equal to block timestamp', async () => { - const epochEndTimeDelta = constants.ZERO_AMOUNT; - const txReceipt = await testContract.goToNextEpochTest(epochEndTimeDelta).awaitTransactionSuccessAsync(); - // tslint:disable-next-line no-unnecessary-type-assertion - const testLog: TestMixinSchedulerGoToNextEpochTestInfoEventArgs = (txReceipt.logs[0] as LogWithDecodedArgs< - TestMixinSchedulerGoToNextEpochTestInfoEventArgs - >).args; - const currentEpoch = await testContract.currentEpoch().callAsync(); - const currentEpochStartTimeInSeconds = await testContract.currentEpochStartTimeInSeconds().callAsync(); - expect(currentEpoch).to.bignumber.equal(testLog.oldEpoch.plus(1)); - expect(currentEpochStartTimeInSeconds).to.bignumber.equal(testLog.blockTimestamp); - }); - - it('Should revert if epoch end time is strictly greater than block timestamp', async () => { - const epochEndTimeDelta = new BigNumber(10); - const tx = testContract.goToNextEpochTest(epochEndTimeDelta).awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(new StakingRevertErrors.BlockTimestampTooLowError()); - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/mixin_stake_storage_test.ts b/contracts/staking/test/unit_tests/mixin_stake_storage_test.ts deleted file mode 100644 index c3d85c148e..0000000000 --- a/contracts/staking/test/unit_tests/mixin_stake_storage_test.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { constants } from '../../src/constants'; -import { StoredBalance } from '../../src/types'; - -import { StakingRevertErrors } from '../../src'; - -import { artifacts } from '../artifacts'; -import { TestMixinStakeStorageContract } from '../wrappers'; - -blockchainTests.resets('MixinStakeStorage unit tests', env => { - let testContract: TestMixinStakeStorageContract; - let defaultUninitializedBalance: StoredBalance; - let defaultSyncedBalance: StoredBalance; - let defaultUnsyncedBalance: StoredBalance; - - const CURRENT_EPOCH = new BigNumber(5); - const INDEX_ZERO = new BigNumber(0); - const INDEX_ONE = new BigNumber(1); - - before(async () => { - testContract = await TestMixinStakeStorageContract.deployFrom0xArtifactAsync( - artifacts.TestMixinStakeStorage, - env.provider, - env.txDefaults, - artifacts, - ); - await testContract.setCurrentEpoch(CURRENT_EPOCH).awaitTransactionSuccessAsync(); - defaultUninitializedBalance = { - currentEpoch: constants.INITIAL_EPOCH, - currentEpochBalance: new BigNumber(0), - nextEpochBalance: new BigNumber(0), - }; - defaultSyncedBalance = { - currentEpoch: CURRENT_EPOCH, - currentEpochBalance: new BigNumber(16), - nextEpochBalance: new BigNumber(16), - }; - defaultUnsyncedBalance = { - currentEpoch: CURRENT_EPOCH.minus(1), - currentEpochBalance: new BigNumber(10), - nextEpochBalance: new BigNumber(16), - }; - }); - - async function getTestBalancesAsync(index: Numberish): Promise { - const storedBalance: Partial = {}; - [ - storedBalance.currentEpoch, - storedBalance.currentEpochBalance, - storedBalance.nextEpochBalance, - ] = await testContract.testBalances(new BigNumber(index)).callAsync(); - return storedBalance as StoredBalance; - } - - describe('Move stake', () => { - async function moveStakeAndVerifyBalancesAsync( - fromBalance: StoredBalance, - toBalance: StoredBalance, - amount: BigNumber, - ): Promise { - await testContract.setStoredBalance(fromBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - await testContract.setStoredBalance(toBalance, INDEX_ONE).awaitTransactionSuccessAsync(); - await testContract.moveStake(INDEX_ZERO, INDEX_ONE, amount).awaitTransactionSuccessAsync(); - - const actualBalances = await Promise.all([ - getTestBalancesAsync(INDEX_ZERO), - getTestBalancesAsync(INDEX_ONE), - ]); - expect(actualBalances[0]).to.deep.equal({ - currentEpoch: CURRENT_EPOCH, - currentEpochBalance: fromBalance.currentEpochBalance, - nextEpochBalance: fromBalance.nextEpochBalance.minus(amount), - }); - expect(actualBalances[1]).to.deep.equal({ - currentEpoch: CURRENT_EPOCH, - currentEpochBalance: toBalance.currentEpochBalance, - nextEpochBalance: toBalance.nextEpochBalance.plus(amount), - }); - } - - it('Updates balances to reflect move', async () => { - await moveStakeAndVerifyBalancesAsync( - defaultSyncedBalance, - defaultSyncedBalance, - defaultSyncedBalance.nextEpochBalance.dividedToIntegerBy(2), - ); - }); - it('Can move amount equal to next epoch balance', async () => { - await moveStakeAndVerifyBalancesAsync( - defaultSyncedBalance, - defaultSyncedBalance, - defaultSyncedBalance.nextEpochBalance, - ); - }); - it('Moves to and initializes a previously uninitalized balance', async () => { - await moveStakeAndVerifyBalancesAsync( - defaultSyncedBalance, - defaultUninitializedBalance, - defaultSyncedBalance.nextEpochBalance.dividedToIntegerBy(2), - ); - }); - it('Noop if pointers are equal', async () => { - await testContract.setStoredBalance(defaultSyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - // If the pointers weren't equal, this would revert with InsufficientBalanceError - await testContract - .moveStake(INDEX_ZERO, INDEX_ZERO, defaultSyncedBalance.nextEpochBalance.plus(1)) - .awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal(defaultSyncedBalance); - }); - it("Reverts if attempting to move more than next epoch's balance", async () => { - await testContract.setStoredBalance(defaultSyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultSyncedBalance.nextEpochBalance.plus(1); - const tx = testContract.moveStake(INDEX_ZERO, INDEX_ONE, amount).awaitTransactionSuccessAsync(); - await expect(tx).to.revertWith( - new StakingRevertErrors.InsufficientBalanceError(amount, defaultSyncedBalance.nextEpochBalance), - ); - }); - }); - - describe('Load balance', () => { - it('Balance does not change state if balance was previously synced in the current epoch', async () => { - await testContract.setStoredBalance(defaultSyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const actualBalance = await testContract.loadCurrentBalance(INDEX_ZERO).callAsync(); - expect(actualBalance).to.deep.equal(defaultSyncedBalance); - }); - it('Balance updates current epoch fields if the balance has not yet been synced in the current epoch', async () => { - await testContract.setStoredBalance(defaultUnsyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const actualBalance = await testContract.loadCurrentBalance(INDEX_ZERO).callAsync(); - expect(actualBalance).to.deep.equal(defaultSyncedBalance); - }); - it('Balance loads unsynced balance from storage without changing fields', async () => { - await testContract.setStoredBalance(defaultUnsyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const actualBalance = await testContract.loadStaleBalance(INDEX_ZERO).callAsync(); - expect(actualBalance).to.deep.equal(defaultUnsyncedBalance); - }); - it('Balance loads synced balance from storage without changing fields', async () => { - await testContract.setStoredBalance(defaultSyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const actualBalance = await testContract.loadStaleBalance(INDEX_ZERO).callAsync(); - expect(actualBalance).to.deep.equal(defaultSyncedBalance); - }); - }); - - describe('Increase/decrease balance', () => { - it('_increaseCurrentAndNextBalance', async () => { - await testContract.setStoredBalance(defaultUnsyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultUnsyncedBalance.currentEpochBalance.dividedToIntegerBy(2); - await testContract.increaseCurrentAndNextBalance(INDEX_ZERO, amount).awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal({ - ...defaultSyncedBalance, - currentEpochBalance: defaultSyncedBalance.currentEpochBalance.plus(amount), - nextEpochBalance: defaultSyncedBalance.nextEpochBalance.plus(amount), - }); - }); - it('_increaseCurrentAndNextBalance (previously uninitialized)', async () => { - await testContract.setStoredBalance(defaultUninitializedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultSyncedBalance.currentEpochBalance; - await testContract.increaseCurrentAndNextBalance(INDEX_ZERO, amount).awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal(defaultSyncedBalance); - }); - it('_decreaseCurrentAndNextBalance', async () => { - await testContract.setStoredBalance(defaultUnsyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultUnsyncedBalance.currentEpochBalance.dividedToIntegerBy(2); - await testContract.decreaseCurrentAndNextBalance(INDEX_ZERO, amount).awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal({ - ...defaultSyncedBalance, - currentEpochBalance: defaultSyncedBalance.currentEpochBalance.minus(amount), - nextEpochBalance: defaultSyncedBalance.nextEpochBalance.minus(amount), - }); - }); - it('_increaseNextBalance', async () => { - await testContract.setStoredBalance(defaultUnsyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultUnsyncedBalance.currentEpochBalance.dividedToIntegerBy(2); - await testContract.increaseNextBalance(INDEX_ZERO, amount).awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal({ - ...defaultSyncedBalance, - nextEpochBalance: defaultSyncedBalance.nextEpochBalance.plus(amount), - }); - }); - it('_increaseCurrentAndNextBalance (previously uninitialized)', async () => { - await testContract.setStoredBalance(defaultUninitializedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultSyncedBalance.currentEpochBalance; - await testContract.increaseNextBalance(INDEX_ZERO, amount).awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal({ - ...defaultSyncedBalance, - currentEpochBalance: new BigNumber(0), - }); - }); - it('_decreaseNextBalance', async () => { - await testContract.setStoredBalance(defaultUnsyncedBalance, INDEX_ZERO).awaitTransactionSuccessAsync(); - const amount = defaultUnsyncedBalance.currentEpochBalance.dividedToIntegerBy(2); - await testContract.decreaseNextBalance(INDEX_ZERO, amount).awaitTransactionSuccessAsync(); - const actualBalance = await getTestBalancesAsync(INDEX_ZERO); - expect(actualBalance).to.deep.equal({ - ...defaultSyncedBalance, - nextEpochBalance: defaultSyncedBalance.nextEpochBalance.minus(amount), - }); - }); - }); -}); diff --git a/contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts b/contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts deleted file mode 100644 index 3d001df18f..0000000000 --- a/contracts/staking/test/unit_tests/mixin_staking_pool_rewards.ts +++ /dev/null @@ -1,496 +0,0 @@ -import { ReferenceFunctions } from '@0x/contracts-exchange-libs'; -import { - blockchainTests, - constants, - expect, - getRandomInteger, - getRandomPortion, - Numberish, - randomAddress, - verifyEventsFromLogs, -} from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; -import { LogEntry, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { StoredBalance } from '../../src/types'; - -import { artifacts } from '../artifacts'; -import { TestMixinStakingPoolRewardsContract, TestMixinStakingPoolRewardsEvents as Events } from '../wrappers'; - -blockchainTests.resets('MixinStakingPoolRewards unit tests', env => { - let testContract: TestMixinStakingPoolRewardsContract; - - const POOL_ID = hexUtils.random(); - const OPERATOR = randomAddress(); - const OPERATOR_SHARE = getRandomInteger(1, constants.PPM_100_PERCENT); - let caller: string; - - before(async () => { - testContract = await TestMixinStakingPoolRewardsContract.deployFrom0xArtifactAsync( - artifacts.TestMixinStakingPoolRewards, - env.provider, - env.txDefaults, - artifacts, - ); - await testContract - .setPool(POOL_ID, { - operator: OPERATOR, - operatorShare: OPERATOR_SHARE, - }) - .awaitTransactionSuccessAsync(); - [caller] = await env.getAccountAddressesAsync(); - }); - - async function setUnfinalizedPoolRewardsAsync( - poolId: string, - reward: Numberish, - membersStake: Numberish, - ): Promise { - await testContract - .setUnfinalizedPoolRewards(poolId, new BigNumber(reward), new BigNumber(membersStake)) - .awaitTransactionSuccessAsync(); - } - - // Set the delegated stake of a delegator in a pool. - // Omitted fields will be randomly generated. - async function setStakeAsync( - poolId: string, - delegator: string, - stake?: Partial, - ): Promise { - const _stake = { - currentEpoch: getRandomInteger(1, 4e9), - currentEpochBalance: getRandomInteger(1, 1e18), - nextEpochBalance: getRandomInteger(1, 1e18), - ...stake, - }; - await testContract - .setDelegatedStakeToPoolByOwner(delegator, poolId, { - currentEpoch: _stake.currentEpoch, - currentEpochBalance: _stake.currentEpochBalance, - nextEpochBalance: _stake.nextEpochBalance, - }) - .awaitTransactionSuccessAsync(); - return _stake; - } - - // Sets up state for a call to `_computeDelegatorReward()` and return the - // finalized rewards it will compute. - async function setComputeDelegatorRewardStateAsync( - poolId: string, - delegator: string, - finalizedReward?: Numberish, - ): Promise { - const stake = await testContract.delegatedStakeToPoolByOwner(delegator, poolId).callAsync(); - // Split the rewards up across the two calls to `_computeMemberRewardOverInterval()` - const reward = finalizedReward === undefined ? getRandomInteger(1, 1e18) : new BigNumber(finalizedReward); - const oldRewards = getRandomPortion(reward); - await testContract - .setMemberRewardsOverInterval( - poolId, - stake.currentEpochBalance, - stake.currentEpoch, - stake.currentEpoch.plus(1), - oldRewards, - ) - .awaitTransactionSuccessAsync(); - const newRewards = reward.minus(oldRewards); - await testContract - .setMemberRewardsOverInterval( - poolId, - stake.nextEpochBalance, - stake.currentEpoch.plus(1), - await testContract.currentEpoch().callAsync(), - newRewards, - ) - .awaitTransactionSuccessAsync(); - return reward; - } - - function toOperatorPortion(operatorShare: Numberish, reward: Numberish): BigNumber { - return ReferenceFunctions.getPartialAmountCeil( - new BigNumber(operatorShare), - new BigNumber(constants.PPM_DENOMINATOR), - new BigNumber(reward), - ); - } - - function toMembersPortion(operatorShare: Numberish, reward: Numberish): BigNumber { - return new BigNumber(reward).minus(toOperatorPortion(operatorShare, reward)); - } - - describe('withdrawDelegatorRewards()', () => { - it('calls `_withdrawAndSyncDelegatorRewards()` with the sender as the member', async () => { - const { logs } = await testContract.withdrawDelegatorRewards(POOL_ID).awaitTransactionSuccessAsync(); - verifyEventsFromLogs( - logs, - [{ poolId: POOL_ID, delegator: caller }], - Events.WithdrawAndSyncDelegatorRewards, - ); - }); - }); - - describe('_withdrawAndSyncDelegatorRewards()', () => { - const POOL_REWARD = getRandomInteger(1, 100e18); - const WETH_RESERVED_FOR_POOL_REWARDS = POOL_REWARD.plus(getRandomInteger(1, 100e18)); - const DELEGATOR = randomAddress(); - let stake: StoredBalance; - - before(async () => { - stake = await setStakeAsync(POOL_ID, DELEGATOR); - await testContract.setPoolRewards(POOL_ID, POOL_REWARD).awaitTransactionSuccessAsync(); - await testContract - .setWethReservedForPoolRewards(WETH_RESERVED_FOR_POOL_REWARDS) - .awaitTransactionSuccessAsync(); - }); - - async function withdrawAndSyncDelegatorRewardsAsync(): Promise { - return testContract.withdrawAndSyncDelegatorRewards(POOL_ID, DELEGATOR).awaitTransactionSuccessAsync(); - } - - it('reverts if the pool is not finalized', async () => { - await setUnfinalizedPoolRewardsAsync(POOL_ID, 0, 1); - const tx = withdrawAndSyncDelegatorRewardsAsync(); - return expect(tx).to.revertWith('POOL_NOT_FINALIZED'); - }); - it('calls `_updateCumulativeReward()`', async () => { - const { logs } = await withdrawAndSyncDelegatorRewardsAsync(); - verifyEventsFromLogs(logs, [{ poolId: POOL_ID }], Events.UpdateCumulativeReward); - }); - it('transfers finalized rewards to the sender', async () => { - const finalizedReward = getRandomPortion(POOL_REWARD); - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward); - const { logs } = await withdrawAndSyncDelegatorRewardsAsync(); - verifyEventsFromLogs( - logs, - [{ _from: testContract.address, _to: DELEGATOR, _value: finalizedReward }], - Events.Transfer, - ); - }); - it('reduces `rewardsByPoolId` for the pool', async () => { - const finalizedReward = getRandomPortion(POOL_REWARD); - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward); - await withdrawAndSyncDelegatorRewardsAsync(); - const poolReward = await testContract.rewardsByPoolId(POOL_ID).callAsync(); - expect(poolReward).to.bignumber.eq(POOL_REWARD.minus(finalizedReward)); - }); - it('reduces `wethReservedForPoolRewards` for the pool', async () => { - const finalizedReward = getRandomPortion(POOL_REWARD); - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward); - await withdrawAndSyncDelegatorRewardsAsync(); - const wethReserved = await testContract.wethReservedForPoolRewards().callAsync(); - expect(wethReserved).to.bignumber.eq(WETH_RESERVED_FOR_POOL_REWARDS.minus(finalizedReward)); - }); - it('syncs `_delegatedStakeToPoolByOwner`', async () => { - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, getRandomPortion(POOL_REWARD)); - await withdrawAndSyncDelegatorRewardsAsync(); - const stakeAfter = await testContract.delegatedStakeToPoolByOwner(DELEGATOR, POOL_ID).callAsync(); - // `_loadCurrentBalance` is overridden to just increment `currentEpoch`. - expect(stakeAfter).to.deep.eq({ - currentEpoch: stake.currentEpoch.plus(1), - currentEpochBalance: stake.currentEpochBalance, - nextEpochBalance: stake.nextEpochBalance, - }); - }); - it('does not transfer zero rewards', async () => { - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, 0); - const { logs } = await withdrawAndSyncDelegatorRewardsAsync(); - verifyEventsFromLogs(logs, [], Events.Transfer); - }); - it('no rewards if the delegated stake epoch == current epoch', async () => { - // Set some finalized rewards that should be ignored. - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, getRandomInteger(1, POOL_REWARD)); - await testContract.setCurrentEpoch(stake.currentEpoch).awaitTransactionSuccessAsync(); - const { logs } = await withdrawAndSyncDelegatorRewardsAsync(); - // There will be no Transfer events if computed rewards are zero. - verifyEventsFromLogs(logs, [], Events.Transfer); - }); - }); - - describe('computeRewardBalanceOfOperator()', () => { - async function computeRewardBalanceOfOperatorAsync(): Promise { - return testContract.computeRewardBalanceOfOperator(POOL_ID).callAsync(); - } - - it('returns only unfinalized rewards', async () => { - const unfinalizedReward = getRandomInteger(1, 1e18); - await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, getRandomInteger(1, 1e18)); - // Set some unfinalized state for a call to `_computeDelegatorReward()`, - // which should not be called. - await setComputeDelegatorRewardStateAsync(POOL_ID, OPERATOR, getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfOperatorAsync(); - const expectedReward = toOperatorPortion(OPERATOR_SHARE, unfinalizedReward); - expect(reward).to.bignumber.eq(expectedReward); - }); - it('returns operator portion of unfinalized rewards', async () => { - const unfinalizedReward = getRandomInteger(1, 1e18); - await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfOperatorAsync(); - const expectedReward = toOperatorPortion(OPERATOR_SHARE, unfinalizedReward); - expect(reward).to.bignumber.eq(expectedReward); - }); - it('returns zero if no unfinalized rewards', async () => { - await setUnfinalizedPoolRewardsAsync(POOL_ID, 0, getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfOperatorAsync(); - expect(reward).to.bignumber.eq(0); - }); - it('returns all unfinalized reward if member stake is zero', async () => { - const unfinalizedReward = getRandomInteger(1, 1e18); - await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, 0); - const reward = await computeRewardBalanceOfOperatorAsync(); - expect(reward).to.bignumber.eq(unfinalizedReward); - }); - it('returns no reward if operator share is zero', async () => { - await testContract - .setPool(POOL_ID, { - operator: OPERATOR, - operatorShare: constants.ZERO_AMOUNT, - }) - .awaitTransactionSuccessAsync(); - await setUnfinalizedPoolRewardsAsync(POOL_ID, getRandomInteger(1, 1e18), getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfOperatorAsync(); - expect(reward).to.bignumber.eq(0); - }); - it('returns all unfinalized reward if operator share is 100%', async () => { - await testContract - .setPool(POOL_ID, { - operator: OPERATOR, - operatorShare: constants.PPM_100_PERCENT, - }) - .awaitTransactionSuccessAsync(); - const unfinalizedReward = getRandomInteger(1, 1e18); - await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfOperatorAsync(); - expect(reward).to.bignumber.eq(unfinalizedReward); - }); - }); - - describe('computeRewardBalanceOfDelegator()', () => { - const DELEGATOR = randomAddress(); - let currentEpoch: BigNumber; - let stake: StoredBalance; - - before(async () => { - currentEpoch = await testContract.currentEpoch().callAsync(); - stake = await setStakeAsync(POOL_ID, DELEGATOR); - }); - - async function computeRewardBalanceOfDelegatorAsync(): Promise { - return testContract.computeRewardBalanceOfDelegator(POOL_ID, DELEGATOR).callAsync(); - } - - function getDelegatorPortionOfUnfinalizedReward( - unfinalizedReward: Numberish, - unfinalizedMembersStake: Numberish, - ): BigNumber { - const unfinalizedStakeBalance = stake.currentEpoch.gte(currentEpoch) - ? stake.currentEpochBalance - : stake.nextEpochBalance; - return ReferenceFunctions.getPartialAmountFloor( - unfinalizedStakeBalance, - new BigNumber(unfinalizedMembersStake), - toMembersPortion(OPERATOR_SHARE, unfinalizedReward), - ); - } - - it('returns zero when no finalized or unfinalized rewards', async () => { - const reward = await computeRewardBalanceOfDelegatorAsync(); - expect(reward).to.bignumber.eq(0); - }); - it('returns only unfinalized rewards when no finalized rewards', async () => { - const unfinalizedReward = getRandomInteger(1, 1e18); - const unfinalizedMembersStake = getRandomInteger(1, 1e18); - await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, unfinalizedMembersStake); - const expectedReward = getDelegatorPortionOfUnfinalizedReward(unfinalizedReward, unfinalizedMembersStake); - const reward = await computeRewardBalanceOfDelegatorAsync(); - expect(reward).to.bignumber.eq(expectedReward); - }); - it("returns zero when delegator's synced stake was zero in the last epoch and no finalized rewards", async () => { - await setStakeAsync(POOL_ID, DELEGATOR, { - ...stake, - currentEpoch: currentEpoch.minus(1), - currentEpochBalance: constants.ZERO_AMOUNT, - }); - await setUnfinalizedPoolRewardsAsync(POOL_ID, getRandomInteger(1, 1e18), getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfDelegatorAsync(); - expect(reward).to.bignumber.eq(0); - }); - it("returns zero when delegator's unsynced stake was zero in the last epoch and no finalized rewards", async () => { - const epoch = 2; - await setStakeAsync(POOL_ID, DELEGATOR, { - ...stake, - currentEpoch: new BigNumber(epoch - 2), - nextEpochBalance: constants.ZERO_AMOUNT, - }); - await testContract.setCurrentEpoch(new BigNumber(epoch)).awaitTransactionSuccessAsync(); - await setUnfinalizedPoolRewardsAsync(POOL_ID, getRandomInteger(1, 1e18), getRandomInteger(1, 1e18)); - const reward = await computeRewardBalanceOfDelegatorAsync(); - expect(reward).to.bignumber.eq(0); - }); - it('returns only finalized rewards when no unfinalized rewards', async () => { - const finalizedReward = getRandomInteger(1, 1e18); - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward); - const reward = await computeRewardBalanceOfDelegatorAsync(); - expect(reward).to.bignumber.eq(finalizedReward); - }); - it('returns both unfinalized and finalized rewards', async () => { - const unfinalizedReward = getRandomInteger(1, 1e18); - const unfinalizedMembersStake = getRandomInteger(1, 1e18); - await setUnfinalizedPoolRewardsAsync(POOL_ID, unfinalizedReward, unfinalizedMembersStake); - const finalizedReward = getRandomInteger(1, 1e18); - await setComputeDelegatorRewardStateAsync(POOL_ID, DELEGATOR, finalizedReward); - const delegatorUnfinalizedReward = getDelegatorPortionOfUnfinalizedReward( - unfinalizedReward, - unfinalizedMembersStake, - ); - const expectedReward = delegatorUnfinalizedReward.plus(finalizedReward); - const reward = await computeRewardBalanceOfDelegatorAsync(); - expect(reward).to.bignumber.eq(expectedReward); - }); - }); - - describe('_syncPoolRewards()', async () => { - const POOL_REWARD = getRandomInteger(1, 100e18); - const WETH_RESERVED_FOR_POOL_REWARDS = POOL_REWARD.plus(getRandomInteger(1, 100e18)); - - before(async () => { - await testContract.setPoolRewards(POOL_ID, POOL_REWARD).awaitTransactionSuccessAsync(); - await testContract - .setWethReservedForPoolRewards(WETH_RESERVED_FOR_POOL_REWARDS) - .awaitTransactionSuccessAsync(); - }); - - async function syncPoolRewardsAsync( - reward: Numberish, - membersStake: Numberish, - ): Promise<[[BigNumber, BigNumber], LogEntry[]]> { - const contractFn = testContract.syncPoolRewards( - POOL_ID, - new BigNumber(reward), - new BigNumber(membersStake), - ); - const result = await contractFn.callAsync(); - const { logs } = await contractFn.awaitTransactionSuccessAsync(); - return [result, logs]; - } - - it("transfers operator's portion of the reward to the operator", async () => { - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - const [, logs] = await syncPoolRewardsAsync(totalReward, membersStake); - const expectedOperatorReward = toOperatorPortion(OPERATOR_SHARE, totalReward); - verifyEventsFromLogs( - logs, - [{ _from: testContract.address, _to: OPERATOR, _value: expectedOperatorReward }], - Events.Transfer, - ); - }); - it("increases `rewardsByPoolId` with members' portion of rewards", async () => { - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - await syncPoolRewardsAsync(totalReward, membersStake); - const expectedMembersReward = toMembersPortion(OPERATOR_SHARE, totalReward); - const poolReward = await testContract.rewardsByPoolId(POOL_ID).callAsync(); - expect(poolReward).to.bignumber.eq(POOL_REWARD.plus(expectedMembersReward)); - }); - it("increases `wethReservedForPoolRewards` with members' portion of rewards", async () => { - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - await syncPoolRewardsAsync(totalReward, membersStake); - const expectedMembersReward = toMembersPortion(OPERATOR_SHARE, totalReward); - const wethReserved = await testContract.wethReservedForPoolRewards().callAsync(); - expect(wethReserved).to.bignumber.eq(WETH_RESERVED_FOR_POOL_REWARDS.plus(expectedMembersReward)); - }); - it("returns operator and members' portion of the reward", async () => { - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - const [[operatorReward, membersReward]] = await syncPoolRewardsAsync(totalReward, membersStake); - const expectedOperatorReward = toOperatorPortion(OPERATOR_SHARE, totalReward); - const expectedMembersReward = toMembersPortion(OPERATOR_SHARE, totalReward); - expect(operatorReward).to.bignumber.eq(expectedOperatorReward); - expect(membersReward).to.bignumber.eq(expectedMembersReward); - }); - it("gives all rewards to operator if members' stake is zero", async () => { - const totalReward = getRandomInteger(1, 1e18); - const [[operatorReward, membersReward], logs] = await syncPoolRewardsAsync(totalReward, 0); - expect(operatorReward).to.bignumber.eq(totalReward); - expect(membersReward).to.bignumber.eq(0); - verifyEventsFromLogs( - logs, - [{ _from: testContract.address, _to: OPERATOR, _value: totalReward }], - Events.Transfer, - ); - }); - it("gives all rewards to members if operator's share is zero", async () => { - const totalReward = getRandomInteger(1, 1e18); - await testContract - .setPool(POOL_ID, { - operator: OPERATOR, - operatorShare: constants.ZERO_AMOUNT, - }) - .awaitTransactionSuccessAsync(); - const [[operatorReward, membersReward], logs] = await syncPoolRewardsAsync( - totalReward, - getRandomInteger(1, 1e18), - ); - expect(operatorReward).to.bignumber.eq(0); - expect(membersReward).to.bignumber.eq(totalReward); - // Should be no transfer to the operator. - verifyEventsFromLogs(logs, [], Events.Transfer); - }); - }); - - describe('_computePoolRewardsSplit', () => { - it("gives all rewards to operator if members' stake is zero", async () => { - const operatorShare = getRandomPortion(constants.PPM_100_PERCENT); - const totalReward = getRandomInteger(1, 1e18); - const membersStake = constants.ZERO_AMOUNT; - const [operatorReward, membersReward] = await testContract - .computePoolRewardsSplit(operatorShare, totalReward, membersStake) - .callAsync(); - expect(operatorReward).to.bignumber.eq(totalReward); - expect(membersReward).to.bignumber.eq(0); - }); - it("gives all rewards to operator if members' stake is zero and operator share is zero", async () => { - const operatorShare = constants.ZERO_AMOUNT; - const totalReward = getRandomInteger(1, 1e18); - const membersStake = constants.ZERO_AMOUNT; - const [operatorReward, membersReward] = await testContract - .computePoolRewardsSplit(operatorShare, totalReward, membersStake) - .callAsync(); - expect(operatorReward).to.bignumber.eq(totalReward); - expect(membersReward).to.bignumber.eq(0); - }); - it('gives all rewards to operator if operator share is 100%', async () => { - const operatorShare = constants.PPM_100_PERCENT; - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - const [operatorReward, membersReward] = await testContract - .computePoolRewardsSplit(operatorShare, totalReward, membersStake) - .callAsync(); - expect(operatorReward).to.bignumber.eq(totalReward); - expect(membersReward).to.bignumber.eq(0); - }); - it('gives all rewards to members if operator share is 0%', async () => { - const operatorShare = constants.ZERO_AMOUNT; - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - const [operatorReward, membersReward] = await testContract - .computePoolRewardsSplit(operatorShare, totalReward, membersStake) - .callAsync(); - expect(operatorReward).to.bignumber.eq(0); - expect(membersReward).to.bignumber.eq(totalReward); - }); - it('splits rewards between operator and members based on operator share', async () => { - const operatorShare = getRandomPortion(constants.PPM_100_PERCENT); - const totalReward = getRandomInteger(1, 1e18); - const membersStake = getRandomInteger(1, 1e18); - const [operatorReward, membersReward] = await testContract - .computePoolRewardsSplit(operatorShare, totalReward, membersStake) - .callAsync(); - expect(operatorReward).to.bignumber.eq(toOperatorPortion(operatorShare, totalReward)); - expect(membersReward).to.bignumber.eq(toMembersPortion(operatorShare, totalReward)); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/params_test.ts b/contracts/staking/test/unit_tests/params_test.ts deleted file mode 100644 index c933242dcc..0000000000 --- a/contracts/staking/test/unit_tests/params_test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { blockchainTests, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { AuthorizableRevertErrors } from '@0x/contracts-utils'; -import { BigNumber } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { IStakingEventsParamsSetEventArgs, TestMixinParamsContract } from '../wrappers'; - -import { constants as stakingConstants } from '../../src/constants'; -import { StakingParams } from '../../src/types'; - -blockchainTests('Configurable Parameters unit tests', env => { - let testContract: TestMixinParamsContract; - let authorizedAddress: string; - let notAuthorizedAddress: string; - - before(async () => { - [authorizedAddress, notAuthorizedAddress] = await env.getAccountAddressesAsync(); - testContract = await TestMixinParamsContract.deployFrom0xArtifactAsync( - artifacts.TestMixinParams, - env.provider, - env.txDefaults, - artifacts, - ); - await testContract.addAuthorizedAddress(authorizedAddress).awaitTransactionSuccessAsync(); - }); - - blockchainTests.resets('setParams()', () => { - async function setParamsAndAssertAsync( - params: Partial, - from?: string, - ): Promise { - const _params = { - ...stakingConstants.DEFAULT_PARAMS, - ...params, - }; - const receipt = await testContract - .setParams( - new BigNumber(_params.epochDurationInSeconds), - new BigNumber(_params.rewardDelegatedStakeWeight), - new BigNumber(_params.minimumPoolStake), - new BigNumber(_params.cobbDouglasAlphaNumerator), - new BigNumber(_params.cobbDouglasAlphaDenominator), - ) - .awaitTransactionSuccessAsync({ from }); - // Assert event. - const events = filterLogsToArguments(receipt.logs, 'ParamsSet'); - expect(events.length).to.eq(1); - const event = events[0]; - expect(event.epochDurationInSeconds).to.bignumber.eq(_params.epochDurationInSeconds); - expect(event.rewardDelegatedStakeWeight).to.bignumber.eq(_params.rewardDelegatedStakeWeight); - expect(event.minimumPoolStake).to.bignumber.eq(_params.minimumPoolStake); - expect(event.cobbDouglasAlphaNumerator).to.bignumber.eq(_params.cobbDouglasAlphaNumerator); - expect(event.cobbDouglasAlphaDenominator).to.bignumber.eq(_params.cobbDouglasAlphaDenominator); - // Assert `getParams()`. - const actual = await testContract.getParams().callAsync(); - expect(actual[0]).to.bignumber.eq(_params.epochDurationInSeconds); - expect(actual[1]).to.bignumber.eq(_params.rewardDelegatedStakeWeight); - expect(actual[2]).to.bignumber.eq(_params.minimumPoolStake); - expect(actual[3]).to.bignumber.eq(_params.cobbDouglasAlphaNumerator); - expect(actual[4]).to.bignumber.eq(_params.cobbDouglasAlphaDenominator); - return receipt; - } - - it('throws if not called by an authorized address', async () => { - const tx = setParamsAndAssertAsync({}, notAuthorizedAddress); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddress); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if `assertValidStorageParams()` throws`', async () => { - await testContract.setShouldFailAssertValidStorageParams(true).awaitTransactionSuccessAsync(); - const tx = setParamsAndAssertAsync({}); - return expect(tx).to.revertWith('ASSERT_VALID_STORAGE_PARAMS_FAILED'); - }); - - it('works if called by owner', async () => { - return setParamsAndAssertAsync({}); - }); - }); -}); -// tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/unit_tests/protocol_fees_test.ts b/contracts/staking/test/unit_tests/protocol_fees_test.ts deleted file mode 100644 index 44b75d0085..0000000000 --- a/contracts/staking/test/unit_tests/protocol_fees_test.ts +++ /dev/null @@ -1,474 +0,0 @@ -import { - blockchainTests, - constants, - expect, - filterLogsToArguments, - getRandomInteger, - Numberish, - randomAddress, -} from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils, StakingRevertErrors } from '@0x/utils'; -import { LogEntry } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { - IStakingEventsEvents, - IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs, - TestProtocolFeesContract, - TestProtocolFeesERC20ProxyTransferFromEventArgs, - TestProtocolFeesEvents, -} from '../wrappers'; - -blockchainTests('Protocol Fees unit tests', env => { - let ownerAddress: string; - let exchangeAddress: string; - let notExchangeAddress: string; - let testContract: TestProtocolFeesContract; - let minimumStake: BigNumber; - - before(async () => { - [ownerAddress, exchangeAddress, notExchangeAddress] = await env.web3Wrapper.getAvailableAddressesAsync(); - - // Deploy the protocol fees contract. - testContract = await TestProtocolFeesContract.deployFrom0xArtifactAsync( - artifacts.TestProtocolFees, - env.provider, - { - ...env.txDefaults, - from: ownerAddress, - }, - artifacts, - exchangeAddress, - ); - - minimumStake = (await testContract.getParams().callAsync())[2]; - }); - - interface CreateTestPoolOpts { - poolId: string; - operatorStake: Numberish; - membersStake: Numberish; - makers: string[]; - } - - async function createTestPoolAsync(opts?: Partial): Promise { - const _opts = { - poolId: hexUtils.random(), - operatorStake: getRandomInteger(minimumStake, '100e18'), - membersStake: getRandomInteger(minimumStake, '100e18'), - makers: _.times(2, () => randomAddress()), - ...opts, - }; - await testContract - .createTestPool( - _opts.poolId, - new BigNumber(_opts.operatorStake), - new BigNumber(_opts.membersStake), - _opts.makers, - ) - .awaitTransactionSuccessAsync(); - return _opts; - } - - blockchainTests.resets('payProtocolFee()', () => { - const DEFAULT_PROTOCOL_FEE_PAID = new BigNumber(150e3).times(1e9); - const { ZERO_AMOUNT } = constants; - const makerAddress = randomAddress(); - const payerAddress = randomAddress(); - - describe('forbidden actions', () => { - it('should revert if called by a non-exchange', async () => { - const tx = testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: notExchangeAddress }); - const expectedError = new StakingRevertErrors.OnlyCallableByExchangeError(notExchangeAddress); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if `protocolFee` is zero with non-zero value sent', async () => { - const tx = testContract - .payProtocolFee(makerAddress, payerAddress, ZERO_AMOUNT) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - const expectedError = new StakingRevertErrors.InvalidProtocolFeePaymentError( - ZERO_AMOUNT, - DEFAULT_PROTOCOL_FEE_PAID, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if `protocolFee` is < than the provided message value', async () => { - const tx = testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID.minus(1) }); - const expectedError = new StakingRevertErrors.InvalidProtocolFeePaymentError( - DEFAULT_PROTOCOL_FEE_PAID, - DEFAULT_PROTOCOL_FEE_PAID.minus(1), - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if `protocolFee` is > than the provided message value', async () => { - const tx = testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID.plus(1) }); - const expectedError = new StakingRevertErrors.InvalidProtocolFeePaymentError( - DEFAULT_PROTOCOL_FEE_PAID, - DEFAULT_PROTOCOL_FEE_PAID.plus(1), - ); - return expect(tx).to.revertWith(expectedError); - }); - }); - - async function getProtocolFeesAsync(poolId: string): Promise { - return (await testContract.getStakingPoolStatsThisEpoch(poolId).callAsync()).feesCollected; - } - - describe('ETH fees', () => { - function assertNoWETHTransferLogs(logs: LogEntry[]): void { - const logsArgs = filterLogsToArguments( - logs, - TestProtocolFeesEvents.ERC20ProxyTransferFrom, - ); - expect(logsArgs).to.deep.eq([]); - } - - it('should not transfer WETH if value is sent', async () => { - await createTestPoolAsync({ operatorStake: minimumStake }); - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - assertNoWETHTransferLogs(receipt.logs); - }); - - it('should credit pool if the maker is in a pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] }); - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - - assertNoWETHTransferLogs(receipt.logs); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID); - }); - - it('should not credit the pool if maker is not in a pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake }); - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - assertNoWETHTransferLogs(receipt.logs); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(ZERO_AMOUNT); - }); - - it('fees paid to the same maker should go to the same pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] }); - const payAsync = async () => { - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - assertNoWETHTransferLogs(receipt.logs); - }; - await payAsync(); - await payAsync(); - const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(expectedTotalFees); - }); - }); - - describe('WETH fees', () => { - function assertWETHTransferLogs(logs: LogEntry[], fromAddress: string, amount: BigNumber): void { - const logsArgs = filterLogsToArguments( - logs, - TestProtocolFeesEvents.ERC20ProxyTransferFrom, - ); - expect(logsArgs.length).to.eq(1); - for (const args of logsArgs) { - expect(args.from).to.eq(fromAddress); - expect(args.to).to.eq(testContract.address); - expect(args.amount).to.bignumber.eq(amount); - } - } - - it('should transfer WETH if no value is sent and the maker is not in a pool', async () => { - await createTestPoolAsync({ operatorStake: minimumStake }); - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: ZERO_AMOUNT }); - assertWETHTransferLogs(receipt.logs, payerAddress, DEFAULT_PROTOCOL_FEE_PAID); - }); - - it('should update `protocolFeesThisEpochByPool` if the maker is in a pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] }); - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: ZERO_AMOUNT }); - assertWETHTransferLogs(receipt.logs, payerAddress, DEFAULT_PROTOCOL_FEE_PAID); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID); - }); - - it('should not update `protocolFeesThisEpochByPool` if maker is not in a pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake }); - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: ZERO_AMOUNT }); - assertWETHTransferLogs(receipt.logs, payerAddress, DEFAULT_PROTOCOL_FEE_PAID); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(ZERO_AMOUNT); - }); - - it('fees paid to the same maker should go to the same pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] }); - const payAsync = async () => { - const receipt = await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: ZERO_AMOUNT }); - assertWETHTransferLogs(receipt.logs, payerAddress, DEFAULT_PROTOCOL_FEE_PAID); - }; - await payAsync(); - await payAsync(); - const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(expectedTotalFees); - }); - - it('fees paid to the same maker in WETH then ETH should go to the same pool', async () => { - const { poolId } = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] }); - const payAsync = async (inWETH: boolean) => { - await testContract - .payProtocolFee(makerAddress, payerAddress, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ - from: exchangeAddress, - value: inWETH ? ZERO_AMOUNT : DEFAULT_PROTOCOL_FEE_PAID, - }); - }; - await payAsync(true); - await payAsync(false); - const expectedTotalFees = DEFAULT_PROTOCOL_FEE_PAID.times(2); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(expectedTotalFees); - }); - }); - - describe('Dust stake', () => { - it('credits pools with stake > minimum', async () => { - const { poolId } = await createTestPoolAsync({ - operatorStake: minimumStake.plus(1), - membersStake: 0, - makers: [makerAddress], - }); - await testContract - .payProtocolFee(makerAddress, constants.NULL_ADDRESS, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - const feesCredited = await getProtocolFeesAsync(poolId); - expect(feesCredited).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID); - }); - - it('credits pools with stake == minimum', async () => { - const { poolId } = await createTestPoolAsync({ - operatorStake: minimumStake, - membersStake: 0, - makers: [makerAddress], - }); - await testContract - .payProtocolFee(makerAddress, constants.NULL_ADDRESS, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - const feesCredited = await getProtocolFeesAsync(poolId); - expect(feesCredited).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID); - }); - - it('does not credit pools with stake < minimum', async () => { - const { poolId } = await createTestPoolAsync({ - operatorStake: minimumStake.minus(1), - membersStake: 0, - makers: [makerAddress], - }); - await testContract - .payProtocolFee(makerAddress, constants.NULL_ADDRESS, DEFAULT_PROTOCOL_FEE_PAID) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: DEFAULT_PROTOCOL_FEE_PAID }); - const feesCredited = await getProtocolFeesAsync(poolId); - expect(feesCredited).to.bignumber.eq(0); - }); - }); - - blockchainTests.resets('Finalization', () => { - let membersStakeWeight: number; - - before(async () => { - membersStakeWeight = (await testContract.getParams().callAsync())[1]; - }); - - interface FinalizationState { - numPoolsToFinalize: BigNumber; - totalFeesCollected: BigNumber; - totalWeightedStake: BigNumber; - } - - async function getFinalizationStateAsync(): Promise { - const aggregatedStats = await testContract.getAggregatedStatsForCurrentEpoch().callAsync(); - return { - numPoolsToFinalize: aggregatedStats.numPoolsToFinalize, - totalFeesCollected: aggregatedStats.totalFeesCollected, - totalWeightedStake: aggregatedStats.totalWeightedStake, - }; - } - - interface PayToMakerResult { - poolEarnedRewardsEvents: IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs[]; - fee: BigNumber; - } - - async function payToMakerAsync(poolMaker: string, fee?: Numberish): Promise { - const _fee = fee === undefined ? getRandomInteger(1, '1e18') : fee; - const receipt = await testContract - .payProtocolFee(poolMaker, payerAddress, new BigNumber(_fee)) - .awaitTransactionSuccessAsync({ from: exchangeAddress, value: _fee }); - const events = filterLogsToArguments( - receipt.logs, - IStakingEventsEvents.StakingPoolEarnedRewardsInEpoch, - ); - return { - fee: new BigNumber(_fee), - poolEarnedRewardsEvents: events, - }; - } - - function toWeightedStake(operatorStake: Numberish, membersStake: Numberish): BigNumber { - return new BigNumber(membersStake) - .times(membersStakeWeight) - .dividedToIntegerBy(constants.PPM_DENOMINATOR) - .plus(operatorStake); - } - - it('no pools to finalize to start', async () => { - const state = await getFinalizationStateAsync(); - expect(state.numPoolsToFinalize).to.bignumber.eq(0); - expect(state.totalFeesCollected).to.bignumber.eq(0); - expect(state.totalWeightedStake).to.bignumber.eq(0); - }); - - it('pool is not registered to start', async () => { - const { poolId } = await createTestPoolAsync(); - const pool = await testContract.getStakingPoolStatsThisEpoch(poolId).callAsync(); - expect(pool.feesCollected).to.bignumber.eq(0); - expect(pool.membersStake).to.bignumber.eq(0); - expect(pool.weightedStake).to.bignumber.eq(0); - }); - - it('correctly emits event for pool the first time it earns a fee', async () => { - const pool = await createTestPoolAsync(); - const { - poolId, - makers: [poolMaker], - } = pool; - const { fee, poolEarnedRewardsEvents } = await payToMakerAsync(poolMaker); - expect(poolEarnedRewardsEvents.length).to.eq(1); - expect(poolEarnedRewardsEvents[0].poolId).to.eq(poolId); - const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch(poolId).callAsync(); - const expectedWeightedStake = toWeightedStake(pool.operatorStake, pool.membersStake); - expect(actualPoolStats.feesCollected).to.bignumber.eq(fee); - expect(actualPoolStats.membersStake).to.bignumber.eq(pool.membersStake); - expect(actualPoolStats.weightedStake).to.bignumber.eq(expectedWeightedStake); - const state = await getFinalizationStateAsync(); - expect(state.numPoolsToFinalize).to.bignumber.eq(1); - expect(state.totalFeesCollected).to.bignumber.eq(fee); - expect(state.totalWeightedStake).to.bignumber.eq(expectedWeightedStake); - }); - - it('only adds to the already activated pool in the same epoch', async () => { - const pool = await createTestPoolAsync(); - const { - poolId, - makers: [poolMaker], - } = pool; - const { fee: fee1 } = await payToMakerAsync(poolMaker); - const { fee: fee2, poolEarnedRewardsEvents } = await payToMakerAsync(poolMaker); - expect(poolEarnedRewardsEvents).to.deep.eq([]); - const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch(poolId).callAsync(); - const expectedWeightedStake = toWeightedStake(pool.operatorStake, pool.membersStake); - const fees = BigNumber.sum(fee1, fee2); - expect(actualPoolStats.feesCollected).to.bignumber.eq(fees); - expect(actualPoolStats.membersStake).to.bignumber.eq(pool.membersStake); - expect(actualPoolStats.weightedStake).to.bignumber.eq(expectedWeightedStake); - const state = await getFinalizationStateAsync(); - expect(state.numPoolsToFinalize).to.bignumber.eq(1); - expect(state.totalFeesCollected).to.bignumber.eq(fees); - expect(state.totalWeightedStake).to.bignumber.eq(expectedWeightedStake); - }); - - it('can activate multiple pools in the same epoch', async () => { - const pools = await Promise.all(_.times(3, async () => createTestPoolAsync())); - let totalFees = new BigNumber(0); - let totalWeightedStake = new BigNumber(0); - for (const pool of pools) { - const { - poolId, - makers: [poolMaker], - } = pool; - const { fee, poolEarnedRewardsEvents } = await payToMakerAsync(poolMaker); - expect(poolEarnedRewardsEvents.length).to.eq(1); - expect(poolEarnedRewardsEvents[0].poolId).to.eq(poolId); - const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch(poolId).callAsync(); - const expectedWeightedStake = toWeightedStake(pool.operatorStake, pool.membersStake); - expect(actualPoolStats.feesCollected).to.bignumber.eq(fee); - expect(actualPoolStats.membersStake).to.bignumber.eq(pool.membersStake); - expect(actualPoolStats.weightedStake).to.bignumber.eq(expectedWeightedStake); - totalFees = totalFees.plus(fee); - totalWeightedStake = totalWeightedStake.plus(expectedWeightedStake); - } - const state = await getFinalizationStateAsync(); - expect(state.numPoolsToFinalize).to.bignumber.eq(pools.length); - expect(state.totalFeesCollected).to.bignumber.eq(totalFees); - expect(state.totalWeightedStake).to.bignumber.eq(totalWeightedStake); - }); - - it('resets the pool after the epoch advances', async () => { - const pool = await createTestPoolAsync(); - const { - poolId, - makers: [poolMaker], - } = pool; - await payToMakerAsync(poolMaker); - await testContract.advanceEpoch().awaitTransactionSuccessAsync(); - const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch(poolId).callAsync(); - expect(actualPoolStats.feesCollected).to.bignumber.eq(0); - expect(actualPoolStats.membersStake).to.bignumber.eq(0); - expect(actualPoolStats.weightedStake).to.bignumber.eq(0); - }); - - describe('Multiple makers', () => { - it('fees paid to different makers in the same pool go to that pool', async () => { - const { poolId, makers } = await createTestPoolAsync(); - const { fee: fee1 } = await payToMakerAsync(makers[0]); - const { fee: fee2 } = await payToMakerAsync(makers[1]); - const expectedTotalFees = BigNumber.sum(fee1, fee2); - const poolFees = await getProtocolFeesAsync(poolId); - expect(poolFees).to.bignumber.eq(expectedTotalFees); - }); - - it('fees paid to makers in different pools go to their respective pools', async () => { - const { - poolId: poolId1, - makers: [maker1], - } = await createTestPoolAsync(); - const { - poolId: poolId2, - makers: [maker2], - } = await createTestPoolAsync(); - const { fee: fee1 } = await payToMakerAsync(maker1); - const { fee: fee2 } = await payToMakerAsync(maker2); - const [poolFees, otherPoolFees] = await Promise.all([ - getProtocolFeesAsync(poolId1), - getProtocolFeesAsync(poolId2), - ]); - expect(poolFees).to.bignumber.eq(fee1); - expect(otherPoolFees).to.bignumber.eq(fee2); - }); - }); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/stake_balances_test.ts b/contracts/staking/test/unit_tests/stake_balances_test.ts deleted file mode 100644 index bf97830143..0000000000 --- a/contracts/staking/test/unit_tests/stake_balances_test.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; - -import { artifacts } from '../artifacts'; -import { TestMixinStakeBalancesContract } from '../wrappers'; - -import { constants as stakingConstants } from '../../src/constants'; -import { StakeStatus, StoredBalance } from '../../src/types'; - -blockchainTests.resets('MixinStakeBalances unit tests', env => { - let testContract: TestMixinStakeBalancesContract; - const { INITIAL_EPOCH } = stakingConstants; - const CURRENT_EPOCH = INITIAL_EPOCH.plus(1); - const EMPTY_BALANCE = { - currentEpochBalance: constants.ZERO_AMOUNT, - nextEpochBalance: constants.ZERO_AMOUNT, - currentEpoch: new BigNumber(1), - }; - - before(async () => { - testContract = await TestMixinStakeBalancesContract.deployFrom0xArtifactAsync( - artifacts.TestMixinStakeBalances, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - function randomAmount(): BigNumber { - return getRandomInteger(1, 100e18); - } - - function randomStoredBalance(): StoredBalance { - return { - currentEpochBalance: randomAmount(), - nextEpochBalance: randomAmount(), - currentEpoch: INITIAL_EPOCH, - }; - } - - // Mirrors the behavior of the `_loadCurrentBalance()` override in - // `TestMixinStakeBalances`. - function toCurrentBalance(balance: StoredBalance): StoredBalance { - return { - ...balance, - currentEpoch: balance.currentEpoch.plus(1), - }; - } - - describe('getGlobalStakeByStatus()', () => { - const delegatedBalance = randomStoredBalance(); - const zrxVaultBalance = randomAmount().plus( - BigNumber.max(delegatedBalance.currentEpochBalance, delegatedBalance.nextEpochBalance), - ); - - before(async () => { - await testContract - .setGlobalStakeByStatus(StakeStatus.Delegated, delegatedBalance) - .awaitTransactionSuccessAsync(); - await testContract.setBalanceOfZrxVault(zrxVaultBalance).awaitTransactionSuccessAsync(); - }); - - it('undelegated stake is the difference between zrx vault balance and global delegated stake', async () => { - const expectedBalance = { - currentEpoch: CURRENT_EPOCH, - currentEpochBalance: zrxVaultBalance.minus(delegatedBalance.currentEpochBalance), - nextEpochBalance: zrxVaultBalance.minus(delegatedBalance.nextEpochBalance), - }; - const actualBalance = await testContract.getGlobalStakeByStatus(StakeStatus.Undelegated).callAsync(); - expect(actualBalance).to.deep.eq(expectedBalance); - }); - - it('delegated stake is the global delegated stake', async () => { - const actualBalance = await testContract.getGlobalStakeByStatus(StakeStatus.Delegated).callAsync(); - expect(actualBalance).to.deep.eq(toCurrentBalance(delegatedBalance)); - }); - - it('undelegated stake throws if the zrx vault balance is below the delegated stake balance', async () => { - const _zrxVaultBalance = BigNumber.min( - delegatedBalance.currentEpochBalance, - delegatedBalance.nextEpochBalance, - ).minus(1); - await testContract.setBalanceOfZrxVault(_zrxVaultBalance).awaitTransactionSuccessAsync(); - const tx = testContract.getGlobalStakeByStatus(StakeStatus.Undelegated).callAsync(); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - _zrxVaultBalance, - delegatedBalance.currentEpochBalance.gt(_zrxVaultBalance) - ? delegatedBalance.currentEpochBalance - : delegatedBalance.nextEpochBalance, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if unknown stake status is passed in', async () => { - const tx = testContract.getGlobalStakeByStatus(2).callAsync(); - return expect(tx).to.be.rejected(); - }); - }); - - describe('getOwnerStakeByStatus()', () => { - const staker = randomAddress(); - const notStaker = randomAddress(); - const delegatedStake = randomStoredBalance(); - const undelegatedStake = randomStoredBalance(); - - before(async () => { - await testContract - .setOwnerStakeByStatus(staker, StakeStatus.Delegated, delegatedStake) - .awaitTransactionSuccessAsync(); - await testContract - .setOwnerStakeByStatus(staker, StakeStatus.Undelegated, undelegatedStake) - .awaitTransactionSuccessAsync(); - }); - - it('throws if unknown stake status is passed in', async () => { - const tx = testContract.getOwnerStakeByStatus(staker, 2).callAsync(); - return expect(tx).to.be.rejected(); - }); - - it('returns empty delegated stake for an unstaked owner', async () => { - const balance = await testContract.getOwnerStakeByStatus(notStaker, StakeStatus.Delegated).callAsync(); - expect(balance).to.deep.eq(EMPTY_BALANCE); - }); - - it('returns empty undelegated stake for an unstaked owner', async () => { - const balance = await testContract.getOwnerStakeByStatus(notStaker, StakeStatus.Undelegated).callAsync(); - expect(balance).to.deep.eq(EMPTY_BALANCE); - }); - - it('returns undelegated stake for a staked owner', async () => { - const balance = await testContract.getOwnerStakeByStatus(staker, StakeStatus.Undelegated).callAsync(); - expect(balance).to.deep.eq(toCurrentBalance(undelegatedStake)); - }); - - it('returns delegated stake for a staked owner', async () => { - const balance = await testContract.getOwnerStakeByStatus(staker, StakeStatus.Delegated).callAsync(); - expect(balance).to.deep.eq(toCurrentBalance(delegatedStake)); - }); - }); - - describe('getTotalStake()', () => { - const staker = randomAddress(); - const notStaker = randomAddress(); - const stakerAmount = randomAmount(); - - before(async () => { - await testContract.setZrxBalanceOf(staker, stakerAmount).awaitTransactionSuccessAsync(); - }); - - it('returns empty for unstaked owner', async () => { - const amount = await testContract.getTotalStake(notStaker).callAsync(); - expect(amount).to.bignumber.eq(0); - }); - - it('returns stake for staked owner', async () => { - const amount = await testContract.getTotalStake(staker).callAsync(); - expect(amount).to.bignumber.eq(stakerAmount); - }); - }); - - describe('getStakeDelegatedToPoolByOwner()', () => { - const staker = randomAddress(); - const notStaker = randomAddress(); - const poolId = hexUtils.random(); - const notPoolId = hexUtils.random(); - const delegatedBalance = randomStoredBalance(); - - before(async () => { - await testContract - .setDelegatedStakeToPoolByOwner(staker, poolId, delegatedBalance) - .awaitTransactionSuccessAsync(); - }); - - it('returns empty for unstaked owner', async () => { - const balance = await testContract.getStakeDelegatedToPoolByOwner(notStaker, poolId).callAsync(); - expect(balance).to.deep.eq(EMPTY_BALANCE); - }); - - it('returns empty for empty pool', async () => { - const balance = await testContract.getStakeDelegatedToPoolByOwner(staker, notPoolId).callAsync(); - expect(balance).to.deep.eq(EMPTY_BALANCE); - }); - - it('returns stake for staked owner in their pool', async () => { - const balance = await testContract.getStakeDelegatedToPoolByOwner(staker, poolId).callAsync(); - expect(balance).to.deep.eq(toCurrentBalance(delegatedBalance)); - }); - }); - - describe('getTotalStakeDelegatedToPool()', () => { - const poolId = hexUtils.random(); - const notPoolId = hexUtils.random(); - const delegatedBalance = randomStoredBalance(); - - before(async () => { - await testContract.setDelegatedStakeByPoolId(poolId, delegatedBalance).awaitTransactionSuccessAsync(); - }); - - it('returns empty for empty pool', async () => { - const balance = await testContract.getTotalStakeDelegatedToPool(notPoolId).callAsync(); - expect(balance).to.deep.eq(EMPTY_BALANCE); - }); - - it('returns stake for staked pool', async () => { - const balance = await testContract.getTotalStakeDelegatedToPool(poolId).callAsync(); - expect(balance).to.deep.eq(toCurrentBalance(delegatedBalance)); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/stake_test.ts b/contracts/staking/test/unit_tests/stake_test.ts deleted file mode 100644 index 9b130ac7d0..0000000000 --- a/contracts/staking/test/unit_tests/stake_test.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { - blockchainTests, - expect, - filterLogs, - filterLogsToArguments, - getRandomInteger, - Numberish, - shortZip, -} from '@0x/contracts-test-utils'; -import { BigNumber, hexUtils, StakingRevertErrors } from '@0x/utils'; -import * as _ from 'lodash'; - -import { StakeStatus } from '../../src/types'; - -import { artifacts } from '../artifacts'; -import { - TestMixinStakeContract, - TestMixinStakeDecreaseCurrentAndNextBalanceEventArgs as DecreaseCurrentAndNextBalanceEventArgs, - TestMixinStakeDecreaseNextBalanceEventArgs as DecreaseNextBalanceEventArgs, - TestMixinStakeEvents as StakeEvents, - TestMixinStakeIncreaseCurrentAndNextBalanceEventArgs as IncreaseCurrentAndNextBalanceEventArgs, - TestMixinStakeIncreaseNextBalanceEventArgs as IncreaseNextBalanceEventArgs, - TestMixinStakeMoveStakeEventArgs as MoveStakeEventArgs, - TestMixinStakeMoveStakeStorageEventArgs as MoveStakeStorageEventArgs, - TestMixinStakeStakeEventArgs as StakeEventArgs, - TestMixinStakeUnstakeEventArgs as UnstakeEventArgs, - TestMixinStakeWithdrawAndSyncDelegatorRewardsEventArgs as WithdrawAndSyncDelegatorRewardsEventArgs, - TestMixinStakeZrxVaultDepositFromEventArgs as ZrxVaultDepositFromEventArgs, - TestMixinStakeZrxVaultWithdrawFromEventArgs as ZrxVaultWithdrawFromEventArgs, -} from '../wrappers'; - -blockchainTests.resets('MixinStake unit tests', env => { - let testContract: TestMixinStakeContract; - let staker: string; - let stakerUndelegatedStakeSlot: string; - let currentEpoch: BigNumber; - - before(async () => { - [staker] = await env.getAccountAddressesAsync(); - testContract = await TestMixinStakeContract.deployFrom0xArtifactAsync( - artifacts.TestMixinStake, - env.provider, - env.txDefaults, - artifacts, - ); - currentEpoch = await testContract.currentEpoch().callAsync(); - stakerUndelegatedStakeSlot = await testContract - .getOwnerStakeByStatusSlot(staker, StakeStatus.Undelegated) - .callAsync(); - }); - - describe('stake()', () => { - it('deposits funds into the ZRX vault', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract.stake(amount).awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.ZrxVaultDepositFrom); - expect(events).to.be.length(1); - expect(events[0].staker).to.eq(staker); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('increases current and next undelegated stake balance', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract.stake(amount).awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - logs, - StakeEvents.IncreaseCurrentAndNextBalance, - ); - expect(events).to.be.length(1); - expect(events[0].balanceSlot).to.eq(stakerUndelegatedStakeSlot); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('raises a `Stake` event', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract.stake(amount).awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.Stake); - expect(events).to.be.length(1); - expect(events[0].staker).to.eq(staker); - expect(events[0].amount).to.bignumber.eq(amount); - }); - }); - - describe('unstake()', () => { - async function setUndelegatedStakeAsync( - currentEpochBalance: Numberish, - nextEpochBalance: Numberish, - ): Promise { - await testContract - .setOwnerStakeByStatus(staker, StakeStatus.Undelegated, { - currentEpoch, - currentEpochBalance: new BigNumber(currentEpochBalance), - nextEpochBalance: new BigNumber(nextEpochBalance), - }) - .awaitTransactionSuccessAsync(); - } - - it('throws if not enough undelegated stake in the current epoch', async () => { - const amount = getRandomInteger(0, 100e18); - await setUndelegatedStakeAsync(amount.minus(1), amount); - const tx = testContract.unstake(amount).awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InsufficientBalanceError(amount, amount.minus(1)); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if not enough undelegated stake in the next epoch', async () => { - const amount = getRandomInteger(0, 100e18); - await setUndelegatedStakeAsync(amount, amount.minus(1)); - const tx = testContract.unstake(amount).awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InsufficientBalanceError(amount, amount.minus(1)); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws if not enough undelegated stake in both epochs', async () => { - const amount = getRandomInteger(0, 100e18); - await setUndelegatedStakeAsync(amount.minus(1), amount.minus(1)); - const tx = testContract.unstake(amount).awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.InsufficientBalanceError(amount, amount.minus(1)); - return expect(tx).to.revertWith(expectedError); - }); - - it('decreases current and next undelegated stake balance', async () => { - const amount = getRandomInteger(0, 100e18); - await setUndelegatedStakeAsync(amount, amount); - const { logs } = await testContract.unstake(amount).awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - logs, - StakeEvents.DecreaseCurrentAndNextBalance, - ); - expect(events).to.be.length(1); - expect(events[0].balanceSlot).to.eq(stakerUndelegatedStakeSlot); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('withdraws funds from the ZRX vault', async () => { - const amount = getRandomInteger(0, 100e18); - await setUndelegatedStakeAsync(amount, amount); - const { logs } = await testContract.unstake(amount).awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.ZrxVaultWithdrawFrom); - expect(events).to.be.length(1); - expect(events[0].staker).to.eq(staker); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('emits an `Unstake` event', async () => { - const amount = getRandomInteger(0, 100e18); - await setUndelegatedStakeAsync(amount, amount); - const { logs } = await testContract.unstake(amount).awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.Unstake); - expect(events).to.be.length(1); - expect(events[0].staker).to.eq(staker); - expect(events[0].amount).to.bignumber.eq(amount); - }); - }); - - describe('moveStake()', () => { - const INVALID_POOL_ERROR = 'INVALID_POOL'; - const INVALID_POOL_ID = hexUtils.leftPad(0); - const VALID_POOL_IDS = [hexUtils.random(), hexUtils.random()]; - let delegatedStakeToPoolByOwnerSlots: string[]; - let delegatedStakeByPoolIdSlots: string[]; - let globalDelegatedStakeSlot: string; - let stakerDelegatedStakeSlot: string; - - before(async () => { - delegatedStakeToPoolByOwnerSlots = await Promise.all( - VALID_POOL_IDS.map(async poolId => - testContract.getDelegatedStakeToPoolByOwnerSlot(poolId, staker).callAsync(), - ), - ); - delegatedStakeByPoolIdSlots = await Promise.all( - VALID_POOL_IDS.map(async poolId => testContract.getDelegatedStakeByPoolIdSlot(poolId).callAsync()), - ); - globalDelegatedStakeSlot = await testContract.getGlobalStakeByStatusSlot(StakeStatus.Delegated).callAsync(); - stakerDelegatedStakeSlot = await testContract - .getOwnerStakeByStatusSlot(staker, StakeStatus.Delegated) - .callAsync(); - }); - - it('throws if the "from" pool is invalid', async () => { - const tx = testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: INVALID_POOL_ID }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(INVALID_POOL_ERROR); - }); - - it('throws if the "to" pool is invalid', async () => { - const tx = testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: INVALID_POOL_ID }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(INVALID_POOL_ERROR); - }); - - it('throws if the "from" and "to" pools are invalid', async () => { - const tx = testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: INVALID_POOL_ID }, - { status: StakeStatus.Delegated, poolId: INVALID_POOL_ID }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - return expect(tx).to.revertWith(INVALID_POOL_ERROR); - }); - - it('withdraws delegator rewards when "from" stake is delegated', async () => { - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[1] }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - logs, - StakeEvents.WithdrawAndSyncDelegatorRewards, - ); - expect(events).to.be.length(1); - expect(events[0].poolId).to.eq(VALID_POOL_IDS[0]); - expect(events[0].delegator).to.eq(staker); - }); - - it('withdraws delegator rewards when "to" stake is delegated', async () => { - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - logs, - StakeEvents.WithdrawAndSyncDelegatorRewards, - ); - expect(events).to.be.length(1); - expect(events[0].poolId).to.eq(VALID_POOL_IDS[1]); - expect(events[0].delegator).to.eq(staker); - }); - - it('withdraws delegator rewards when both stakes are both delegated', async () => { - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - logs, - StakeEvents.WithdrawAndSyncDelegatorRewards, - ); - expect(events).to.be.length(2); - for (const [event, poolId] of shortZip(events, VALID_POOL_IDS)) { - expect(event.poolId).to.eq(poolId); - expect(event.delegator).to.eq(staker); - } - }); - - it('does not withdraw delegator rewards when both stakes are both undelegated', async () => { - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[1] }, - getRandomInteger(0, 100e18), - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments( - logs, - StakeEvents.WithdrawAndSyncDelegatorRewards, - ); - expect(events).to.be.length(0); - }); - - it('decreases pool and global delegated stake counters when "from" stake is delegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const decreaseNextBalanceEvents = filterLogsToArguments( - logs, - StakeEvents.DecreaseNextBalance, - ); - const counters = [ - delegatedStakeToPoolByOwnerSlots[0], - delegatedStakeByPoolIdSlots[0], - globalDelegatedStakeSlot, - ]; - expect(decreaseNextBalanceEvents).to.be.length(3); - for (const [event, slot] of shortZip(decreaseNextBalanceEvents, counters)) { - expect(event.balanceSlot).to.eq(slot); - expect(event.amount).to.bignumber.eq(amount); - } - }); - - it('increases pool and global delegated stake counters when "to" stake is delegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const increaseNextBalanceEvents = filterLogsToArguments( - logs, - StakeEvents.IncreaseNextBalance, - ); - const counters = [ - delegatedStakeToPoolByOwnerSlots[1], - delegatedStakeByPoolIdSlots[1], - globalDelegatedStakeSlot, - ]; - expect(increaseNextBalanceEvents).to.be.length(3); - for (const [event, slot] of shortZip(increaseNextBalanceEvents, counters)) { - expect(event.balanceSlot).to.eq(slot); - expect(event.amount).to.bignumber.eq(amount); - } - }); - - it('decreases then increases pool and global delegated stake counters when both stakes are delegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const decreaseNextBalanceEvents = filterLogs( - logs, - StakeEvents.DecreaseNextBalance, - ); - const increaseNextBalanceEvents = filterLogs( - logs, - StakeEvents.IncreaseNextBalance, - ); - const decreaseCounters = [ - delegatedStakeToPoolByOwnerSlots[0], - delegatedStakeByPoolIdSlots[0], - globalDelegatedStakeSlot, - ]; - expect(decreaseNextBalanceEvents).to.be.length(3); - for (const [event, slot] of shortZip(decreaseNextBalanceEvents, decreaseCounters)) { - expect(event.args.balanceSlot).to.eq(slot); - expect(event.args.amount).to.bignumber.eq(amount); - } - const increaseCounters = [ - delegatedStakeToPoolByOwnerSlots[1], - delegatedStakeByPoolIdSlots[1], - globalDelegatedStakeSlot, - ]; - expect(increaseNextBalanceEvents).to.be.length(3); - for (const [event, slot] of shortZip(increaseNextBalanceEvents, increaseCounters)) { - expect(event.args.balanceSlot).to.eq(slot); - expect(event.args.amount).to.bignumber.eq(amount); - } - // Check that all decreases occur before the increases. - const maxDecreaseIndex = _.max(decreaseNextBalanceEvents.map(e => e.logIndex)) as number; - const maxIncreaseIndex = _.max(increaseNextBalanceEvents.map(e => e.logIndex)) as number; - expect(maxDecreaseIndex).to.be.lt(maxIncreaseIndex); - }); - - it('does not change pool and global delegated stake counters when both stakes are undelegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const decreaseNextBalanceEvents = filterLogsToArguments( - logs, - StakeEvents.DecreaseNextBalance, - ); - const increaseNextBalanceEvents = filterLogsToArguments( - logs, - StakeEvents.IncreaseNextBalance, - ); - expect(decreaseNextBalanceEvents).to.be.length(0); - expect(increaseNextBalanceEvents).to.be.length(0); - }); - - it('does nothing when moving the owner stake from undelegated to undelegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.MoveStakeStorage); - expect(events).to.be.length(0); - }); - - it('does nothing when moving zero stake', async () => { - const amount = new BigNumber(0); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.MoveStakeStorage); - expect(events).to.be.length(0); - }); - - it('moves the owner stake between the same pointer when both are delegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.MoveStakeStorage); - expect(events).to.be.length(1); - expect(events[0].fromBalanceSlot).to.eq(stakerDelegatedStakeSlot); - expect(events[0].toBalanceSlot).to.eq(stakerDelegatedStakeSlot); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('moves the owner stake between different pointers when "from" is undelegated and "to" is delegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.MoveStakeStorage); - expect(events).to.be.length(1); - expect(events[0].fromBalanceSlot).to.eq(stakerUndelegatedStakeSlot); - expect(events[0].toBalanceSlot).to.eq(stakerDelegatedStakeSlot); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('moves the owner stake between different pointers when "from" is delegated and "to" is undelegated', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.MoveStakeStorage); - expect(events).to.be.length(1); - expect(events[0].fromBalanceSlot).to.eq(stakerDelegatedStakeSlot); - expect(events[0].toBalanceSlot).to.eq(stakerUndelegatedStakeSlot); - expect(events[0].amount).to.bignumber.eq(amount); - }); - - it('emits a `MoveStake` event', async () => { - const amount = getRandomInteger(0, 100e18); - const { logs } = await testContract - .moveStake( - { status: StakeStatus.Undelegated, poolId: VALID_POOL_IDS[0] }, - { status: StakeStatus.Delegated, poolId: VALID_POOL_IDS[1] }, - amount, - ) - .awaitTransactionSuccessAsync(); - const events = filterLogsToArguments(logs, StakeEvents.MoveStake); - expect(events).to.be.length(1); - expect(events[0].staker).to.eq(staker); - expect(events[0].amount).to.bignumber.eq(amount); - expect(events[0].fromStatus).to.eq(StakeStatus.Undelegated); - expect(events[0].toStatus).to.eq(StakeStatus.Delegated); - expect(events[0].fromPool).to.eq(VALID_POOL_IDS[0]); - expect(events[0].toPool).to.eq(VALID_POOL_IDS[1]); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/staking_pool_test.ts b/contracts/staking/test/unit_tests/staking_pool_test.ts deleted file mode 100644 index 9615a79747..0000000000 --- a/contracts/staking/test/unit_tests/staking_pool_test.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { - blockchainTests, - constants, - expect, - filterLogsToArguments, - verifyEventsFromLogs, -} from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { BigNumber, hexUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { StakingRevertErrors } from '../../src'; - -import { artifacts } from '../artifacts'; -import { - TestMixinStakingPoolContract, - TestMixinStakingPoolEvents, - TestMixinStakingPoolStakingPoolCreatedEventArgs as StakingPoolCreated, -} from '../wrappers'; - -blockchainTests.resets('MixinStakingPool unit tests', env => { - let testContract: TestMixinStakingPoolContract; - let operator: string; - let maker: string; - let notOperatorOrMaker: string; - - before(async () => { - [operator, maker, notOperatorOrMaker] = await env.getAccountAddressesAsync(); - testContract = await TestMixinStakingPoolContract.deployFrom0xArtifactAsync( - artifacts.TestMixinStakingPool, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - function toNextPoolId(lastPoolId: string): string { - return hexUtils.leftPad(new BigNumber(lastPoolId.slice(2), 16).plus(1)); - } - - function randomOperatorShare(): number { - return _.random(0, constants.PPM_100_PERCENT); - } - - interface CreatePoolOpts { - poolId: string; - operator: string; - operatorShare: number; - } - - async function createPoolAsync(opts?: Partial): Promise { - const _opts = { - poolId: hexUtils.random(), - operator, - operatorShare: randomOperatorShare(), - ...opts, - }; - await testContract - .setPoolById(_opts.poolId, { - operator: _opts.operator, - operatorShare: _opts.operatorShare, - }) - .awaitTransactionSuccessAsync(); - return _opts; - } - - async function addMakerToPoolAsync(poolId: string, _maker: string): Promise { - await testContract.setPoolIdByMaker(poolId, _maker).awaitTransactionSuccessAsync(); - } - - describe('onlyStakingPoolOperator modifier', () => { - it('fails if not called by the pool operator', async () => { - const { poolId } = await createPoolAsync(); - const tx = testContract.testOnlyStakingPoolOperatorModifier(poolId).callAsync({ from: notOperatorOrMaker }); - const expectedError = new StakingRevertErrors.OnlyCallableByPoolOperatorError(notOperatorOrMaker, poolId); - return expect(tx).to.revertWith(expectedError); - }); - it('fails if called by a pool maker', async () => { - const { poolId } = await createPoolAsync(); - await addMakerToPoolAsync(poolId, maker); - const tx = testContract.testOnlyStakingPoolOperatorModifier(poolId).callAsync({ from: maker }); - const expectedError = new StakingRevertErrors.OnlyCallableByPoolOperatorError(maker, poolId); - return expect(tx).to.revertWith(expectedError); - }); - it('succeeds if called by the pool operator', async () => { - const { poolId } = await createPoolAsync(); - await testContract.testOnlyStakingPoolOperatorModifier(poolId).callAsync({ from: operator }); - }); - }); - - describe('createStakingPool()', () => { - let nextPoolId: string; - - before(async () => { - nextPoolId = toNextPoolId(await testContract.lastPoolId().callAsync()); - }); - - it('fails if the next pool ID overflows', async () => { - await testContract.setLastPoolId(hexUtils.toHex(constants.MAX_UINT256)).awaitTransactionSuccessAsync(); - const tx = testContract.createStakingPool(randomOperatorShare(), false).awaitTransactionSuccessAsync(); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow, - constants.MAX_UINT256, - new BigNumber(1), - ); - return expect(tx).to.revertWith(expectedError); - }); - it('fails if the operator share is invalid', async () => { - const operatorShare = constants.PPM_100_PERCENT + 1; - const tx = testContract.createStakingPool(operatorShare, false).awaitTransactionSuccessAsync(); - const expectedError = new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - nextPoolId, - operatorShare, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('operator can create and own multiple pools', async () => { - const { logs: logs1 } = await testContract - .createStakingPool(randomOperatorShare(), false) - .awaitTransactionSuccessAsync(); - const { logs: logs2 } = await testContract - .createStakingPool(randomOperatorShare(), false) - .awaitTransactionSuccessAsync(); - const createEvents = filterLogsToArguments( - [...logs1, ...logs2], - TestMixinStakingPoolEvents.StakingPoolCreated, - ); - expect(createEvents).to.be.length(2); - const poolIds = createEvents.map(e => e.poolId); - expect(poolIds[0]).to.not.eq(poolIds[1]); - const pools = await Promise.all( - poolIds.map(async poolId => testContract.getStakingPool(poolId).callAsync()), - ); - expect(pools[0].operator).to.eq(pools[1].operator); - }); - it('operator can only be maker of one pool', async () => { - await testContract.createStakingPool(randomOperatorShare(), true).awaitTransactionSuccessAsync(); - const { logs } = await testContract - .createStakingPool(randomOperatorShare(), true) - .awaitTransactionSuccessAsync(); - const createEvents = filterLogsToArguments( - logs, - TestMixinStakingPoolEvents.StakingPoolCreated, - ); - const makerPool = await testContract.poolIdByMaker(operator).callAsync(); - expect(makerPool).to.eq(createEvents[0].poolId); - }); - it('computes correct next pool ID', async () => { - const { logs } = await testContract - .createStakingPool(randomOperatorShare(), false) - .awaitTransactionSuccessAsync(); - const createEvents = filterLogsToArguments( - logs, - TestMixinStakingPoolEvents.StakingPoolCreated, - ); - const poolId = createEvents[0].poolId; - expect(poolId).to.eq(nextPoolId); - }); - it('increments last pool ID counter', async () => { - await testContract.createStakingPool(randomOperatorShare(), false).awaitTransactionSuccessAsync(); - const lastPoolIdAfter = await testContract.lastPoolId().callAsync(); - expect(lastPoolIdAfter).to.eq(nextPoolId); - }); - it('records pool details', async () => { - const operatorShare = randomOperatorShare(); - await testContract.createStakingPool(operatorShare, false).awaitTransactionSuccessAsync({ from: operator }); - const pool = await testContract.getStakingPool(nextPoolId).callAsync(); - expect(pool.operator).to.eq(operator); - expect(pool.operatorShare).to.bignumber.eq(operatorShare); - }); - it('records pool details when operator share is 100%', async () => { - const operatorShare = constants.PPM_100_PERCENT; - await testContract.createStakingPool(operatorShare, false).awaitTransactionSuccessAsync({ from: operator }); - const pool = await testContract.getStakingPool(nextPoolId).callAsync(); - expect(pool.operator).to.eq(operator); - expect(pool.operatorShare).to.bignumber.eq(operatorShare); - }); - it('records pool details when operator share is 0%', async () => { - const operatorShare = constants.ZERO_AMOUNT; - await testContract.createStakingPool(operatorShare, false).awaitTransactionSuccessAsync({ from: operator }); - const pool = await testContract.getStakingPool(nextPoolId).callAsync(); - expect(pool.operator).to.eq(operator); - expect(pool.operatorShare).to.bignumber.eq(operatorShare); - }); - it('returns the next pool ID', async () => { - const poolId = await testContract.createStakingPool(randomOperatorShare(), false).callAsync({ - from: operator, - }); - expect(poolId).to.eq(nextPoolId); - }); - it('can add operator as a maker', async () => { - const operatorShare = randomOperatorShare(); - await testContract.createStakingPool(operatorShare, true).awaitTransactionSuccessAsync({ from: operator }); - const makerPoolId = await testContract.poolIdByMaker(operator).callAsync(); - expect(makerPoolId).to.eq(nextPoolId); - }); - it('emits a `StakingPoolCreated` event', async () => { - const operatorShare = randomOperatorShare(); - const { logs } = await testContract.createStakingPool(operatorShare, false).awaitTransactionSuccessAsync({ - from: operator, - }); - verifyEventsFromLogs( - logs, - [ - { - poolId: nextPoolId, - operator, - operatorShare: new BigNumber(operatorShare), - }, - ], - TestMixinStakingPoolEvents.StakingPoolCreated, - ); - }); - it('emits a `MakerStakingPoolSet` event when also joining as a maker', async () => { - const operatorShare = randomOperatorShare(); - const { logs } = await testContract.createStakingPool(operatorShare, true).awaitTransactionSuccessAsync({ - from: operator, - }); - verifyEventsFromLogs( - logs, - [ - { - makerAddress: operator, - poolId: nextPoolId, - }, - ], - TestMixinStakingPoolEvents.MakerStakingPoolSet, - ); - }); - }); - - describe('decreaseStakingPoolOperatorShare()', () => { - it('fails if not called by operator', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - const tx = testContract - .decreaseStakingPoolOperatorShare(poolId, operatorShare - 1) - .awaitTransactionSuccessAsync({ from: notOperatorOrMaker }); - const expectedError = new StakingRevertErrors.OnlyCallableByPoolOperatorError(notOperatorOrMaker, poolId); - return expect(tx).to.revertWith(expectedError); - }); - it('fails if called by maker', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - await addMakerToPoolAsync(poolId, maker); - const tx = testContract - .decreaseStakingPoolOperatorShare(poolId, operatorShare - 1) - .awaitTransactionSuccessAsync({ from: maker }); - const expectedError = new StakingRevertErrors.OnlyCallableByPoolOperatorError(maker, poolId); - return expect(tx).to.revertWith(expectedError); - }); - it('fails if operator share is greater than current', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - const tx = testContract - .decreaseStakingPoolOperatorShare(poolId, operatorShare + 1) - .awaitTransactionSuccessAsync({ from: operator }); - const expectedError = new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.CanOnlyDecreaseOperatorShare, - poolId, - operatorShare + 1, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('fails if operator share is greater than PPM_100_PERCENT', async () => { - const { poolId } = await createPoolAsync(); - const tx = testContract - .decreaseStakingPoolOperatorShare(poolId, constants.PPM_100_PERCENT + 1) - .awaitTransactionSuccessAsync({ from: operator }); - const expectedError = new StakingRevertErrors.OperatorShareError( - StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge, - poolId, - constants.PPM_100_PERCENT + 1, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('records new operator share', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - await testContract - .decreaseStakingPoolOperatorShare(poolId, operatorShare - 1) - .awaitTransactionSuccessAsync({ from: operator }); - const pool = await testContract.getStakingPool(poolId).callAsync(); - expect(pool.operatorShare).to.bignumber.eq(operatorShare - 1); - }); - it('does not modify operator share if equal to current', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - await testContract.decreaseStakingPoolOperatorShare(poolId, operatorShare).awaitTransactionSuccessAsync({ - from: operator, - }); - const pool = await testContract.getStakingPool(poolId).callAsync(); - expect(pool.operatorShare).to.bignumber.eq(operatorShare); - }); - it('does not modify operator', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - await testContract - .decreaseStakingPoolOperatorShare(poolId, operatorShare - 1) - .awaitTransactionSuccessAsync({ from: operator }); - const pool = await testContract.getStakingPool(poolId).callAsync(); - expect(pool.operator).to.eq(operator); - }); - it('emits an `OperatorShareDecreased` event', async () => { - const { poolId, operatorShare } = await createPoolAsync(); - const { logs } = await testContract - .decreaseStakingPoolOperatorShare(poolId, operatorShare - 1) - .awaitTransactionSuccessAsync({ from: operator }); - verifyEventsFromLogs( - logs, - [ - { - poolId, - oldOperatorShare: new BigNumber(operatorShare), - newOperatorShare: new BigNumber(operatorShare - 1), - }, - ], - TestMixinStakingPoolEvents.OperatorShareDecreased, - ); - }); - }); - - describe('joinStakingPoolAsMaker()', () => { - it('records sender as maker for the pool', async () => { - const { poolId } = await createPoolAsync(); - await testContract.joinStakingPoolAsMaker(poolId).awaitTransactionSuccessAsync({ from: maker }); - const makerPoolId = await testContract.poolIdByMaker(maker).callAsync(); - expect(makerPoolId).to.eq(poolId); - }); - it('operator can join as maker for the pool', async () => { - const { poolId } = await createPoolAsync(); - await testContract.joinStakingPoolAsMaker(poolId).awaitTransactionSuccessAsync({ from: operator }); - const makerPoolId = await testContract.poolIdByMaker(operator).callAsync(); - expect(makerPoolId).to.eq(poolId); - }); - it('can join the same pool as a maker twice', async () => { - const { poolId } = await createPoolAsync(); - await testContract.joinStakingPoolAsMaker(poolId).awaitTransactionSuccessAsync({ from: maker }); - await testContract.joinStakingPoolAsMaker(poolId).awaitTransactionSuccessAsync({ from: maker }); - const makerPoolId = await testContract.poolIdByMaker(maker).callAsync(); - expect(makerPoolId).to.eq(poolId); - }); - it('can only be a maker in one pool at a time', async () => { - const { poolId: poolId1 } = await createPoolAsync(); - const { poolId: poolId2 } = await createPoolAsync(); - await testContract.joinStakingPoolAsMaker(poolId1).awaitTransactionSuccessAsync({ from: maker }); - let makerPoolId = await testContract.poolIdByMaker(maker).callAsync(); - expect(makerPoolId).to.eq(poolId1); - await testContract.joinStakingPoolAsMaker(poolId2).awaitTransactionSuccessAsync({ from: maker }); - makerPoolId = await testContract.poolIdByMaker(maker).callAsync(); - expect(makerPoolId).to.eq(poolId2); - }); - it('emits a `MakerStakingPoolSet` event', async () => { - const { poolId } = await createPoolAsync(); - const { logs } = await testContract.joinStakingPoolAsMaker(poolId).awaitTransactionSuccessAsync({ - from: maker, - }); - verifyEventsFromLogs( - logs, - [ - { - makerAddress: maker, - poolId, - }, - ], - TestMixinStakingPoolEvents.MakerStakingPoolSet, - ); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/staking_proxy_test.ts b/contracts/staking/test/unit_tests/staking_proxy_test.ts deleted file mode 100644 index 1c56b18b61..0000000000 --- a/contracts/staking/test/unit_tests/staking_proxy_test.ts +++ /dev/null @@ -1,300 +0,0 @@ -import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; -import { AuthorizableRevertErrors } from '@0x/contracts-utils'; -import { BigNumber, StakingRevertErrors } from '@0x/utils'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { - StakingProxyEvents, - TestProxyDestinationContract, - TestProxyDestinationEvents, - TestStakingProxyUnitContract, -} from '../wrappers'; - -import { constants as stakingConstants } from '../../src/constants'; - -blockchainTests.resets('StakingProxy unit tests', env => { - const testString = 'Hello, World!'; - const testRevertString = 'Goodbye, World!'; - let accounts: string[]; - let owner: string; - let authorizedAddress: string; - let notAuthorizedAddresses: string[]; - let testProxyContract: TestStakingProxyUnitContract; - let testContractViaProxy: TestProxyDestinationContract; - let testContract: TestProxyDestinationContract; - let testContract2: TestProxyDestinationContract; - - before(async () => { - // Create accounts - accounts = await env.getAccountAddressesAsync(); - [owner, authorizedAddress, ...notAuthorizedAddresses] = accounts; - - // Deploy contracts - testContract = await TestProxyDestinationContract.deployFrom0xArtifactAsync( - artifacts.TestProxyDestination, - env.provider, - env.txDefaults, - artifacts, - ); - testContract2 = await TestProxyDestinationContract.deployFrom0xArtifactAsync( - artifacts.TestProxyDestination, - env.provider, - env.txDefaults, - artifacts, - ); - testProxyContract = await TestStakingProxyUnitContract.deployFrom0xArtifactAsync( - artifacts.TestStakingProxyUnit, - env.provider, - env.txDefaults, - artifacts, - testContract.address, - ); - const logDecoderDependencies = _.mapValues(artifacts, v => v.compilerOutput.abi); - testContractViaProxy = new TestProxyDestinationContract( - testProxyContract.address, - env.provider, - env.txDefaults, - logDecoderDependencies, - ); - - // Add authorized address to Staking Proxy - await testProxyContract.addAuthorizedAddress(authorizedAddress).sendTransactionAsync({ from: owner }); - }); - - describe('Fallback function', () => { - it('should pass back the return value of the destination contract', async () => { - const returnValue = await testContractViaProxy.echo(testString).callAsync(); - expect(returnValue).to.equal(testString); - }); - - it('should revert with correct value when destination reverts', async () => { - return expect(testContractViaProxy.die().callAsync()).to.revertWith(testRevertString); - }); - - it('should revert if no staking contract is attached', async () => { - await testProxyContract.detachStakingContract().awaitTransactionSuccessAsync({ from: authorizedAddress }); - const expectedError = new StakingRevertErrors.ProxyDestinationCannotBeNilError(); - const tx = testContractViaProxy.echo(testString).callAsync(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('attachStakingContract', () => { - it('should successfully attaching a new staking contract', async () => { - // Cache existing staking contract and attach a new one - const initStakingContractAddress = await testProxyContract.stakingContract().callAsync(); - const txReceipt = await testProxyContract - .attachStakingContract(testContract2.address) - .awaitTransactionSuccessAsync({ from: authorizedAddress }); - - // Validate `ContractAttachedToProxy` event - verifyEventsFromLogs( - txReceipt.logs, - [ - { - newStakingContractAddress: testContract2.address, - }, - ], - StakingProxyEvents.StakingContractAttachedToProxy, - ); - - // Check that `init` was called on destination contract - verifyEventsFromLogs( - txReceipt.logs, - [ - { - initCalled: true, - }, - ], - TestProxyDestinationEvents.InitCalled, - ); - - // Validate new staking contract address - const finalStakingContractAddress = await testProxyContract.stakingContract().callAsync(); - expect(finalStakingContractAddress).to.be.equal(testContract2.address); - expect(finalStakingContractAddress).to.not.equal(initStakingContractAddress); - }); - - it('should revert if call to `init` on new staking contract fails', async () => { - await testProxyContract.setInitFailFlag().awaitTransactionSuccessAsync(); - const tx = testProxyContract.attachStakingContract(testContract2.address).awaitTransactionSuccessAsync({ - from: authorizedAddress, - }); - const expectedError = 'INIT_FAIL_FLAG_SET'; - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if called by unauthorized address', async () => { - const tx = testProxyContract.attachStakingContract(testContract2.address).awaitTransactionSuccessAsync({ - from: notAuthorizedAddresses[0], - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddresses[0]); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('detachStakingContract', () => { - it('should detach staking contract', async () => { - // Cache existing staking contract and attach a new one - const initStakingContractAddress = await testProxyContract.stakingContract().callAsync(); - const txReceipt = await testProxyContract.detachStakingContract().awaitTransactionSuccessAsync({ - from: authorizedAddress, - }); - - // Validate that event was emitted - verifyEventsFromLogs(txReceipt.logs, [{}], StakingProxyEvents.StakingContractDetachedFromProxy); - - // Validate staking contract address was unset - const finalStakingContractAddress = await testProxyContract.stakingContract().callAsync(); - expect(finalStakingContractAddress).to.be.equal(stakingConstants.NIL_ADDRESS); - expect(finalStakingContractAddress).to.not.equal(initStakingContractAddress); - }); - - it('should revert if called by unauthorized address', async () => { - const tx = testProxyContract.detachStakingContract().awaitTransactionSuccessAsync({ - from: notAuthorizedAddresses[0], - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorizedAddresses[0]); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('batchExecute', () => { - it('should execute no-op if no calls to make', async () => { - await testProxyContract.batchExecute([]).awaitTransactionSuccessAsync(); - }); - - it('should call one function and return the output', async () => { - const calls = [testContract.echo(testString).getABIEncodedTransactionData()]; - const rawResults = await testProxyContract.batchExecute(calls).callAsync(); - expect(rawResults.length).to.equal(1); - const returnValues = [testContract.getABIDecodedReturnData<{}>('echo', rawResults[0])]; - expect(returnValues[0]).to.equal(testString); - }); - - it('should call multiple functions and return their outputs', async () => { - const calls = [ - testContract.echo(testString).getABIEncodedTransactionData(), - testContract.doMath(new BigNumber(2), new BigNumber(1)).getABIEncodedTransactionData(), - ]; - const rawResults = await testProxyContract.batchExecute(calls).callAsync(); - expect(rawResults.length).to.equal(2); - const returnValues = [ - testContract.getABIDecodedReturnData('echo', rawResults[0]), - testContract.getABIDecodedReturnData('doMath', rawResults[1]), - ]; - expect(returnValues[0]).to.equal(testString); - expect(returnValues[1][0]).to.bignumber.equal(new BigNumber(3)); - expect(returnValues[1][1]).to.bignumber.equal(new BigNumber(1)); - }); - - it('should revert if a call reverts', async () => { - const calls = [ - testContract.echo(testString).getABIEncodedTransactionData(), - testContract.die().getABIEncodedTransactionData(), - testContract.doMath(new BigNumber(2), new BigNumber(1)).getABIEncodedTransactionData(), - ]; - const tx = testProxyContract.batchExecute(calls).callAsync(); - const expectedError = testRevertString; - return expect(tx).to.revertWith(expectedError); - }); - - it('should revert if no staking contract is attached', async () => { - await testProxyContract.detachStakingContract().awaitTransactionSuccessAsync({ from: authorizedAddress }); - const calls = [testContract.echo(testString).getABIEncodedTransactionData()]; - - const tx = testProxyContract.batchExecute(calls).callAsync(); - const expectedError = new StakingRevertErrors.ProxyDestinationCannotBeNilError(); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('assertValidStorageParams', () => { - const validStorageParams = { - epochDurationInSeconds: new BigNumber(stakingConstants.ONE_DAY_IN_SECONDS * 5), - cobbDouglasAlphaNumerator: new BigNumber(1), - cobbDouglasAlphaDenominator: new BigNumber(1), - rewardDelegatedStakeWeight: constants.PPM_DENOMINATOR, - minimumPoolStake: new BigNumber(100), - }; - it('should not revert if all storage params are valid', async () => { - await testProxyContract.setTestStorageParams(validStorageParams).awaitTransactionSuccessAsync(); - await testProxyContract.assertValidStorageParams().callAsync(); - }); - it('should revert if `epochDurationInSeconds` is less than 5 days', async () => { - const invalidStorageParams = { - ...validStorageParams, - epochDurationInSeconds: new BigNumber(0), - }; - await testProxyContract.setTestStorageParams(invalidStorageParams).awaitTransactionSuccessAsync(); - const tx = testProxyContract.assertValidStorageParams().callAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidEpochDuration, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if `epochDurationInSeconds` is greater than 30 days', async () => { - const invalidStorageParams = { - ...validStorageParams, - epochDurationInSeconds: new BigNumber(stakingConstants.ONE_DAY_IN_SECONDS * 31), - }; - await testProxyContract.setTestStorageParams(invalidStorageParams).awaitTransactionSuccessAsync(); - const tx = testProxyContract.assertValidStorageParams().callAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidEpochDuration, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if `cobbDouglasAlphaNumerator` is greater than `cobbDouglasAlphaDenominator`', async () => { - const invalidStorageParams = { - ...validStorageParams, - cobbDouglasAlphaNumerator: new BigNumber(2), - cobbDouglasAlphaDenominator: new BigNumber(1), - }; - await testProxyContract.setTestStorageParams(invalidStorageParams).awaitTransactionSuccessAsync(); - const tx = testProxyContract.assertValidStorageParams().callAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if `cobbDouglasAlphaDenominator` equals zero', async () => { - const invalidStorageParams = { - ...validStorageParams, - cobbDouglasAlphaDenominator: new BigNumber(0), - }; - await testProxyContract.setTestStorageParams(invalidStorageParams).awaitTransactionSuccessAsync(); - const tx = testProxyContract.assertValidStorageParams().callAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidCobbDouglasAlpha, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if `rewardDelegatedStakeWeight` is greater than PPM_DENOMINATOR', async () => { - const invalidStorageParams = { - ...validStorageParams, - rewardDelegatedStakeWeight: new BigNumber(constants.PPM_DENOMINATOR + 1), - }; - await testProxyContract.setTestStorageParams(invalidStorageParams).awaitTransactionSuccessAsync(); - const tx = testProxyContract.assertValidStorageParams().callAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidRewardDelegatedStakeWeight, - ); - return expect(tx).to.revertWith(expectedError); - }); - it('should revert if `minimumPoolStake` is less than two', async () => { - const invalidStorageParams = { - ...validStorageParams, - minimumPoolStake: new BigNumber(1), - }; - await testProxyContract.setTestStorageParams(invalidStorageParams).awaitTransactionSuccessAsync(); - const tx = testProxyContract.assertValidStorageParams().callAsync(); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCodes.InvalidMinimumPoolStake, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); -}); -// tslint:disable: max-file-line-count diff --git a/contracts/staking/test/unit_tests/zrx_vault_test.ts b/contracts/staking/test/unit_tests/zrx_vault_test.ts deleted file mode 100644 index 65c5039303..0000000000 --- a/contracts/staking/test/unit_tests/zrx_vault_test.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { RevertReason } from '@0x/types'; -import { AuthorizableRevertErrors, BigNumber, SafeMathRevertErrors, StakingRevertErrors } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { constants as stakingConstants } from '../../src/constants'; - -import { artifacts } from '../artifacts'; -import { - ZrxVaultContract, - ZrxVaultDepositEventArgs, - ZrxVaultInCatastrophicFailureModeEventArgs, - ZrxVaultStakingProxySetEventArgs, - ZrxVaultWithdrawEventArgs, - ZrxVaultZrxProxySetEventArgs, -} from '../wrappers'; - -blockchainTests.resets('ZrxVault unit tests', env => { - let accounts: string[]; - let owner: string; - let nonOwnerAddresses: string[]; - let erc20Wrapper: ERC20Wrapper; - let zrxVault: ZrxVaultContract; - let zrxAssetData: string; - let zrxProxyAddress: string; - - before(async () => { - // create accounts - accounts = await env.getAccountAddressesAsync(); - [owner, ...nonOwnerAddresses] = accounts; - - // set up ERC20Wrapper - erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner); - // deploy erc20 proxy - const erc20ProxyContract = await erc20Wrapper.deployProxyAsync(); - zrxProxyAddress = erc20ProxyContract.address; - // deploy zrx token - const [zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, constants.DUMMY_TOKEN_DECIMALS); - zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenContract.address); - - await erc20Wrapper.setBalancesAndAllowancesAsync(); - - zrxVault = await ZrxVaultContract.deployFrom0xArtifactAsync( - artifacts.ZrxVault, - env.provider, - env.txDefaults, - artifacts, - zrxProxyAddress, - zrxTokenContract.address, - ); - - await zrxVault.addAuthorizedAddress(owner).awaitTransactionSuccessAsync(); - - // configure erc20 proxy to accept calls from zrx vault - await erc20ProxyContract.addAuthorizedAddress(zrxVault.address).awaitTransactionSuccessAsync(); - }); - - enum ZrxTransfer { - Deposit, - Withdrawal, - } - - async function verifyTransferPostconditionsAsync( - transferType: ZrxTransfer, - staker: string, - amount: BigNumber, - initialVaultBalance: BigNumber, - initialTokenBalance: BigNumber, - receipt: TransactionReceiptWithDecodedLogs, - ): Promise { - const eventArgs = - transferType === ZrxTransfer.Deposit - ? filterLogsToArguments(receipt.logs, 'Deposit') - : filterLogsToArguments(receipt.logs, 'Withdraw'); - expect(eventArgs.length).to.equal(1); - expect(eventArgs[0].staker).to.equal(staker); - expect(eventArgs[0].amount).to.bignumber.equal(amount); - - const newVaultBalance = await zrxVault.balanceOf(staker).callAsync(); - const newTokenBalance = await erc20Wrapper.getBalanceAsync(staker, zrxAssetData); - const [expectedVaultBalance, expectedTokenBalance] = - transferType === ZrxTransfer.Deposit - ? [initialVaultBalance.plus(amount), initialTokenBalance.minus(amount)] - : [initialVaultBalance.minus(amount), initialTokenBalance.plus(amount)]; - expect(newVaultBalance).to.bignumber.equal(expectedVaultBalance); - expect(newTokenBalance).to.bignumber.equal(expectedTokenBalance); - } - - describe('Normal operation', () => { - describe('Setting proxies', () => { - async function verifyStakingProxySetAsync( - receipt: TransactionReceiptWithDecodedLogs, - newProxy: string, - ): Promise { - const eventArgs = filterLogsToArguments( - receipt.logs, - 'StakingProxySet', - ); - expect(eventArgs.length).to.equal(1); - expect(eventArgs[0].stakingProxyAddress).to.equal(newProxy); - const actualAddress = await zrxVault.stakingProxyAddress().callAsync(); - expect(actualAddress).to.equal(newProxy); - } - - it('Owner can set the ZRX proxy', async () => { - const newProxy = nonOwnerAddresses[0]; - const receipt = await zrxVault.setZrxProxy(newProxy).awaitTransactionSuccessAsync({ - from: owner, - }); - const eventArgs = filterLogsToArguments(receipt.logs, 'ZrxProxySet'); - expect(eventArgs.length).to.equal(1); - expect(eventArgs[0].zrxProxyAddress).to.equal(newProxy); - }); - it('Authorized address can set the ZRX proxy', async () => { - const [authorized, newProxy] = nonOwnerAddresses; - await zrxVault.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - const receipt = await zrxVault.setZrxProxy(newProxy).awaitTransactionSuccessAsync({ - from: authorized, - }); - const eventArgs = filterLogsToArguments(receipt.logs, 'ZrxProxySet'); - expect(eventArgs.length).to.equal(1); - expect(eventArgs[0].zrxProxyAddress).to.equal(newProxy); - }); - it('Non-authorized address cannot set the ZRX proxy', async () => { - const [notAuthorized, newProxy] = nonOwnerAddresses; - const tx = zrxVault.setZrxProxy(newProxy).awaitTransactionSuccessAsync({ - from: notAuthorized, - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorized); - expect(tx).to.revertWith(expectedError); - }); - it('Owner can set the staking proxy', async () => { - const newProxy = nonOwnerAddresses[0]; - const receipt = await zrxVault.setStakingProxy(newProxy).awaitTransactionSuccessAsync({ - from: owner, - }); - await verifyStakingProxySetAsync(receipt, newProxy); - }); - it('Authorized address can set the staking proxy', async () => { - const [authorized, newProxy] = nonOwnerAddresses; - await zrxVault.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - const receipt = await zrxVault.setStakingProxy(newProxy).awaitTransactionSuccessAsync({ - from: authorized, - }); - await verifyStakingProxySetAsync(receipt, newProxy); - }); - it('Non-authorized address cannot set the staking proxy', async () => { - const [notAuthorized, newProxy] = nonOwnerAddresses; - const tx = zrxVault.setStakingProxy(newProxy).awaitTransactionSuccessAsync({ - from: notAuthorized, - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorized); - expect(tx).to.revertWith(expectedError); - const actualAddress = await zrxVault.stakingProxyAddress().callAsync(); - expect(actualAddress).to.equal(stakingConstants.NIL_ADDRESS); - }); - }); - describe('ZRX management', () => { - let staker: string; - let stakingProxy: string; - let initialVaultBalance: BigNumber; - let initialTokenBalance: BigNumber; - - before(async () => { - [staker, stakingProxy] = nonOwnerAddresses; - await zrxVault.setStakingProxy(stakingProxy).awaitTransactionSuccessAsync({ from: owner }); - await zrxVault.depositFrom(staker, new BigNumber(10)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - }); - - beforeEach(async () => { - initialVaultBalance = await zrxVault.balanceOf(staker).callAsync(); - initialTokenBalance = await erc20Wrapper.getBalanceAsync(staker, zrxAssetData); - }); - - describe('Deposit', () => { - it('Staking proxy can deposit zero amount on behalf of staker', async () => { - const receipt = await zrxVault - .depositFrom(staker, constants.ZERO_AMOUNT) - .awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Deposit, - staker, - constants.ZERO_AMOUNT, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it('Staking proxy can deposit nonzero amount on behalf of staker', async () => { - const receipt = await zrxVault.depositFrom(staker, new BigNumber(1)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Deposit, - staker, - new BigNumber(1), - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it('Staking proxy can deposit entire ZRX balance on behalf of staker', async () => { - const receipt = await zrxVault - .depositFrom(staker, initialTokenBalance) - .awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Deposit, - staker, - initialTokenBalance, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it("Reverts if attempting to deposit more than staker's ZRX balance", async () => { - const tx = zrxVault.depositFrom(staker, initialTokenBalance.plus(1)).sendTransactionAsync({ - from: stakingProxy, - }); - return expect(tx).to.revertWith(RevertReason.TransferFailed); - }); - }); - describe('Withdrawal', () => { - it('Staking proxy can withdraw zero amount on behalf of staker', async () => { - const receipt = await zrxVault - .withdrawFrom(staker, constants.ZERO_AMOUNT) - .awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Withdrawal, - staker, - constants.ZERO_AMOUNT, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it('Staking proxy can withdraw nonzero amount on behalf of staker', async () => { - const receipt = await zrxVault.withdrawFrom(staker, new BigNumber(1)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Withdrawal, - staker, - new BigNumber(1), - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it('Staking proxy can withdraw entire vault balance on behalf of staker', async () => { - const receipt = await zrxVault - .withdrawFrom(staker, initialVaultBalance) - .awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Withdrawal, - staker, - initialVaultBalance, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it("Reverts if attempting to withdraw more than staker's vault balance", async () => { - const tx = zrxVault.withdrawFrom(staker, initialVaultBalance.plus(1)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - const expectedError = new SafeMathRevertErrors.Uint256BinOpError( - SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow, - initialVaultBalance, - initialVaultBalance.plus(1), - ); - expect(tx).to.revertWith(expectedError); - }); - }); - }); - }); - - describe('Catastrophic Failure Mode', () => { - describe('Authorization', () => { - async function verifyCatastrophicFailureModeAsync( - sender: string, - receipt: TransactionReceiptWithDecodedLogs, - ): Promise { - const eventArgs = filterLogsToArguments( - receipt.logs, - 'InCatastrophicFailureMode', - ); - expect(eventArgs.length).to.equal(1); - expect(eventArgs[0].sender).to.equal(sender); - expect(await zrxVault.isInCatastrophicFailure().callAsync()).to.be.true(); - } - - it('Owner can turn on Catastrophic Failure Mode', async () => { - const receipt = await zrxVault.enterCatastrophicFailure().awaitTransactionSuccessAsync({ from: owner }); - await verifyCatastrophicFailureModeAsync(owner, receipt); - }); - it('Authorized address can turn on Catastrophic Failure Mode', async () => { - const authorized = nonOwnerAddresses[0]; - await zrxVault.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - const receipt = await zrxVault.enterCatastrophicFailure().awaitTransactionSuccessAsync({ - from: authorized, - }); - await verifyCatastrophicFailureModeAsync(authorized, receipt); - }); - it('Non-authorized address cannot turn on Catastrophic Failure Mode', async () => { - const notAuthorized = nonOwnerAddresses[0]; - const tx = zrxVault.enterCatastrophicFailure().awaitTransactionSuccessAsync({ - from: notAuthorized, - }); - const expectedError = new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthorized); - expect(tx).to.revertWith(expectedError); - expect(await zrxVault.isInCatastrophicFailure().callAsync()).to.be.false(); - }); - it('Catastrophic Failure Mode can only be turned on once', async () => { - const authorized = nonOwnerAddresses[0]; - await zrxVault.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - await zrxVault.enterCatastrophicFailure().awaitTransactionSuccessAsync({ - from: authorized, - }); - const expectedError = new StakingRevertErrors.OnlyCallableIfNotInCatastrophicFailureError(); - return expect(zrxVault.enterCatastrophicFailure().awaitTransactionSuccessAsync()).to.revertWith( - expectedError, - ); - }); - }); - - describe('Affected functionality', () => { - let staker: string; - let stakingProxy: string; - let initialVaultBalance: BigNumber; - let initialTokenBalance: BigNumber; - - before(async () => { - [staker, stakingProxy, ...nonOwnerAddresses] = nonOwnerAddresses; - await zrxVault.setStakingProxy(stakingProxy).awaitTransactionSuccessAsync({ from: owner }); - await zrxVault.depositFrom(staker, new BigNumber(10)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - await zrxVault.enterCatastrophicFailure().awaitTransactionSuccessAsync({ from: owner }); - }); - - beforeEach(async () => { - initialVaultBalance = await zrxVault.balanceOf(staker).callAsync(); - initialTokenBalance = await erc20Wrapper.getBalanceAsync(staker, zrxAssetData); - }); - - it('Owner cannot set the ZRX proxy', async () => { - const newProxy = nonOwnerAddresses[0]; - const tx = zrxVault.setZrxProxy(newProxy).awaitTransactionSuccessAsync({ - from: owner, - }); - const expectedError = new StakingRevertErrors.OnlyCallableIfNotInCatastrophicFailureError(); - expect(tx).to.revertWith(expectedError); - const actualAddress = await zrxVault.zrxAssetProxy().callAsync(); - expect(actualAddress).to.equal(zrxProxyAddress); - }); - it('Authorized address cannot set the ZRX proxy', async () => { - const [authorized, newProxy] = nonOwnerAddresses; - await zrxVault.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner }); - const tx = zrxVault.setZrxProxy(newProxy).awaitTransactionSuccessAsync({ - from: authorized, - }); - const expectedError = new StakingRevertErrors.OnlyCallableIfNotInCatastrophicFailureError(); - expect(tx).to.revertWith(expectedError); - const actualAddress = await zrxVault.zrxAssetProxy().callAsync(); - expect(actualAddress).to.equal(zrxProxyAddress); - }); - it('Staking proxy cannot deposit ZRX', async () => { - const tx = zrxVault.depositFrom(staker, new BigNumber(1)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - const expectedError = new StakingRevertErrors.OnlyCallableIfNotInCatastrophicFailureError(); - expect(tx).to.revertWith(expectedError); - }); - - describe('Withdrawal', () => { - it('Staking proxy cannot call `withdrawFrom`', async () => { - const tx = zrxVault.withdrawFrom(staker, new BigNumber(1)).awaitTransactionSuccessAsync({ - from: stakingProxy, - }); - const expectedError = new StakingRevertErrors.OnlyCallableIfNotInCatastrophicFailureError(); - expect(tx).to.revertWith(expectedError); - }); - it('Staker can withdraw all their ZRX', async () => { - const receipt = await zrxVault.withdrawAllFrom(staker).awaitTransactionSuccessAsync({ - from: staker, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Withdrawal, - staker, - initialVaultBalance, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it('Owner can withdraw ZRX on behalf of a staker', async () => { - const receipt = await zrxVault.withdrawAllFrom(staker).awaitTransactionSuccessAsync({ - from: owner, - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Withdrawal, - staker, - initialVaultBalance, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - it('Non-owner address can withdraw ZRX on behalf of a staker', async () => { - const receipt = await zrxVault.withdrawAllFrom(staker).awaitTransactionSuccessAsync({ - from: nonOwnerAddresses[0], - }); - await verifyTransferPostconditionsAsync( - ZrxTransfer.Withdrawal, - staker, - initialVaultBalance, - initialVaultBalance, - initialTokenBalance, - receipt, - ); - }); - }); - }); - }); -}); diff --git a/contracts/staking/test/utils/api_wrapper.ts b/contracts/staking/test/utils/api_wrapper.ts deleted file mode 100644 index 3572168a40..0000000000 --- a/contracts/staking/test/utils/api_wrapper.ts +++ /dev/null @@ -1,282 +0,0 @@ -import { ERC20Wrapper } from '@0x/contracts-asset-proxy'; -import { artifacts as erc20Artifacts, DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20'; -import { BlockchainTestsEnvironment, constants, filterLogsToArguments, txDefaults } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { BlockParamLiteral, ContractArtifact, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { artifacts } from '../artifacts'; -import { - IStakingEventsEpochEndedEventArgs, - IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs, - StakingProxyContract, - TestCobbDouglasContract, - TestStakingContract, - TestStakingEvents, - ZrxVaultContract, -} from '../wrappers'; - -import { constants as stakingConstants } from '../../src/constants'; -import { DecodedLogs, EndOfEpochInfo, StakingParams } from '../../src/types'; - -export class StakingApiWrapper { - // The address of the real Staking.sol contract - public stakingContractAddress: string; - // The StakingProxy.sol contract wrapped as a StakingContract to borrow API - public stakingContract: TestStakingContract; - // The StakingProxy.sol contract as a StakingProxyContract - public stakingProxyContract: StakingProxyContract; - public zrxVaultContract: ZrxVaultContract; - public zrxTokenContract: DummyERC20TokenContract; - public wethContract: WETH9Contract; - public cobbDouglasContract: TestCobbDouglasContract; - public utils = { - // Epoch Utils - fastForwardToNextEpochAsync: async (): Promise => { - // increase timestamp of next block by how many seconds we need to - // get to the next epoch. - const epochEndTime = await this.stakingContract.getCurrentEpochEarliestEndTimeInSeconds().callAsync(); - const lastBlockTime = await this._web3Wrapper.getBlockTimestampAsync('latest'); - const dt = Math.max(0, epochEndTime.minus(lastBlockTime).toNumber()); - await this._web3Wrapper.increaseTimeAsync(dt); - // mine next block - await this._web3Wrapper.mineBlockAsync(); - }, - - skipToNextEpochAndFinalizeAsync: async (): Promise => { - await this.utils.fastForwardToNextEpochAsync(); - const endOfEpochInfo = await this.utils.endEpochAsync(); - const allLogs = [] as DecodedLogs; - for (const poolId of endOfEpochInfo.activePoolIds) { - const receipt = await this.stakingContract.finalizePool(poolId).awaitTransactionSuccessAsync(); - allLogs.splice(allLogs.length, 0, ...(receipt.logs as DecodedLogs)); - } - return allLogs; - }, - - endEpochAsync: async (): Promise => { - const activePoolIds = await this.utils.findActivePoolIdsAsync(); - const receipt = await this.stakingContract.endEpoch().awaitTransactionSuccessAsync(); - const [epochEndedEvent] = filterLogsToArguments( - receipt.logs, - TestStakingEvents.EpochEnded, - ); - return { - closingEpoch: epochEndedEvent.epoch, - activePoolIds, - rewardsAvailable: epochEndedEvent.rewardsAvailable, - totalFeesCollected: epochEndedEvent.totalFeesCollected, - totalWeightedStake: epochEndedEvent.totalWeightedStake, - }; - }, - - findActivePoolIdsAsync: async (epoch?: number): Promise => { - const _epoch = epoch !== undefined ? epoch : await this.stakingContract.currentEpoch().callAsync(); - const events = filterLogsToArguments( - await this.stakingContract.getLogsAsync( - TestStakingEvents.StakingPoolEarnedRewardsInEpoch, - { fromBlock: BlockParamLiteral.Earliest, toBlock: BlockParamLiteral.Latest }, - { epoch: new BigNumber(_epoch) }, - ), - TestStakingEvents.StakingPoolEarnedRewardsInEpoch, - ); - return events.map(e => e.poolId); - }, - - // Other Utils - createStakingPoolAsync: async ( - operatorAddress: string, - operatorShare: number, - addOperatorAsMaker: boolean, - ): Promise => { - const txReceipt = await this.stakingContract - .createStakingPool(operatorShare, addOperatorAsMaker) - .awaitTransactionSuccessAsync({ from: operatorAddress }); - const createStakingPoolLog = txReceipt.logs[0]; - const poolId = (createStakingPoolLog as any).args.poolId; - return poolId; - }, - - getZrxTokenBalanceOfZrxVaultAsync: async (): Promise => { - return this.zrxTokenContract.balanceOf(this.zrxVaultContract.address).callAsync(); - }, - - setParamsAsync: async (params: Partial): Promise => { - const _params = { - ...stakingConstants.DEFAULT_PARAMS, - ...params, - }; - return this.stakingContract - .setParams( - new BigNumber(_params.epochDurationInSeconds), - new BigNumber(_params.rewardDelegatedStakeWeight), - new BigNumber(_params.minimumPoolStake), - new BigNumber(_params.cobbDouglasAlphaNumerator), - new BigNumber(_params.cobbDouglasAlphaDenominator), - ) - .awaitTransactionSuccessAsync(); - }, - - getAvailableRewardsBalanceAsync: async (): Promise => { - const [ethBalance, wethBalance, reservedRewards] = await Promise.all([ - this._web3Wrapper.getBalanceInWeiAsync(this.stakingProxyContract.address), - this.wethContract.balanceOf(this.stakingProxyContract.address).callAsync(), - this.stakingContract.wethReservedForPoolRewards().callAsync(), - ]); - return BigNumber.sum(ethBalance, wethBalance).minus(reservedRewards); - }, - - getParamsAsync: async (): Promise => { - return (_.zipObject( - [ - 'epochDurationInSeconds', - 'rewardDelegatedStakeWeight', - 'minimumPoolStake', - 'cobbDouglasAlphaNumerator', - 'cobbDouglasAlphaDenominator', - 'wethProxyAddress', - 'zrxVaultAddress', - ], - await this.stakingContract.getParams().callAsync(), - ) as any) as StakingParams; - }, - - cobbDouglasAsync: async ( - totalRewards: BigNumber, - ownerFees: BigNumber, - totalFees: BigNumber, - ownerStake: BigNumber, - totalStake: BigNumber, - ): Promise => { - const { cobbDouglasAlphaNumerator, cobbDouglasAlphaDenominator } = await this.utils.getParamsAsync(); - return this.cobbDouglasContract - .cobbDouglas( - totalRewards, - ownerFees, - totalFees, - ownerStake, - totalStake, - new BigNumber(cobbDouglasAlphaNumerator), - new BigNumber(cobbDouglasAlphaDenominator), - ) - .callAsync(); - }, - }; - - private readonly _web3Wrapper: Web3Wrapper; - - constructor( - env: BlockchainTestsEnvironment, - ownerAddress: string, - stakingProxyContract: StakingProxyContract, - stakingContract: TestStakingContract, - zrxVaultContract: ZrxVaultContract, - zrxTokenContract: DummyERC20TokenContract, - wethContract: WETH9Contract, - cobbDouglasContract: TestCobbDouglasContract, - ) { - this._web3Wrapper = env.web3Wrapper; - this.zrxVaultContract = zrxVaultContract; - this.zrxTokenContract = zrxTokenContract; - this.wethContract = wethContract; - this.cobbDouglasContract = cobbDouglasContract; - this.stakingContractAddress = stakingContract.address; - this.stakingProxyContract = stakingProxyContract; - // disguise the staking proxy as a StakingContract - const logDecoderDependencies = _.mapValues({ ...artifacts, ...erc20Artifacts }, v => v.compilerOutput.abi); - this.stakingContract = new TestStakingContract( - stakingProxyContract.address, - env.provider, - { - ...env.txDefaults, - from: ownerAddress, - to: stakingProxyContract.address, - gas: 3e6, - gasPrice: 0, - }, - logDecoderDependencies, - ); - } -} - -/** - * Deploys and configures all staking contracts and returns a StakingApiWrapper instance, which - * holds the deployed contracts and serves as the entry point for their public functions. - */ -export async function deployAndConfigureContractsAsync( - env: BlockchainTestsEnvironment, - ownerAddress: string, - erc20Wrapper: ERC20Wrapper, - customStakingArtifact?: ContractArtifact, -): Promise { - // deploy erc20 proxy - const erc20ProxyContract = await erc20Wrapper.deployProxyAsync(); - // deploy zrx token - const [zrxTokenContract] = await erc20Wrapper.deployDummyTokensAsync(1, constants.DUMMY_TOKEN_DECIMALS); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - - // deploy WETH - const wethContract = await WETH9Contract.deployFrom0xArtifactAsync( - erc20Artifacts.WETH9, - env.provider, - txDefaults, - artifacts, - ); - - // deploy zrx vault - const zrxVaultContract = await ZrxVaultContract.deployFrom0xArtifactAsync( - artifacts.ZrxVault, - env.provider, - env.txDefaults, - artifacts, - erc20ProxyContract.address, - zrxTokenContract.address, - ); - - await zrxVaultContract.addAuthorizedAddress(ownerAddress).awaitTransactionSuccessAsync(); - - // deploy staking contract - const stakingContract = await TestStakingContract.deployFrom0xArtifactAsync( - customStakingArtifact !== undefined ? customStakingArtifact : artifacts.TestStaking, - env.provider, - env.txDefaults, - artifacts, - wethContract.address, - zrxVaultContract.address, - ); - - // deploy staking proxy - const stakingProxyContract = await StakingProxyContract.deployFrom0xArtifactAsync( - artifacts.StakingProxy, - env.provider, - env.txDefaults, - artifacts, - stakingContract.address, - ); - - await stakingProxyContract.addAuthorizedAddress(ownerAddress).awaitTransactionSuccessAsync(); - - // deploy cobb douglas contract - const cobbDouglasContract = await TestCobbDouglasContract.deployFrom0xArtifactAsync( - artifacts.TestCobbDouglas, - env.provider, - txDefaults, - artifacts, - ); - - // configure erc20 proxy to accept calls from zrx vault - await erc20ProxyContract.addAuthorizedAddress(zrxVaultContract.address).awaitTransactionSuccessAsync(); - // set staking proxy contract in zrx vault - await zrxVaultContract.setStakingProxy(stakingProxyContract.address).awaitTransactionSuccessAsync(); - return new StakingApiWrapper( - env, - ownerAddress, - stakingProxyContract, - stakingContract, - zrxVaultContract, - zrxTokenContract, - wethContract, - cobbDouglasContract, - ); -} diff --git a/contracts/staking/test/utils/cumulative_reward_tracking_simulation.ts b/contracts/staking/test/utils/cumulative_reward_tracking_simulation.ts deleted file mode 100644 index 0945a798d6..0000000000 --- a/contracts/staking/test/utils/cumulative_reward_tracking_simulation.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { BlockchainTestsEnvironment, expect, toBaseUnitAmount, txDefaults } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; -import { DecodedLogEntry, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { DecodedLogs, StakeInfo, StakeStatus } from '../../src/types'; -import { artifacts } from '../artifacts'; -import { TestCumulativeRewardTrackingContract, TestCumulativeRewardTrackingEvents } from '../wrappers'; - -import { StakingApiWrapper } from './api_wrapper'; - -export enum TestAction { - Finalize, - Delegate, - Undelegate, - PayProtocolFee, - CreatePool, -} - -interface TestLog { - event: string; - epoch: number; -} - -export class CumulativeRewardTrackingSimulation { - private readonly _amountToStake = toBaseUnitAmount(100); - private readonly _protocolFee = new BigNumber(10); - private readonly _stakingApiWrapper: StakingApiWrapper; - private readonly _staker: string; - private readonly _poolOperator: string; - private readonly _takerAddress: string; - private readonly _exchangeAddress: string; - private _testCumulativeRewardTrackingContract?: TestCumulativeRewardTrackingContract; - private _poolId: string; - - private static _extractTestLogs(txReceiptLogs: DecodedLogs): TestLog[] { - const logs = []; - for (const log of txReceiptLogs) { - const wantedEvents = [TestCumulativeRewardTrackingEvents.SetCumulativeReward] as string[]; - if (wantedEvents.indexOf(log.event) !== -1) { - logs.push({ - event: log.event, - epoch: log.args.epoch.toNumber(), - }); - } - } - return logs; - } - - private static _assertTestLogs(expectedSequence: TestLog[], txReceiptLogs: DecodedLogs): void { - const logs = CumulativeRewardTrackingSimulation._extractTestLogs(txReceiptLogs); - expect(logs.length).to.be.equal(expectedSequence.length); - for (let i = 0; i < expectedSequence.length; i++) { - const expectedLog = expectedSequence[i]; - const actualLog = logs[i]; - expect(expectedLog.event).to.exist(''); - expect(actualLog.event, `testing event name of ${JSON.stringify(expectedLog)}`).to.be.equal( - expectedLog.event, - ); - expect(actualLog.epoch, `testing epoch of ${JSON.stringify(expectedLog)}`).to.be.equal(expectedLog.epoch); - } - } - - constructor(stakingApiWrapper: StakingApiWrapper, actors: string[]) { - this._stakingApiWrapper = stakingApiWrapper; - // setup actors - this._staker = actors[0]; - this._poolOperator = actors[1]; - this._takerAddress = actors[2]; - this._exchangeAddress = actors[3]; - this._poolId = ''; - } - - public async deployAndConfigureTestContractsAsync(env: BlockchainTestsEnvironment): Promise { - // set exchange address - await this._stakingApiWrapper.stakingContract - .addExchangeAddress(this._exchangeAddress) - .awaitTransactionSuccessAsync(); - this._testCumulativeRewardTrackingContract = await TestCumulativeRewardTrackingContract.deployFrom0xArtifactAsync( - artifacts.TestCumulativeRewardTracking, - env.provider, - txDefaults, - artifacts, - this._stakingApiWrapper.wethContract.address, - this._stakingApiWrapper.zrxVaultContract.address, - ); - } - - public getTestCumulativeRewardTrackingContract(): TestCumulativeRewardTrackingContract { - if (this._testCumulativeRewardTrackingContract === undefined) { - throw new Error(`Contract has not been deployed. Run 'deployAndConfigureTestContractsAsync'.`); - } - return this._testCumulativeRewardTrackingContract; - } - - public async runTestAsync( - initActions: TestAction[], - testActions: TestAction[], - expectedTestLogs: TestLog[], - ): Promise { - await this._executeActionsAsync(initActions); - await this._stakingApiWrapper.stakingProxyContract - .attachStakingContract(this.getTestCumulativeRewardTrackingContract().address) - .awaitTransactionSuccessAsync(); - const testLogs = await this._executeActionsAsync(testActions); - CumulativeRewardTrackingSimulation._assertTestLogs(expectedTestLogs, testLogs); - } - - private async _executeActionsAsync(actions: TestAction[]): Promise { - const combinedLogs = [] as DecodedLogs; - for (const action of actions) { - let receipt: TransactionReceiptWithDecodedLogs | undefined; - let logs = [] as DecodedLogs; - switch (action) { - case TestAction.Finalize: - logs = await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync(); - break; - - case TestAction.Delegate: - await this._stakingApiWrapper.stakingContract.stake(this._amountToStake).sendTransactionAsync({ - from: this._staker, - }); - receipt = await this._stakingApiWrapper.stakingContract - .moveStake( - new StakeInfo(StakeStatus.Undelegated), - new StakeInfo(StakeStatus.Delegated, this._poolId), - this._amountToStake, - ) - .awaitTransactionSuccessAsync({ from: this._staker }); - break; - - case TestAction.Undelegate: - receipt = await this._stakingApiWrapper.stakingContract - .moveStake( - new StakeInfo(StakeStatus.Delegated, this._poolId), - new StakeInfo(StakeStatus.Undelegated), - this._amountToStake, - ) - .awaitTransactionSuccessAsync({ from: this._staker }); - break; - - case TestAction.PayProtocolFee: - receipt = await this._stakingApiWrapper.stakingContract - .payProtocolFee(this._poolOperator, this._takerAddress, this._protocolFee) - .awaitTransactionSuccessAsync({ from: this._exchangeAddress, value: this._protocolFee }); - break; - - case TestAction.CreatePool: - receipt = await this._stakingApiWrapper.stakingContract - .createStakingPool(0, true) - .awaitTransactionSuccessAsync({ from: this._poolOperator }); - const createStakingPoolLog = receipt.logs[0]; - // tslint:disable-next-line no-unnecessary-type-assertion - this._poolId = (createStakingPoolLog as DecodedLogEntry).args.poolId; - break; - - default: - throw new Error('Unrecognized test action'); - } - if (receipt !== undefined) { - logs = receipt.logs as DecodedLogs; - } - combinedLogs.splice(combinedLogs.length, 0, ...logs); - } - return combinedLogs; - } -} diff --git a/contracts/staking/test/utils/queue.ts b/contracts/staking/test/utils/queue.ts deleted file mode 100644 index 4a6d602988..0000000000 --- a/contracts/staking/test/utils/queue.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as _ from 'lodash'; - -export class Queue { - private _store: T[] = []; - constructor(store?: T[]) { - this._store = store !== undefined ? _.cloneDeep(store) : []; - } - public pushBack(val: T): void { - this._store.push(val); - } - public pushFront(val: T): void { - this._store.unshift(val); - } - public popFront(): T { - if (this._store.length === 0) { - throw new Error('Queue is empty'); - } - return this._store.shift() as T; - } - public popBack(): T { - if (this._store.length === 0) { - throw new Error('Queue is empty'); - } - const backElement = this._store.splice(-1, 1)[0]; - return backElement; - } - public mergeBack(q: Queue): void { - this._store = this._store.concat(q._store); - } - public mergeFront(q: Queue): 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/contracts/staking/test/wrappers.ts b/contracts/staking/test/wrappers.ts deleted file mode 100644 index 02a2aa183a..0000000000 --- a/contracts/staking/test/wrappers.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ----------------------------------------------------------------------------- - * Warning: This file is auto-generated by contracts-gen. Don't edit manually. - * ----------------------------------------------------------------------------- - */ -export * from '../test/generated-wrappers/i_staking'; -export * from '../test/generated-wrappers/i_staking_events'; -export * from '../test/generated-wrappers/i_staking_proxy'; -export * from '../test/generated-wrappers/i_storage'; -export * from '../test/generated-wrappers/i_storage_init'; -export * from '../test/generated-wrappers/i_structs'; -export * from '../test/generated-wrappers/i_zrx_vault'; -export * from '../test/generated-wrappers/lib_cobb_douglas'; -export * from '../test/generated-wrappers/lib_fixed_math'; -export * from '../test/generated-wrappers/lib_fixed_math_rich_errors'; -export * from '../test/generated-wrappers/lib_safe_downcast'; -export * from '../test/generated-wrappers/lib_staking_rich_errors'; -export * from '../test/generated-wrappers/mixin_abstract'; -export * from '../test/generated-wrappers/mixin_constants'; -export * from '../test/generated-wrappers/mixin_cumulative_rewards'; -export * from '../test/generated-wrappers/mixin_deployment_constants'; -export * from '../test/generated-wrappers/mixin_exchange_fees'; -export * from '../test/generated-wrappers/mixin_exchange_manager'; -export * from '../test/generated-wrappers/mixin_finalizer'; -export * from '../test/generated-wrappers/mixin_params'; -export * from '../test/generated-wrappers/mixin_scheduler'; -export * from '../test/generated-wrappers/mixin_stake'; -export * from '../test/generated-wrappers/mixin_stake_balances'; -export * from '../test/generated-wrappers/mixin_stake_storage'; -export * from '../test/generated-wrappers/mixin_staking_pool'; -export * from '../test/generated-wrappers/mixin_staking_pool_rewards'; -export * from '../test/generated-wrappers/mixin_storage'; -export * from '../test/generated-wrappers/staking'; -export * from '../test/generated-wrappers/staking_patch'; -export * from '../test/generated-wrappers/staking_proxy'; -export * from '../test/generated-wrappers/test_assert_storage_params'; -export * from '../test/generated-wrappers/test_cobb_douglas'; -export * from '../test/generated-wrappers/test_cumulative_reward_tracking'; -export * from '../test/generated-wrappers/test_delegator_rewards'; -export * from '../test/generated-wrappers/test_exchange_manager'; -export * from '../test/generated-wrappers/test_finalizer'; -export * from '../test/generated-wrappers/test_init_target'; -export * from '../test/generated-wrappers/test_lib_fixed_math'; -export * from '../test/generated-wrappers/test_lib_safe_downcast'; -export * from '../test/generated-wrappers/test_mixin_cumulative_rewards'; -export * from '../test/generated-wrappers/test_mixin_params'; -export * from '../test/generated-wrappers/test_mixin_scheduler'; -export * from '../test/generated-wrappers/test_mixin_stake'; -export * from '../test/generated-wrappers/test_mixin_stake_balances'; -export * from '../test/generated-wrappers/test_mixin_stake_storage'; -export * from '../test/generated-wrappers/test_mixin_staking_pool'; -export * from '../test/generated-wrappers/test_mixin_staking_pool_rewards'; -export * from '../test/generated-wrappers/test_protocol_fees'; -export * from '../test/generated-wrappers/test_proxy_destination'; -export * from '../test/generated-wrappers/test_staking'; -export * from '../test/generated-wrappers/test_staking_no_w_e_t_h'; -export * from '../test/generated-wrappers/test_staking_proxy'; -export * from '../test/generated-wrappers/test_staking_proxy_unit'; -export * from '../test/generated-wrappers/test_storage_layout_and_constants'; -export * from '../test/generated-wrappers/zrx_vault'; diff --git a/contracts/staking/truffle-config.js b/contracts/staking/truffle-config.js deleted file mode 100644 index 4942f2446e..0000000000 --- a/contracts/staking/truffle-config.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Use this file to configure your truffle project. It's seeded with some - * common settings for different networks and features like migrations, - * compilation and testing. Uncomment the ones you need or modify - * them to suit your project as necessary. - * - * More information about configuration can be found at: - * - * truffleframework.com/docs/advanced/configuration - * - * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) - * to sign your transactions before they're sent to a remote public node. Infura accounts - * are available for free at: infura.io/register. - * - * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate - * public/private key pairs. If you're publishing your code to GitHub make sure you load this - * phrase from a file you've .gitignored so it doesn't accidentally become public. - * - */ - -// const HDWalletProvider = require('truffle-hdwallet-provider'); -// const infuraKey = "fj4jll3k....."; -// -// const fs = require('fs'); -// const mnemonic = fs.readFileSync(".secret").toString().trim(); - -module.exports = { - /** - * Networks define how you connect to your ethereum client and let you set the - * defaults web3 uses to send transactions. If you don't specify one truffle - * will spin up a development blockchain for you on port 9545 when you - * run `develop` or `test`. You can ask a truffle command to use a specific - * network from the command line, e.g - * - * $ truffle test --network - */ - - networks: { - // Useful for testing. The `development` name is special - truffle uses it by default - // if it's defined here and no other network is specified at the command line. - // You should run a client (like ganache-cli, geth or parity) in a separate terminal - // tab if you use this network and you must also set the `host`, `port` and `network_id` - // options below to some value. - // - // development: { - // host: "127.0.0.1", // Localhost (default: none) - // port: 8545, // Standard Ethereum port (default: none) - // network_id: "*", // Any network (default: none) - // }, - // Another network with more advanced options... - // advanced: { - // port: 8777, // Custom port - // network_id: 1342, // Custom network - // gas: 8500000, // Gas sent with each transaction (default: ~6700000) - // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - // from:
, // Account to send txs from (default: accounts[0]) - // websockets: true // Enable EventEmitter interface for web3 (default: false) - // }, - // Useful for deploying to a public network. - // NB: It's important to wrap the provider as a function. - // ropsten: { - // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), - // network_id: 3, // Ropsten's id - // gas: 5500000, // Ropsten has a lower block limit than mainnet - // confirmations: 2, // # of confs to wait between deployments. (default: 0) - // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - // }, - // Useful for private networks - // private: { - // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), - // network_id: 2111, // This network is yours, in the cloud. - // production: true // Treats this network as if it was a public net. (default: false) - // } - }, - - // Set default mocha options here, use special reporters etc. - mocha: { - // timeout: 100000 - }, - - // Configure your compilers - compilers: { - solc: { - version: '0.5.11', - settings: { - evmVersion: 'istanbul', - optimizer: { - enabled: true, - runs: 1000000, - details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, - }, - }, - }, - }, -}; diff --git a/contracts/staking/tsconfig.json b/contracts/staking/tsconfig.json deleted file mode 100644 index fb170dab85..0000000000 --- a/contracts/staking/tsconfig.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, - "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": [ - "generated-artifacts/IStaking.json", - "generated-artifacts/IStakingEvents.json", - "generated-artifacts/IStakingProxy.json", - "generated-artifacts/IZrxVault.json", - "generated-artifacts/LibStakingRichErrors.json", - "generated-artifacts/Staking.json", - "generated-artifacts/StakingProxy.json", - "generated-artifacts/TestStaking.json", - "generated-artifacts/ZrxVault.json", - "test/generated-artifacts/IStaking.json", - "test/generated-artifacts/IStakingEvents.json", - "test/generated-artifacts/IStakingProxy.json", - "test/generated-artifacts/IStorage.json", - "test/generated-artifacts/IStorageInit.json", - "test/generated-artifacts/IStructs.json", - "test/generated-artifacts/IZrxVault.json", - "test/generated-artifacts/LibCobbDouglas.json", - "test/generated-artifacts/LibFixedMath.json", - "test/generated-artifacts/LibFixedMathRichErrors.json", - "test/generated-artifacts/LibSafeDowncast.json", - "test/generated-artifacts/LibStakingRichErrors.json", - "test/generated-artifacts/MixinAbstract.json", - "test/generated-artifacts/MixinConstants.json", - "test/generated-artifacts/MixinCumulativeRewards.json", - "test/generated-artifacts/MixinDeploymentConstants.json", - "test/generated-artifacts/MixinExchangeFees.json", - "test/generated-artifacts/MixinExchangeManager.json", - "test/generated-artifacts/MixinFinalizer.json", - "test/generated-artifacts/MixinParams.json", - "test/generated-artifacts/MixinScheduler.json", - "test/generated-artifacts/MixinStake.json", - "test/generated-artifacts/MixinStakeBalances.json", - "test/generated-artifacts/MixinStakeStorage.json", - "test/generated-artifacts/MixinStakingPool.json", - "test/generated-artifacts/MixinStakingPoolRewards.json", - "test/generated-artifacts/MixinStorage.json", - "test/generated-artifacts/Staking.json", - "test/generated-artifacts/StakingPatch.json", - "test/generated-artifacts/StakingProxy.json", - "test/generated-artifacts/TestAssertStorageParams.json", - "test/generated-artifacts/TestCobbDouglas.json", - "test/generated-artifacts/TestCumulativeRewardTracking.json", - "test/generated-artifacts/TestDelegatorRewards.json", - "test/generated-artifacts/TestExchangeManager.json", - "test/generated-artifacts/TestFinalizer.json", - "test/generated-artifacts/TestInitTarget.json", - "test/generated-artifacts/TestLibFixedMath.json", - "test/generated-artifacts/TestLibSafeDowncast.json", - "test/generated-artifacts/TestMixinCumulativeRewards.json", - "test/generated-artifacts/TestMixinParams.json", - "test/generated-artifacts/TestMixinScheduler.json", - "test/generated-artifacts/TestMixinStake.json", - "test/generated-artifacts/TestMixinStakeBalances.json", - "test/generated-artifacts/TestMixinStakeStorage.json", - "test/generated-artifacts/TestMixinStakingPool.json", - "test/generated-artifacts/TestMixinStakingPoolRewards.json", - "test/generated-artifacts/TestProtocolFees.json", - "test/generated-artifacts/TestProxyDestination.json", - "test/generated-artifacts/TestStaking.json", - "test/generated-artifacts/TestStakingNoWETH.json", - "test/generated-artifacts/TestStakingProxy.json", - "test/generated-artifacts/TestStakingProxyUnit.json", - "test/generated-artifacts/TestStorageLayoutAndConstants.json", - "test/generated-artifacts/ZrxVault.json" - ], - "exclude": ["./deploy/solc/solc_bin"] -} diff --git a/contracts/staking/tslint.json b/contracts/staking/tslint.json deleted file mode 100644 index 1efab0706b..0000000000 --- a/contracts/staking/tslint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "custom-no-magic-numbers": false, - "restrict-plus-operands": false - } -} diff --git a/contracts/staking/typedoc-tsconfig.json b/contracts/staking/typedoc-tsconfig.json deleted file mode 100644 index c9b0af1ae6..0000000000 --- a/contracts/staking/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/contracts/test-utils/src/index.ts b/contracts/test-utils/src/index.ts index 9371ae9f09..c8cf2e397b 100644 --- a/contracts/test-utils/src/index.ts +++ b/contracts/test-utils/src/index.ts @@ -31,11 +31,6 @@ export { BatchMatchOrder, ContractName, ERC20BalancesByOwner, - ERC1155FungibleHoldingsByOwner, - ERC1155HoldingsByOwner, - ERC1155Holdings, - ERC1155NonFungibleHoldingsByOwner, - ERC721TokenIdsByOwner, EthBalancesByOwner, FillEventArgs, MarketBuyOrders, diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts index 2db80a1437..12a3a341f1 100644 --- a/contracts/test-utils/src/types.ts +++ b/contracts/test-utils/src/types.ts @@ -10,33 +10,6 @@ export interface ERC20BalancesByOwner { }; } -export interface ERC721TokenIdsByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: BigNumber[]; - }; -} - -export interface ERC1155FungibleHoldingsByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: { - [tokenId: string]: BigNumber; - }; - }; -} - -export interface ERC1155NonFungibleHoldingsByOwner { - [ownerAddress: string]: { - [tokenAddress: string]: { - [tokenId: string]: BigNumber[]; - }; - }; -} - -export interface ERC1155HoldingsByOwner { - fungible: ERC1155FungibleHoldingsByOwner; - nonFungible: ERC1155NonFungibleHoldingsByOwner; -} - export interface EthBalancesByOwner { [owner: string]: BigNumber; } @@ -142,21 +115,8 @@ export interface MatchOrder { rightSignature: string; } -export interface ERC1155Holdings { - [owner: string]: { - [contract: string]: { - fungible: { - [tokenId: string]: BigNumber; - }; - nonFungible: BigNumber[]; - }; - }; -} - export interface TokenBalances { erc20: ERC20BalancesByOwner; - erc721: ERC721TokenIdsByOwner; - erc1155: ERC1155Holdings; eth: EthBalancesByOwner; } diff --git a/contracts/exchange-libs/contracts/src/LibMath.sol b/contracts/utils/contracts/src/LibMath.sol similarity index 98% rename from contracts/exchange-libs/contracts/src/LibMath.sol rename to contracts/utils/contracts/src/LibMath.sol index e18c746bf1..1df06f436e 100644 --- a/contracts/exchange-libs/contracts/src/LibMath.sol +++ b/contracts/utils/contracts/src/LibMath.sol @@ -18,8 +18,8 @@ pragma solidity ^0.5.9; -import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; -import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; +import "./LibSafeMath.sol"; +import "./LibRichErrors.sol"; import "./LibMathRichErrors.sol"; diff --git a/contracts/exchange-libs/contracts/src/LibMathRichErrors.sol b/contracts/utils/contracts/src/LibMathRichErrors.sol similarity index 100% rename from contracts/exchange-libs/contracts/src/LibMathRichErrors.sol rename to contracts/utils/contracts/src/LibMathRichErrors.sol diff --git a/contracts/exchange-libs/contracts/test/TestLibMath.sol b/contracts/utils/contracts/test/TestLibMath.sol similarity index 100% rename from contracts/exchange-libs/contracts/test/TestLibMath.sol rename to contracts/utils/contracts/test/TestLibMath.sol diff --git a/contracts/utils/package.json b/contracts/utils/package.json index c7760e7578..b42706ecc5 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -36,9 +36,9 @@ "compile:truffle": "truffle compile" }, "config": { - "publicInterfaceContracts": "Authorizable,IAuthorizable,IOwnable,LibAddress,LibAddressArray,LibAddressArrayRichErrors,LibAuthorizableRichErrors,LibBytes,LibBytesRichErrors,LibEIP1271,LibEIP712,LibFractions,LibOwnableRichErrors,LibReentrancyGuardRichErrors,LibRichErrors,LibSafeMath,LibSafeMathRichErrors,Ownable,ReentrancyGuard,Refundable", + "publicInterfaceContracts": "Authorizable,IAuthorizable,IOwnable,LibAddress,LibAddressArray,LibAddressArrayRichErrors,LibAuthorizableRichErrors,LibBytes,LibBytesRichErrors,LibEIP1271,LibEIP712,LibFractions,LibOwnableRichErrors,LibReentrancyGuardRichErrors,LibRichErrors,LibMath,LibMathRichErrors,LibSafeMath,LibSafeMathRichErrors,Ownable,ReentrancyGuard,Refundable", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(Authorizable|AuthorizableV06|D18|DeploymentConstants|IAuthorizable|IAuthorizableV06|IOwnable|IOwnableV06|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibAuthorizableRichErrorsV06|LibBytes|LibBytesRichErrors|LibBytesRichErrorsV06|LibBytesV06|LibEIP1271|LibEIP712|LibFractions|LibMathRichErrorsV06|LibMathV06|LibOwnableRichErrors|LibOwnableRichErrorsV06|LibReentrancyGuardRichErrors|LibReentrancyGuardRichErrorsV06|LibRichErrors|LibRichErrorsV06|LibSafeMath|LibSafeMathRichErrors|LibSafeMathRichErrorsV06|LibSafeMathV06|Ownable|OwnableV06|ReentrancyGuard|ReentrancyGuardV06|Refundable|TestAuthorizable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json" + "abis": "./test/generated-artifacts/@(Authorizable|AuthorizableV06|D18|DeploymentConstants|IAuthorizable|IAuthorizableV06|IOwnable|IOwnableV06|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibAuthorizableRichErrorsV06|LibBytes|LibBytesRichErrors|LibBytesRichErrorsV06|LibBytesV06|LibEIP1271|LibEIP712|LibFractions|LibMath|LibMathRichErrors|LibMathRichErrorsV06|LibMathV06|LibOwnableRichErrors|LibOwnableRichErrorsV06|LibReentrancyGuardRichErrors|LibReentrancyGuardRichErrorsV06|LibRichErrors|LibRichErrorsV06|LibSafeMath|LibSafeMathRichErrors|LibSafeMathRichErrorsV06|LibSafeMathV06|Ownable|OwnableV06|ReentrancyGuard|ReentrancyGuardV06|Refundable|TestAuthorizable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibMath|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json" }, "repository": { "type": "git", diff --git a/contracts/utils/src/artifacts.ts b/contracts/utils/src/artifacts.ts index 9a894a4f0f..7b4d4213f3 100644 --- a/contracts/utils/src/artifacts.ts +++ b/contracts/utils/src/artifacts.ts @@ -17,6 +17,8 @@ import * as LibBytesRichErrors from '../generated-artifacts/LibBytesRichErrors.j import * as LibEIP1271 from '../generated-artifacts/LibEIP1271.json'; import * as LibEIP712 from '../generated-artifacts/LibEIP712.json'; import * as LibFractions from '../generated-artifacts/LibFractions.json'; +import * as LibMath from '../generated-artifacts/LibMath.json'; +import * as LibMathRichErrors from '../generated-artifacts/LibMathRichErrors.json'; import * as LibOwnableRichErrors from '../generated-artifacts/LibOwnableRichErrors.json'; import * as LibReentrancyGuardRichErrors from '../generated-artifacts/LibReentrancyGuardRichErrors.json'; import * as LibRichErrors from '../generated-artifacts/LibRichErrors.json'; @@ -41,6 +43,8 @@ export const artifacts = { LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, LibReentrancyGuardRichErrors: LibReentrancyGuardRichErrors as ContractArtifact, LibRichErrors: LibRichErrors as ContractArtifact, + LibMath: LibMath as ContractArtifact, + LibMathRichErrors: LibMathRichErrors as ContractArtifact, LibSafeMath: LibSafeMath as ContractArtifact, LibSafeMathRichErrors: LibSafeMathRichErrors as ContractArtifact, Ownable: Ownable as ContractArtifact, diff --git a/contracts/utils/src/reference_functions.ts b/contracts/utils/src/reference_functions.ts index cd67f4a089..91d2ae21f6 100644 --- a/contracts/utils/src/reference_functions.ts +++ b/contracts/utils/src/reference_functions.ts @@ -1,4 +1,4 @@ -import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; +import { BigNumber, LibMathRevertErrors, SafeMathRevertErrors } from '@0x/utils'; const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); @@ -52,3 +52,77 @@ export function safeDiv(a: BigNumber, b: BigNumber): BigNumber { } return a.dividedToIntegerBy(b); } + +// LibMath + +/** + * Checks if rounding error >= 0.1% when rounding down. + */ +export function isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { + if (denominator.eq(0)) { + throw new LibMathRevertErrors.DivisionByZeroError(); + } + if (numerator.eq(0) || target.eq(0)) { + return false; + } + const remainder = numerator.times(target).mod(denominator); + // Need to do this separately because solidity evaluates RHS of the comparison expression first. + const rhs = safeMul(numerator, target); + const lhs = safeMul(remainder, new BigNumber(1000)); + return lhs.gte(rhs); +} + +/** + * Checks if rounding error >= 0.1% when rounding up. + */ +export function isRoundingErrorCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { + if (denominator.eq(0)) { + throw new LibMathRevertErrors.DivisionByZeroError(); + } + if (numerator.eq(0) || target.eq(0)) { + return false; + } + let remainder = numerator.times(target).mod(denominator); + remainder = safeSub(denominator, remainder).mod(denominator); + // Need to do this separately because solidity evaluates RHS of the comparison expression first. + const rhs = safeMul(numerator, target); + const lhs = safeMul(remainder, new BigNumber(1000)); + return lhs.gte(rhs); +} + +/** + * Calculates partial value given a numerator and denominator rounded down. + * Reverts if rounding error is >= 0.1% + */ +export function safeGetPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + if (isRoundingErrorFloor(numerator, denominator, target)) { + throw new LibMathRevertErrors.RoundingError(numerator, denominator, target); + } + return safeDiv(safeMul(numerator, target), denominator); +} + +/** + * Calculates partial value given a numerator and denominator rounded down. + * Reverts if rounding error is >= 0.1% + */ +export function safeGetPartialAmountCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + if (isRoundingErrorCeil(numerator, denominator, target)) { + throw new LibMathRevertErrors.RoundingError(numerator, denominator, target); + } + return safeDiv(safeAdd(safeMul(numerator, target), safeSub(denominator, new BigNumber(1))), denominator); +} + +/** + * Calculates partial value given a numerator and denominator rounded down. + */ +export function getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + return safeDiv(safeMul(numerator, target), denominator); +} + +/** + * Calculates partial value given a numerator and denominator rounded down. + */ +export function getPartialAmountCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + const sub = safeSub(denominator, new BigNumber(1)); // This is computed first to simulate Solidity's order of operations + return safeDiv(safeAdd(safeMul(numerator, target), sub), denominator); +} diff --git a/contracts/utils/src/wrappers.ts b/contracts/utils/src/wrappers.ts index fe1277f8e8..b403af0b7e 100644 --- a/contracts/utils/src/wrappers.ts +++ b/contracts/utils/src/wrappers.ts @@ -15,6 +15,8 @@ export * from '../generated-wrappers/lib_bytes_rich_errors'; export * from '../generated-wrappers/lib_e_i_p1271'; export * from '../generated-wrappers/lib_e_i_p712'; export * from '../generated-wrappers/lib_fractions'; +export * from '../generated-wrappers/lib_math'; +export * from '../generated-wrappers/lib_math_rich_errors'; export * from '../generated-wrappers/lib_ownable_rich_errors'; export * from '../generated-wrappers/lib_reentrancy_guard_rich_errors'; export * from '../generated-wrappers/lib_rich_errors'; diff --git a/contracts/utils/test/artifacts.ts b/contracts/utils/test/artifacts.ts index 8fca550294..2868d4e26a 100644 --- a/contracts/utils/test/artifacts.ts +++ b/contracts/utils/test/artifacts.ts @@ -25,6 +25,8 @@ import * as LibBytesV06 from '../test/generated-artifacts/LibBytesV06.json'; import * as LibEIP1271 from '../test/generated-artifacts/LibEIP1271.json'; import * as LibEIP712 from '../test/generated-artifacts/LibEIP712.json'; import * as LibFractions from '../test/generated-artifacts/LibFractions.json'; +import * as LibMath from '../test/generated-artifacts/LibMath.json'; +import * as LibMathRichErrors from '../test/generated-artifacts/LibMathRichErrors.json'; import * as LibMathRichErrorsV06 from '../test/generated-artifacts/LibMathRichErrorsV06.json'; import * as LibMathV06 from '../test/generated-artifacts/LibMathV06.json'; import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json'; @@ -47,6 +49,7 @@ import * as TestLibAddress from '../test/generated-artifacts/TestLibAddress.json import * as TestLibAddressArray from '../test/generated-artifacts/TestLibAddressArray.json'; import * as TestLibBytes from '../test/generated-artifacts/TestLibBytes.json'; import * as TestLibEIP712 from '../test/generated-artifacts/TestLibEIP712.json'; +import * as TestLibMath from '../test/generated-artifacts/TestLibMath.json'; import * as TestLibRichErrors from '../test/generated-artifacts/TestLibRichErrors.json'; import * as TestLibSafeMath from '../test/generated-artifacts/TestLibSafeMath.json'; import * as TestLogDecoding from '../test/generated-artifacts/TestLogDecoding.json'; @@ -68,6 +71,8 @@ export const artifacts = { LibEIP1271: LibEIP1271 as ContractArtifact, LibEIP712: LibEIP712 as ContractArtifact, LibFractions: LibFractions as ContractArtifact, + LibMath: LibMath as ContractArtifact, + LibMathRichErrors: LibMathRichErrors as ContractArtifact, LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, LibReentrancyGuardRichErrors: LibReentrancyGuardRichErrors as ContractArtifact, LibRichErrors: LibRichErrors as ContractArtifact, @@ -98,6 +103,7 @@ export const artifacts = { TestLibAddressArray: TestLibAddressArray as ContractArtifact, TestLibBytes: TestLibBytes as ContractArtifact, TestLibEIP712: TestLibEIP712 as ContractArtifact, + TestLibMath: TestLibMath as ContractArtifact, TestLibRichErrors: TestLibRichErrors as ContractArtifact, TestLibSafeMath: TestLibSafeMath as ContractArtifact, TestLogDecoding: TestLogDecoding as ContractArtifact, diff --git a/contracts/exchange-libs/test/lib_math.ts b/contracts/utils/test/lib_math.ts similarity index 99% rename from contracts/exchange-libs/test/lib_math.ts rename to contracts/utils/test/lib_math.ts index 4575f200ff..30303a1b6e 100644 --- a/contracts/exchange-libs/test/lib_math.ts +++ b/contracts/utils/test/lib_math.ts @@ -6,8 +6,7 @@ import { testCombinatoriallyWithReferenceFunc, uint256Values, } from '@0x/contracts-test-utils'; -import { SafeMathRevertErrors } from '@0x/contracts-utils'; -import { BigNumber, LibMathRevertErrors } from '@0x/utils'; +import { BigNumber, LibMathRevertErrors, SafeMathRevertErrors } from '@0x/utils'; import { getPartialAmountCeil, diff --git a/contracts/utils/test/wrappers.ts b/contracts/utils/test/wrappers.ts index fe570e9d32..8f75985e7a 100644 --- a/contracts/utils/test/wrappers.ts +++ b/contracts/utils/test/wrappers.ts @@ -23,6 +23,8 @@ export * from '../test/generated-wrappers/lib_bytes_v06'; export * from '../test/generated-wrappers/lib_e_i_p1271'; export * from '../test/generated-wrappers/lib_e_i_p712'; export * from '../test/generated-wrappers/lib_fractions'; +export * from '../test/generated-wrappers/lib_math'; +export * from '../test/generated-wrappers/lib_math_rich_errors'; export * from '../test/generated-wrappers/lib_math_rich_errors_v06'; export * from '../test/generated-wrappers/lib_math_v06'; export * from '../test/generated-wrappers/lib_ownable_rich_errors'; @@ -45,6 +47,7 @@ export * from '../test/generated-wrappers/test_lib_address'; export * from '../test/generated-wrappers/test_lib_address_array'; export * from '../test/generated-wrappers/test_lib_bytes'; export * from '../test/generated-wrappers/test_lib_e_i_p712'; +export * from '../test/generated-wrappers/test_lib_math'; export * from '../test/generated-wrappers/test_lib_rich_errors'; export * from '../test/generated-wrappers/test_lib_safe_math'; export * from '../test/generated-wrappers/test_log_decoding'; diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json index e68f43c2ea..0f4ccb13e4 100644 --- a/contracts/utils/tsconfig.json +++ b/contracts/utils/tsconfig.json @@ -15,6 +15,8 @@ "generated-artifacts/LibEIP1271.json", "generated-artifacts/LibEIP712.json", "generated-artifacts/LibFractions.json", + "generated-artifacts/LibMath.json", + "generated-artifacts/LibMathRichErrors.json", "generated-artifacts/LibOwnableRichErrors.json", "generated-artifacts/LibReentrancyGuardRichErrors.json", "generated-artifacts/LibRichErrors.json", @@ -43,6 +45,8 @@ "test/generated-artifacts/LibEIP1271.json", "test/generated-artifacts/LibEIP712.json", "test/generated-artifacts/LibFractions.json", + "test/generated-artifacts/LibMath.json", + "test/generated-artifacts/LibMathRichErrors.json", "test/generated-artifacts/LibMathRichErrorsV06.json", "test/generated-artifacts/LibMathV06.json", "test/generated-artifacts/LibOwnableRichErrors.json", @@ -65,6 +69,7 @@ "test/generated-artifacts/TestLibAddressArray.json", "test/generated-artifacts/TestLibBytes.json", "test/generated-artifacts/TestLibEIP712.json", + "test/generated-artifacts/TestLibMath.json", "test/generated-artifacts/TestLibRichErrors.json", "test/generated-artifacts/TestLibSafeMath.json", "test/generated-artifacts/TestLogDecoding.json", diff --git a/package.json b/package.json index 5c1e13fb0e..aa8cf02616 100644 --- a/package.json +++ b/package.json @@ -51,11 +51,11 @@ "verdaccio": "docker run --rm -i -p 4873:4873 0xorg/verdaccio" }, "config": { - "contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator @0x/contracts-broker @0x/contracts-zero-ex @0x/contracts-treasury", - "nonContractPackages": "@0x/order-utils @0x/migrations @0x/contract-wrappers @0x/contract-addresses @0x/contract-artifacts @0x/contract-wrappers-test @0x/asset-swapper", - "ignoreTestsForPackages": "@0x/contracts-integrations @0x/contracts-staking @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator", + "contractsPackages": "@0x/contracts-erc20 @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-zero-ex @0x/contracts-treasury", + "nonContractPackages": "@0x/migrations @0x/contract-wrappers @0x/contract-addresses @0x/contract-artifacts @0x/contract-wrappers-test @0x/asset-swapper", + "ignoreTestsForPackages": "", "mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic", - "packagesWithDocPages": "@0x/contract-wrappers @0x/order-utils @0x/migrations", + "packagesWithDocPages": "@0x/contract-wrappers @0x/migrations", "ignoreDependencyVersions": "@types/styled-components @types/node", "ignoreDependencyVersionsForPackage": "contract-wrappers" }, diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index 518dccc34f..550a5292f2 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -211,21 +211,21 @@ }, "1337": { "erc20Proxy": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48", - "erc721Proxy": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401", - "erc1155Proxy": "0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8", + "erc721Proxy": "0x0000000000000000000000000000000000000000", + "erc1155Proxy": "0x0000000000000000000000000000000000000000", "zrxToken": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c", "etherToken": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082", - "exchange": "0x48bacb9266a570d521063ef5dd96e61686dbe788", + "exchange": "0x0000000000000000000000000000000000000000", "assetProxyOwner": "0x0000000000000000000000000000000000000000", - "erc20BridgeProxy": "0x371b13d97f4bf77d724e78c16b7dc74099f40e84", + "erc20BridgeProxy": "0x0000000000000000000000000000000000000000", "zeroExGovernor": "0x0000000000000000000000000000000000000000", - "forwarder": "0xa4b3e1659c473623287b2cc13b194705cd792525", - "coordinatorRegistry": "0xaa86dda78e9434aca114b6676fc742a18d15a1cc", - "coordinator": "0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29", - "multiAssetProxy": "0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db", - "staticCallProxy": "0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f", - "devUtils": "0xb23672f74749bf7916ba6827c64111a4d6de7f11", - "exchangeV2": "0x48bacb9266a570d521063ef5dd96e61686dbe788", + "forwarder": "0x0000000000000000000000000000000000000000", + "coordinatorRegistry": "0x0000000000000000000000000000000000000000", + "coordinator": "0x0000000000000000000000000000000000000000", + "multiAssetProxy": "0x0000000000000000000000000000000000000000", + "staticCallProxy": "0x0000000000000000000000000000000000000000", + "devUtils": "0x0000000000000000000000000000000000000000", + "exchangeV2": "0x0000000000000000000000000000000000000000", "zrxVault": "0xf23276778860e420acfc18ebeebf7e829b06965c", "staking": "0x8a063452f7df2614db1bca3a85ef35da40cf0835", "stakingProxy": "0x59adefa01843c627ba5d6aa350292b4b7ccae67a", diff --git a/packages/contract-wrappers-test/.npmignore b/packages/contract-wrappers-test/.npmignore deleted file mode 100644 index ea588d4859..0000000000 --- a/packages/contract-wrappers-test/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Blacklist tests and publish scripts -/lib/test/* -/lib/monorepo_scripts/ -# Package specific ignore diff --git a/packages/contract-wrappers-test/coverage/.gitkeep b/packages/contract-wrappers-test/coverage/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/contract-wrappers-test/package.json b/packages/contract-wrappers-test/package.json deleted file mode 100644 index 47f6a716c8..0000000000 --- a/packages/contract-wrappers-test/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@0x/contract-wrappers-test", - "version": "12.2.53", - "engines": { - "node": ">=6.12" - }, - "description": "Tests for @0x/contract-wrappers", - "directories": { - "test": "test" - }, - "scripts": { - "build": "tsc -b", - "build:ci": "yarn build", - "lint": "tslint --format stylish --project . --exclude **/lib/**/*", - "fix": "tslint --fix --format stylish --project .--exclude **/lib/**/*", - "test:circleci": "run-s test:coverage", - "test": "yarn run_mocha", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 30000 --bail --exit", - "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", - "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "prettier": "prettier --write **/* --config ../../.prettierrc", - "clean": "shx rm -rf lib" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/packages/contract-wrappers-test", - "devDependencies": { - "@0x/contract-wrappers": "^13.17.4", - "@0x/contracts-test-utils": "^5.4.8", - "@0x/dev-utils": "^4.2.7", - "@0x/migrations": "^8.1.1", - "@0x/order-utils": "^10.4.28", - "@0x/subproviders": "^6.5.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "@types/nock": "^10.0.3", - "chai": "^4.0.1", - "dirty-chai": "^2.0.1", - "mocha": "^6.2.0", - "shx": "^0.2.2", - "tslint": "5.11.0", - "typescript": "4.2.2" - }, - "private": true, - "publishConfig": { - "access": "private" - } -} diff --git a/packages/contract-wrappers-test/test/calldata_decoder_test.ts b/packages/contract-wrappers-test/test/calldata_decoder_test.ts deleted file mode 100644 index ce6a9c7499..0000000000 --- a/packages/contract-wrappers-test/test/calldata_decoder_test.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { constants, OrderFactory } from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { migrateOnceAsync } from '@0x/migrations'; -import { SignedOrder } from '@0x/types'; -import { addressUtils, BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { ContractAddresses, ContractWrappers } from '@0x/contract-wrappers'; - -import { chaiSetup } from './utils/chai_setup'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; - -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('ABI Decoding Calldata', () => { - const defaultERC20MakerAssetAddress = addressUtils.generatePseudoRandomAddress(); - const matchOrdersSignature = - 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes),bytes,bytes)'; - const chainId: number = constants.TESTRPC_CHAIN_ID; - let signedOrderLeft: SignedOrder; - let signedOrderRight: SignedOrder; - let orderLeft = {}; - let orderRight = {}; - let matchOrdersTxData: string; - let contractAddresses: ContractAddresses; - let contractWrappers: ContractWrappers; - - before(async () => { - // Create accounts - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const [makerAddressLeft, makerAddressRight] = accounts; - const [privateKeyLeft, privateKeyRight] = constants.TESTRPC_PRIVATE_KEYS; - const exchangeAddress = addressUtils.generatePseudoRandomAddress(); - const feeRecipientAddress = addressUtils.generatePseudoRandomAddress(); - const domainInfo = { - exchangeAddress, - chainId, - }; - - contractAddresses = await migrateOnceAsync(provider); - await blockchainLifecycle.startAsync(); - const config = { - chainId: constants.TESTRPC_CHAIN_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - - // Create orders to match. - // Values are arbitrary, with the exception of maker addresses (generated above). - orderLeft = { - makerAddress: makerAddressLeft, - makerAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - makerAssetAmount: new BigNumber(10), - takerAddress: '0x0000000000000000000000000000000000000000', - takerAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - takerAssetAmount: new BigNumber(1), - feeRecipientAddress, - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - makerFeeAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - takerFeeAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - senderAddress: '0x0000000000000000000000000000000000000000', - expirationTimeSeconds: new BigNumber(1549498915), - salt: new BigNumber(217), - }; - orderRight = { - makerAddress: makerAddressRight, - makerAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - makerAssetAmount: new BigNumber(1), - takerAddress: '0x0000000000000000000000000000000000000000', - takerAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - takerAssetAmount: new BigNumber(8), - feeRecipientAddress, - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - makerFeeAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - takerFeeAssetData: await contractWrappers.devUtils - .encodeERC20AssetData(defaultERC20MakerAssetAddress) - .callAsync(), - senderAddress: '0x0000000000000000000000000000000000000000', - expirationTimeSeconds: new BigNumber(1549498915), - salt: new BigNumber(50010), - }; - const orderFactoryLeft = new OrderFactory(privateKeyLeft, orderLeft); - signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync(domainInfo); - const orderFactoryRight = new OrderFactory(privateKeyRight, orderRight); - signedOrderRight = await orderFactoryRight.newSignedOrderAsync(domainInfo); - // Encode match orders transaction - matchOrdersTxData = contractWrappers.exchange - .matchOrders(signedOrderLeft, signedOrderRight, signedOrderLeft.signature, signedOrderRight.signature) - .getABIEncodedTransactionData(); - }); - - describe('decode', () => { - it('should successfully decode Exchange.matchOrders calldata', async () => { - const contractName = 'Exchange'; - const decodedTxData = contractWrappers - .getAbiDecoder() - .decodeCalldataOrThrow(matchOrdersTxData, contractName); - const expectedFunctionName = 'matchOrders'; - const expectedFunctionArguments = { - leftOrder: orderLeft, - rightOrder: orderRight, - leftSignature: signedOrderLeft.signature, - rightSignature: signedOrderRight.signature, - }; - expect(decodedTxData.functionName).to.be.equal(expectedFunctionName); - expect(decodedTxData.functionSignature).to.be.equal(matchOrdersSignature); - expect(decodedTxData.functionArguments).to.be.deep.equal(expectedFunctionArguments); - }); - it('should throw if cannot decode calldata', async () => { - const badTxData = '0x01020304'; - expect(() => { - contractWrappers.getAbiDecoder().decodeCalldataOrThrow(badTxData); - }).to.throw("No functions registered for selector '0x01020304'"); - }); - }); -}); diff --git a/packages/contract-wrappers-test/test/global_hooks.ts b/packages/contract-wrappers-test/test/global_hooks.ts deleted file mode 100644 index 7a71d75923..0000000000 --- a/packages/contract-wrappers-test/test/global_hooks.ts +++ /dev/null @@ -1,6 +0,0 @@ -before('set up mocha', async function(): Promise { - // HACK: Since the migrations take longer then our global mocha timeout limit - // we manually increase it for this before hook. - const mochaTestTimeoutMs = 500000; - this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this -}); diff --git a/packages/contract-wrappers-test/test/utils/chai_setup.ts b/packages/contract-wrappers-test/test/utils/chai_setup.ts deleted file mode 100644 index e721397b28..0000000000 --- a/packages/contract-wrappers-test/test/utils/chai_setup.ts +++ /dev/null @@ -1 +0,0 @@ -export { chaiSetup } from '@0x/dev-utils'; diff --git a/packages/contract-wrappers-test/test/utils/constants.ts b/packages/contract-wrappers-test/test/utils/constants.ts deleted file mode 100644 index 261c248b76..0000000000 --- a/packages/contract-wrappers-test/test/utils/constants.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export const constants = { - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - ROPSTEN_CHAIN_ID: 3, - KOVAN_CHAIN_ID: 42, - AWAIT_TRANSACTION_MINED_MS: 0, - KOVAN_RPC_URL: 'https://kovan.infura.io/', - ROPSTEN_RPC_URL: 'https://ropsten.infura.io/', - ZRX_DECIMALS: 18, - DUMMY_TOKEN_NAME: '', - DUMMY_TOKEN_SYMBOL: '', - DUMMY_TOKEN_DECIMALS: 18, - DUMMY_TOKEN_TOTAL_SUPPLY: new BigNumber(10 ** 27), // tslint:disable-line:custom-no-magic-numbers - NUM_DUMMY_ERC20_TO_DEPLOY: 3, - NUM_DUMMY_ERC721_TO_DEPLOY: 1, - ZERO_AMOUNT: new BigNumber(0), -}; diff --git a/packages/contract-wrappers-test/test/utils/web3_wrapper.ts b/packages/contract-wrappers-test/test/utils/web3_wrapper.ts deleted file mode 100644 index f704897ab7..0000000000 --- a/packages/contract-wrappers-test/test/utils/web3_wrapper.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { devConstants, web3Factory } from '@0x/dev-utils'; -import { Web3ProviderEngine } from '@0x/subproviders'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -const txDefaults = { - from: devConstants.TESTRPC_FIRST_ADDRESS, - gas: devConstants.GAS_LIMIT, -}; -const provider: Web3ProviderEngine = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true }); -const web3Wrapper = new Web3Wrapper(provider); - -export { provider, web3Wrapper, txDefaults }; diff --git a/packages/contract-wrappers-test/tsconfig.json b/packages/contract-wrappers-test/tsconfig.json deleted file mode 100644 index 03390d35cc..0000000000 --- a/packages/contract-wrappers-test/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "." - }, - "include": ["./src/**/*", "./test/**/*"], - "exclude": ["node_modules"] -} diff --git a/packages/contract-wrappers-test/tslint.json b/packages/contract-wrappers-test/tslint.json deleted file mode 100644 index dd9053357e..0000000000 --- a/packages/contract-wrappers-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["@0x/tslint-config"] -} diff --git a/packages/migrations/package.json b/packages/migrations/package.json index b32d673e4c..fa4e179615 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -90,6 +90,7 @@ "@ledgerhq/hw-app-eth": "^4.3.0", "@types/web3-provider-engine": "^14.0.0", "ethereum-types": "^3.5.0", + "ethereumjs-util": "^7.1.0", "ethers": "~4.0.4", "lodash": "^4.17.11" }, diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts index 63cd8b4268..1af6081cee 100644 --- a/packages/migrations/src/migration.ts +++ b/packages/migrations/src/migration.ts @@ -1,24 +1,6 @@ -import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { - artifacts as assetProxyArtifacts, - ERC1155ProxyContract, - ERC20BridgeProxyContract, - ERC20ProxyContract, - ERC721ProxyContract, - MultiAssetProxyContract, - StaticCallProxyContract, -} from '@0x/contracts-asset-proxy'; -import { - artifacts as coordinatorArtifacts, - CoordinatorContract, - CoordinatorRegistryContract, -} from '@0x/contracts-coordinator'; -import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils'; -import { artifacts as erc1155Artifacts, ERC1155MintableContract } from '@0x/contracts-erc1155'; +import { ChainId, ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; +import { artifacts as assetProxyArtifacts, ERC20ProxyContract } from '@0x/contracts-asset-proxy'; import { artifacts as erc20Artifacts, DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20'; -import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721'; -import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange'; -import { artifacts as forwarderArtifacts, ForwarderContract } from '@0x/contracts-exchange-forwarder'; import { artifacts as stakingArtifacts, StakingProxyContract, @@ -37,20 +19,15 @@ import { } from '@0x/contracts-zero-ex'; import { Web3ProviderEngine } from '@0x/subproviders'; import { BigNumber, providerUtils } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider, TxData } from 'ethereum-types'; +import { bufferToHex, rlphash } from 'ethereumjs-util'; import { constants } from './utils/constants'; -import { erc20TokenInfo, erc721TokenInfo } from './utils/token_info'; +import { erc20TokenInfo } from './utils/token_info'; const allArtifacts = { ...assetProxyArtifacts, - ...coordinatorArtifacts, - ...devUtilsArtifacts, - ...erc1155Artifacts, - ...erc20Artifacts, - ...erc721Artifacts, - ...exchangeArtifacts, - ...forwarderArtifacts, ...stakingArtifacts, ...exchangeProxyArtifacts, ...assetProxyArtifacts, @@ -58,6 +35,49 @@ const allArtifacts = { const { NULL_ADDRESS } = constants; +// tslint:disable:custom-no-magic-numbers + +function getDeploymentNonce(deployer: string, address: string): number { + for (let i = 0; i < 10000; i++) { + const candidate = bufferToHex(rlphash([deployer, i]).slice(12)); + if (candidate.toLowerCase() === address.toLowerCase()) { + return i; + } + } + throw new Error(`Exhausted all attempts to find ${address} deployed by ${deployer}`); +} + +async function deployAtAddressAsync( + cb: () => Promise, + provider: SupportedProvider, + txDefaults: TxData, + wantedAddress: string, +): Promise { + await untilWantedAddressAsync(wantedAddress, provider, txDefaults); + return cb(); +} + +/** + * Increases addresses nonce until the deployment of a contract would occur at the wanted address. + */ +async function untilWantedAddressAsync( + wantedAddress: string, + provider: SupportedProvider, + txDefaults: TxData, + offset: number = 0, +): Promise { + const web3Wrapper = new Web3Wrapper(provider); + const from = txDefaults.from; + const currentNonce = await web3Wrapper.getAccountNonceAsync(from); + const wantedNonce = getDeploymentNonce(from, wantedAddress); + + if (currentNonce > wantedNonce) { + throw new Error(`Current nonce is ${currentNonce} but wanted nonce is ${wantedNonce}`); + } + for (let i = 0; i < wantedNonce - currentNonce + offset; i++) { + await web3Wrapper.sendTransactionAsync({ from, to: from, value: new BigNumber(0) }); + } +} /** * Creates and deploys all the contracts that are required for the latest * version of the 0x protocol. @@ -70,49 +90,45 @@ export async function runMigrationsAsync( txDefaults: TxData, ): Promise { const provider = providerUtils.standardizeOrThrow(supportedProvider); - const chainId = new BigNumber(await providerUtils.getChainIdAsync(provider)); + const expectedAddresses = getContractAddressesForChainOrThrow(ChainId.Ganache); - // Proxies - const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC20Proxy, + const erc20Proxy = await deployAtAddressAsync( + () => + ERC20ProxyContract.deployFrom0xArtifactAsync( + assetProxyArtifacts.ERC20Proxy, + provider, + txDefaults, + allArtifacts, + ), provider, txDefaults, - allArtifacts, - ); - const erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC721Proxy, - provider, - txDefaults, - allArtifacts, + expectedAddresses.erc20Proxy, ); // ZRX - const zrxToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyERC20Token, + const zrxToken = await deployAtAddressAsync( + () => + DummyERC20TokenContract.deployFrom0xArtifactAsync( + erc20Artifacts.DummyERC20Token, + provider, + txDefaults, + allArtifacts, + '0x Protocol Token', + 'ZRX', + new BigNumber(18), + new BigNumber(1000000000000000000000000000), + ), provider, txDefaults, - allArtifacts, - '0x Protocol Token', - 'ZRX', - new BigNumber(18), - new BigNumber(1000000000000000000000000000), + expectedAddresses.zrxToken, ); // Ether token - const etherToken = await WETH9Contract.deployFrom0xArtifactAsync( - erc20Artifacts.WETH9, + const etherToken = await deployAtAddressAsync( + () => WETH9Contract.deployFrom0xArtifactAsync(erc20Artifacts.WETH9, provider, txDefaults, allArtifacts), provider, txDefaults, - allArtifacts, - ); - - // Exchange - const exchange = await ExchangeContract.deployFrom0xArtifactAsync( - exchangeArtifacts.Exchange, - provider, - txDefaults, - allArtifacts, - chainId, + expectedAddresses.etherToken, ); // Dummy ERC20 tokens @@ -131,178 +147,62 @@ export async function runMigrationsAsync( ); } - // ERC721 - // tslint:disable-next-line:no-unused-variable - const cryptoKittieToken = await DummyERC721TokenContract.deployFrom0xArtifactAsync( - erc721Artifacts.DummyERC721Token, - provider, - txDefaults, - allArtifacts, - erc721TokenInfo[0].name, - erc721TokenInfo[0].symbol, - ); - - // 1155 Asset Proxy - const erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC1155Proxy, - provider, - txDefaults, - allArtifacts, - ); - - const staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.StaticCallProxy, - provider, - txDefaults, - allArtifacts, - ); - - const multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.MultiAssetProxy, - provider, - txDefaults, - allArtifacts, - ); - - await erc20Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - await erc721Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - await erc1155Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - await multiAssetProxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - - // MultiAssetProxy - await erc20Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync(txDefaults); - await erc721Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync(txDefaults); - await erc1155Proxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync(txDefaults); - await multiAssetProxy.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync(txDefaults); - await multiAssetProxy.registerAssetProxy(erc721Proxy.address).awaitTransactionSuccessAsync(txDefaults); - await multiAssetProxy.registerAssetProxy(erc1155Proxy.address).awaitTransactionSuccessAsync(txDefaults); - await multiAssetProxy.registerAssetProxy(staticCallProxy.address).awaitTransactionSuccessAsync(txDefaults); - - // Register the Asset Proxies to the Exchange - await exchange.registerAssetProxy(erc20Proxy.address).awaitTransactionSuccessAsync(txDefaults); - await exchange.registerAssetProxy(erc721Proxy.address).awaitTransactionSuccessAsync(txDefaults); - await exchange.registerAssetProxy(erc1155Proxy.address).awaitTransactionSuccessAsync(txDefaults); - await exchange.registerAssetProxy(multiAssetProxy.address).awaitTransactionSuccessAsync(txDefaults); - await exchange.registerAssetProxy(staticCallProxy.address).awaitTransactionSuccessAsync(txDefaults); - - // CoordinatorRegistry - const coordinatorRegistry = await CoordinatorRegistryContract.deployFrom0xArtifactAsync( - coordinatorArtifacts.CoordinatorRegistry, - provider, - txDefaults, - allArtifacts, - ); - - // Coordinator - const coordinator = await CoordinatorContract.deployFrom0xArtifactAsync( - coordinatorArtifacts.Coordinator, - provider, - txDefaults, - allArtifacts, - exchange.address, - chainId, - ); - - // Dev Utils - const devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - devUtilsArtifacts.DevUtils, - devUtilsArtifacts, - provider, - txDefaults, - allArtifacts, - exchange.address, - NULL_ADDRESS, - NULL_ADDRESS, - ); - - // tslint:disable-next-line:no-unused-variable - const erc1155DummyToken = await ERC1155MintableContract.deployFrom0xArtifactAsync( - erc1155Artifacts.ERC1155Mintable, - provider, - txDefaults, - allArtifacts, - ); - - const erc20BridgeProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync( - assetProxyArtifacts.ERC20BridgeProxy, - provider, - txDefaults, - allArtifacts, - ); - await exchange.registerAssetProxy(erc20BridgeProxy.address).awaitTransactionSuccessAsync(txDefaults); - await erc20BridgeProxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - await erc20BridgeProxy.addAuthorizedAddress(multiAssetProxy.address).awaitTransactionSuccessAsync(txDefaults); - await multiAssetProxy.registerAssetProxy(erc20BridgeProxy.address).awaitTransactionSuccessAsync(txDefaults); - const zrxProxy = erc20Proxy.address; - const zrxVault = await ZrxVaultContract.deployFrom0xArtifactAsync( - stakingArtifacts.ZrxVault, + const zrxVault = await deployAtAddressAsync( + () => + ZrxVaultContract.deployFrom0xArtifactAsync( + stakingArtifacts.ZrxVault, + provider, + txDefaults, + allArtifacts, + zrxProxy, + zrxToken.address, + ), provider, txDefaults, - allArtifacts, - zrxProxy, - zrxToken.address, + expectedAddresses.zrxVault, ); // Note we use TestStakingContract as the deployed bytecode of a StakingContract // has the tokens hardcoded - const stakingLogic = await TestStakingContract.deployFrom0xArtifactAsync( - stakingArtifacts.TestStaking, + const stakingLogic = await deployAtAddressAsync( + () => + TestStakingContract.deployFrom0xArtifactAsync( + stakingArtifacts.TestStaking, + provider, + txDefaults, + allArtifacts, + etherToken.address, + zrxVault.address, + ), provider, txDefaults, - allArtifacts, - etherToken.address, - zrxVault.address, + expectedAddresses.staking, ); - const stakingProxy = await StakingProxyContract.deployFrom0xArtifactAsync( - stakingArtifacts.StakingProxy, + const stakingProxy = await deployAtAddressAsync( + () => + StakingProxyContract.deployFrom0xArtifactAsync( + stakingArtifacts.StakingProxy, + provider, + txDefaults, + allArtifacts, + stakingLogic.address, + ), provider, txDefaults, - allArtifacts, - stakingLogic.address, + expectedAddresses.stakingProxy, ); await erc20Proxy.addAuthorizedAddress(zrxVault.address).awaitTransactionSuccessAsync(txDefaults); // Reference the Proxy as the StakingContract for setup - const stakingDel = await new TestStakingContract(stakingProxy.address, provider, txDefaults); + await new TestStakingContract(stakingProxy.address, provider, txDefaults); await stakingProxy.addAuthorizedAddress(txDefaults.from).awaitTransactionSuccessAsync(txDefaults); - await stakingDel.addExchangeAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - await exchange.setProtocolFeeCollectorAddress(stakingProxy.address).awaitTransactionSuccessAsync(txDefaults); - await exchange.setProtocolFeeMultiplier(new BigNumber(70000)).awaitTransactionSuccessAsync(txDefaults); await zrxVault.addAuthorizedAddress(txDefaults.from).awaitTransactionSuccessAsync(txDefaults); await zrxVault.setStakingProxy(stakingProxy.address).awaitTransactionSuccessAsync(txDefaults); await stakingLogic.addAuthorizedAddress(txDefaults.from).awaitTransactionSuccessAsync(txDefaults); - await stakingLogic.addExchangeAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults); - - // Forwarder - // Deployed after Exchange and Staking is configured as it queries - // in the constructor - const { exchangeV2: exchangeV2Address } = getContractAddressesForChainOrThrow(chainId.toNumber()); - const forwarder = await ForwarderContract.deployFrom0xArtifactAsync( - forwarderArtifacts.Forwarder, - provider, - txDefaults, - allArtifacts, - exchange.address, - exchangeV2Address || NULL_ADDRESS, - etherToken.address, - ); - - // JAM - // tslint:disable-next-line:no-unused-variable - const jamToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - erc20Artifacts.DummyERC20Token, - provider, - txDefaults, - allArtifacts, - 'JAM Token', - 'JAM', - new BigNumber(18), - new BigNumber(1000000000000000000000000000), - ); // Exchange Proxy ////////////////////////////////////////////////////////// @@ -314,60 +214,93 @@ export async function runMigrationsAsync( etherToken.address, ); + // HACK: Full migration first deploys a Migrator + await untilWantedAddressAsync(expectedAddresses.exchangeProxy, provider, txDefaults, -1); + const exchangeProxy = await fullMigrateExchangeProxyAsync(txDefaults.from, provider, txDefaults); const exchangeProxyFlashWalletAddress = await exchangeProxy.getTransformWallet().callAsync(); // Deploy transformers. - const wethTransformer = await WethTransformerContract.deployFrom0xArtifactAsync( - exchangeProxyArtifacts.WethTransformer, + const wethTransformer = await deployAtAddressAsync( + () => + WethTransformerContract.deployFrom0xArtifactAsync( + exchangeProxyArtifacts.WethTransformer, + provider, + txDefaults, + allArtifacts, + etherToken.address, + ), provider, txDefaults, - allArtifacts, - etherToken.address, + expectedAddresses.transformers.wethTransformer, ); - const payTakerTransformer = await PayTakerTransformerContract.deployFrom0xArtifactAsync( - exchangeProxyArtifacts.PayTakerTransformer, + const payTakerTransformer = await deployAtAddressAsync( + () => + PayTakerTransformerContract.deployFrom0xArtifactAsync( + exchangeProxyArtifacts.PayTakerTransformer, + provider, + txDefaults, + allArtifacts, + ), provider, txDefaults, - allArtifacts, + expectedAddresses.transformers.payTakerTransformer, ); - const affiliateFeeTransformer = await AffiliateFeeTransformerContract.deployFrom0xArtifactAsync( - exchangeProxyArtifacts.AffiliateFeeTransformer, + const affiliateFeeTransformer = await deployAtAddressAsync( + () => + AffiliateFeeTransformerContract.deployFrom0xArtifactAsync( + exchangeProxyArtifacts.AffiliateFeeTransformer, + provider, + txDefaults, + allArtifacts, + ), provider, txDefaults, - allArtifacts, + expectedAddresses.transformers.affiliateFeeTransformer, ); - const fillQuoteTransformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync( - exchangeProxyArtifacts.FillQuoteTransformer, + const fillQuoteTransformer = await deployAtAddressAsync( + () => + FillQuoteTransformerContract.deployFrom0xArtifactAsync( + exchangeProxyArtifacts.FillQuoteTransformer, + provider, + txDefaults, + allArtifacts, + bridgeAdapter.address, + exchangeProxy.address, + ), provider, txDefaults, - allArtifacts, - bridgeAdapter.address, - exchangeProxy.address, + expectedAddresses.transformers.fillQuoteTransformer, ); - const positiveSlippageFeeTransformer = await PositiveSlippageFeeTransformerContract.deployFrom0xArtifactAsync( - exchangeProxyArtifacts.PositiveSlippageFeeTransformer, + const positiveSlippageFeeTransformer = await deployAtAddressAsync( + () => + PositiveSlippageFeeTransformerContract.deployFrom0xArtifactAsync( + exchangeProxyArtifacts.PositiveSlippageFeeTransformer, + provider, + txDefaults, + allArtifacts, + ), provider, txDefaults, - allArtifacts, + expectedAddresses.transformers.positiveSlippageFeeTransformer, ); const contractAddresses = { erc20Proxy: erc20Proxy.address, - erc721Proxy: erc721Proxy.address, - erc1155Proxy: erc1155Proxy.address, + erc721Proxy: NULL_ADDRESS, + erc1155Proxy: NULL_ADDRESS, zrxToken: zrxToken.address, etherToken: etherToken.address, - exchange: exchange.address, + exchange: NULL_ADDRESS, assetProxyOwner: NULL_ADDRESS, - erc20BridgeProxy: erc20BridgeProxy.address, + erc20BridgeProxy: NULL_ADDRESS, zeroExGovernor: NULL_ADDRESS, - forwarder: forwarder.address, - coordinatorRegistry: coordinatorRegistry.address, - coordinator: coordinator.address, - multiAssetProxy: multiAssetProxy.address, - staticCallProxy: staticCallProxy.address, - devUtils: devUtils.address, - exchangeV2: exchangeV2Address || NULL_ADDRESS, + forwarder: NULL_ADDRESS, + coordinatorRegistry: NULL_ADDRESS, + coordinator: NULL_ADDRESS, + multiAssetProxy: NULL_ADDRESS, + staticCallProxy: NULL_ADDRESS, + devUtils: NULL_ADDRESS, + exchangeV2: NULL_ADDRESS, zrxVault: zrxVault.address, staking: stakingLogic.address, stakingProxy: stakingProxy.address, diff --git a/packages/migrations/src/test_contract_configs.ts b/packages/migrations/src/test_contract_configs.ts index 8b0728a0f4..f15bb390ec 100644 --- a/packages/migrations/src/test_contract_configs.ts +++ b/packages/migrations/src/test_contract_configs.ts @@ -1,16 +1,9 @@ #!/usr/bin/env node import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { - ERC1155ProxyContract, - ERC20ProxyContract, - ERC721ProxyContract, - MultiAssetProxyContract, -} from '@0x/contracts-asset-proxy'; -import { ExchangeContract } from '@0x/contracts-exchange'; +import { ERC20ProxyContract } from '@0x/contracts-asset-proxy'; import { ZeroExGovernorContract } from '@0x/contracts-multisig'; import { StakingContract, StakingProxyContract, ZrxVaultContract } from '@0x/contracts-staking'; import { EmptyWalletSubprovider, RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { AssetProxyId } from '@0x/types'; import { logUtils, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider } from 'ethereum-types'; @@ -41,91 +34,13 @@ async function testContractConfigsAsync(provider: SupportedProvider): Promise { - const exchangeOwner = await exchangeV2.owner().callAsync(); - warnIfMismatch(exchangeOwner, governor.address, 'Unexpected ExchangeV2 owner'); - - const registeredERC20Proxy = await exchangeV2.getAssetProxy(AssetProxyId.ERC20).callAsync(); - warnIfMismatch(registeredERC20Proxy, erc20Proxy.address, 'Unexpected ERC20Proxy registered in ExchangeV2'); - - const registeredERC721Proxy = await exchangeV2.getAssetProxy(AssetProxyId.ERC721).callAsync(); - warnIfMismatch(registeredERC721Proxy, erc721Proxy.address, 'Unexpected ERC721Proxy registered in ExchangeV2'); - - const registeredERC1155Proxy = await exchangeV2.getAssetProxy(AssetProxyId.ERC1155).callAsync(); - warnIfMismatch( - registeredERC1155Proxy, - erc1155Proxy.address, - 'Unexpected ERC1155Proxy registered in ExchangeV2', - ); - - const registeredMultiAssetProxy = await exchangeV2.getAssetProxy(AssetProxyId.MultiAsset).callAsync(); - warnIfMismatch( - registeredMultiAssetProxy, - multiAssetProxy.address, - 'Unexpected MultiAssetProxy registered in ExchangeV2', - ); - - const registeredStaticCallProxy = await exchangeV2.getAssetProxy(AssetProxyId.StaticCall).callAsync(); - warnIfMismatch( - registeredStaticCallProxy, - addresses.staticCallProxy, - 'Unexpected StaticCallProxy registered in ExchangeV2', - ); - } - - async function verifyExchangeV3ConfigsAsync(): Promise { - const exchangeOwner = await exchange.owner().callAsync(); - warnIfMismatch(exchangeOwner, governor.address, 'Unexpected Exchange owner'); - - const registeredERC20Proxy = await exchange.getAssetProxy(AssetProxyId.ERC20).callAsync(); - warnIfMismatch(registeredERC20Proxy, erc20Proxy.address, 'Unexpected ERC20Proxy registered in Exchange'); - - const registeredERC721Proxy = await exchange.getAssetProxy(AssetProxyId.ERC721).callAsync(); - warnIfMismatch(registeredERC721Proxy, erc721Proxy.address, 'Unexpected ERC721Proxy registered in Exchange'); - - const registeredERC1155Proxy = await exchange.getAssetProxy(AssetProxyId.ERC1155).callAsync(); - warnIfMismatch(registeredERC1155Proxy, erc1155Proxy.address, 'Unexpected ERC1155Proxy registered in Exchange'); - - const registeredMultiAssetProxy = await exchange.getAssetProxy(AssetProxyId.MultiAsset).callAsync(); - warnIfMismatch( - registeredMultiAssetProxy, - multiAssetProxy.address, - 'Unexpected MultiAssetProxy registered in Exchange', - ); - - const registeredStaticCallProxy = await exchange.getAssetProxy(AssetProxyId.StaticCall).callAsync(); - warnIfMismatch( - registeredStaticCallProxy, - addresses.staticCallProxy, - 'Unexpected StaticCallProxy registered in Exchange', - ); - - const registeredERC20BridgeProxy = await exchange.getAssetProxy(AssetProxyId.ERC20Bridge).callAsync(); - warnIfMismatch( - registeredERC20BridgeProxy, - addresses.erc20BridgeProxy, - 'Unexpected ERC20BridgeProxy registered in Exchange', - ); - - const protocolFeeCollector = await exchange.protocolFeeCollector().callAsync(); - warnIfMismatch(protocolFeeCollector, addresses.stakingProxy, 'Unexpected StakingProxy attached to Exchange'); - - const protocolFeeMultiplier = await exchange.protocolFeeMultiplier().callAsync(); - warnIfMismatch(protocolFeeMultiplier.toString(), '150000', 'Unexpected protocolFeeMultiplier in Exchange'); - } - async function verifyAssetProxyConfigsAsync(): Promise { // Verify ERC20Proxy configs const erc20ProxyOwner = await erc20Proxy.owner().callAsync(); @@ -134,54 +49,9 @@ async function testContractConfigsAsync(provider: SupportedProvider): Promise { @@ -373,8 +179,6 @@ async function testContractConfigsAsync(provider: SupportedProvider): Promise constants.ZERO_AMOUNT), ]); await submitAndExecuteTransactionAsync(governor, governor.address, batchTransactionData); - - await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync( - devUtilsArtifacts.DevUtils, - devUtilsArtifacts, - provider, - txDefaults, - devUtilsArtifacts, - exchange.address, - chaiBridge.address, - dydxBridge.address, - ); - - await CoordinatorContract.deployFrom0xArtifactAsync( - coordinatorArtifacts.Coordinator, - provider, - txDefaults, - coordinatorArtifacts, - exchange.address, - chainId, - ); - - await ForwarderContract.deployFrom0xArtifactAsync( - forwarderArtifacts.Forwarder, - provider, - txDefaults, - forwarderArtifacts, - exchange.address, - deployedAddresses.exchangeV2, - deployedAddresses.etherToken, - ); } (async () => { diff --git a/packages/migrations/src/utils/timelocks.ts b/packages/migrations/src/utils/timelocks.ts index 28eb0cb9c3..7d49c351ac 100644 --- a/packages/migrations/src/utils/timelocks.ts +++ b/packages/migrations/src/utils/timelocks.ts @@ -1,5 +1,4 @@ import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { ExchangeContract } from '@0x/contracts-exchange'; import { StakingContract, StakingProxyContract, ZrxVaultContract } from '@0x/contracts-staking'; import { IAuthorizableContract, IOwnableContract } from '@0x/contracts-utils'; import { Web3ProviderEngine } from '@0x/subproviders'; @@ -25,7 +24,6 @@ export function getTimelockRegistrationsByChainId(chainId: number): TimelockRegi const ownableInterface = new IOwnableContract(constants.NULL_ADDRESS, provider); const zrxVault = new ZrxVaultContract(constants.NULL_ADDRESS, provider); const stakingProxy = new StakingProxyContract(constants.NULL_ADDRESS, provider); - const exchange = new ExchangeContract(constants.NULL_ADDRESS, provider); const stakingLogic = new StakingContract(constants.NULL_ADDRESS, provider); const noTimelockRegistrations = [ @@ -40,59 +38,12 @@ export function getTimelockRegistrationsByChainId(chainId: number): TimelockRegi functionSelector: authorizableInterface.getSelector('removeAuthorizedAddressAtIndex'), secondsTimeLocked: constants.ZERO_AMOUNT, }, - { - destination: deployedAddresses.erc721Proxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddress'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.erc721Proxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddressAtIndex'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.erc1155Proxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddress'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.erc1155Proxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddressAtIndex'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.multiAssetProxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddress'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.multiAssetProxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddressAtIndex'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.erc20BridgeProxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddress'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.erc20BridgeProxy, - functionSelector: authorizableInterface.getSelector('removeAuthorizedAddressAtIndex'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, // ZrxVault timelocks { destination: deployedAddresses.zrxVault, functionSelector: zrxVault.getSelector('enterCatastrophicFailure'), secondsTimeLocked: constants.ZERO_AMOUNT, }, - // Exchange timelocks - - { - destination: deployedAddresses.exchange, - functionSelector: exchange.getSelector('detachProtocolFeeCollector'), - secondsTimeLocked: constants.ZERO_AMOUNT, - }, ]; const customTimelockRegistrations = [ @@ -188,19 +139,6 @@ export function getTimelockRegistrationsByChainId(chainId: number): TimelockRegi secondsTimeLocked: chainId === constants.MAINNET_CHAIN_ID ? constants.TWENTY_DAYS_IN_SEC : constants.ZERO_AMOUNT, }, - // Exchange timelocks - { - destination: deployedAddresses.exchange, - functionSelector: exchange.getSelector('setProtocolFeeMultiplier'), - secondsTimeLocked: - chainId === constants.MAINNET_CHAIN_ID ? constants.TEN_DAYS_IN_SEC : constants.ZERO_AMOUNT, - }, - { - destination: deployedAddresses.exchange, - functionSelector: exchange.getSelector('setProtocolFeeCollectorAddress'), - secondsTimeLocked: - chainId === constants.MAINNET_CHAIN_ID ? constants.TWENTY_DAYS_IN_SEC : constants.ZERO_AMOUNT, - }, ]; return [...noTimelockRegistrations, ...customTimelockRegistrations]; diff --git a/packages/order-utils/.npmignore b/packages/order-utils/.npmignore deleted file mode 100644 index ea588d4859..0000000000 --- a/packages/order-utils/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Blacklist tests and publish scripts -/lib/test/* -/lib/monorepo_scripts/ -# Package specific ignore diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json deleted file mode 100644 index 1b6e98d797..0000000000 --- a/packages/order-utils/CHANGELOG.json +++ /dev/null @@ -1,1419 +0,0 @@ -[ - { - "timestamp": 1628665757, - "version": "10.4.28", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1628225642, - "version": "10.4.27", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1624356181, - "version": "10.4.26", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1623382456, - "version": "10.4.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1622609597, - "version": "10.4.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621944788, - "version": "10.4.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1621600614, - "version": "10.4.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1620214333, - "version": "10.4.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1619596077, - "version": "10.4.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1617311315, - "version": "10.4.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1616005394, - "version": "10.4.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1614141718, - "version": "10.4.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1612950500, - "version": "10.4.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1611648096, - "version": "10.4.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1610510890, - "version": "10.4.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1609802516, - "version": "10.4.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608692071, - "version": "10.4.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1608245516, - "version": "10.4.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607485227, - "version": "10.4.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1607381756, - "version": "10.4.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1606961263, - "version": "10.4.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605763885, - "version": "10.4.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1605302002, - "version": "10.4.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604385937, - "version": "10.4.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604376968, - "version": "10.4.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1604355662, - "version": "10.4.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603851023, - "version": "10.4.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1603833198, - "version": "10.4.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "10.4.0", - "changes": [ - { - "note": "Add gitpkg.", - "pr": 2649 - }, - { - "note": "Fix `decodeAffiliateFeeTransformerData`", - "pr": 2658 - }, - { - "note": "Add `refundReceiver` field to `FillQuoteTransformer.TransformData`.", - "pr": 2657 - }, - { - "note": "Add `findTransformerNonce()` and `getTransformerAddress()` functions.", - "pr": 2657 - }, - { - "note": "Fix EP signature utils schema assertion.", - "pr": 2657 - }, - { - "note": "Add `rfqtTakerAddress` to `FillQuoteTransformerData`", - "pr": 2692 - } - ], - "timestamp": 1603265572 - }, - { - "version": "10.3.0", - "changes": [ - { - "note": "Add ERC20 Transformer utils and export useful constants.", - "pr": 2604 - }, - { - "note": "Add `getOrderHash()`, `getExchangeTransactionHash()`, `getExchangeProxyTransactionHash()`", - "pr": 2610 - } - ], - "timestamp": 1594788383 - }, - { - "timestamp": 1592969527, - "version": "10.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1583220306, - "version": "10.2.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582837861, - "version": "10.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1582623685, - "version": "10.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1581748629, - "version": "10.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "10.2.0", - "changes": [ - { - "note": "Remove use of ambient `DevUtils` instances.", - "pr": 2462 - }, - { - "note": "Make hash computing tooling non-async again.", - "pr": 2462 - }, - { - "note": "Add `transactionHashUtils`.", - "pr": 2462 - } - ], - "timestamp": 1581204851 - }, - { - "timestamp": 1580988106, - "version": "10.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1580811564, - "version": "10.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1579682890, - "version": "10.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "10.1.0", - "changes": [ - { - "note": "Export `isERC20AssetData`, `isERC20BridgeAssetData` and other equivalents.", - "pr": 2421 - } - ], - "timestamp": 1578272714 - }, - { - "timestamp": 1576540892, - "version": "10.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "10.0.0", - "changes": [ - { - "note": "Removed from assetDataUtils: individual decoding functions and assert functions", - "pr": 2388 - }, - { - "note": "Add ERC20Bridge support to assetDataUtils", - "pr": 2388 - } - ], - "timestamp": 1575931811 - }, - { - "version": "9.0.0", - "changes": [ - { - "note": "[Breaking] Removed `OrderStateUtils`, `OrderValidationUtils`, `ExchangeTransferSimulator` and all abstract and store classes. For order validation, please use the `DevUtils` contract wrapper method `getOrderRelevantState`|`getOrderRelevantStates`", - "pr": 2324 - }, - { - "note": "Removed exports CoordinatorRevertErrors, ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors, orderHashUtils, orderParsingUtils, StakingRevertErrors and transactionHashUtils", - "pr": 2321 - }, - { - "note": "Removed many functions from export signatureUtils", - "pr": 2321 - }, - { - "note": "Removed function isValidOrderHash from export orderHashUtils", - "pr": 2321 - }, - { - "note": "Remove `TransferFailedError` from `ForwarderRevertErrors`.", - "pr": 2309 - }, - { - "note": "All references to network ID have been removed, and references to chain ID have been introduced instead", - "pr": 2313 - }, - { - "note": "Add `chainId` `OrderValidationUtils`, `OrderFactory`", - "pr": 1742 - }, - { - "note": "Update tools to use new `Order` and `ZeroExTransaction` structure", - "pr": 1742 - }, - { - "note": "Update domain schema for Exchange and Coordinator", - "pr": 1742 - }, - { - "note": "Add Exchange `RevertError` types to `ExchangeRevertErrors`", - "pr": 1761 - }, - { - "note": "Add `SignatureOrderValidatorError` type to `ExchangeRevertErrors`", - "pr": 1774 - }, - { - "note": "Add `SignatureWalletOrderValidatorError` type to `ExchangeRevertErrors`", - "pr": 1774 - }, - { - "note": "Reorder parameters of some `RevertError` types to match smart contracts.", - "pr": 1790 - }, - { - "note": "Use arbitrary fee tokens instead of ZRX (ZEIP-28) for tools needed by contracts packages.", - "pr": 1819 - }, - { - "note": "Update `RevertError` types for new base constructor", - "pr": 1819 - }, - { - "note": "Add `Expired` TransactionErrorCode", - "pr": 1832 - }, - { - "note": "Add `expirationTimeSeconds` to `ZeroExTransaction` parameters used for hashing", - "pr": 1832 - }, - { - "note": "Add `validator` field to `SignatureValidatorError` `RevertError` types.", - "pr": 1885 - }, - { - "note": "Remove unused `RevertError` types.", - "pr": 1885 - }, - { - "note": "Add `ExchangeRevertErrors.SignatureErrorCode.InvalidSigner`.", - "pr": 2042 - }, - { - "note": "Add `takerAssetFillAmount` field to `IncompleteFillError` type", - "pr": 2075 - }, - { - "note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.", - "pr": 2075 - }, - { - "note": "Add EIP712 types for Staking", - "pr": 1910 - }, - { - "note": "Add `InvalidCobbDouglasAlphaError` `RevertError` type to `StakingRevertErrors`", - "pr": 2109 - }, - { - "note": "Rename `OperatorShareMustBeBetween0And100Error` `RevertError` type to `InvalidPoolOperatorShareError`.", - "pr": 2109 - }, - { - "note": "Add `TransactionGasPriceError` and `TransactionInvalidContextError` to error registry.", - "pr": 2109 - }, - { - "note": "Add `EthVaultNotSetError, `RewardVaultNotSetError`, and `InvalidStakeStatusError` to error registry.", - "pr": 2118 - }, - { - "note": "Add `InvalidStakeStatusError` to error registry.", - "pr": 2126 - }, - { - "note": "Add `InitializationError`, `InvalidParamValue` to `StakingRevertErrors`.", - "pr": 2131 - }, - { - "note": "Add `CumulativeRewardIntervalError`.", - "pr": 2154 - }, - { - "note": "Remove `validateOrderFillableOrThrowAsync`, `simpleValidateOrderFillableOrThrowAsync`, `validateMakerTransferThrowIfInvalidAsync`", - "pr": 2181 - }, - { - "note": "Add `PreviousEpochNotFinalizedError` to `StakingRevertErrors`.", - "pr": 2155 - }, - { - "note": "Add `InvalidMinimumPoolStake` to `StakingRevertErrors.InvalidParamValueErrorCode`.", - "pr": 2155 - }, - { - "note": "Renamed `OnlyCallableByPoolOperatorOrMakerError` to `OnlyCallableByPoolOperatorError`.", - "pr": 2250 - }, - { - "note": "Removed protocol fee != 0 error.", - "pr": 2278 - } - ], - "timestamp": 1575296764 - }, - { - "version": "8.5.0-beta.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1575290197 - }, - { - "version": "8.5.0-beta.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1574238768 - }, - { - "version": "8.5.0-beta.2", - "changes": [ - { - "note": "[Breaking] Removed `OrderStateUtils`, `OrderValidationUtils`, `ExchangeTransferSimulator` and all abstract and store classes. For order validation, please use the `DevUtils` contract wrapper method `getOrderRelevantState`|`getOrderRelevantStates`", - "pr": 2324 - }, - { - "note": "Removed exports CoordinatorRevertErrors, ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors, orderHashUtils, orderParsingUtils, StakingRevertErrors and transactionHashUtils", - "pr": 2321 - }, - { - "note": "Removed many functions from export signatureUtils", - "pr": 2321 - }, - { - "note": "Removed function isValidOrderHash from export orderHashUtils", - "pr": 2321 - } - ], - "timestamp": 1574030254 - }, - { - "version": "8.5.0-beta.1", - "changes": [ - { - "note": "Remove `TransferFailedError` from `ForwarderRevertErrors`.", - "pr": 2309 - }, - { - "note": "All references to network ID have been removed, and references to chain ID have been introduced instead", - "pr": 2313 - } - ], - "timestamp": 1573159180 - }, - { - "version": "8.5.0-beta.0", - "changes": [ - { - "note": "Add `chainId` `OrderValidationUtils`, `OrderFactory`", - "pr": 1742 - }, - { - "note": "Update tools to use new `Order` and `ZeroExTransaction` structure", - "pr": 1742 - }, - { - "note": "Update domain schema for Exchange and Coordinator", - "pr": 1742 - }, - { - "note": "Add Exchange `RevertError` types to `ExchangeRevertErrors`", - "pr": 1761 - }, - { - "note": "Add `SignatureOrderValidatorError` type to `ExchangeRevertErrors`", - "pr": 1774 - }, - { - "note": "Add `SignatureWalletOrderValidatorError` type to `ExchangeRevertErrors`", - "pr": 1774 - }, - { - "note": "Reorder parameters of some `RevertError` types to match smart contracts.", - "pr": 1790 - }, - { - "note": "Use arbitrary fee tokens instead of ZRX (ZEIP-28) for tools needed by contracts packages.", - "pr": 1819 - }, - { - "note": "Update `RevertError` types for new base constructor", - "pr": 1819 - }, - { - "note": "Add `Expired` TransactionErrorCode", - "pr": 1832 - }, - { - "note": "Add `expirationTimeSeconds` to `ZeroExTransaction` parameters used for hashing", - "pr": 1832 - }, - { - "note": "Add `validator` field to `SignatureValidatorError` `RevertError` types.", - "pr": 1885 - }, - { - "note": "Remove unused `RevertError` types.", - "pr": 1885 - }, - { - "note": "Add `ExchangeRevertErrors.SignatureErrorCode.InvalidSigner`.", - "pr": 2042 - }, - { - "note": "Add `takerAssetFillAmount` field to `IncompleteFillError` type", - "pr": 2075 - }, - { - "note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.", - "pr": 2075 - }, - { - "note": "Add EIP712 types for Staking", - "pr": 1910 - }, - { - "note": "Add `InvalidCobbDouglasAlphaError` `RevertError` type to `StakingRevertErrors`", - "pr": 2109 - }, - { - "note": "Rename `OperatorShareMustBeBetween0And100Error` `RevertError` type to `InvalidPoolOperatorShareError`.", - "pr": 2109 - }, - { - "note": "Add `TransactionGasPriceError` and `TransactionInvalidContextError` to error registry.", - "pr": 2109 - }, - { - "note": "Add `EthVaultNotSetError, `RewardVaultNotSetError`, and `InvalidStakeStatusError` to error registry.", - "pr": 2118 - }, - { - "note": "Add `InvalidStakeStatusError` to error registry.", - "pr": 2126 - }, - { - "note": "Add `InitializationError`, `InvalidParamValue` to `StakingRevertErrors`.", - "pr": 2131 - }, - { - "note": "Add `CumulativeRewardIntervalError`.", - "pr": 2154 - }, - { - "note": "Remove `validateOrderFillableOrThrowAsync`, `simpleValidateOrderFillableOrThrowAsync`, `validateMakerTransferThrowIfInvalidAsync`", - "pr": 2181 - }, - { - "note": "Add `PreviousEpochNotFinalizedError` to `StakingRevertErrors`.", - "pr": 2155 - }, - { - "note": "Add `InvalidMinimumPoolStake` to `StakingRevertErrors.InvalidParamValueErrorCode`.", - "pr": 2155 - }, - { - "note": "Renamed `OnlyCallableByPoolOperatorOrMakerError` to `OnlyCallableByPoolOperatorError`.", - "pr": 2250 - }, - { - "note": "Removed protocol fee != 0 error.", - "pr": 2278 - } - ], - "timestamp": 1570135330 - }, - { - "version": "8.4.0", - "changes": [ - { - "note": "Implement `simpleValidateOrderFillableOrThrowAsync`", - "pr": 2096 - } - ], - "timestamp": 1568744790 - }, - { - "timestamp": 1567521715, - "version": "8.3.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "8.3.0", - "changes": [ - { - "note": "Fix isValidValidatorSignatureAsync, allow to pass exchangeAddress to isValidSignatureAsync.", - "pr": 2017 - }, - { - "note": "Fix `Wallet` and `Validator` signature validation", - "pr": 2078 - } - ], - "timestamp": 1566446343 - }, - { - "timestamp": 1565296576, - "version": "8.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "8.2.4", - "changes": [ - { - "note": "Updated calls to .deploy0xArtifactAsync to include log decode dependencies.", - "pr": 1995 - } - ], - "timestamp": 1564604963 - }, - { - "version": "8.2.3", - "changes": [ - { - "note": "Ensure `assetData` is word aligned", - "pr": 1964 - } - ], - "timestamp": 1563957393 - }, - { - "timestamp": 1563193019, - "version": "8.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "8.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "8.2.0", - "changes": [ - { - "note": "Add support for encoding/decoding StaticCallProxy assetData", - "pr": 1863 - }, - { - "note": "Add support for marketSell utils", - "pr": 1914 - }, - { - "note": "Add support for encoding/decoding DutchAuction assetData", - "pr": 1943 - }, - { - "note": "Added `validateMakerTransferThrowIfInvalidAsync` to OrderValidationUtils", - "pr": 1937 - } - ], - "timestamp": 1563006338 - }, - { - "timestamp": 1558712885, - "version": "8.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "8.1.0", - "changes": [ - { - "note": "Add `ecSignTransactionAsync`", - "pr": 1817 - } - ], - "timestamp": 1557961111 - }, - { - "version": "8.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1557799313 - }, - { - "version": "8.0.0", - "changes": [ - { - "note": "Renamed `OrderError` to `TypedDataError`", - "pr": 1792 - } - ], - "timestamp": 1557507213 - }, - { - "version": "7.2.0", - "changes": [ - { - "note": "Added `orderCalculationUtils`", - "pr": 1714 - } - ], - "timestamp": 1554997931 - }, - { - "timestamp": 1553183790, - "version": "7.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "7.1.0", - "changes": [ - { - "note": "Add Coordinator EIP712 constants", - "pr": 1705 - }, - { - "note": "Added encoding/decoding for ERC1155 asset data", - "pr": 1661 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "7.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "7.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "7.0.0", - "changes": [ - { - "note": "Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38", - "pr": 1627 - }, - { - "note": "Update provider params to type SupportedProvider which outlines all supported providers", - "pr": 1627 - } - ], - "timestamp": 1551130135 - }, - { - "version": "6.1.0", - "changes": [ - { - "note": "Updated implementation of `generatePseudoRandomSalt` to use generator from @0x/utils", - "pr": 1569 - } - ], - "timestamp": 1549733923 - }, - { - "version": "6.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "version": "6.0.0", - "changes": { - "note": "Stop exporting the EIP712 schemas" - }, - "timestamp": 1549504360 - }, - { - "version": "5.0.0", - "changes": [ - { - "note": "Add `transactionHashUtils`", - "pr": 1576 - }, - { - "note": "Refactor `eip712Utils` to allow custom domain params", - "pr": 1576 - }, - { - "note": "Export constant EIP712 params", - "pr": 1576 - } - ], - "timestamp": 1549452781 - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - }, - { - "note": "Fix preSigned `isSignatureValidAsync` check", - "pr": 1580 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547561734, - "version": "3.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "3.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.1.0", - "changes": [ - { - "note": "Use new ABI encoder, add encoding/decoding logic for MultiAsset assetData, and add information to return values in orderStateUtils", - "pr": 1363 - } - ], - "timestamp": 1547040760 - }, - { - "version": "3.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544739608 - }, - { - "version": "3.0.6", - "changes": [ - { - "note": "Fix bug in wallet signature type verification", - "pr": 1414 - } - ], - "timestamp": 1544570656 - }, - { - "timestamp": 1544482891, - "version": "3.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1543401373, - "version": "3.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542821676, - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542208198, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542134075, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync`", - "pr": 1235 - }, - { - "note": "Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive", - "pr": 1235 - }, - { - "note": "Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218)", - "pr": 1235 - }, - { - "note": "Modified the `AbstractOrderFilledCancelledFetcher` interface slightly such that `isOrderCancelledAsync` accepts a `signedOrder` instead of an `orderHash` param", - "pr": 1235 - } - ], - "timestamp": 1542028948 - }, - { - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1541740904 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Added `ecSignOrderAsync` to first sign an order using `eth_signTypedData` and fallback to `eth_sign`.", - "pr": 1102 - }, - { - "note": "Added `ecSignTypedDataOrderAsync` to sign an order exclusively using `eth_signTypedData`.", - "pr": 1102 - }, - { - "note": "Rename `ecSignOrderHashAsync` to `ecSignHashAsync` removing `SignerType` parameter.", - "pr": 1102 - }, - { - "note": "Use `AssetData` union type for function return values.", - "pr": 1131 - } - ], - "timestamp": 1539871071 - }, - { - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1538693146 - }, - { - "version": "1.0.6", - "changes": [ - { - "note": "Add signerAddress normalization to `isValidECSignature` to avoid `invalid address recovery` error if caller supplies a checksummed address", - "pr": 1096 - } - ], - "timestamp": 1538157789 - }, - { - "timestamp": 1537907159, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537875740, - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537541580, - "version": "1.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.2", - "changes": [ - { - "note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts." - } - ], - "timestamp": 1537369748 - }, - { - "version": "1.0.1", - "changes": [ - { - "note": "Export `orderParsingUtils`", - "pr": 1044 - } - ], - "timestamp": 1536142250 - }, - { - "version": "1.0.1-rc.6", - "changes": [ - { - "note": "Fix missing `BlockParamLiteral` type import issue" - } - ], - "timestamp": 1535377027 - }, - { - "version": "1.0.1-rc.5", - "changes": [ - { - "note": "Remove Caller and Trezor SignatureTypes", - "pr": 1015 - } - ] - }, - { - "version": "1.0.1-rc.4", - "changes": [ - { - "note": "Remove rounding error being thrown when maker amount is very small", - "pr": 959 - }, - { - "note": "Added rateUtils and sortingUtils", - "pr": 953 - }, - { - "note": "Update marketUtils api such that all optional parameters are bundled into one optional param and more defaults are provided", - "pr": 954 - }, - { - "note": "Instead of exporting signature util methods individually, they are now exported as `signatureUtils`", - "pr": 924 - }, - { - "note": "Export types: `SignedOrder`, `Order`, `OrderRelevantState`, `OrderState`, `ECSignature`, `ERC20AssetData`, `ERC721AssetData`, `AssetProxyId`, `SignerType`, `SignatureType`, `OrderStateValid`, `OrderStateInvalid`, `ExchangeContractErrs`, `TradeSide`, `TransferType`, `FindFeeOrdersThatCoverFeesForTargetOrdersOpts`, `FindOrdersThatCoverMakerAssetFillAmountOpts`, `FeeOrdersAndRemainingFeeAmount`, `OrdersAndRemainingFillAmount`, `Provider`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload`", - "pr": 924 - }, - { - "note": "Rename `resultOrders` to `resultFeeOrders` for object returned by `findFeeOrdersThatCoverFeesForTargetOrders` in `marketUtils` api", - "pr": 997 - }, - { - "note": "Make `sortFeeOrdersByFeeAdjustedRate` in `sortingUtils` generic", - "pr": 997 - }, - { - "note": "Update `findFeeOrdersThatCoverFeesForTargetOrders` to round the the nearest integer when calculating required fees", - "pr": 997 - } - ], - "timestamp": 1535133899 - }, - { - "version": "1.0.1-rc.3", - "changes": [ - { - "pr": 914, - "note": "Update ecSignOrderHashAsync to return signature string with signature type byte. Removes messagePrefixOpts." - }, - { - "note": "Added a synchronous `createOrder` method in `orderFactory`, updated public interfaces to support some optional parameters", - "pr": 936 - }, - { - "note": "Added marketUtils", - "pr": 937 - }, - { - "note": "Dependencies updated" - } - ], - "timestamp": 1534210131 - }, - { - "version": "1.0.1-rc.2", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1532619515 - }, - { - "version": "1.0.1-rc.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1532605697 - }, - { - "version": "1.0.0", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1532357734 - }, - { - "version": "1.0.0-rc.2", - "changes": [ - { - "note": "Upgrade ethereumjs-abi dep including a fix so that addresses starting with 0 are properly decoded by `decodeERC20AssetData`" - } - ], - "timestamp": 1532357734 - }, - { - "timestamp": 1532043000, - "version": "1.0.0-rc.1", - "changes": [ - { - "note": "Refactor to work with V2 of 0x protocol", - "pr": 636 - }, - { - "note": "Export parseECSignature method", - "pr": 684 - }, - { - "note": "Handle Typed Arrays when hashing data", - "pr": 894 - } - ] - }, - { - "timestamp": 1531919263, - "version": "0.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1531149657, - "version": "0.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1529397769, - "version": "0.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527616612, - "version": "0.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.5", - "changes": [ - { - "note": "Add orderStateUtils, a module for computing order state needed to decide if an order is still valid" - } - ], - "timestamp": 1527008794 - }, - { - "timestamp": 1525477860, - "version": "0.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525453812, - "version": "0.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525428773, - "version": "0.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - } -] diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md deleted file mode 100644 index 5f8f479f84..0000000000 --- a/packages/order-utils/CHANGELOG.md +++ /dev/null @@ -1,544 +0,0 @@ - - -CHANGELOG - -## v10.4.28 - _August 11, 2021_ - - * Dependencies updated - -## v10.4.27 - _August 6, 2021_ - - * Dependencies updated - -## v10.4.26 - _June 22, 2021_ - - * Dependencies updated - -## v10.4.25 - _June 11, 2021_ - - * Dependencies updated - -## v10.4.24 - _June 2, 2021_ - - * Dependencies updated - -## v10.4.23 - _May 25, 2021_ - - * Dependencies updated - -## v10.4.22 - _May 21, 2021_ - - * Dependencies updated - -## v10.4.21 - _May 5, 2021_ - - * Dependencies updated - -## v10.4.20 - _April 28, 2021_ - - * Dependencies updated - -## v10.4.19 - _April 1, 2021_ - - * Dependencies updated - -## v10.4.18 - _March 17, 2021_ - - * Dependencies updated - -## v10.4.17 - _February 24, 2021_ - - * Dependencies updated - -## v10.4.16 - _February 10, 2021_ - - * Dependencies updated - -## v10.4.15 - _January 26, 2021_ - - * Dependencies updated - -## v10.4.14 - _January 13, 2021_ - - * Dependencies updated - -## v10.4.13 - _January 4, 2021_ - - * Dependencies updated - -## v10.4.12 - _December 23, 2020_ - - * Dependencies updated - -## v10.4.11 - _December 17, 2020_ - - * Dependencies updated - -## v10.4.10 - _December 9, 2020_ - - * Dependencies updated - -## v10.4.9 - _December 7, 2020_ - - * Dependencies updated - -## v10.4.8 - _December 3, 2020_ - - * Dependencies updated - -## v10.4.7 - _November 19, 2020_ - - * Dependencies updated - -## v10.4.6 - _November 13, 2020_ - - * Dependencies updated - -## v10.4.5 - _November 3, 2020_ - - * Dependencies updated - -## v10.4.4 - _November 3, 2020_ - - * Dependencies updated - -## v10.4.3 - _November 2, 2020_ - - * Dependencies updated - -## v10.4.2 - _October 28, 2020_ - - * Dependencies updated - -## v10.4.1 - _October 27, 2020_ - - * Dependencies updated - -## v10.4.0 - _October 21, 2020_ - - * Add gitpkg. (#2649) - * Fix `decodeAffiliateFeeTransformerData` (#2658) - * Add `refundReceiver` field to `FillQuoteTransformer.TransformData`. (#2657) - * Add `findTransformerNonce()` and `getTransformerAddress()` functions. (#2657) - * Fix EP signature utils schema assertion. (#2657) - * Add `rfqtTakerAddress` to `FillQuoteTransformerData` (#2692) - -## v10.3.0 - _July 15, 2020_ - - * Add ERC20 Transformer utils and export useful constants. (#2604) - * Add `getOrderHash()`, `getExchangeTransactionHash()`, `getExchangeProxyTransactionHash()` (#2610) - -## v10.2.5 - _June 24, 2020_ - - * Dependencies updated - -## v10.2.4 - _March 3, 2020_ - - * Dependencies updated - -## v10.2.3 - _February 27, 2020_ - - * Dependencies updated - -## v10.2.2 - _February 25, 2020_ - - * Dependencies updated - -## v10.2.1 - _February 15, 2020_ - - * Dependencies updated - -## v10.2.0 - _February 8, 2020_ - - * Remove use of ambient `DevUtils` instances. (#2462) - * Make hash computing tooling non-async again. (#2462) - * Add `transactionHashUtils`. (#2462) - -## v10.1.3 - _February 6, 2020_ - - * Dependencies updated - -## v10.1.2 - _February 4, 2020_ - - * Dependencies updated - -## v10.1.1 - _January 22, 2020_ - - * Dependencies updated - -## v10.1.0 - _January 6, 2020_ - - * Export `isERC20AssetData`, `isERC20BridgeAssetData` and other equivalents. (#2421) - -## v10.0.1 - _December 17, 2019_ - - * Dependencies updated - -## v10.0.0 - _December 9, 2019_ - - * Removed from assetDataUtils: individual decoding functions and assert functions (#2388) - * Add ERC20Bridge support to assetDataUtils (#2388) - -## v9.0.0 - _December 2, 2019_ - - * [Breaking] Removed `OrderStateUtils`, `OrderValidationUtils`, `ExchangeTransferSimulator` and all abstract and store classes. For order validation, please use the `DevUtils` contract wrapper method `getOrderRelevantState`|`getOrderRelevantStates` (#2324) - * Removed exports CoordinatorRevertErrors, ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors, orderHashUtils, orderParsingUtils, StakingRevertErrors and transactionHashUtils (#2321) - * Removed many functions from export signatureUtils (#2321) - * Removed function isValidOrderHash from export orderHashUtils (#2321) - * Remove `TransferFailedError` from `ForwarderRevertErrors`. (#2309) - * All references to network ID have been removed, and references to chain ID have been introduced instead (#2313) - * Add `chainId` `OrderValidationUtils`, `OrderFactory` (#1742) - * Update tools to use new `Order` and `ZeroExTransaction` structure (#1742) - * Update domain schema for Exchange and Coordinator (#1742) - * Add Exchange `RevertError` types to `ExchangeRevertErrors` (#1761) - * Add `SignatureOrderValidatorError` type to `ExchangeRevertErrors` (#1774) - * Add `SignatureWalletOrderValidatorError` type to `ExchangeRevertErrors` (#1774) - * Reorder parameters of some `RevertError` types to match smart contracts. (#1790) - * Use arbitrary fee tokens instead of ZRX (ZEIP-28) for tools needed by contracts packages. (#1819) - * Update `RevertError` types for new base constructor (#1819) - * Add `Expired` TransactionErrorCode (#1832) - * Add `expirationTimeSeconds` to `ZeroExTransaction` parameters used for hashing (#1832) - * Add `validator` field to `SignatureValidatorError` `RevertError` types. (#1885) - * Remove unused `RevertError` types. (#1885) - * Add `ExchangeRevertErrors.SignatureErrorCode.InvalidSigner`. (#2042) - * Add `takerAssetFillAmount` field to `IncompleteFillError` type (#2075) - * Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields. (#2075) - * Add EIP712 types for Staking (#1910) - * Add `InvalidCobbDouglasAlphaError` `RevertError` type to `StakingRevertErrors` (#2109) - * Rename `OperatorShareMustBeBetween0And100Error` `RevertError` type to `InvalidPoolOperatorShareError`. (#2109) - * Add `TransactionGasPriceError` and `TransactionInvalidContextError` to error registry. (#2109) - * Add `EthVaultNotSetError, `RewardVaultNotSetError`, and `InvalidStakeStatusError` to error registry. (#2118) - * Add `InvalidStakeStatusError` to error registry. (#2126) - * Add `InitializationError`, `InvalidParamValue` to `StakingRevertErrors`. (#2131) - * Add `CumulativeRewardIntervalError`. (#2154) - * Remove `validateOrderFillableOrThrowAsync`, `simpleValidateOrderFillableOrThrowAsync`, `validateMakerTransferThrowIfInvalidAsync` (#2181) - * Add `PreviousEpochNotFinalizedError` to `StakingRevertErrors`. (#2155) - * Add `InvalidMinimumPoolStake` to `StakingRevertErrors.InvalidParamValueErrorCode`. (#2155) - * Renamed `OnlyCallableByPoolOperatorOrMakerError` to `OnlyCallableByPoolOperatorError`. (#2250) - * Removed protocol fee != 0 error. (#2278) - -## v8.5.0-beta.4 - _December 2, 2019_ - - * Dependencies updated - -## v8.5.0-beta.3 - _November 20, 2019_ - - * Dependencies updated - -## v8.5.0-beta.2 - _November 17, 2019_ - - * [Breaking] Removed `OrderStateUtils`, `OrderValidationUtils`, `ExchangeTransferSimulator` and all abstract and store classes. For order validation, please use the `DevUtils` contract wrapper method `getOrderRelevantState`|`getOrderRelevantStates` (#2324) - * Removed exports CoordinatorRevertErrors, ExchangeRevertErrors, ForwarderRevertErrors, LibMathRevertErrors, orderHashUtils, orderParsingUtils, StakingRevertErrors and transactionHashUtils (#2321) - * Removed many functions from export signatureUtils (#2321) - * Removed function isValidOrderHash from export orderHashUtils (#2321) - -## v8.5.0-beta.1 - _November 7, 2019_ - - * Remove `TransferFailedError` from `ForwarderRevertErrors`. (#2309) - * All references to network ID have been removed, and references to chain ID have been introduced instead (#2313) - -## v8.5.0-beta.0 - _October 3, 2019_ - - * Add `chainId` `OrderValidationUtils`, `OrderFactory` (#1742) - * Update tools to use new `Order` and `ZeroExTransaction` structure (#1742) - * Update domain schema for Exchange and Coordinator (#1742) - * Add Exchange `RevertError` types to `ExchangeRevertErrors` (#1761) - * Add `SignatureOrderValidatorError` type to `ExchangeRevertErrors` (#1774) - * Add `SignatureWalletOrderValidatorError` type to `ExchangeRevertErrors` (#1774) - * Reorder parameters of some `RevertError` types to match smart contracts. (#1790) - * Use arbitrary fee tokens instead of ZRX (ZEIP-28) for tools needed by contracts packages. (#1819) - * Update `RevertError` types for new base constructor (#1819) - * Add `Expired` TransactionErrorCode (#1832) - * Add `expirationTimeSeconds` to `ZeroExTransaction` parameters used for hashing (#1832) - * Add `validator` field to `SignatureValidatorError` `RevertError` types. (#1885) - * Remove unused `RevertError` types. (#1885) - * Add `ExchangeRevertErrors.SignatureErrorCode.InvalidSigner`. (#2042) - * Add `takerAssetFillAmount` field to `IncompleteFillError` type (#2075) - * Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields. (#2075) - * Add EIP712 types for Staking (#1910) - * Add `InvalidCobbDouglasAlphaError` `RevertError` type to `StakingRevertErrors` (#2109) - * Rename `OperatorShareMustBeBetween0And100Error` `RevertError` type to `InvalidPoolOperatorShareError`. (#2109) - * Add `TransactionGasPriceError` and `TransactionInvalidContextError` to error registry. (#2109) - * Add `EthVaultNotSetError, `RewardVaultNotSetError`, and `InvalidStakeStatusError` to error registry. (#2118) - * Add `InvalidStakeStatusError` to error registry. (#2126) - * Add `InitializationError`, `InvalidParamValue` to `StakingRevertErrors`. (#2131) - * Add `CumulativeRewardIntervalError`. (#2154) - * Remove `validateOrderFillableOrThrowAsync`, `simpleValidateOrderFillableOrThrowAsync`, `validateMakerTransferThrowIfInvalidAsync` (#2181) - * Add `PreviousEpochNotFinalizedError` to `StakingRevertErrors`. (#2155) - * Add `InvalidMinimumPoolStake` to `StakingRevertErrors.InvalidParamValueErrorCode`. (#2155) - * Renamed `OnlyCallableByPoolOperatorOrMakerError` to `OnlyCallableByPoolOperatorError`. (#2250) - * Removed protocol fee != 0 error. (#2278) - -## v8.4.0 - _September 17, 2019_ - - * Implement `simpleValidateOrderFillableOrThrowAsync` (#2096) - -## v8.3.1 - _September 3, 2019_ - - * Dependencies updated - -## v8.3.0 - _August 22, 2019_ - - * Fix isValidValidatorSignatureAsync, allow to pass exchangeAddress to isValidSignatureAsync. (#2017) - * Fix `Wallet` and `Validator` signature validation (#2078) - -## v8.2.5 - _August 8, 2019_ - - * Dependencies updated - -## v8.2.4 - _July 31, 2019_ - - * Updated calls to .deploy0xArtifactAsync to include log decode dependencies. (#1995) - -## v8.2.3 - _July 24, 2019_ - - * Ensure `assetData` is word aligned (#1964) - -## v8.2.2 - _July 15, 2019_ - - * Dependencies updated - -## v8.2.1 - _July 13, 2019_ - - * Dependencies updated - -## v8.2.0 - _July 13, 2019_ - - * Add support for encoding/decoding StaticCallProxy assetData (#1863) - * Add support for marketSell utils (#1914) - * Add support for encoding/decoding DutchAuction assetData (#1943) - * Added `validateMakerTransferThrowIfInvalidAsync` to OrderValidationUtils (#1937) - -## v8.1.1 - _May 24, 2019_ - - * Dependencies updated - -## v8.1.0 - _May 15, 2019_ - - * Add `ecSignTransactionAsync` (#1817) - -## v8.0.2 - _May 14, 2019_ - - * Dependencies updated - -## v8.0.0 - _May 10, 2019_ - - * Renamed `OrderError` to `TypedDataError` (#1792) - -## v7.2.0 - _April 11, 2019_ - - * Added `orderCalculationUtils` (#1714) - -## v7.1.1 - _March 21, 2019_ - - * Dependencies updated - -## v7.1.0 - _March 20, 2019_ - - * Add Coordinator EIP712 constants (#1705) - * Added encoding/decoding for ERC1155 asset data (#1661) - -## v7.0.2 - _March 1, 2019_ - - * Dependencies updated - -## v7.0.1 - _February 26, 2019_ - - * Dependencies updated - -## v7.0.0 - _February 25, 2019_ - - * Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38 (#1627) - * Update provider params to type SupportedProvider which outlines all supported providers (#1627) - -## v6.1.0 - _February 9, 2019_ - - * Updated implementation of `generatePseudoRandomSalt` to use generator from @0x/utils (#1569) - -## v6.0.1 - _February 7, 2019_ - - * Dependencies updated - -## v6.0.0 - _February 7, 2019_ - - * undefined - -## v5.0.0 - _February 6, 2019_ - - * Add `transactionHashUtils` (#1576) - * Refactor `eip712Utils` to allow custom domain params (#1576) - * Export constant EIP712 params (#1576) - -## v4.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - * Fix preSigned `isSignatureValidAsync` check (#1580) - -## v3.1.2 - _January 15, 2019_ - - * Dependencies updated - -## v3.1.1 - _January 11, 2019_ - - * Dependencies updated - -## v3.1.0 - _January 9, 2019_ - - * Use new ABI encoder, add encoding/decoding logic for MultiAsset assetData, and add information to return values in orderStateUtils (#1363) - -## v3.0.7 - _December 13, 2018_ - - * Dependencies updated - -## v3.0.6 - _December 11, 2018_ - - * Fix bug in wallet signature type verification (#1414) - -## v3.0.5 - _December 10, 2018_ - - * Dependencies updated - -## v3.0.4 - _November 28, 2018_ - - * Dependencies updated - -## v3.0.3 - _November 21, 2018_ - - * Dependencies updated - -## v3.0.2 - _November 14, 2018_ - - * Dependencies updated - -## v3.0.1 - _November 13, 2018_ - - * Dependencies updated - -## v3.0.0 - _November 12, 2018_ - - * Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync` (#1235) - * Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive (#1235) - * Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218) (#1235) - * Modified the `AbstractOrderFilledCancelledFetcher` interface slightly such that `isOrderCancelledAsync` accepts a `signedOrder` instead of an `orderHash` param (#1235) - -## v2.0.1 - _November 9, 2018_ - - * Dependencies updated - -## v2.0.0 - _October 18, 2018_ - - * Added `ecSignOrderAsync` to first sign an order using `eth_signTypedData` and fallback to `eth_sign`. (#1102) - * Added `ecSignTypedDataOrderAsync` to sign an order exclusively using `eth_signTypedData`. (#1102) - * Rename `ecSignOrderHashAsync` to `ecSignHashAsync` removing `SignerType` parameter. (#1102) - * Use `AssetData` union type for function return values. (#1131) - -## v1.0.7 - _October 4, 2018_ - - * Dependencies updated - -## v1.0.6 - _September 28, 2018_ - - * Add signerAddress normalization to `isValidECSignature` to avoid `invalid address recovery` error if caller supplies a checksummed address (#1096) - -## v1.0.5 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.4 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.3 - _September 21, 2018_ - - * Dependencies updated - -## v1.0.2 - _September 19, 2018_ - - * Drastically reduce the bundle size by removing unused parts of included contract artifacts. - -## v1.0.1 - _September 5, 2018_ - - * Export `orderParsingUtils` (#1044) - -## v1.0.1-rc.6 - _August 27, 2018_ - - * Fix missing `BlockParamLiteral` type import issue - -## v1.0.1-rc.5 - _Invalid date_ - - * Remove Caller and Trezor SignatureTypes (#1015) - -## v1.0.1-rc.4 - _August 24, 2018_ - - * Remove rounding error being thrown when maker amount is very small (#959) - * Added rateUtils and sortingUtils (#953) - * Update marketUtils api such that all optional parameters are bundled into one optional param and more defaults are provided (#954) - * Instead of exporting signature util methods individually, they are now exported as `signatureUtils` (#924) - * Export types: `SignedOrder`, `Order`, `OrderRelevantState`, `OrderState`, `ECSignature`, `ERC20AssetData`, `ERC721AssetData`, `AssetProxyId`, `SignerType`, `SignatureType`, `OrderStateValid`, `OrderStateInvalid`, `ExchangeContractErrs`, `TradeSide`, `TransferType`, `FindFeeOrdersThatCoverFeesForTargetOrdersOpts`, `FindOrdersThatCoverMakerAssetFillAmountOpts`, `FeeOrdersAndRemainingFeeAmount`, `OrdersAndRemainingFillAmount`, `Provider`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload` (#924) - * Rename `resultOrders` to `resultFeeOrders` for object returned by `findFeeOrdersThatCoverFeesForTargetOrders` in `marketUtils` api (#997) - * Make `sortFeeOrdersByFeeAdjustedRate` in `sortingUtils` generic (#997) - * Update `findFeeOrdersThatCoverFeesForTargetOrders` to round the the nearest integer when calculating required fees (#997) - -## v1.0.1-rc.3 - _August 14, 2018_ - - * Update ecSignOrderHashAsync to return signature string with signature type byte. Removes messagePrefixOpts. (#914) - * Added a synchronous `createOrder` method in `orderFactory`, updated public interfaces to support some optional parameters (#936) - * Added marketUtils (#937) - * Dependencies updated - -## v1.0.1-rc.2 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.1-rc.1 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.0 - _July 23, 2018_ - - * Dependencies updated - -## v1.0.0-rc.2 - _July 23, 2018_ - - * Upgrade ethereumjs-abi dep including a fix so that addresses starting with 0 are properly decoded by `decodeERC20AssetData` - -## v1.0.0-rc.1 - _July 19, 2018_ - - * Refactor to work with V2 of 0x protocol (#636) - * Export parseECSignature method (#684) - * Handle Typed Arrays when hashing data (#894) - -## v0.0.9 - _July 18, 2018_ - - * Dependencies updated - -## v0.0.8 - _July 9, 2018_ - - * Dependencies updated - -## v0.0.7 - _June 19, 2018_ - - * Dependencies updated - -## v0.0.6 - _May 29, 2018_ - - * Dependencies updated - -## v0.0.5 - _May 22, 2018_ - - * Add orderStateUtils, a module for computing order state needed to decide if an order is still valid - -## v0.0.4 - _May 4, 2018_ - - * Dependencies updated - -## v0.0.3 - _May 4, 2018_ - - * Dependencies updated - -## v0.0.2 - _May 4, 2018_ - - * Dependencies updated diff --git a/packages/order-utils/README.md b/packages/order-utils/README.md deleted file mode 100644 index 0ffbc4e15f..0000000000 --- a/packages/order-utils/README.md +++ /dev/null @@ -1,65 +0,0 @@ -## @0x/order-utils - -0x order-related utilities for those developing on top of 0x protocol. - -### Read the [Documentation](https://0x.org/docs/tools/order-utils). - -## Installation - -```bash -yarn add @0x/order-utils -``` - -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"], -} -``` - -## Contributing - -We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. - -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=@0x/order-utils yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/order-utils yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` diff --git a/packages/order-utils/coverage/.gitkeep b/packages/order-utils/coverage/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/order-utils/docs/reference.mdx b/packages/order-utils/docs/reference.mdx deleted file mode 100644 index 38b7866881..0000000000 --- a/packages/order-utils/docs/reference.mdx +++ /dev/null @@ -1,2937 +0,0 @@ - - - - - - - - -# Enumeration: TypedDataError - - -## Enumeration members - -### InvalidMetamaskSigner - -• **InvalidMetamaskSigner**: = "MetaMask provider must be wrapped in a MetamaskSubprovider (from the '@0x/subproviders' package) in order to work with this method." - -*Defined in [order-utils/src/types.ts:5](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L5)* - -___ - -### InvalidSignature - -• **InvalidSignature**: = "INVALID_SIGNATURE" - -*Defined in [order-utils/src/types.ts:4](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L4)* - -
- -# Enumeration: AssetProxyId - - -## Enumeration members - -### ERC1155 - -• **ERC1155**: = "0xa7cb5fb7" - -*Defined in [types/src/index.ts:166](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L166)* - -___ - -### ERC20 - -• **ERC20**: = "0xf47261b0" - -*Defined in [types/src/index.ts:163](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L163)* - -___ - -### ERC20Bridge - -• **ERC20Bridge**: = "0xdc1600f3" - -*Defined in [types/src/index.ts:168](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L168)* - -___ - -### ERC721 - -• **ERC721**: = "0x02571792" - -*Defined in [types/src/index.ts:164](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L164)* - -___ - -### MultiAsset - -• **MultiAsset**: = "0x94cfcdd7" - -*Defined in [types/src/index.ts:165](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L165)* - -___ - -### StaticCall - -• **StaticCall**: = "0xc339d10a" - -*Defined in [types/src/index.ts:167](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L167)* - -
- - - - - - - - - - - - - -# Enumeration: SignatureType - - -## Enumeration members - -### EIP1271Wallet - -• **EIP1271Wallet**: - -*Defined in [types/src/index.ts:158](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L158)* - -___ - -### EIP712 - -• **EIP712**: - -*Defined in [types/src/index.ts:153](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L153)* - -___ - -### EthSign - -• **EthSign**: - -*Defined in [types/src/index.ts:154](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L154)* - -___ - -### Illegal - -• **Illegal**: - -*Defined in [types/src/index.ts:151](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L151)* - -___ - -### Invalid - -• **Invalid**: - -*Defined in [types/src/index.ts:152](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L152)* - -___ - -### NSignatureTypes - -• **NSignatureTypes**: - -*Defined in [types/src/index.ts:159](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L159)* - -___ - -### PreSigned - -• **PreSigned**: - -*Defined in [types/src/index.ts:157](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L157)* - -___ - -### Validator - -• **Validator**: - -*Defined in [types/src/index.ts:156](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L156)* - -___ - -### Wallet - -• **Wallet**: - -*Defined in [types/src/index.ts:155](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L155)* - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Interface: EIP1193Provider - - -## Properties - -### isEIP1193 - -• **isEIP1193**: *boolean* - -*Defined in [ethereum-types/src/index.ts:73](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L73)* - -## Methods - -### on - -▸ **on**(`event`: [EIP1193Event](#eip1193event), `listener`: function): *this* - -*Defined in [ethereum-types/src/index.ts:75](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L75)* - -**Parameters:** - -▪ **event**: *[EIP1193Event](#eip1193event)* - -▪ **listener**: *function* - -▸ (`result`: any): *void* - -**Parameters:** - -Name | Type | ------- | ------ | -`result` | any | - -**Returns:** *this* - -___ - -### send - -▸ **send**(`method`: string, `params?`: any[]): *`Promise`* - -*Defined in [ethereum-types/src/index.ts:74](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L74)* - -**Parameters:** - -Name | Type | ------- | ------ | -`method` | string | -`params?` | any[] | - -**Returns:** *`Promise`* - -
- - - - - - - - - - - - - -# Interface: GanacheProvider - - -## Methods - -### sendAsync - -â–¸ **sendAsync**(`payload`: [JSONRPCRequestPayload](_ethereum_types_src_index_.jsonrpcrequestpayload.md), `callback`: [JSONRPCErrorCallback](#jsonrpcerrorcallback)): *void* - -*Defined in [ethereum-types/src/index.ts:14](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L14)* - -**Parameters:** - -Name | Type | ------- | ------ | -`payload` | [JSONRPCRequestPayload](#class-jsonrpcrequestpayload) | -`callback` | [JSONRPCErrorCallback](#jsonrpcerrorcallback) | - -**Returns:** *void* - -
- - - -# Interface: JSONRPCRequestPayload - - -## Properties - -### id - -• **id**: *number* - -*Defined in [ethereum-types/src/index.ts:331](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L331)* - -___ - -### jsonrpc - -• **jsonrpc**: *string* - -*Defined in [ethereum-types/src/index.ts:332](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L332)* - -___ - -### method - -• **method**: *string* - -*Defined in [ethereum-types/src/index.ts:330](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L330)* - -___ - -### params - -• **params**: *any[]* - -*Defined in [ethereum-types/src/index.ts:329](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L329)* - -
- -# Interface: JSONRPCResponseError - - -## Properties - -### code - -• **code**: *number* - -*Defined in [ethereum-types/src/index.ts:337](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L337)* - -___ - -### message - -• **message**: *string* - -*Defined in [ethereum-types/src/index.ts:336](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L336)* - -
- -# Interface: JSONRPCResponsePayload - - -## Properties - -### `Optional` error - -• **error**? : *[JSONRPCResponseError](#class-jsonrpcresponseerror)* - -*Defined in [ethereum-types/src/index.ts:344](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L344)* - -___ - -### id - -• **id**: *number* - -*Defined in [ethereum-types/src/index.ts:342](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L342)* - -___ - -### jsonrpc - -• **jsonrpc**: *string* - -*Defined in [ethereum-types/src/index.ts:343](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L343)* - -___ - -### result - -• **result**: *any* - -*Defined in [ethereum-types/src/index.ts:341](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L341)* - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Interface: Web3JsV1Provider - -Web3.js version 1 provider interface -This provider interface was implemented in the pre-1.0Beta releases for Web3.js. -This interface allowed sending synchonous requests, support for which was later dropped. - - -## Methods - -### send - -â–¸ **send**(`payload`: [JSONRPCRequestPayload](_ethereum_types_src_index_.jsonrpcrequestpayload.md)): *[JSONRPCResponsePayload](#class-jsonrpcresponsepayload)* - -*Defined in [ethereum-types/src/index.ts:45](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L45)* - -**Parameters:** - -Name | Type | ------- | ------ | -`payload` | [JSONRPCRequestPayload](#class-jsonrpcrequestpayload) | - -**Returns:** *[JSONRPCResponsePayload](#class-jsonrpcresponsepayload)* - -___ - -### sendAsync - -â–¸ **sendAsync**(`payload`: [JSONRPCRequestPayload](_ethereum_types_src_index_.jsonrpcrequestpayload.md), `callback`: [JSONRPCErrorCallback](#jsonrpcerrorcallback)): *void* - -*Defined in [ethereum-types/src/index.ts:44](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L44)* - -**Parameters:** - -Name | Type | ------- | ------ | -`payload` | [JSONRPCRequestPayload](#class-jsonrpcrequestpayload) | -`callback` | [JSONRPCErrorCallback](#jsonrpcerrorcallback) | - -**Returns:** *void* - -
- -# Interface: Web3JsV2Provider - -Web3.js version 2 provider interface -This provider interface was used in a couple of Web3.js 1.0 beta releases -before the first attempts to conform to EIP1193 - - -## Methods - -### send - -â–¸ **send**(`payload`: [JSONRPCRequestPayload](_ethereum_types_src_index_.jsonrpcrequestpayload.md), `callback`: [JSONRPCErrorCallback](#jsonrpcerrorcallback)): *void* - -*Defined in [ethereum-types/src/index.ts:54](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L54)* - -**Parameters:** - -Name | Type | ------- | ------ | -`payload` | [JSONRPCRequestPayload](#class-jsonrpcrequestpayload) | -`callback` | [JSONRPCErrorCallback](#jsonrpcerrorcallback) | - -**Returns:** *void* - -
- -# Interface: Web3JsV3Provider - -Web3.js version 3 provider interface -This provider interface was implemented with the hopes for conforming to the EIP1193 spec, -however it does not conform entirely. - - -## Methods - -### send - -â–¸ **send**(`method`: string, `params?`: any[]): *`Promise`* - -*Defined in [ethereum-types/src/index.ts:63](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L63)* - -**Parameters:** - -Name | Type | ------- | ------ | -`method` | string | -`params?` | any[] | - -**Returns:** *`Promise`* - -
- -# Interface: ZeroExProvider - -The interface for the provider used internally by 0x libraries -Any property we use from any SupportedProvider should we explicitly -add here - - -## Properties - -### `Optional` isMetaMask - -• **isMetaMask**? : *undefined | false | true* - -*Defined in [ethereum-types/src/index.ts:31](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L31)* - -___ - -### `Optional` isParity - -• **isParity**? : *undefined | false | true* - -*Defined in [ethereum-types/src/index.ts:32](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L32)* - -___ - -### `Optional` isZeroExProvider - -• **isZeroExProvider**? : *undefined | false | true* - -*Defined in [ethereum-types/src/index.ts:30](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L30)* - -## Methods - -### `Optional` enable - -▸ **enable**(): *`Promise`* - -*Defined in [ethereum-types/src/index.ts:34](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L34)* - -**Returns:** *`Promise`* - -___ - -### sendAsync - -▸ **sendAsync**(`payload`: [JSONRPCRequestPayload](_ethereum_types_src_index_.jsonrpcrequestpayload.md), `callback`: [JSONRPCErrorCallback](#jsonrpcerrorcallback)): *void* - -*Defined in [ethereum-types/src/index.ts:35](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L35)* - -**Parameters:** - -Name | Type | ------- | ------ | -`payload` | [JSONRPCRequestPayload](#class-jsonrpcrequestpayload) | -`callback` | [JSONRPCErrorCallback](#jsonrpcerrorcallback) | - -**Returns:** *void* - -___ - -### `Optional` stop - -▸ **stop**(): *void* - -*Defined in [ethereum-types/src/index.ts:33](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L33)* - -**Returns:** *void* - -
- - - -# Interface: FeeOrdersAndRemainingFeeAmount <**T**> - -## Type parameters - -▪ **T** - - -## Properties - -### feeOrdersRemainingFillableMakerAssetAmounts - -• **feeOrdersRemainingFillableMakerAssetAmounts**: *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:68](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L68)* - -___ - -### remainingFeeAmount - -• **remainingFeeAmount**: *`BigNumber`* - -*Defined in [order-utils/src/types.ts:69](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L69)* - -___ - -### resultFeeOrders - -• **resultFeeOrders**: *`T`[]* - -*Defined in [order-utils/src/types.ts:67](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L67)* - -
- -# Interface: FindFeeOrdersThatCoverFeesForTargetOrdersOpts - -remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. -You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values. -Defaults to `makerAssetAmount` values from the orders param. -remainingFillableFeeAmounts: An array of BigNumbers corresponding to the feeOrders parameter. -You can use OrderStateUtils @0x/order-utils to perform blockchain lookups for these values. -Defaults to `makerAssetAmount` values from the feeOrders param. -slippageBufferAmount: An additional amount of fee to be covered by the result in case of trade collisions or partial fills. -Defaults to 0 - - -## Properties - -### `Optional` remainingFillableFeeAmounts - -• **remainingFillableFeeAmounts**? : *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:62](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L62)* - -___ - -### `Optional` remainingFillableMakerAssetAmounts - -• **remainingFillableMakerAssetAmounts**? : *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:61](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L61)* - -___ - -### `Optional` slippageBufferAmount - -• **slippageBufferAmount**? : *`BigNumber`* - -*Defined in [order-utils/src/types.ts:63](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L63)* - -
- -# Interface: FindOrdersThatCoverMakerAssetFillAmountOpts - -remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. -You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values. -Defaults to `makerAssetAmount` values from the orders param. -slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills. -Defaults to 0 - - -## Properties - -### `Optional` remainingFillableMakerAssetAmounts - -• **remainingFillableMakerAssetAmounts**? : *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:34](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L34)* - -___ - -### `Optional` slippageBufferAmount - -• **slippageBufferAmount**? : *`BigNumber`* - -*Defined in [order-utils/src/types.ts:35](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L35)* - -
- -# Interface: FindOrdersThatCoverTakerAssetFillAmountOpts - -remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. -You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values. -Defaults to `makerAssetAmount` values from the orders param. -slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills. -Defaults to 0 - - -## Properties - -### `Optional` remainingFillableTakerAssetAmounts - -• **remainingFillableTakerAssetAmounts**? : *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:46](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L46)* - -___ - -### `Optional` slippageBufferAmount - -• **slippageBufferAmount**? : *`BigNumber`* - -*Defined in [order-utils/src/types.ts:47](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L47)* - -
- -# Interface: OrdersAndRemainingMakerFillAmount <**T**> - -## Type parameters - -▪ **T** - - -## Properties - -### ordersRemainingFillableMakerAssetAmounts - -• **ordersRemainingFillableMakerAssetAmounts**: *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:74](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L74)* - -___ - -### remainingFillAmount - -• **remainingFillAmount**: *`BigNumber`* - -*Defined in [order-utils/src/types.ts:75](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L75)* - -___ - -### resultOrders - -• **resultOrders**: *`T`[]* - -*Defined in [order-utils/src/types.ts:73](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L73)* - -
- -# Interface: OrdersAndRemainingTakerFillAmount <**T**> - -## Type parameters - -▪ **T** - - -## Properties - -### ordersRemainingFillableTakerAssetAmounts - -• **ordersRemainingFillableTakerAssetAmounts**: *`BigNumber`[]* - -*Defined in [order-utils/src/types.ts:80](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L80)* - -___ - -### remainingFillAmount - -• **remainingFillAmount**: *`BigNumber`* - -*Defined in [order-utils/src/types.ts:81](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L81)* - -___ - -### resultOrders - -• **resultOrders**: *`T`[]* - -*Defined in [order-utils/src/types.ts:79](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/types.ts#L79)* - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -# Interface: DutchAuctionData - - -## Properties - -### assetData - -• **assetData**: *[AssetData](#assetdata)* - -*Defined in [types/src/index.ts:219](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L219)* - -___ - -### beginAmount - -• **beginAmount**: *`BigNumber`* - -*Defined in [types/src/index.ts:221](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L221)* - -___ - -### beginTimeSeconds - -• **beginTimeSeconds**: *`BigNumber`* - -*Defined in [types/src/index.ts:220](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L220)* - -
- - - -# Interface: ECSignature - -Elliptic Curve signature - - -## Properties - -### r - -• **r**: *string* - -*Defined in [types/src/index.ts:62](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L62)* - -___ - -### s - -• **s**: *string* - -*Defined in [types/src/index.ts:63](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L63)* - -___ - -### v - -• **v**: *number* - -*Defined in [types/src/index.ts:61](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L61)* - -
- -# Interface: EIP712DomainWithDefaultSchema - - -## Properties - -### chainId - -• **chainId**: *number* - -*Defined in [types/src/index.ts:793](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L793)* - -___ - -### `Optional` name - -• **name**? : *undefined | string* - -*Defined in [types/src/index.ts:791](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L791)* - -___ - -### verifyingContract - -• **verifyingContract**: *string* - -*Defined in [types/src/index.ts:794](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L794)* - -___ - -### `Optional` version - -• **version**? : *undefined | string* - -*Defined in [types/src/index.ts:792](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L792)* - -
- -# Interface: EIP712Object - - -## Hierarchy - -* **EIP712Parameter** - - -## Properties - -### name - -• **name**: *string* - -*Defined in [types/src/index.ts:732](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L732)* - -___ - -### type - -• **type**: *string* - -*Defined in [types/src/index.ts:733](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L733)* - -
- -# Interface: EIP712TypedData - - -## Properties - -### domain - -• **domain**: *[EIP712Object](#class-eip712object)* - -*Defined in [types/src/index.ts:748](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L748)* - -___ - -### message - -• **message**: *[EIP712Object](#class-eip712object)* - -*Defined in [types/src/index.ts:749](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L749)* - -___ - -### primaryType - -• **primaryType**: *string* - -*Defined in [types/src/index.ts:750](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L750)* - -___ - -### types - -• **types**: *[EIP712Types](#class-eip712types)* - -*Defined in [types/src/index.ts:747](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L747)* - -
- -# Interface: EIP712Types - - -## Hierarchy - -* **ElementType** - - -## Properties - -### name - -• **name**: *string* - -*Defined in [types/src/index.ts:686](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L686)* - -___ - -### typeDocType - -• **typeDocType**: *[TypeDocTypes](#enumeration-typedoctypes)* - -*Defined in [types/src/index.ts:687](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L687)* - -
- -# Interface: ERC1155AssetData - - -## Properties - -### assetProxyId - -• **assetProxyId**: *string* - -*Defined in [types/src/index.ts:183](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L183)* - -___ - -### callbackData - -• **callbackData**: *string* - -*Defined in [types/src/index.ts:187](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L187)* - -___ - -### tokenAddress - -• **tokenAddress**: *string* - -*Defined in [types/src/index.ts:184](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L184)* - -___ - -### tokenIds - -• **tokenIds**: *`BigNumber`[]* - -*Defined in [types/src/index.ts:185](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L185)* - -___ - -### tokenValues - -• **tokenValues**: *`BigNumber`[]* - -*Defined in [types/src/index.ts:186](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L186)* - -
- - - -# Interface: ERC20AssetData - - -## Properties - -### assetProxyId - -• **assetProxyId**: *string* - -*Defined in [types/src/index.ts:172](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L172)* - -___ - -### tokenAddress - -• **tokenAddress**: *string* - -*Defined in [types/src/index.ts:173](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L173)* - -
- -# Interface: ERC721AssetData - - -## Properties - -### assetProxyId - -• **assetProxyId**: *string* - -*Defined in [types/src/index.ts:177](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L177)* - -___ - -### tokenAddress - -• **tokenAddress**: *string* - -*Defined in [types/src/index.ts:178](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L178)* - -___ - -### tokenId - -• **tokenId**: *`BigNumber`* - -*Defined in [types/src/index.ts:179](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L179)* - -
- - - - - - - - - - - - - - - - - -# Interface: MultiAssetData - - -## Properties - -### amounts - -• **amounts**: *`BigNumber`[]* - -*Defined in [types/src/index.ts:208](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L208)* - -___ - -### assetProxyId - -• **assetProxyId**: *string* - -*Defined in [types/src/index.ts:207](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L207)* - -___ - -### nestedAssetData - -• **nestedAssetData**: *string[]* - -*Defined in [types/src/index.ts:209](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L209)* - -
- -# Interface: MultiAssetDataWithRecursiveDecoding - - -## Properties - -### amounts - -• **amounts**: *`BigNumber`[]* - -*Defined in [types/src/index.ts:214](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L214)* - -___ - -### assetProxyId - -• **assetProxyId**: *string* - -*Defined in [types/src/index.ts:213](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L213)* - -___ - -### nestedAssetData - -• **nestedAssetData**: *[SingleAssetData](#singleassetdata)[]* - -*Defined in [types/src/index.ts:215](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L215)* - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Interface: SignedOrder - - -## Properties - -### chainId - -• **chainId**: *number* - -*Inherited from [Order](#interface-order).[chainId](#chainid)* - -*Defined in [types/src/index.ts:14](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L14)* - -___ - -### exchangeAddress - -• **exchangeAddress**: *string* - -*Inherited from [Order](#interface-order).[exchangeAddress](#exchangeaddress)* - -*Defined in [types/src/index.ts:15](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L15)* - -___ - -### expirationTimeSeconds - -• **expirationTimeSeconds**: *`BigNumber`* - -*Inherited from [Order](#interface-order).[expirationTimeSeconds](#expirationtimeseconds)* - -*Defined in [types/src/index.ts:24](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L24)* - -___ - -### feeRecipientAddress - -• **feeRecipientAddress**: *string* - -*Inherited from [Order](#interface-order).[feeRecipientAddress](#feerecipientaddress)* - -*Defined in [types/src/index.ts:18](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L18)* - -___ - -### makerAddress - -• **makerAddress**: *string* - -*Inherited from [Order](#interface-order).[makerAddress](#makeraddress)* - -*Defined in [types/src/index.ts:16](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L16)* - -___ - -### makerAssetAmount - -• **makerAssetAmount**: *`BigNumber`* - -*Inherited from [Order](#interface-order).[makerAssetAmount](#makerassetamount)* - -*Defined in [types/src/index.ts:20](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L20)* - -___ - -### makerAssetData - -• **makerAssetData**: *string* - -*Inherited from [Order](#interface-order).[makerAssetData](#makerassetdata)* - -*Defined in [types/src/index.ts:26](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L26)* - -___ - -### makerFee - -• **makerFee**: *`BigNumber`* - -*Inherited from [Order](#interface-order).[makerFee](#makerfee)* - -*Defined in [types/src/index.ts:22](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L22)* - -___ - -### makerFeeAssetData - -• **makerFeeAssetData**: *string* - -*Inherited from [Order](#interface-order).[makerFeeAssetData](#makerfeeassetdata)* - -*Defined in [types/src/index.ts:28](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L28)* - -___ - -### salt - -• **salt**: *`BigNumber`* - -*Inherited from [Order](#interface-order).[salt](#salt)* - -*Defined in [types/src/index.ts:25](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L25)* - -___ - -### senderAddress - -• **senderAddress**: *string* - -*Inherited from [Order](#interface-order).[senderAddress](#senderaddress)* - -*Defined in [types/src/index.ts:19](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L19)* - -___ - -### signature - -• **signature**: *string* - -*Defined in [types/src/index.ts:33](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L33)* - -___ - -### takerAddress - -• **takerAddress**: *string* - -*Inherited from [Order](#interface-order).[takerAddress](#takeraddress)* - -*Defined in [types/src/index.ts:17](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L17)* - -___ - -### takerAssetAmount - -• **takerAssetAmount**: *`BigNumber`* - -*Inherited from [Order](#interface-order).[takerAssetAmount](#takerassetamount)* - -*Defined in [types/src/index.ts:21](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L21)* - -___ - -### takerAssetData - -• **takerAssetData**: *string* - -*Inherited from [Order](#interface-order).[takerAssetData](#takerassetdata)* - -*Defined in [types/src/index.ts:27](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L27)* - -___ - -### takerFee - -• **takerFee**: *`BigNumber`* - -*Inherited from [Order](#interface-order).[takerFee](#takerfee)* - -*Defined in [types/src/index.ts:23](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L23)* - -___ - -### takerFeeAssetData - -• **takerFeeAssetData**: *string* - -*Inherited from [Order](#interface-order).[takerFeeAssetData](#takerfeeassetdata)* - -*Defined in [types/src/index.ts:29](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L29)* - -
- -# Interface: SignedZeroExTransaction - - -## Properties - -### data - -• **data**: *string* - -*Inherited from [ZeroExTransaction](#interface-zeroextransaction).[data](#data)* - -*Defined in [types/src/index.ts:49](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L49)* - -___ - -### domain - -• **domain**: *[EIP712DomainWithDefaultSchema](#class-eip712domainwithdefaultschema)* - -*Inherited from [ZeroExTransaction](#interface-zeroextransaction).[domain](#domain)* - -*Defined in [types/src/index.ts:50](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L50)* - -___ - -### expirationTimeSeconds - -• **expirationTimeSeconds**: *`BigNumber`* - -*Inherited from [ZeroExTransaction](#interface-zeroextransaction).[expirationTimeSeconds](#expirationtimeseconds)* - -*Defined in [types/src/index.ts:46](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L46)* - -___ - -### gasPrice - -• **gasPrice**: *`BigNumber`* - -*Inherited from [ZeroExTransaction](#interface-zeroextransaction).[gasPrice](#gasprice)* - -*Defined in [types/src/index.ts:47](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L47)* - -___ - -### salt - -• **salt**: *`BigNumber`* - -*Inherited from [ZeroExTransaction](#interface-zeroextransaction).[salt](#salt)* - -*Defined in [types/src/index.ts:45](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L45)* - -___ - -### signature - -• **signature**: *string* - -*Defined in [types/src/index.ts:54](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L54)* - -___ - -### signerAddress - -• **signerAddress**: *string* - -*Inherited from [ZeroExTransaction](#interface-zeroextransaction).[signerAddress](#signeraddress)* - -*Defined in [types/src/index.ts:48](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L48)* - -
- - - - - - - - - - - - - -# Interface: StaticCallAssetData - - -## Properties - -### assetProxyId - -• **assetProxyId**: *string* - -*Defined in [types/src/index.ts:191](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L191)* - -___ - -### callResultHash - -• **callResultHash**: *string* - -*Defined in [types/src/index.ts:194](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L194)* - -___ - -### callTarget - -• **callTarget**: *string* - -*Defined in [types/src/index.ts:192](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L192)* - -___ - -### staticCallData - -• **staticCallData**: *string* - -*Defined in [types/src/index.ts:193](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L193)* - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -# Interface: ValidatorSignature - -Validator signature components - - -## Properties - -### signature - -• **signature**: *string* - -*Defined in [types/src/index.ts:71](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L71)* - -___ - -### validatorAddress - -• **validatorAddress**: *string* - -*Defined in [types/src/index.ts:70](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L70)* - -
- -# Interface: ZeroExTransaction - -ZeroExTransaction for use with 0x Exchange executeTransaction - - -## Properties - -### data - -• **data**: *string* - -*Defined in [types/src/index.ts:49](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L49)* - -___ - -### domain - -• **domain**: *[EIP712DomainWithDefaultSchema](#class-eip712domainwithdefaultschema)* - -*Defined in [types/src/index.ts:50](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L50)* - -___ - -### expirationTimeSeconds - -• **expirationTimeSeconds**: *`BigNumber`* - -*Defined in [types/src/index.ts:46](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L46)* - -___ - -### gasPrice - -• **gasPrice**: *`BigNumber`* - -*Defined in [types/src/index.ts:47](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L47)* - -___ - -### salt - -• **salt**: *`BigNumber`* - -*Defined in [types/src/index.ts:45](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L45)* - -___ - -### signerAddress - -• **signerAddress**: *string* - -*Defined in [types/src/index.ts:48](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L48)* - -
- - - - -## Type aliases - - - -### AssetData - -Ƭ **AssetData**: *[SingleAssetData](_types_src_index_.md#singleassetdata) | [MultiAssetData](#interface-multiassetdata) | [MultiAssetDataWithRecursiveDecoding](#interface-multiassetdatawithrecursivedecoding)* - -*Defined in [types/src/index.ts:224](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L224)* - -___ - - - - - -### EIP712ObjectValue - -Ƭ **EIP712ObjectValue**: *string | number | [EIP712Object](#interface-eip712object)* - -*Defined in [types/src/index.ts:740](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L740)* - -___ - - - - - - - - - - - -### SingleAssetData - -Ƭ **SingleAssetData**: *[ERC20AssetData](#interface-erc20assetdata) | [ERC721AssetData](#interface-erc721assetdata) | [ERC1155AssetData](#interface-erc1155assetdata) | [StaticCallAssetData](#interface-staticcallassetdata)* - -*Defined in [types/src/index.ts:204](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/types/src/index.ts#L204)* - -
- - - - -## Type aliases - - - - - - - - - - - - - -### EIP1193Event - -Ƭ **EIP1193Event**: *"accountsChanged" | "networkChanged" | "close" | "connect" | "notification"* - -*Defined in [ethereum-types/src/index.ts:70](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L70)* - -Interface for providers that conform to EIP 1193 -Source: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md - -___ - - - - - - - -### JSONRPCErrorCallback - -Ƭ **JSONRPCErrorCallback**: *function* - -*Defined in [ethereum-types/src/index.ts:3](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L3)* - -#### Type declaration: - -▸ (`err`: `Error` | null, `result?`: [JSONRPCResponsePayload](#interface-jsonrpcresponsepayload)): *void* - -**Parameters:** - -Name | Type | ------- | ------ | -`err` | `Error` \| null | -`result?` | [JSONRPCResponsePayload](#interface-jsonrpcresponsepayload) | - -___ - - - - - - - - - - - -### SupportedProvider - -Ƭ **SupportedProvider**: *[Web3JsProvider](_ethereum_types_src_index_.md#web3jsprovider) | [GanacheProvider](#interface-ganacheprovider) | [EIP1193Provider](#interface-eip1193provider) | [ZeroExProvider](#interface-zeroexprovider)* - -*Defined in [ethereum-types/src/index.ts:9](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L9)* - -Do not create your own provider. Use an existing provider from a Web3 or ProviderEngine library -Read more about Providers in the guides section of the 0x docs. - -___ - - - - - -### Web3JsProvider - -Ƭ **Web3JsProvider**: *[Web3JsV1Provider](#interface-web3jsv1provider) | [Web3JsV2Provider](#interface-web3jsv2provider) | [Web3JsV3Provider](#interface-web3jsv3provider)* - -*Defined in [ethereum-types/src/index.ts:11](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/ethereum-types/src/index.ts#L11)* - -
- - - - -## Object literals - -### `Const` assetDataUtils - -#### â–ª **assetDataUtils**: *object* - -*Defined in [order-utils/src/asset_data_utils.ts:23](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L23)* - -#### assertIsERC1155AssetData - -â–¸ **assertIsERC1155AssetData**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:397](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L397)* - -Throws if the assetData is not ERC1155. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -#### assertIsERC20AssetData - -â–¸ **assertIsERC20AssetData**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:353](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L353)* - -Throws if the length or assetProxyId are invalid for the ERC20Proxy. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -#### assertIsERC721AssetData - -â–¸ **assertIsERC721AssetData**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:375](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L375)* - -Throws if the length or assetProxyId are invalid for the ERC721Proxy. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -#### assertIsMultiAssetData - -â–¸ **assertIsMultiAssetData**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:419](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L419)* - -Throws if the length or assetProxyId are invalid for the MultiAssetProxy. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -#### assertIsStaticCallAssetData - -â–¸ **assertIsStaticCallAssetData**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:441](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L441)* - -Throws if the assetData is not StaticCallData. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -#### assertWordAlignedAssetData - -â–¸ **assertWordAlignedAssetData**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:463](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L463)* - -Throws if the assetData is not padded to 32 bytes. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -#### decodeAssetDataOrThrow - -â–¸ **decodeAssetDataOrThrow**(`assetData`: string): *[SingleAssetData](#singleassetdata) | `MultiAssetData`* - -*Defined in [order-utils/src/asset_data_utils.ts:502](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L502)* - -Decode any assetData into its corresponding assetData object - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *[SingleAssetData](#singleassetdata) | `MultiAssetData`* - -Either a ERC20, ERC721, ERC1155, or MultiAsset assetData object - -#### decodeAssetProxyId - -â–¸ **decodeAssetProxyId**(`assetData`: string): *`AssetProxyId`* - -*Defined in [order-utils/src/asset_data_utils.ts:294](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L294)* - -Decode and return the assetProxyId from the assetData - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`AssetProxyId`* - -The assetProxyId - -#### decodeDutchAuctionData - -â–¸ **decodeDutchAuctionData**(`dutchAuctionData`: string): *`DutchAuctionData`* - -*Defined in [order-utils/src/asset_data_utils.ts:263](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L263)* - -Dutch auction details are encoded with the asset data for a 0x order. This function decodes a hex -encoded assetData string, containing information both about the asset being traded and the -dutch auction. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`dutchAuctionData` | string | Hex encoded assetData string for the asset being auctioned. | - -**Returns:** *`DutchAuctionData`* - -An object containing the auction asset, auction begin time and auction begin amount. - -#### decodeERC1155AssetData - -â–¸ **decodeERC1155AssetData**(`assetData`: string): *`ERC1155AssetData`* - -*Defined in [order-utils/src/asset_data_utils.ts:107](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L107)* - -Decodes an ERC1155 assetData hex string into its corresponding ERC1155 components. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`ERC1155AssetData`* - -An object containing the decoded tokenAddress, tokenIds, tokenValues, callbackData & assetProxyId - -#### decodeERC20AssetData - -â–¸ **decodeERC20AssetData**(`assetData`: string): *`ERC20AssetData`* - -*Defined in [order-utils/src/asset_data_utils.ts:41](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L41)* - -Decodes an ERC20 assetData hex string into its corresponding ERC20 tokenAddress & assetProxyId - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`ERC20AssetData`* - -An object containing the decoded tokenAddress & assetProxyId - -#### decodeERC721AssetData - -â–¸ **decodeERC721AssetData**(`assetData`: string): *`ERC721AssetData`* - -*Defined in [order-utils/src/asset_data_utils.ts:70](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L70)* - -Decodes an ERC721 assetData hex string into its corresponding ERC721 tokenAddress, tokenId & assetProxyId - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`ERC721AssetData`* - -An object containing the decoded tokenAddress, tokenId & assetProxyId - -#### decodeMultiAssetData - -â–¸ **decodeMultiAssetData**(`assetData`: string): *`MultiAssetData`* - -*Defined in [order-utils/src/asset_data_utils.ts:149](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L149)* - -Decodes a MultiAsset assetData hex string into its corresponding amounts and nestedAssetData - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`MultiAssetData`* - -An object containing the decoded amounts and nestedAssetData - -#### decodeMultiAssetDataRecursively - -â–¸ **decodeMultiAssetDataRecursively**(`assetData`: string): *`MultiAssetDataWithRecursiveDecoding`* - -*Defined in [order-utils/src/asset_data_utils.ts:175](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L175)* - -Decodes a MultiAsset assetData hex string into its corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened) - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`MultiAssetDataWithRecursiveDecoding`* - -An object containing the decoded amounts and nestedAssetData - -#### decodeStaticCallAssetData - -â–¸ **decodeStaticCallAssetData**(`assetData`: string): *`StaticCallAssetData`* - -*Defined in [order-utils/src/asset_data_utils.ts:225](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L225)* - -Decoded StaticCall assetData into its corresponding callTarget, staticCallData, and expected callResultHash - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string to decode | - -**Returns:** *`StaticCallAssetData`* - -An object containing the decoded callTarget, staticCallData, and expected callResultHash - -#### encodeDutchAuctionAssetData - -â–¸ **encodeDutchAuctionAssetData**(`assetData`: string, `beginTimeSeconds`: `BigNumber`, `beginAmount`: `BigNumber`): *string* - -*Defined in [order-utils/src/asset_data_utils.ts:245](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L245)* - -Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex -encoded assetData string, containing information both about the asset being traded and the -dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string for the asset being auctioned. | -`beginTimeSeconds` | `BigNumber` | Begin time of the dutch auction. | -`beginAmount` | `BigNumber` | Starting amount being sold in the dutch auction. | - -**Returns:** *string* - -The hex encoded assetData string. - -#### encodeERC1155AssetData - -â–¸ **encodeERC1155AssetData**(`tokenAddress`: string, `tokenIds`: `BigNumber`[], `tokenValues`: `BigNumber`[], `callbackData`: string): *string* - -*Defined in [order-utils/src/asset_data_utils.ts:91](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L91)* - -Encodes a set of ERC1155 assets into an assetData string, usable in the makerAssetData or -takerAssetData fields of a 0x order. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`tokenAddress` | string | The token address of the ERC1155 contract | -`tokenIds` | `BigNumber`[] | The Id's of the ERC1155 tokens to transfer | -`tokenValues` | `BigNumber`[] | The values of each respective token Id to transfer | -`callbackData` | string | The data forwarded to a receiver, if receiver is a contract. | - -**Returns:** *string* - -The hex encoded assetData string - -#### encodeERC20AssetData - -â–¸ **encodeERC20AssetData**(`tokenAddress`: string): *string* - -*Defined in [order-utils/src/asset_data_utils.ts:30](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L30)* - -Encodes an ERC20 token address into a hex encoded assetData string, usable in the makerAssetData or -takerAssetData fields in a 0x order. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`tokenAddress` | string | The ERC20 token address to encode | - -**Returns:** *string* - -The hex encoded assetData string - -#### encodeERC721AssetData - -â–¸ **encodeERC721AssetData**(`tokenAddress`: string, `tokenId`: `BigNumber`): *string* - -*Defined in [order-utils/src/asset_data_utils.ts:59](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L59)* - -Encodes an ERC721 token address into a hex encoded assetData string, usable in the makerAssetData or -takerAssetData fields in a 0x order. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`tokenAddress` | string | The ERC721 token address to encode | -`tokenId` | `BigNumber` | The ERC721 tokenId to encode | - -**Returns:** *string* - -The hex encoded assetData string - -#### encodeMultiAssetData - -â–¸ **encodeMultiAssetData**(`amounts`: `BigNumber`[], `nestedAssetData`: string[]): *string* - -*Defined in [order-utils/src/asset_data_utils.ts:130](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L130)* - -Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or -takerAssetData fields in a 0x order. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`amounts` | `BigNumber`[] | Amounts of each asset that correspond to a single unit within an order. | -`nestedAssetData` | string[] | assetData strings that correspond to a valid assetProxyId. | - -**Returns:** *string* - -The hex encoded assetData string - -#### encodeStaticCallAssetData - -â–¸ **encodeStaticCallAssetData**(`callTarget`: string, `staticCallData`: string, `callResultHash`: string): *string* - -*Defined in [order-utils/src/asset_data_utils.ts:214](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L214)* - -Encodes StaticCallProxy data into an assetData hex string - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`callTarget` | string | Address of contract to call from StaticCallProxy | -`staticCallData` | string | The function data that will be called on the callTarget contract | -`callResultHash` | string | The keccak256 hash of the ABI encoded expected output of the static call | - -**Returns:** *string* - -The hex encoded assetData string - -#### isERC1155AssetData - -â–¸ **isERC1155AssetData**(`decodedAssetData`: [SingleAssetData](#singleassetdata) | `MultiAssetData`): *boolean* - -*Defined in [order-utils/src/asset_data_utils.ts:332](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L332)* - -Checks if the decoded asset data is valid ERC1155 data - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`decodedAssetData` | [SingleAssetData](#singleassetdata) \| `MultiAssetData` | The decoded asset data to check | - -**Returns:** *boolean* - -#### isERC20AssetData - -â–¸ **isERC20AssetData**(`decodedAssetData`: [SingleAssetData](#singleassetdata) | `MultiAssetData`): *boolean* - -*Defined in [order-utils/src/asset_data_utils.ts:318](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L318)* - -Checks if the decoded asset data is valid ERC20 data - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`decodedAssetData` | [SingleAssetData](#singleassetdata) \| `MultiAssetData` | The decoded asset data to check | - -**Returns:** *boolean* - -#### isERC721AssetData - -â–¸ **isERC721AssetData**(`decodedAssetData`: [SingleAssetData](#singleassetdata) | `MultiAssetData`): *boolean* - -*Defined in [order-utils/src/asset_data_utils.ts:325](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L325)* - -Checks if the decoded asset data is valid ERC721 data - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`decodedAssetData` | [SingleAssetData](#singleassetdata) \| `MultiAssetData` | The decoded asset data to check | - -**Returns:** *boolean* - -#### isMultiAssetData - -â–¸ **isMultiAssetData**(`decodedAssetData`: [SingleAssetData](#singleassetdata) | `MultiAssetData`): *boolean* - -*Defined in [order-utils/src/asset_data_utils.ts:339](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L339)* - -Checks if the decoded asset data is valid MultiAsset data - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`decodedAssetData` | [SingleAssetData](#singleassetdata) \| `MultiAssetData` | The decoded asset data to check | - -**Returns:** *boolean* - -#### isStaticCallAssetData - -â–¸ **isStaticCallAssetData**(`decodedAssetData`: [SingleAssetData](#singleassetdata) | `MultiAssetData`): *boolean* - -*Defined in [order-utils/src/asset_data_utils.ts:346](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L346)* - -Checks if the decoded asset data is valid StaticCall data - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`decodedAssetData` | [SingleAssetData](#singleassetdata) \| `MultiAssetData` | The decoded asset data to check | - -**Returns:** *boolean* - -#### validateAssetDataOrThrow - -â–¸ **validateAssetDataOrThrow**(`assetData`: string): *void* - -*Defined in [order-utils/src/asset_data_utils.ts:475](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/asset_data_utils.ts#L475)* - -Throws if the length or assetProxyId are invalid for the corresponding AssetProxy. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`assetData` | string | Hex encoded assetData string | - -**Returns:** *void* - -
- - - - -## Object literals - -#### `Const` eip712Utils - -#### â–ª **eip712Utils**: *object* - -*Defined in [order-utils/src/eip712_utils.ts:18](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/eip712_utils.ts#L18)* - -#### createCoordinatorApprovalTypedDataAsync - -â–¸ **createCoordinatorApprovalTypedDataAsync**(`transaction`: `SignedZeroExTransaction`, `verifyingContract`: string, `txOrigin`: string): *`Promise`* - -*Defined in [order-utils/src/eip712_utils.ts:104](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/eip712_utils.ts#L104)* - -Creates an Coordinator typedData EIP712TypedData object for use with the Coordinator extension contract - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`transaction` | `SignedZeroExTransaction` | A 0x transaction | -`verifyingContract` | string | The coordinator extension contract address that will be verifying the typedData | -`txOrigin` | string | The desired `tx.origin` that should be able to submit an Ethereum txn involving this 0x transaction | - -**Returns:** *`Promise`* - -A typed data object - -#### createOrderTypedData - -â–¸ **createOrderTypedData**(`order`: `Order`): *`EIP712TypedData`* - -*Defined in [order-utils/src/eip712_utils.ts:57](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/eip712_utils.ts#L57)* - -Creates an Order EIP712TypedData object for use with signTypedData. - -**Parameters:** - -Name | Type | ------- | ------ | -`order` | `Order` | - -**Returns:** *`EIP712TypedData`* - -A typed data object - -#### createTypedData - -â–¸ **createTypedData**(`primaryType`: string, `types`: `EIP712Types`, `message`: `EIP712Object`, `domain`: `EIP712DomainWithDefaultSchema`): *`EIP712TypedData`* - -*Defined in [order-utils/src/eip712_utils.ts:27](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/eip712_utils.ts#L27)* - -Creates a EIP712TypedData object specific to the 0x protocol for use with signTypedData. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`primaryType` | string | The primary type found in message | -`types` | `EIP712Types` | The additional types for the data in message | -`message` | `EIP712Object` | The contents of the message | -`domain` | `EIP712DomainWithDefaultSchema` | Domain containing a name (optional), version (optional), and verifying contract address | - -**Returns:** *`EIP712TypedData`* - -A typed data object - -#### createZeroExTransactionTypedData - -â–¸ **createZeroExTransactionTypedData**(`zeroExTransaction`: `ZeroExTransaction`): *`EIP712TypedData`* - -*Defined in [order-utils/src/eip712_utils.ts:82](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/eip712_utils.ts#L82)* - -Creates an ExecuteTransaction EIP712TypedData object for use with signTypedData and -0x Exchange executeTransaction. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`zeroExTransaction` | `ZeroExTransaction` | the 0x transaction | - -**Returns:** *`EIP712TypedData`* - -A typed data object - -
- - - - -## Object literals - -#### `Const` marketUtils - -#### ▪ **marketUtils**: *object* - -*Defined in [order-utils/src/market_utils.ts:17](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/market_utils.ts#L17)* - -#### findFeeOrdersThatCoverFeesForTargetOrders - -▸ **findFeeOrdersThatCoverFeesForTargetOrders**<**T**>(`orders`: `T`[], `feeOrders`: `T`[], `opts?`: [FindFeeOrdersThatCoverFeesForTargetOrdersOpts](#interface-findfeeordersthatcoverfeesfortargetordersopts)): *[FeeOrdersAndRemainingFeeAmount](#interface-feeordersandremainingfeeamount)‹*`T`*›* - -*Defined in [order-utils/src/market_utils.ts:64](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/market_utils.ts#L64)* - -Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX -in order to fill the takerFees required by orders plus a slippageBufferAmount. -Iterates from first feeOrder to last. Sort the feeOrders by ascending rate in order to get the subset of -feeOrders that will cost the least ETH. - -**Type parameters:** - -▪ **T**: *`Order`* - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`orders` | `T`[] | An array of objects that extend the Order interface. All orders should specify ZRX as the makerAsset and WETH as the takerAsset. | -`feeOrders` | `T`[] | An array of objects that extend the Order interface. All orders should specify ZRX as the makerAsset and WETH as the takerAsset. | -`opts?` | [FindFeeOrdersThatCoverFeesForTargetOrdersOpts](#interface-findfeeordersthatcoverfeesfortargetordersopts) | Optional arguments this function accepts. | - -**Returns:** *[FeeOrdersAndRemainingFeeAmount](#interface-feeordersandremainingfeeamount)‹*`T`*›* - -Resulting orders and remaining fee amount that could not be covered by the input. - -#### findOrdersThatCoverMakerAssetFillAmount - -▸ **findOrdersThatCoverMakerAssetFillAmount**<**T**>(`orders`: `T`[], `makerAssetFillAmount`: `BigNumber`, `opts?`: [FindOrdersThatCoverMakerAssetFillAmountOpts](#interface-findordersthatcovermakerassetfillamountopts)): *[OrdersAndRemainingMakerFillAmount](#interface-ordersandremainingmakerfillamount)‹*`T`*›* - -*Defined in [order-utils/src/market_utils.ts:40](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/market_utils.ts#L40)* - -Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount -in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last order. -Sort the input by ascending rate in order to get the subset of orders that will cost the least ETH. - -**Type parameters:** - -▪ **T**: *`Order`* - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`orders` | `T`[] | An array of objects that extend the Order interface. All orders should specify the same makerAsset. All orders should specify WETH as the takerAsset. | -`makerAssetFillAmount` | `BigNumber` | The amount of makerAsset desired to be filled. | -`opts?` | [FindOrdersThatCoverMakerAssetFillAmountOpts](#interface-findordersthatcovermakerassetfillamountopts) | Optional arguments this function accepts. | - -**Returns:** *[OrdersAndRemainingMakerFillAmount](#interface-ordersandremainingmakerfillamount)‹*`T`*›* - -Resulting orders and remaining fill amount that could not be covered by the input. - -#### findOrdersThatCoverTakerAssetFillAmount - -▸ **findOrdersThatCoverTakerAssetFillAmount**<**T**>(`orders`: `T`[], `takerAssetFillAmount`: `BigNumber`, `opts?`: [FindOrdersThatCoverTakerAssetFillAmountOpts](#interface-findordersthatcovertakerassetfillamountopts)): *[OrdersAndRemainingTakerFillAmount](#interface-ordersandremainingtakerfillamount)‹*`T`*›* - -*Defined in [order-utils/src/market_utils.ts:18](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/market_utils.ts#L18)* - -**Type parameters:** - -▪ **T**: *`Order`* - -**Parameters:** - -Name | Type | ------- | ------ | -`orders` | `T`[] | -`takerAssetFillAmount` | `BigNumber` | -`opts?` | [FindOrdersThatCoverTakerAssetFillAmountOpts](#interface-findordersthatcovertakerassetfillamountopts) | - -**Returns:** *[OrdersAndRemainingTakerFillAmount](#interface-ordersandremainingtakerfillamount)‹*`T`*›* - -
- - - - -## Object literals - -#### `Const` orderCalculationUtils - -#### â–ª **orderCalculationUtils**: *object* - -*Defined in [order-utils/src/order_calculation_utils.ts:6](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L6)* - -#### getMakerFeeAmount - -â–¸ **getMakerFeeAmount**(`order`: `Order`, `makerFillAmount`: `BigNumber`): *`BigNumber`* - -*Defined in [order-utils/src/order_calculation_utils.ts:75](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L75)* - -Given an amount of maker asset, calculate the fee amount required for the maker - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order | -`makerFillAmount` | `BigNumber` | the amount of maker asset | - -**Returns:** *`BigNumber`* - -#### getMakerFillAmount - -â–¸ **getMakerFillAmount**(`order`: `Order`, `takerFillAmount`: `BigNumber`): *`BigNumber`* - -*Defined in [order-utils/src/order_calculation_utils.ts:36](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L36)* - -Given an amount of taker asset, calculate the the amount of maker asset - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order | -`takerFillAmount` | `BigNumber` | - | - -**Returns:** *`BigNumber`* - -#### getTakerFeeAmount - -â–¸ **getTakerFeeAmount**(`order`: `Order`, `takerFillAmount`: `BigNumber`): *`BigNumber`* - -*Defined in [order-utils/src/order_calculation_utils.ts:62](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L62)* - -Given an amount of taker asset, calculate the fee amount required for the taker - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order | -`takerFillAmount` | `BigNumber` | the amount of taker asset | - -**Returns:** *`BigNumber`* - -#### getTakerFillAmount - -â–¸ **getTakerFillAmount**(`order`: `Order`, `makerFillAmount`: `BigNumber`): *`BigNumber`* - -*Defined in [order-utils/src/order_calculation_utils.ts:49](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L49)* - -Given an amount of maker asset, calculate the equivalent amount in taker asset - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order | -`makerFillAmount` | `BigNumber` | the amount of maker asset | - -**Returns:** *`BigNumber`* - -#### getTakerFillAmountForFeeOrder - -â–¸ **getTakerFillAmountForFeeOrder**(`order`: `Order`, `makerFillAmount`: `BigNumber`): *[`BigNumber`, `BigNumber`]* - -*Defined in [order-utils/src/order_calculation_utils.ts:89](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L89)* - -Given a desired amount of ZRX from a fee order, calculate the amount of taker asset required to fill. -Also calculate how much ZRX needs to be purchased in order to fill the desired amount plus the taker fee amount - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order | -`makerFillAmount` | `BigNumber` | the amount of maker asset | - -**Returns:** *[`BigNumber`, `BigNumber`]* - -#### isOpenOrder - -â–¸ **isOpenOrder**(`order`: `Order`): *boolean* - -*Defined in [order-utils/src/order_calculation_utils.ts:28](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L28)* - -Determines if the order is open and fillable by any taker. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order | - -**Returns:** *boolean* - -#### isOrderExpired - -â–¸ **isOrderExpired**(`order`: `Order`): *boolean* - -*Defined in [order-utils/src/order_calculation_utils.ts:11](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L11)* - -Determines if the order is expired given the current time - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order for expiry calculation | - -**Returns:** *boolean* - -#### willOrderExpire - -â–¸ **willOrderExpire**(`order`: `Order`, `secondsFromNow`: number): *boolean* - -*Defined in [order-utils/src/order_calculation_utils.ts:19](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/order_calculation_utils.ts#L19)* - -Calculates if the order will expire in the future. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`order` | `Order` | The order for expiry calculation | -`secondsFromNow` | number | The amount of seconds from current time | - -**Returns:** *boolean* - -
- - - - -## Object literals - -#### `Const` rateUtils - -#### â–ª **rateUtils**: *object* - -*Defined in [order-utils/src/rate_utils.ts:8](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/rate_utils.ts#L8)* - -#### getFeeAdjustedRateOfFeeOrder - -â–¸ **getFeeAdjustedRateOfFeeOrder**(`feeOrder`: `Order`): *`BigNumber`* - -*Defined in [order-utils/src/rate_utils.ts:36](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/rate_utils.ts#L36)* - -Takes a fee order (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) and calculates -the fee adjusted rate (WETH/ZRX) by dividing the takerAssetAmount by the makerAmount minus the takerFee - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`feeOrder` | `Order` | An object that conforms to the order interface | - -**Returns:** *`BigNumber`* - -The rate (WETH/ZRX) of the fee order adjusted for fees - -#### getFeeAdjustedRateOfOrder - -â–¸ **getFeeAdjustedRateOfOrder**(`order`: `Order`, `feeRate`: `BigNumber`): *`BigNumber`* - -*Defined in [order-utils/src/rate_utils.ts:18](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/rate_utils.ts#L18)* - -Takes an order and calculates the fee adjusted rate (takerAsset/makerAsset) by calculating how much takerAsset -is required to cover the fees (feeRate * takerFee), adding the takerAssetAmount and dividing by makerAssetAmount - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`order` | `Order` | - | An object that conforms to the order interface | -`feeRate` | `BigNumber` | constants.ZERO_AMOUNT | The market rate of ZRX denominated in takerAssetAmount (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) Defaults to 0 | - -**Returns:** *`BigNumber`* - -The rate (takerAsset/makerAsset) of the order adjusted for fees - -
- - - - -## Functions - -#### generatePseudoRandomSalt - -â–¸ **generatePseudoRandomSalt**(): *`BigNumber`* - -*Defined in [order-utils/src/salt.ts:9](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/salt.ts#L9)* - -Generates a pseudo-random 256-bit salt. -The salt can be included in a 0x order, ensuring that the order generates a unique orderHash -and will not collide with other outstanding orders that are identical in all other parameters. - -**Returns:** *`BigNumber`* - -A pseudo-random 256-bit number that can be used as a salt. - -
- - - - -## Functions - -#### isValidECSignature - -â–¸ **isValidECSignature**(`data`: string, `signature`: `ECSignature`, `signerAddress`: string): *boolean* - -*Defined in [order-utils/src/signature_utils.ts:353](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L353)* - -Checks if the supplied elliptic curve signature corresponds to signing `data` with -the private key corresponding to `signerAddress` - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`data` | string | The hex encoded data signed by the supplied signature. | -`signature` | `ECSignature` | An object containing the elliptic curve signature parameters. | -`signerAddress` | string | The hex encoded address that signed the data, producing the supplied signature. | - -**Returns:** *boolean* - -Whether the ECSignature is valid. - -___ - -### parseSignatureHexAsVRS - -â–¸ **parseSignatureHexAsVRS**(`signatureHex`: string): *`ECSignature`* - -*Defined in [order-utils/src/signature_utils.ts:311](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L311)* - -Parses a signature hex string, which is assumed to be in the VRS format. - -**Parameters:** - -Name | Type | ------- | ------ | -`signatureHex` | string | - -**Returns:** *`ECSignature`* - -## Object literals - -### `Const` signatureUtils - -#### â–ª **signatureUtils**: *object* - -*Defined in [order-utils/src/signature_utils.ts:26](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L26)* - -#### addSignedMessagePrefix - -â–¸ **addSignedMessagePrefix**(`message`: string): *string* - -*Defined in [order-utils/src/signature_utils.ts:284](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L284)* - -Adds the relevant prefix to the message being signed. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`message` | string | Message to sign | - -**Returns:** *string* - -Prefixed message - -#### convertECSignatureToSignatureHex - -â–¸ **convertECSignatureToSignatureHex**(`ecSignature`: `ECSignature`): *string* - -*Defined in [order-utils/src/signature_utils.ts:258](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L258)* - -Combines ECSignature with V,R,S and the EthSign signature type for use in 0x protocol - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`ecSignature` | `ECSignature` | The ECSignature of the signed data | - -**Returns:** *string* - -Hex encoded string of signature (v,r,s) with Signature Type - -#### convertToSignatureWithType - -â–¸ **convertToSignatureWithType**(`signature`: string, `signatureType`: `SignatureType`): *string* - -*Defined in [order-utils/src/signature_utils.ts:274](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L274)* - -Combines the signature proof and the Signature Type. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`signature` | string | The hex encoded signature proof | -`signatureType` | `SignatureType` | The signature type, i.e EthSign, Wallet etc. | - -**Returns:** *string* - -Hex encoded string of signature proof with Signature Type - -#### ecSignHashAsync - -â–¸ **ecSignHashAsync**(`supportedProvider`: [SupportedProvider](#supportedprovider), `msgHash`: string, `signerAddress`: string): *`Promise`* - -*Defined in [order-utils/src/signature_utils.ts:209](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L209)* - -Signs a hash using `eth_sign` and returns its elliptic curve signature and signature type. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`supportedProvider` | [SupportedProvider](#supportedprovider) | Web3 provider to use for all JSON RPC requests | -`msgHash` | string | Hex encoded message to sign. | -`signerAddress` | string | The hex encoded Ethereum address you wish to sign it with. This address must be available via the supplied Provider. | - -**Returns:** *`Promise`* - -A hex encoded string containing the Elliptic curve signature generated by signing the msgHash and the Signature Type. - -#### ecSignOrderAsync - -â–¸ **ecSignOrderAsync**(`supportedProvider`: [SupportedProvider](#supportedprovider), `order`: `Order`, `signerAddress`: string): *`Promise`* - -*Defined in [order-utils/src/signature_utils.ts:36](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L36)* - -Signs an order and returns a SignedOrder. First `eth_signTypedData` is requested -then a fallback to `eth_sign` if not available on the supplied provider. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`supportedProvider` | [SupportedProvider](#supportedprovider) | Web3 provider to use for all JSON RPC requests | -`order` | `Order` | The Order to sign. | -`signerAddress` | string | The hex encoded Ethereum address you wish to sign it with. This address must be available via the supplied Provider. | - -**Returns:** *`Promise`* - -A SignedOrder containing the order and Elliptic curve signature with Signature Type. - -#### ecSignTransactionAsync - -â–¸ **ecSignTransactionAsync**(`supportedProvider`: [SupportedProvider](#supportedprovider), `transaction`: `ZeroExTransaction`, `signerAddress`: string): *`Promise`* - -*Defined in [order-utils/src/signature_utils.ts:117](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L117)* - -Signs a transaction and returns a SignedZeroExTransaction. First `eth_signTypedData` is requested -then a fallback to `eth_sign` if not available on the supplied provider. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`supportedProvider` | [SupportedProvider](#supportedprovider) | Web3 provider to use for all JSON RPC requests | -`transaction` | `ZeroExTransaction` | The ZeroExTransaction to sign. | -`signerAddress` | string | The hex encoded Ethereum address you wish to sign it with. This address must be available via the supplied Provider. | - -**Returns:** *`Promise`* - -A SignedTransaction containing the order and Elliptic curve signature with Signature Type. - -#### ecSignTypedDataOrderAsync - -â–¸ **ecSignTypedDataOrderAsync**(`supportedProvider`: [SupportedProvider](#supportedprovider), `order`: `Order`, `signerAddress`: string): *`Promise`* - -*Defined in [order-utils/src/signature_utils.ts:73](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L73)* - -Signs an order using `eth_signTypedData` and returns a SignedOrder. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`supportedProvider` | [SupportedProvider](#supportedprovider) | Web3 provider to use for all JSON RPC requests | -`order` | `Order` | The Order to sign. | -`signerAddress` | string | The hex encoded Ethereum address you wish to sign it with. This address must be available via the supplied Provider. | - -**Returns:** *`Promise`* - -A SignedOrder containing the order and Elliptic curve signature with Signature Type. - -#### ecSignTypedDataTransactionAsync - -â–¸ **ecSignTypedDataTransactionAsync**(`supportedProvider`: [SupportedProvider](#supportedprovider), `transaction`: `ZeroExTransaction`, `signerAddress`: string): *`Promise`* - -*Defined in [order-utils/src/signature_utils.ts:166](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L166)* - -Signs a ZeroExTransaction using `eth_signTypedData` and returns a SignedZeroExTransaction. - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`supportedProvider` | [SupportedProvider](#supportedprovider) | Web3 provider to use for all JSON RPC requests | -`transaction` | `ZeroExTransaction` | The ZeroEx Transaction to sign. | -`signerAddress` | string | The hex encoded Ethereum address you wish to sign it with. This address must be available via the supplied Provider. | - -**Returns:** *`Promise`* - -A SignedZeroExTransaction containing the ZeroExTransaction and Elliptic curve signature with Signature Type. - -#### parseValidatorSignature - -â–¸ **parseValidatorSignature**(`signature`: string): *`ValidatorSignature`* - -*Defined in [order-utils/src/signature_utils.ts:296](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/signature_utils.ts#L296)* - -Parse a hex-encoded Validator signature into validator address and signature components - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`signature` | string | A hex encoded Validator 0x Protocol signature | - -**Returns:** *`ValidatorSignature`* - -A ValidatorSignature with validatorAddress and signature parameters - -
- - - - -## Object literals - -#### `Const` sortingUtils - -#### â–ª **sortingUtils**: *object* - -*Defined in [order-utils/src/sorting_utils.ts:10](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/sorting_utils.ts#L10)* - -#### sortFeeOrdersByFeeAdjustedRate - -â–¸ **sortFeeOrdersByFeeAdjustedRate**<**T**>(`feeOrders`: `T`[]): *`T`[]* - -*Defined in [order-utils/src/sorting_utils.ts:35](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/sorting_utils.ts#L35)* - -Takes an array of fee orders (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) -and sorts them by rate in ascending order (best rate first). Adjusts the rate according to the takerFee. - -**Type parameters:** - -â–ª **T**: *`Order`* - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`feeOrders` | `T`[] | An array of objects that extend the Order interface. All orders should specify ZRX as the makerAsset and WETH as the takerAsset. | - -**Returns:** *`T`[]* - -The input orders sorted by rate in ascending order - -#### sortOrdersByFeeAdjustedRate - -â–¸ **sortOrdersByFeeAdjustedRate**<**T**>(`orders`: `T`[], `feeRate`: `BigNumber`): *`T`[]* - -*Defined in [order-utils/src/sorting_utils.ts:21](https://github.com/0xProject/0x-monorepo/blob/34538f2ce/packages/order-utils/src/sorting_utils.ts#L21)* - -Takes an array of orders and sorts them by takerAsset/makerAsset rate in ascending order (best rate first). -Adjusts the rate of each order according to the feeRate and takerFee for that order. - -**Type parameters:** - -â–ª **T**: *`Order`* - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`orders` | `T`[] | - | An array of objects that extend the Order interface. All orders should specify ZRX as the makerAsset and WETH as the takerAsset. | -`feeRate` | `BigNumber` | constants.ZERO_AMOUNT | The market rate of ZRX denominated in takerAssetAmount (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) Defaults to 0 | - -**Returns:** *`T`[]* - -The input orders sorted by rate in ascending order - -
- - - -
- diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json deleted file mode 100644 index a3d7bb1473..0000000000 --- a/packages/order-utils/package.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "@0x/order-utils", - "version": "10.4.28", - "engines": { - "node": ">=6.12" - }, - "description": "0x order utils", - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "build": "yarn tsc -b", - "build:ci": "yarn build", - "publish:private": "yarn clean && yarn build && gitpkg publish", - "test": "yarn run_mocha", - "rebuild_and_test": "run-s build test", - "test:circleci": "yarn test:coverage", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --timeout 10000 --bail --exit", - "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", - "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "clean": "shx rm -rf lib generated_docs", - "lint": "tslint --format stylish --project .", - "fix": "tslint --fix --format stylish --project .", - "diff_docs": "git diff --exit-code ./docs", - "s3:sync_md_docs": "aws s3 sync ./docs s3://docs-markdown/${npm_package_name}/v${npm_package_version} --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers", - "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", - "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "config": { - "postpublish": { - "assets": [] - } - }, - "gitpkg": { - "registry": "git@github.com:0xProject/gitpkg-registry.git" - }, - "license": "Apache-2.0", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/protocol.git" - }, - "bugs": { - "url": "https://github.com/0xProject/protocol/issues" - }, - "homepage": "https://github.com/0xProject/protocol/tree/main/packages/order-utils", - "devDependencies": { - "@0x/dev-utils": "^4.2.7", - "@0x/subproviders": "^6.5.3", - "@0x/ts-doc-gen": "^0.0.28", - "@0x/tslint-config": "^4.1.4", - "@0x/types": "^3.3.3", - "@0x/typescript-typings": "^5.2.0", - "@types/bn.js": "^4.11.0", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@types/node": "12.12.54", - "@types/web3-provider-engine": "^14.0.0", - "chai": "^4.0.1", - "ethereum-types": "^3.5.0", - "gitpkg": "https://github.com/0xProject/gitpkg.git", - "make-promises-safe": "^1.1.0", - "mocha": "^6.2.0", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "sinon": "^4.0.0", - "tslint": "5.11.0", - "typedoc": "~0.16.11", - "typescript": "4.2.2", - "web3-provider-engine": "14.0.6" - }, - "dependencies": { - "@0x/assert": "^3.0.27", - "@0x/contract-addresses": "^6.6.0", - "@0x/contract-wrappers": "^13.17.4", - "@0x/json-schemas": "^6.1.3", - "@0x/utils": "^6.4.3", - "@0x/web3-wrapper": "^7.5.3", - "ethereumjs-util": "^7.0.10", - "ethers": "~4.0.4", - "lodash": "^4.17.11" - }, - "publishConfig": { - "access": "public" - }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" -} diff --git a/packages/order-utils/src/assert.ts b/packages/order-utils/src/assert.ts deleted file mode 100644 index e00f7be0c8..0000000000 --- a/packages/order-utils/src/assert.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { assert as sharedAssert } from '@0x/assert'; -import { SignatureType } from '@0x/types'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -// tslint:enable:no-unused-variable -import * as _ from 'lodash'; - -import { utils } from './utils'; - -export const assert = { - ...sharedAssert, - async isSenderAddressAsync( - variableName: string, - senderAddressHex: string, - web3Wrapper: Web3Wrapper, - ): Promise { - sharedAssert.isETHAddressHex(variableName, senderAddressHex); - const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex); - sharedAssert.assert( - isSenderAddressAvailable, - `Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`, - ); - }, - isOneOfExpectedSignatureTypes(signature: string, signatureTypes: SignatureType[]): void { - sharedAssert.isHexString('signature', signature); - const signatureTypeIndexIfExists = utils.getSignatureTypeIndexIfExists(signature); - const isExpectedSignatureType = _.includes(signatureTypes, signatureTypeIndexIfExists); - if (!isExpectedSignatureType) { - throw new Error( - `Unexpected signatureType: ${signatureTypeIndexIfExists}. Valid signature types: ${signatureTypes}`, - ); - } - }, -}; diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts deleted file mode 100644 index ead6837dde..0000000000 --- a/packages/order-utils/src/asset_data_utils.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { IAssetDataContract } from '@0x/contract-wrappers'; -import { - AssetData, - AssetProxyId, - ERC1155AssetData, - ERC20AssetData, - ERC20BridgeAssetData, - ERC721AssetData, - MultiAssetData, - MultiAssetDataWithRecursiveDecoding, - SingleAssetData, - StaticCallAssetData, -} from '@0x/types'; -import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils'; -import * as _ from 'lodash'; - -const fakeProvider = { isEIP1193: true } as any; -const assetDataEncoder = new IAssetDataContract(NULL_ADDRESS, fakeProvider); - -export const assetDataUtils = { - encodeERC20AssetData(tokenAddress: string): string { - return assetDataEncoder.ERC20Token(tokenAddress).getABIEncodedTransactionData(); - }, - encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string { - return assetDataEncoder.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData(); - }, - encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string { - return assetDataEncoder.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData(); - }, - encodeERC1155AssetData( - tokenAddress: string, - tokenIds: BigNumber[], - tokenValues: BigNumber[], - callbackData: string, - ): string { - return assetDataEncoder - .ERC1155Assets(tokenAddress, tokenIds, tokenValues, callbackData) - .getABIEncodedTransactionData(); - }, - encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string { - return assetDataEncoder.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData(); - }, - encodeStaticCallAssetData( - staticCallTargetAddress: string, - staticCallData: string, - expectedReturnDataHash: string, - ): string { - return assetDataEncoder - .StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash) - .getABIEncodedTransactionData(); - }, - /** - * Decode any assetData into its corresponding assetData object - * @param assetData Hex encoded assetData string to decode - * @return Either a ERC20, ERC20Bridge, ERC721, ERC1155, StaticCall, or MultiAsset assetData object - */ - decodeAssetDataOrThrow(assetData: string): AssetData { - const assetProxyId = hexUtils.slice(assetData, 0, 4); // tslint:disable-line:custom-no-magic-numbers - switch (assetProxyId) { - case AssetProxyId.ERC20: { - const tokenAddress = assetDataEncoder.getABIDecodedTransactionData('ERC20Token', assetData); - return { - assetProxyId, - tokenAddress, - }; - } - case AssetProxyId.ERC20Bridge: { - const [tokenAddress, bridgeAddress, bridgeData] = assetDataEncoder.getABIDecodedTransactionData< - [string, string, string] - >('ERC20Bridge', assetData); - return { - assetProxyId, - tokenAddress, - bridgeAddress, - bridgeData, - }; - } - case AssetProxyId.ERC721: { - const [tokenAddress, tokenId] = assetDataEncoder.getABIDecodedTransactionData<[string, BigNumber]>( - 'ERC721Token', - assetData, - ); - return { - assetProxyId, - tokenAddress, - tokenId, - }; - } - case AssetProxyId.ERC1155: { - const [ - tokenAddress, - tokenIds, - tokenValues, - callbackData, - ] = assetDataEncoder.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>( - 'ERC1155Assets', - assetData, - ); - return { - assetProxyId, - tokenAddress, - tokenIds, - tokenValues, - callbackData, - }; - } - case AssetProxyId.MultiAsset: { - const [amounts, nestedAssetData] = assetDataEncoder.getABIDecodedTransactionData< - [BigNumber[], string[]] - >('MultiAsset', assetData); - - const multiAssetData: MultiAssetData = { - assetProxyId, - amounts, - nestedAssetData, - }; - return multiAssetData; - } - case AssetProxyId.StaticCall: - const [callTarget, staticCallData, callResultHash] = assetDataEncoder.getABIDecodedTransactionData< - [string, string, string] - >('StaticCall', assetData); - return { - assetProxyId, - callTarget, - staticCallData, - callResultHash, - }; - default: - throw new Error(`Unhandled asset proxy ID: ${assetProxyId}`); - } - }, - /** - * Decodes a MultiAsset assetData hex string into its corresponding amounts and decoded nestedAssetData elements (all nested elements are flattened) - * @param assetData Hex encoded assetData string to decode - * @return An object containing the decoded amounts and nestedAssetData - */ - decodeMultiAssetDataRecursively(assetData: string): MultiAssetDataWithRecursiveDecoding { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData) as MultiAssetData; // tslint:disable-line:no-unnecessary-type-assertion - if (decodedAssetData.assetProxyId !== AssetProxyId.MultiAsset) { - throw new Error(`Not a MultiAssetData. Use 'decodeAssetDataOrThrow' instead`); - } - const amounts: any[] = []; - const decodedNestedAssetData = decodedAssetData.nestedAssetData.map((nestedAssetDataElement, index) => { - const decodedNestedAssetDataElement = assetDataUtils.decodeAssetDataOrThrow(nestedAssetDataElement); - if (decodedNestedAssetDataElement.assetProxyId === AssetProxyId.MultiAsset) { - const recursivelyDecodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively( - nestedAssetDataElement, - ); - amounts.push( - recursivelyDecodedAssetData.amounts.map(amountElement => - amountElement.times(decodedAssetData.amounts[index]), - ), - ); - return recursivelyDecodedAssetData.nestedAssetData; - } else { - amounts.push(decodedAssetData.amounts[index]); - return decodedNestedAssetDataElement; - } - }); - const flattenedAmounts = _.flattenDeep(amounts); - const flattenedDecodedNestedAssetData = _.flattenDeep(decodedNestedAssetData); - return { - assetProxyId: decodedAssetData.assetProxyId, - amounts: flattenedAmounts, - // tslint:disable-next-line:no-unnecessary-type-assertion - nestedAssetData: flattenedDecodedNestedAssetData as SingleAssetData[], - }; - }, - isERC20TokenAssetData(assetData: AssetData): assetData is ERC20AssetData { - return assetData.assetProxyId === AssetProxyId.ERC20; - }, - isERC20BridgeAssetData(assetData: AssetData): assetData is ERC20BridgeAssetData { - return assetData.assetProxyId === AssetProxyId.ERC20Bridge; - }, - isERC1155TokenAssetData(assetData: AssetData): assetData is ERC1155AssetData { - return assetData.assetProxyId === AssetProxyId.ERC1155; - }, - isERC721TokenAssetData(assetData: AssetData): assetData is ERC721AssetData { - return assetData.assetProxyId === AssetProxyId.ERC721; - }, - isMultiAssetData(assetData: AssetData): assetData is MultiAssetData { - return assetData.assetProxyId === AssetProxyId.MultiAsset; - }, - isStaticCallAssetData(assetData: AssetData): assetData is StaticCallAssetData { - return assetData.assetProxyId === AssetProxyId.StaticCall; - }, -}; diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts deleted file mode 100644 index d4295a75f5..0000000000 --- a/packages/order-utils/src/constants.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; -import { BigNumber, NULL_ADDRESS, NULL_BYTES } from '@0x/utils'; -import { MethodAbi } from 'ethereum-types'; - -const ERC20_METHOD_ABI: MethodAbi = { - constant: false, - inputs: [ - { - name: 'tokenContract', - type: 'address', - }, - ], - name: 'ERC20Token', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -}; - -const ERC721_METHOD_ABI: MethodAbi = { - constant: false, - inputs: [ - { - name: 'tokenContract', - type: 'address', - }, - { - name: 'tokenId', - type: 'uint256', - }, - ], - name: 'ERC721Token', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -}; - -const MULTI_ASSET_METHOD_ABI: MethodAbi = { - constant: false, - inputs: [ - { - name: 'amounts', - type: 'uint256[]', - }, - { - name: 'nestedAssetData', - type: 'bytes[]', - }, - ], - name: 'MultiAsset', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -}; - -const ERC1155_METHOD_ABI: MethodAbi = { - constant: false, - inputs: [ - { name: 'tokenAddress', type: 'address' }, - { name: 'tokenIds', type: 'uint256[]' }, - { name: 'tokenValues', type: 'uint256[]' }, - { name: 'callbackData', type: 'bytes' }, - ], - name: 'ERC1155Assets', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -}; - -const STATIC_CALL_METHOD_ABI: MethodAbi = { - constant: false, - inputs: [ - { name: 'callTarget', type: 'address' }, - { name: 'staticCallData', type: 'bytes' }, - { name: 'callResultHash', type: 'bytes32' }, - ], - name: 'StaticCall', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -}; - -export const constants = { - NULL_ADDRESS, - FAKED_PROVIDER: { isEIP1193: true }, - NULL_BYTES, - NULL_ERC20_ASSET_DATA: '0xf47261b00000000000000000000000000000000000000000000000000000000000000000', - // tslint:disable-next-line:custom-no-magic-numbers - UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), - TESTRPC_CHAIN_ID: 1337, - ADDRESS_LENGTH: 20, - ERC20_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 74, // 36 bytes - ERC721_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 138, // 68 bytes - ERC1155_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 266, // 132 bytes - MULTI_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 138, // 68 bytes - STATIC_CALL_ASSET_DATA_MIN_CHAR_LENGTH_WITH_PREFIX: 202, // 100 bytes - SELECTOR_CHAR_LENGTH_WITH_PREFIX: 10, // 4 bytes - INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite - ZERO_AMOUNT: new BigNumber(0), - EXCHANGE_DOMAIN_NAME: '0x Protocol', - EXCHANGE_DOMAIN_VERSION: '3.0.0', - DEFAULT_DOMAIN_SCHEMA: { - name: 'EIP712Domain', - parameters: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - }, - EXCHANGE_ORDER_SCHEMA: { - name: 'Order', - parameters: [ - { name: 'makerAddress', type: 'address' }, - { name: 'takerAddress', type: 'address' }, - { name: 'feeRecipientAddress', type: 'address' }, - { name: 'senderAddress', type: 'address' }, - { name: 'makerAssetAmount', type: 'uint256' }, - { name: 'takerAssetAmount', type: 'uint256' }, - { name: 'makerFee', type: 'uint256' }, - { name: 'takerFee', type: 'uint256' }, - { name: 'expirationTimeSeconds', type: 'uint256' }, - { name: 'salt', type: 'uint256' }, - { name: 'makerAssetData', type: 'bytes' }, - { name: 'takerAssetData', type: 'bytes' }, - { name: 'makerFeeAssetData', type: 'bytes' }, - { name: 'takerFeeAssetData', type: 'bytes' }, - ], - }, - EXCHANGE_ZEROEX_TRANSACTION_SCHEMA: { - name: 'ZeroExTransaction', - parameters: [ - { name: 'salt', type: 'uint256' }, - { name: 'expirationTimeSeconds', type: 'uint256' }, - { name: 'gasPrice', type: 'uint256' }, - { name: 'signerAddress', type: 'address' }, - { name: 'data', type: 'bytes' }, - ], - }, - COORDINATOR_DOMAIN_NAME: '0x Protocol Coordinator', - COORDINATOR_DOMAIN_VERSION: '3.0.0', - COORDINATOR_APPROVAL_SCHEMA: { - name: 'CoordinatorApproval', - parameters: [ - { name: 'txOrigin', type: 'address' }, - { name: 'transactionHash', type: 'bytes32' }, - { name: 'transactionSignature', type: 'bytes' }, - ], - }, - MAINNET_EXCHANGE_PROXY_DOMAIN: { - name: 'ZeroEx', - version: '1.0.0', - chainId: 1, - verifyingContract: getContractAddressesForChainOrThrow(1).exchangeProxy, - }, - EXCHANGE_PROXY_MTX_SCEHMA: { - name: 'MetaTransactionData', - parameters: [ - { name: 'signer', type: 'address' }, - { name: 'sender', type: 'address' }, - { name: 'minGasPrice', type: 'uint256' }, - { name: 'maxGasPrice', type: 'uint256' }, - { name: 'expirationTimeSeconds', type: 'uint256' }, - { name: 'salt', type: 'uint256' }, - { name: 'callData', type: 'bytes' }, - { name: 'value', type: 'uint256' }, - { name: 'feeToken', type: 'address' }, - { name: 'feeAmount', type: 'uint256' }, - ], - }, - ERC20_METHOD_ABI, - ERC721_METHOD_ABI, - MULTI_ASSET_METHOD_ABI, - ERC1155_METHOD_ABI, - STATIC_CALL_METHOD_ABI, - IS_VALID_WALLET_SIGNATURE_MAGIC_VALUE: '0xb0671381', - IS_VALID_VALIDATOR_SIGNATURE_MAGIC_VALUE: '0x42b38674', - /* - * The pseudo-token address for ETH used by the Exchange Proxy's `tranformERC20()`. - */ - ETH_TOKEN_ADDRESS: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', -}; diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts deleted file mode 100644 index b2183716f1..0000000000 --- a/packages/order-utils/src/eip712_utils.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { assert } from '@0x/assert'; -import { schemas } from '@0x/json-schemas'; -import { - EIP712DomainWithDefaultSchema, - EIP712Object, - EIP712TypedData, - EIP712Types, - ExchangeProxyMetaTransaction, - Order, - SignedZeroExTransaction, - ZeroExTransaction, -} from '@0x/types'; -import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { constants } from './constants'; - -export const eip712Utils = { - /** - * Creates a EIP712TypedData object specific to the 0x protocol for use with signTypedData. - * @param primaryType The primary type found in message - * @param types The additional types for the data in message - * @param message The contents of the message - * @param domain Domain containing a name (optional), version (optional), and verifying contract address - * @return A typed data object - */ - createTypedData: ( - primaryType: string, - types: EIP712Types, - message: EIP712Object, - domain: EIP712DomainWithDefaultSchema, - ): EIP712TypedData => { - assert.isETHAddressHex('verifyingContract', domain.verifyingContract); - assert.isString('primaryType', primaryType); - const typedData = { - types: { - EIP712Domain: constants.DEFAULT_DOMAIN_SCHEMA.parameters, - ...types, - }, - domain: { - name: domain.name === undefined ? constants.EXCHANGE_DOMAIN_NAME : domain.name, - version: domain.version === undefined ? constants.EXCHANGE_DOMAIN_VERSION : domain.version, - chainId: domain.chainId, - verifyingContract: domain.verifyingContract, - }, - message, - primaryType, - }; - assert.doesConformToSchema('typedData', typedData, schemas.eip712TypedDataSchema); - return typedData; - }, - /** - * Creates an Order EIP712TypedData object for use with signTypedData. - * @param Order the order - * @return A typed data object - */ - createOrderTypedData: (order: Order): EIP712TypedData => { - assert.doesConformToSchema('order', order, schemas.orderSchema, [schemas.hexSchema]); - const normalizedOrder = _.mapValues(order, value => { - return !_.isString(value) ? value.toString() : value; - }); - const partialDomain = { - chainId: order.chainId, - verifyingContract: order.exchangeAddress, - }; - // Since we are passing in the EXCHANGE_ORDER_SCHEMA - // order paramaters that are not in there get ignored at hashing time - const typedData = eip712Utils.createTypedData( - constants.EXCHANGE_ORDER_SCHEMA.name, - { Order: constants.EXCHANGE_ORDER_SCHEMA.parameters }, - normalizedOrder, - partialDomain, - ); - return typedData; - }, - /** - * Creates an ExecuteTransaction EIP712TypedData object for use with signTypedData and - * 0x Exchange executeTransaction. - * @param zeroExTransaction the 0x transaction - * @return A typed data object - */ - createZeroExTransactionTypedData: (zeroExTransaction: ZeroExTransaction): EIP712TypedData => { - assert.isNumber('domain.chainId', zeroExTransaction.domain.chainId); - assert.isETHAddressHex('domain.verifyingContract', zeroExTransaction.domain.verifyingContract); - assert.doesConformToSchema('zeroExTransaction', zeroExTransaction, schemas.zeroExTransactionSchema); - const normalizedTransaction = _.mapValues(zeroExTransaction, value => { - return !_.isString(value) ? value.toString() : value; - }); - const typedData = eip712Utils.createTypedData( - constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name, - { ZeroExTransaction: constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.parameters }, - normalizedTransaction, - zeroExTransaction.domain, - ); - return typedData; - }, - /** - * Creates an Coordinator typedData EIP712TypedData object for use with the Coordinator extension contract - * @param transaction A 0x transaction - * @param verifyingContract The coordinator extension contract address that will be verifying the typedData - * @param txOrigin The desired `tx.origin` that should be able to submit an Ethereum txn involving this 0x transaction - * @return A typed data object - */ - createCoordinatorApprovalTypedData( - transaction: SignedZeroExTransaction, - verifyingContract: string, - txOrigin: string, - ): EIP712TypedData { - const domain = { - ...transaction.domain, - name: constants.COORDINATOR_DOMAIN_NAME, - version: constants.COORDINATOR_DOMAIN_VERSION, - verifyingContract, - }; - // TODO(dorothy-zbornak): Refactor these hash files so we can reuse - // `transactionHashUtils` here without a circular dep. - const transactionHash = hexUtils.toHex( - signTypedDataUtils.generateTypedDataHash(eip712Utils.createZeroExTransactionTypedData(transaction)), - ); - const approval = { - txOrigin, - transactionHash, - transactionSignature: transaction.signature, - }; - const typedData = eip712Utils.createTypedData( - constants.COORDINATOR_APPROVAL_SCHEMA.name, - { - CoordinatorApproval: constants.COORDINATOR_APPROVAL_SCHEMA.parameters, - }, - approval, - domain, - ); - return typedData; - }, - createExchangeProxyMetaTransactionTypedData(mtx: ExchangeProxyMetaTransaction): EIP712TypedData { - return eip712Utils.createTypedData( - constants.EXCHANGE_PROXY_MTX_SCEHMA.name, - { - MetaTransactionData: constants.EXCHANGE_PROXY_MTX_SCEHMA.parameters, - }, - _.mapValues( - _.omit(mtx, 'domain'), - // tslint:disable-next-line: custom-no-magic-numbers - v => (BigNumber.isBigNumber(v) ? v.toString(10) : v), - ) as EIP712Object, // tslint:disable-line:no-unnecessary-type-assertion - { - ...constants.MAINNET_EXCHANGE_PROXY_DOMAIN, - ...mtx.domain, - }, - ); - }, -}; diff --git a/packages/order-utils/src/hash_utils.ts b/packages/order-utils/src/hash_utils.ts deleted file mode 100644 index 57859f0843..0000000000 --- a/packages/order-utils/src/hash_utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ExchangeProxyMetaTransaction, Order, ZeroExTransaction } from '@0x/types'; -import { hexUtils, signTypedDataUtils } from '@0x/utils'; - -import { eip712Utils } from './eip712_utils'; -import { orderHashUtils } from './order_hash_utils'; -import { transactionHashUtils } from './transaction_hash_utils'; - -/** - * Compute the EIP712 hash of an order. - */ -export function getOrderHash(order: Order): string { - return orderHashUtils.getOrderHash(order); -} - -/** - * Compute the EIP712 hash of an Exchange meta-transaction. - */ -export function getExchangeMetaTransactionHash(tx: ZeroExTransaction): string { - return transactionHashUtils.getTransactionHash(tx); -} - -/** - * Compute the EIP712 hash of an Exchange Proxy meta-transaction. - */ -export function getExchangeProxyMetaTransactionHash(mtx: ExchangeProxyMetaTransaction): string { - return hexUtils.toHex( - signTypedDataUtils.generateTypedDataHash(eip712Utils.createExchangeProxyMetaTransactionTypedData(mtx)), - ); -} diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts deleted file mode 100644 index d8f1e458d5..0000000000 --- a/packages/order-utils/src/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -export { signatureUtils } from './signature_utils'; -export { generatePseudoRandomSalt } from './salt'; -export { marketUtils } from './market_utils'; -export { rateUtils } from './rate_utils'; -export { sortingUtils } from './sorting_utils'; -export { orderCalculationUtils } from './order_calculation_utils'; -export { orderHashUtils } from './order_hash_utils'; -export { transactionHashUtils } from './transaction_hash_utils'; -export { assetDataUtils } from './asset_data_utils'; - -export { eip712Utils } from './eip712_utils'; - -export { - SupportedProvider, - JSONRPCRequestPayload, - JSONRPCErrorCallback, - JSONRPCResponsePayload, - JSONRPCResponseError, - Web3JsProvider, - GanacheProvider, - EIP1193Provider, - ZeroExProvider, - EIP1193Event, - Web3JsV1Provider, - Web3JsV2Provider, - Web3JsV3Provider, -} from 'ethereum-types'; - -export { - SignedOrder, - Order, - ECSignature, - AssetData, - SingleAssetData, - ERC20AssetData, - ERC20BridgeAssetData, - ERC721AssetData, - ERC1155AssetData, - MultiAssetData, - StaticCallAssetData, - MultiAssetDataWithRecursiveDecoding, - SignatureType, - EIP712Parameter, - EIP712TypedData, - EIP712Types, - EIP712Object, - EIP712ObjectValue, - EIP712DomainWithDefaultSchema, - ZeroExTransaction, - SignedZeroExTransaction, - ValidatorSignature, - ExchangeProxyMetaTransaction, - SignedExchangeProxyMetaTransaction, -} from '@0x/types'; - -export { - TypedDataError, - FindFeeOrdersThatCoverFeesForTargetOrdersOpts, - FindOrdersThatCoverMakerAssetFillAmountOpts, - FindOrdersThatCoverTakerAssetFillAmountOpts, - FeeOrdersAndRemainingFeeAmount, - OrdersAndRemainingTakerFillAmount, - OrdersAndRemainingMakerFillAmount, -} from './types'; - -export { - FillQuoteTransformerSide, - FillQuoteTransformerData, - encodeFillQuoteTransformerData, - decodeFillQuoteTransformerData, - WethTransformerData, - encodeWethTransformerData, - decodeWethTransformerData, - PayTakerTransformerData, - encodePayTakerTransformerData, - decodePayTakerTransformerData, - AffiliateFeeTransformerData, - encodeAffiliateFeeTransformerData, - decodeAffiliateFeeTransformerData, - PositiveSlippageFeeTransformerData, - encodePositiveSlippageFeeTransformerData, - decodePositiveSlippageFeeTransformerData, - findTransformerNonce, - getTransformerAddress, -} from './transformer_utils'; - -export { getOrderHash, getExchangeMetaTransactionHash, getExchangeProxyMetaTransactionHash } from './hash_utils'; - -import { constants } from './constants'; -export const NULL_ADDRESS = constants.NULL_ADDRESS; -export const NULL_BYTES = constants.NULL_BYTES; -export const ZERO_AMOUNT = constants.ZERO_AMOUNT; -export const NULL_ERC20_ASSET_DATA = constants.NULL_ERC20_ASSET_DATA; -export const ETH_TOKEN_ADDRESS = constants.ETH_TOKEN_ADDRESS; diff --git a/packages/order-utils/src/market_utils.ts b/packages/order-utils/src/market_utils.ts deleted file mode 100644 index 591d223139..0000000000 --- a/packages/order-utils/src/market_utils.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { schemas } from '@0x/json-schemas'; -import { MarketOperation, Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { assert } from './assert'; -import { constants } from './constants'; -import { - FeeOrdersAndRemainingFeeAmount, - FindFeeOrdersThatCoverFeesForTargetOrdersOpts, - FindOrdersThatCoverMakerAssetFillAmountOpts, - FindOrdersThatCoverTakerAssetFillAmountOpts, - OrdersAndRemainingMakerFillAmount, - OrdersAndRemainingTakerFillAmount, -} from './types'; - -export const marketUtils = { - findOrdersThatCoverTakerAssetFillAmount( - orders: T[], - takerAssetFillAmount: BigNumber, - opts?: FindOrdersThatCoverTakerAssetFillAmountOpts, - ): OrdersAndRemainingTakerFillAmount { - return findOrdersThatCoverAssetFillAmount( - orders, - takerAssetFillAmount, - MarketOperation.Sell, - opts, - ) as OrdersAndRemainingTakerFillAmount; - }, - /** - * Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount - * in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last order. - * Sort the input by ascending rate in order to get the subset of orders that will cost the least ETH. - * @param orders An array of objects that extend the Order interface. All orders should specify the same makerAsset. - * All orders should specify WETH as the takerAsset. - * @param makerAssetFillAmount The amount of makerAsset desired to be filled. - * @param opts Optional arguments this function accepts. - * @return Resulting orders and remaining fill amount that could not be covered by the input. - */ - findOrdersThatCoverMakerAssetFillAmount( - orders: T[], - makerAssetFillAmount: BigNumber, - opts?: FindOrdersThatCoverMakerAssetFillAmountOpts, - ): OrdersAndRemainingMakerFillAmount { - return findOrdersThatCoverAssetFillAmount( - orders, - makerAssetFillAmount, - MarketOperation.Buy, - opts, - ) as OrdersAndRemainingMakerFillAmount; - }, - /** - * Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX - * in order to fill the takerFees required by orders plus a slippageBufferAmount. - * Iterates from first feeOrder to last. Sort the feeOrders by ascending rate in order to get the subset of - * feeOrders that will cost the least ETH. - * @param orders An array of objects that extend the Order interface. All orders should specify ZRX as - * the makerAsset and WETH as the takerAsset. - * @param feeOrders An array of objects that extend the Order interface. All orders should specify ZRX as - * the makerAsset and WETH as the takerAsset. - * @param opts Optional arguments this function accepts. - * @return Resulting orders and remaining fee amount that could not be covered by the input. - */ - findFeeOrdersThatCoverFeesForTargetOrders( - orders: T[], - feeOrders: T[], - opts?: FindFeeOrdersThatCoverFeesForTargetOrdersOpts, - ): FeeOrdersAndRemainingFeeAmount { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - assert.doesConformToSchema('feeOrders', feeOrders, schemas.ordersSchema); - // try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from orders - const remainingFillableMakerAssetAmounts = _.get( - opts, - 'remainingFillableMakerAssetAmounts', - _.map(orders, order => order.makerAssetAmount), - ) as BigNumber[]; - _.forEach(remainingFillableMakerAssetAmounts, (amount, index) => - assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount), - ); - assert.assert( - orders.length === remainingFillableMakerAssetAmounts.length, - 'Expected orders.length to equal opts.remainingFillableMakerAssetAmounts.length', - ); - // try to get remainingFillableFeeAmounts from opts, if it's not there, use makerAssetAmount values from feeOrders - const remainingFillableFeeAmounts = _.get( - opts, - 'remainingFillableFeeAmounts', - _.map(feeOrders, order => order.makerAssetAmount), - ) as BigNumber[]; - _.forEach(remainingFillableFeeAmounts, (amount, index) => - assert.isValidBaseUnitAmount(`remainingFillableFeeAmounts[${index}]`, amount), - ); - assert.assert( - feeOrders.length === remainingFillableFeeAmounts.length, - 'Expected feeOrders.length to equal opts.remainingFillableFeeAmounts.length', - ); - // try to get slippageBufferAmount from opts, if it's not there, default to 0 - const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber; - assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount); - // calculate total amount of ZRX needed to fill orders - const totalFeeAmount = _.reduce( - orders, - (accFees, order, index) => { - const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index]; - const feeToFillMakerAssetAmountAvailable = makerAssetAmountAvailable - .multipliedBy(order.takerFee) - .dividedToIntegerBy(order.makerAssetAmount); - return accFees.plus(feeToFillMakerAssetAmountAvailable); - }, - constants.ZERO_AMOUNT, - ); - const { - resultOrders, - remainingFillAmount, - ordersRemainingFillableMakerAssetAmounts, - } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(feeOrders, totalFeeAmount, { - remainingFillableMakerAssetAmounts: remainingFillableFeeAmounts, - slippageBufferAmount, - }); - return { - resultFeeOrders: resultOrders, - remainingFeeAmount: remainingFillAmount, - feeOrdersRemainingFillableMakerAssetAmounts: ordersRemainingFillableMakerAssetAmounts, - }; - // TODO: add more orders here to cover rounding - // https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarding-contract-specification.md#over-buying-zrx - }, -}; - -function findOrdersThatCoverAssetFillAmount( - orders: T[], - assetFillAmount: BigNumber, - operation: MarketOperation, - opts?: FindOrdersThatCoverTakerAssetFillAmountOpts | FindOrdersThatCoverMakerAssetFillAmountOpts, -): OrdersAndRemainingTakerFillAmount | OrdersAndRemainingMakerFillAmount { - const variablePrefix = operation === MarketOperation.Buy ? 'Maker' : 'Taker'; - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - assert.isValidBaseUnitAmount('assetFillAmount', assetFillAmount); - // try to get remainingFillableTakerAssetAmounts from opts, if it's not there, use takerAssetAmount values from orders - const remainingFillableAssetAmounts = _.get( - opts, - `remainingFillable${variablePrefix}AssetAmounts`, - _.map(orders, order => (operation === MarketOperation.Buy ? order.makerAssetAmount : order.takerAssetAmount)), - ) as BigNumber[]; - _.forEach(remainingFillableAssetAmounts, (amount, index) => - assert.isValidBaseUnitAmount(`remainingFillable${variablePrefix}AssetAmount[${index}]`, amount), - ); - assert.assert( - orders.length === remainingFillableAssetAmounts.length, - `Expected orders.length to equal opts.remainingFillable${variablePrefix}AssetAmounts.length`, - ); - // try to get slippageBufferAmount from opts, if it's not there, default to 0 - const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber; - assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount); - // calculate total amount of asset needed to be filled - const totalFillAmount = assetFillAmount.plus(slippageBufferAmount); - // iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount - const result = _.reduce( - orders, - ({ resultOrders, remainingFillAmount, ordersRemainingFillableAssetAmounts }, order, index) => { - if (remainingFillAmount.isLessThanOrEqualTo(constants.ZERO_AMOUNT)) { - return { - resultOrders, - remainingFillAmount: constants.ZERO_AMOUNT, - ordersRemainingFillableAssetAmounts, - }; - } else { - const assetAmountAvailable = remainingFillableAssetAmounts[index]; - const shouldIncludeOrder = assetAmountAvailable.gt(constants.ZERO_AMOUNT); - // if there is no assetAmountAvailable do not append order to resultOrders - // if we have exceeded the total amount we want to fill set remainingFillAmount to 0 - return { - resultOrders: shouldIncludeOrder ? _.concat(resultOrders, order) : resultOrders, - ordersRemainingFillableAssetAmounts: shouldIncludeOrder - ? _.concat(ordersRemainingFillableAssetAmounts, assetAmountAvailable) - : ordersRemainingFillableAssetAmounts, - remainingFillAmount: BigNumber.max( - constants.ZERO_AMOUNT, - remainingFillAmount.minus(assetAmountAvailable), - ), - }; - } - }, - { - resultOrders: [] as T[], - remainingFillAmount: totalFillAmount, - ordersRemainingFillableAssetAmounts: [] as BigNumber[], - }, - ); - - const { - ordersRemainingFillableAssetAmounts: resultOrdersRemainingFillableAssetAmounts, - // tslint:disable-next-line: trailing-comma - ...ordersAndRemainingFillAmount - } = result; - - if (operation === MarketOperation.Buy) { - return { - ...ordersAndRemainingFillAmount, - ordersRemainingFillableMakerAssetAmounts: resultOrdersRemainingFillableAssetAmounts, - }; - } else { - return { - ...ordersAndRemainingFillAmount, - ordersRemainingFillableTakerAssetAmounts: resultOrdersRemainingFillableAssetAmounts, - }; - } -} diff --git a/packages/order-utils/src/order_calculation_utils.ts b/packages/order-utils/src/order_calculation_utils.ts deleted file mode 100644 index d6818830f7..0000000000 --- a/packages/order-utils/src/order_calculation_utils.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { constants } from './constants'; - -export const orderCalculationUtils = { - /** - * Determines if the order is expired given the current time - * @param order The order for expiry calculation - */ - isOrderExpired(order: Order): boolean { - return orderCalculationUtils.willOrderExpire(order, 0); - }, - /** - * Calculates if the order will expire in the future. - * @param order The order for expiry calculation - * @param secondsFromNow The amount of seconds from current time - */ - willOrderExpire(order: Order, secondsFromNow: number): boolean { - const millisecondsInSecond = 1000; - const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).integerValue(); - return order.expirationTimeSeconds.isLessThan(currentUnixTimestampSec.plus(secondsFromNow)); - }, - /** - * Determines if the order is open and fillable by any taker. - * @param order The order - */ - isOpenOrder(order: Order): boolean { - return order.takerAddress === constants.NULL_ADDRESS; - }, - /** - * Given an amount of taker asset, calculate the the amount of maker asset - * @param order The order - * @param makerFillAmount the amount of taker asset - */ - getMakerFillAmount(order: Order, takerFillAmount: BigNumber): BigNumber { - // Round down because exchange rate favors Maker - const makerFillAmount = takerFillAmount - .multipliedBy(order.makerAssetAmount) - .div(order.takerAssetAmount) - .integerValue(BigNumber.ROUND_FLOOR); - return makerFillAmount; - }, - /** - * Given an amount of maker asset, calculate the equivalent amount in taker asset - * @param order The order - * @param makerFillAmount the amount of maker asset - */ - getTakerFillAmount(order: Order, makerFillAmount: BigNumber): BigNumber { - // Round up because exchange rate favors Maker - const takerFillAmount = makerFillAmount - .multipliedBy(order.takerAssetAmount) - .div(order.makerAssetAmount) - .integerValue(BigNumber.ROUND_CEIL); - return takerFillAmount; - }, - /** - * Given an amount of taker asset, calculate the fee amount required for the taker - * @param order The order - * @param takerFillAmount the amount of taker asset - */ - getTakerFeeAmount(order: Order, takerFillAmount: BigNumber): BigNumber { - // Round down because Taker fee rate favors Taker - const takerFeeAmount = takerFillAmount - .multipliedBy(order.takerFee) - .div(order.takerAssetAmount) - .integerValue(BigNumber.ROUND_FLOOR); - return takerFeeAmount; - }, - /** - * Given an amount of maker asset, calculate the fee amount required for the maker - * @param order The order - * @param makerFillAmount the amount of maker asset - */ - getMakerFeeAmount(order: Order, makerFillAmount: BigNumber): BigNumber { - // Round down because Maker fee rate favors Maker - const makerFeeAmount = makerFillAmount - .multipliedBy(order.makerFee) - .div(order.makerAssetAmount) - .integerValue(BigNumber.ROUND_FLOOR); - return makerFeeAmount; - }, - /** - * Given a desired amount of ZRX from a fee order, calculate the amount of taker asset required to fill. - * Also calculate how much ZRX needs to be purchased in order to fill the desired amount plus the taker fee amount - * @param order The order - * @param makerFillAmount the amount of maker asset - */ - getTakerFillAmountForFeeOrder(order: Order, makerFillAmount: BigNumber): [BigNumber, BigNumber] { - // For each unit of TakerAsset we buy (MakerAsset - TakerFee) - const adjustedTakerFillAmount = makerFillAmount - .multipliedBy(order.takerAssetAmount) - .div(order.makerAssetAmount.minus(order.takerFee)) - .integerValue(BigNumber.ROUND_CEIL); - // The amount that we buy will be greater than makerFillAmount, since we buy some amount for fees. - const adjustedMakerFillAmount = orderCalculationUtils.getMakerFillAmount(order, adjustedTakerFillAmount); - return [adjustedTakerFillAmount, adjustedMakerFillAmount]; - }, -}; diff --git a/packages/order-utils/src/order_factory.ts b/packages/order-utils/src/order_factory.ts deleted file mode 100644 index dee7d79316..0000000000 --- a/packages/order-utils/src/order_factory.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Order, SignedOrder } from '@0x/types'; -import { BigNumber, providerUtils } from '@0x/utils'; -import { SupportedProvider } from 'ethereum-types'; - -import { constants } from './constants'; -import { orderHashUtils } from './order_hash_utils'; -import { generatePseudoRandomSalt } from './salt'; -import { signatureUtils } from './signature_utils'; -import { CreateOrderOpts } from './types'; - -export const orderFactory = { - createOrderFromPartial(partialOrder: Partial): Order { - const chainId: number = getChainIdFromPartial(partialOrder); - const defaultOrder = generateEmptyOrder(chainId); - return { - ...defaultOrder, - ...partialOrder, - }; - }, - createSignedOrderFromPartial(partialSignedOrder: Partial): SignedOrder { - const chainId: number = getChainIdFromPartial(partialSignedOrder); - const defaultOrder = generateEmptySignedOrder(chainId); - return { - ...defaultOrder, - ...partialSignedOrder, - }; - }, - createOrder( - makerAddress: string, - makerAssetAmount: BigNumber, - makerAssetData: string, - takerAssetAmount: BigNumber, - takerAssetData: string, - exchangeAddress: string, - chainId: number, - createOrderOpts: CreateOrderOpts = generateDefaultCreateOrderOpts(), - ): Order { - const defaultCreateOrderOpts = generateDefaultCreateOrderOpts(); - const order = { - makerAddress, - makerAssetAmount, - takerAssetAmount, - makerAssetData, - takerAssetData, - makerFeeAssetData: createOrderOpts.makerFeeAssetData || makerAssetData, - takerFeeAssetData: createOrderOpts.takerFeeAssetData || takerAssetData, - takerAddress: createOrderOpts.takerAddress || defaultCreateOrderOpts.takerAddress, - senderAddress: createOrderOpts.senderAddress || defaultCreateOrderOpts.senderAddress, - makerFee: createOrderOpts.makerFee || defaultCreateOrderOpts.makerFee, - takerFee: createOrderOpts.takerFee || defaultCreateOrderOpts.takerFee, - feeRecipientAddress: createOrderOpts.feeRecipientAddress || defaultCreateOrderOpts.feeRecipientAddress, - salt: createOrderOpts.salt || defaultCreateOrderOpts.salt, - expirationTimeSeconds: - createOrderOpts.expirationTimeSeconds || defaultCreateOrderOpts.expirationTimeSeconds, - exchangeAddress, - chainId, - }; - return order; - }, - async createSignedOrderAsync( - supportedProvider: SupportedProvider, - makerAddress: string, - makerAssetAmount: BigNumber, - makerAssetData: string, - takerAssetAmount: BigNumber, - takerAssetData: string, - exchangeAddress: string, - createOrderOpts?: CreateOrderOpts, - ): Promise { - const order = orderFactory.createOrder( - makerAddress, - makerAssetAmount, - makerAssetData, - takerAssetAmount, - takerAssetData, - exchangeAddress, - await providerUtils.getChainIdAsync(supportedProvider), - createOrderOpts, - ); - const orderHash = orderHashUtils.getOrderHash(order); - const signature = await signatureUtils.ecSignHashAsync(supportedProvider, orderHash, makerAddress); - const signedOrder: SignedOrder = { ...order, signature }; - return signedOrder; - }, -}; - -function getChainIdFromPartial(partialOrder: Partial | Partial): number { - const chainId = partialOrder.chainId; - if (chainId === undefined || !Number.isInteger(chainId)) { - throw new Error('chainId must be valid'); - } - return chainId; -} - -function generateEmptySignedOrder(chainId: number): SignedOrder { - return { - ...generateEmptyOrder(chainId), - signature: constants.NULL_BYTES, - }; -} - -function generateEmptyOrder(chainId: number): Order { - return { - senderAddress: constants.NULL_ADDRESS, - makerAddress: constants.NULL_ADDRESS, - takerAddress: constants.NULL_ADDRESS, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - makerAssetAmount: constants.ZERO_AMOUNT, - takerAssetAmount: constants.ZERO_AMOUNT, - makerAssetData: constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - makerFeeAssetData: constants.NULL_BYTES, - takerFeeAssetData: constants.NULL_BYTES, - salt: generatePseudoRandomSalt(), - feeRecipientAddress: constants.NULL_ADDRESS, - expirationTimeSeconds: constants.INFINITE_TIMESTAMP_SEC, - exchangeAddress: constants.NULL_ADDRESS, - chainId, - }; -} - -function generateDefaultCreateOrderOpts(): { - takerAddress: string; - senderAddress: string; - makerFee: BigNumber; - takerFee: BigNumber; - feeRecipientAddress: string; - salt: BigNumber; - expirationTimeSeconds: BigNumber; -} { - return { - takerAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - makerFee: constants.ZERO_AMOUNT, - takerFee: constants.ZERO_AMOUNT, - feeRecipientAddress: constants.NULL_ADDRESS, - salt: generatePseudoRandomSalt(), - expirationTimeSeconds: constants.INFINITE_TIMESTAMP_SEC, - }; -} diff --git a/packages/order-utils/src/order_hash_utils.ts b/packages/order-utils/src/order_hash_utils.ts deleted file mode 100644 index 89d4682729..0000000000 --- a/packages/order-utils/src/order_hash_utils.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Order } from '@0x/types'; -import { hexUtils, signTypedDataUtils } from '@0x/utils'; - -import { eip712Utils } from './eip712_utils'; - -export const orderHashUtils = { - getOrderHash: (order: Order): string => { - return hexUtils.toHex(signTypedDataUtils.generateTypedDataHash(eip712Utils.createOrderTypedData(order))); - }, -}; diff --git a/packages/order-utils/src/rate_utils.ts b/packages/order-utils/src/rate_utils.ts deleted file mode 100644 index dacdbd5a29..0000000000 --- a/packages/order-utils/src/rate_utils.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { schemas } from '@0x/json-schemas'; -import { Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { assert } from './assert'; -import { constants } from './constants'; - -export const rateUtils = { - /** - * Takes an order and calculates the fee adjusted rate (takerAsset/makerAsset) by calculating how much takerAsset - * is required to cover the fees (feeRate * takerFee), adding the takerAssetAmount and dividing by makerAssetAmount - * @param order An object that conforms to the order interface - * @param feeRate The market rate of ZRX denominated in takerAssetAmount - * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) - * Defaults to 0 - * @return The rate (takerAsset/makerAsset) of the order adjusted for fees - */ - getFeeAdjustedRateOfOrder(order: Order, feeRate: BigNumber = constants.ZERO_AMOUNT): BigNumber { - assert.doesConformToSchema('order', order, schemas.orderSchema); - assert.isBigNumber('feeRate', feeRate); - assert.assert( - feeRate.gte(constants.ZERO_AMOUNT), - `Expected feeRate: ${feeRate} to be greater than or equal to 0`, - ); - const takerAssetAmountNeededToPayForFees = order.takerFee.multipliedBy(feeRate); - const totalTakerAssetAmount = takerAssetAmountNeededToPayForFees.plus(order.takerAssetAmount); - const rate = totalTakerAssetAmount.div(order.makerAssetAmount); - return rate; - }, - /** - * Takes a fee order (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) and calculates - * the fee adjusted rate (WETH/ZRX) by dividing the takerAssetAmount by the makerAmount minus the takerFee - * @param feeOrder An object that conforms to the order interface - * @return The rate (WETH/ZRX) of the fee order adjusted for fees - */ - getFeeAdjustedRateOfFeeOrder(feeOrder: Order): BigNumber { - assert.doesConformToSchema('feeOrder', feeOrder, schemas.orderSchema); - const zrxAmountAfterFees = feeOrder.makerAssetAmount.minus(feeOrder.takerFee); - assert.assert( - zrxAmountAfterFees.isGreaterThan(constants.ZERO_AMOUNT), - `Expected takerFee: ${JSON.stringify(feeOrder.takerFee)} to be less than makerAssetAmount: ${JSON.stringify( - feeOrder.makerAssetAmount, - )}`, - ); - const rate = feeOrder.takerAssetAmount.div(zrxAmountAfterFees); - return rate; - }, -}; diff --git a/packages/order-utils/src/remaining_fillable_calculator.ts b/packages/order-utils/src/remaining_fillable_calculator.ts deleted file mode 100644 index 6a18c51afd..0000000000 --- a/packages/order-utils/src/remaining_fillable_calculator.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export class RemainingFillableCalculator { - private readonly _isPercentageFee: boolean; - // Transferrable Amount is the minimum of Approval and Balance - private readonly _transferrableAssetAmount: BigNumber; - private readonly _transferrableFeeAmount: BigNumber; - private readonly _remainingOrderAssetAmount: BigNumber; - private readonly _remainingOrderFeeAmount: BigNumber; - private readonly _orderFee: BigNumber; - private readonly _orderAssetAmount: BigNumber; - constructor( - orderFee: BigNumber, - orderAssetAmount: BigNumber, - isPercentageFee: boolean, - transferrableAssetAmount: BigNumber, - transferrableFeeAmount: BigNumber, - remainingOrderAssetAmount: BigNumber, - ) { - this._orderFee = orderFee; - this._orderAssetAmount = orderAssetAmount; - this._isPercentageFee = isPercentageFee; - this._transferrableAssetAmount = transferrableAssetAmount; - this._transferrableFeeAmount = transferrableFeeAmount; - this._remainingOrderAssetAmount = remainingOrderAssetAmount; - this._remainingOrderFeeAmount = orderAssetAmount.eq(0) - ? new BigNumber(0) - : remainingOrderAssetAmount.times(orderFee).dividedToIntegerBy(orderAssetAmount); - } - public computeRemainingFillable(): BigNumber { - if (this._hasSufficientFundsForFeeAndTransferAmount()) { - return this._remainingOrderAssetAmount; - } - if (this._orderFee.isZero()) { - return BigNumber.min(this._remainingOrderAssetAmount, this._transferrableAssetAmount); - } - return this._calculatePartiallyFillableAssetAmount(); - } - private _hasSufficientFundsForFeeAndTransferAmount(): boolean { - if (this._isPercentageFee) { - const totalTransferAmountRequired = this._remainingOrderAssetAmount.plus(this._remainingOrderFeeAmount); - const hasSufficientFunds = this._transferrableAssetAmount.isGreaterThanOrEqualTo( - totalTransferAmountRequired, - ); - return hasSufficientFunds; - } else { - const hasSufficientFundsForTransferAmount = this._transferrableAssetAmount.isGreaterThanOrEqualTo( - this._remainingOrderAssetAmount, - ); - const hasSufficientFundsForFeeAmount = this._transferrableFeeAmount.isGreaterThanOrEqualTo( - this._remainingOrderFeeAmount, - ); - const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount; - return hasSufficientFunds; - } - } - private _calculatePartiallyFillableAssetAmount(): BigNumber { - // Given an order for 200 wei for 2 Fee wei fee, find 100 wei for 1 Fee wei. Order ratio is then 100:1 - const orderToFeeRatio = this._orderAssetAmount.dividedBy(this._orderFee); - // The number of times the trader (maker or taker) can fill the order, if each fill only required the transfer of a single - // baseUnit of fee tokens. - // Given 2 Fee wei, the maximum amount of times trader can fill this order, in terms of fees, is 2 - const fillableTimesInFeeBaseUnits = BigNumber.min(this._transferrableFeeAmount, this._remainingOrderFeeAmount); - // The number of times the trader can fill the order, given the traders asset Balance - // Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, trader can fill this order 1 time. - let fillableTimesInAssetUnits = this._transferrableAssetAmount.dividedBy(orderToFeeRatio); - if (this._isPercentageFee) { - // If Fee is the trader asset, the Fee and the trader fill amount need to be removed from the same pool; - // 200 Fee wei for 2Fee wei fee can only be filled once (need 202 Fee wei) - const totalAssetPooled = this._transferrableAssetAmount; - // The purchasing power here is less as the tokens are taken from the same Pool - // For every one number of fills, we have to take an extra Fee out of the pool - fillableTimesInAssetUnits = totalAssetPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1))); - } - // When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored. - // This can result in a RoundingError being thrown by the Exchange Contract. - const partiallyFillableAssetAmount = fillableTimesInAssetUnits - .times(this._orderAssetAmount) - .dividedToIntegerBy(this._orderFee); - const partiallyFillableFeeAmount = fillableTimesInFeeBaseUnits - .times(this._orderAssetAmount) - .dividedToIntegerBy(this._orderFee); - const partiallyFillableAmount = BigNumber.min(partiallyFillableAssetAmount, partiallyFillableFeeAmount); - return partiallyFillableAmount; - } -} diff --git a/packages/order-utils/src/salt.ts b/packages/order-utils/src/salt.ts deleted file mode 100644 index a7cc4aea05..0000000000 --- a/packages/order-utils/src/salt.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { BigNumber, generatePseudoRandom256BitNumber } from '@0x/utils'; - -/** - * Generates a pseudo-random 256-bit salt. - * The salt can be included in a 0x order, ensuring that the order generates a unique orderHash - * and will not collide with other outstanding orders that are identical in all other parameters. - * @return A pseudo-random 256-bit number that can be used as a salt. - */ -export function generatePseudoRandomSalt(): BigNumber { - const salt = generatePseudoRandom256BitNumber(); - return salt; -} diff --git a/packages/order-utils/src/schemas/validate_order_fillable_opts_schema.ts b/packages/order-utils/src/schemas/validate_order_fillable_opts_schema.ts deleted file mode 100644 index 2e111af04c..0000000000 --- a/packages/order-utils/src/schemas/validate_order_fillable_opts_schema.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const validateOrderFillableOptsSchema = { - id: '/ValidateOrderFillableOpts', - properties: { - expectedFillTakerTokenAmount: { $ref: '/wholeNumberSchema' }, - }, - type: 'object', -}; diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts deleted file mode 100644 index 993030a44b..0000000000 --- a/packages/order-utils/src/signature_utils.ts +++ /dev/null @@ -1,456 +0,0 @@ -import { schemas } from '@0x/json-schemas'; -import { - ECSignature, - ExchangeProxyMetaTransaction, - Order, - SignatureType, - SignedExchangeProxyMetaTransaction, - SignedOrder, - SignedZeroExTransaction, - ValidatorSignature, - ZeroExTransaction, -} from '@0x/types'; -import { hexUtils, providerUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { SupportedProvider } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { assert } from './assert'; -import { eip712Utils } from './eip712_utils'; -import { getExchangeProxyMetaTransactionHash } from './hash_utils'; -import { orderHashUtils } from './order_hash_utils'; -import { transactionHashUtils } from './transaction_hash_utils'; -import { TypedDataError } from './types'; - -export const signatureUtils = { - /** - * Signs an order and returns a SignedOrder. First `eth_signTypedData` is requested - * then a fallback to `eth_sign` if not available on the supplied provider. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param order The Order to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address - * must be available via the supplied Provider. - * @return A SignedOrder containing the order and Elliptic curve signature with Signature Type. - */ - async ecSignOrderAsync( - supportedProvider: SupportedProvider, - order: Order, - signerAddress: string, - ): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema, [schemas.hexSchema]); - try { - const signedOrder = await signatureUtils.ecSignTypedDataOrderAsync(supportedProvider, order, signerAddress); - return signedOrder; - } catch (err) { - // HACK: We are unable to handle specific errors thrown since provider is not an object - // under our control. It could be Metamask Web3, Ethers, or any general RPC provider. - // We check for a user denying the signature request in a way that supports Metamask and - // Coinbase Wallet. Unfortunately for signers with a different error message, - // they will receive two signature requests. - if (err.message.includes('User denied message signature')) { - throw err; - } - const orderHash = orderHashUtils.getOrderHash(order); - const signatureHex = await signatureUtils.ecSignHashAsync(supportedProvider, orderHash, signerAddress); - const signedOrder = { - ...order, - signature: signatureHex, - }; - return signedOrder; - } - }, - /** - * Signs an order using `eth_signTypedData` and returns a SignedOrder. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param order The Order to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address - * must be available via the supplied Provider. - * @return A SignedOrder containing the order and Elliptic curve signature with Signature Type. - */ - async ecSignTypedDataOrderAsync( - supportedProvider: SupportedProvider, - order: Order, - signerAddress: string, - ): Promise { - const provider = providerUtils.standardizeOrThrow(supportedProvider); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.doesConformToSchema('order', order, schemas.orderSchema, [schemas.hexSchema]); - const web3Wrapper = new Web3Wrapper(provider); - await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); - const normalizedSignerAddress = signerAddress.toLowerCase(); - const typedData = eip712Utils.createOrderTypedData(order); - try { - const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData); - const ecSignatureRSV = parseSignatureHexAsRSV(signature); - const signatureBuffer = Buffer.concat([ - ethUtil.toBuffer(ecSignatureRSV.v), - ethUtil.toBuffer(ecSignatureRSV.r), - ethUtil.toBuffer(ecSignatureRSV.s), - ethUtil.toBuffer(SignatureType.EIP712), - ]); - const signatureHex = `0x${signatureBuffer.toString('hex')}`; - return { - ...order, - signature: signatureHex, - }; - } catch (err) { - // Detect if Metamask to transition users to the MetamaskSubprovider - if ((provider as any).isMetaMask) { - throw new Error(TypedDataError.InvalidMetamaskSigner); - } else { - throw err; - } - } - }, - /** - * Signs a transaction and returns a SignedZeroExTransaction. First `eth_signTypedData` is requested - * then a fallback to `eth_sign` if not available on the supplied provider. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param transaction The ZeroExTransaction to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address - * must be available via the supplied Provider. - * @return A SignedTransaction containing the order and Elliptic curve signature with Signature Type. - */ - async ecSignTransactionAsync( - supportedProvider: SupportedProvider, - transaction: ZeroExTransaction, - signerAddress: string, - ): Promise { - assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]); - try { - const signedTransaction = await signatureUtils.ecSignTypedDataTransactionAsync( - supportedProvider, - transaction, - signerAddress, - ); - return signedTransaction; - } catch (err) { - // HACK: We are unable to handle specific errors thrown since provider is not an object - // under our control. It could be Metamask Web3, Ethers, or any general RPC provider. - // We check for a user denying the signature request in a way that supports Metamask and - // Coinbase Wallet. Unfortunately for signers with a different error message, - // they will receive two signature requests. - if (err.message.includes('User denied message signature')) { - throw err; - } - const transactionHash = transactionHashUtils.getTransactionHash(transaction); - const signatureHex = await signatureUtils.ecSignHashAsync( - supportedProvider, - transactionHash, - signerAddress, - ); - const signedTransaction = { - ...transaction, - signature: signatureHex, - }; - return signedTransaction; - } - }, - /** - * Signs a ZeroExTransaction using `eth_signTypedData` and returns a SignedZeroExTransaction. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param transaction The ZeroEx Transaction to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address - * must be available via the supplied Provider. - * @return A SignedZeroExTransaction containing the ZeroExTransaction and Elliptic curve signature with Signature Type. - */ - async ecSignTypedDataTransactionAsync( - supportedProvider: SupportedProvider, - transaction: ZeroExTransaction, - signerAddress: string, - ): Promise { - const provider = providerUtils.standardizeOrThrow(supportedProvider); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]); - const web3Wrapper = new Web3Wrapper(provider); - await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); - const normalizedSignerAddress = signerAddress.toLowerCase(); - const typedData = eip712Utils.createZeroExTransactionTypedData(transaction); - try { - const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData); - const ecSignatureRSV = parseSignatureHexAsRSV(signature); - const signatureBuffer = Buffer.concat([ - ethUtil.toBuffer(ecSignatureRSV.v), - ethUtil.toBuffer(ecSignatureRSV.r), - ethUtil.toBuffer(ecSignatureRSV.s), - ethUtil.toBuffer(SignatureType.EIP712), - ]); - const signatureHex = `0x${signatureBuffer.toString('hex')}`; - return { - ...transaction, - signature: signatureHex, - }; - } catch (err) { - // Detect if Metamask to transition users to the MetamaskSubprovider - if ((provider as any).isMetaMask) { - throw new Error(TypedDataError.InvalidMetamaskSigner); - } else { - throw err; - } - } - }, - /** - * Signs an Exchange Proxy meta-transaction and returns a SignedExchangeProxyMetaTransaction. - * First `eth_signTypedData` is requested then a fallback to `eth_sign` if not - * available on the supplied provider. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param transaction The ExchangeProxyMetaTransaction to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address - * must be available via the supplied Provider. - * @return A SignedExchangeProxyMetaTransaction containing the order and - * elliptic curve signature with Signature Type. - */ - async ecSignExchangeProxyMetaTransactionAsync( - supportedProvider: SupportedProvider, - transaction: ExchangeProxyMetaTransaction, - signerAddress: string, - ): Promise { - assert.doesConformToSchema('transaction', transaction, schemas.exchangeProxyMetaTransactionSchema, [ - schemas.hexSchema, - ]); - try { - const signedTransaction = await signatureUtils.ecSignTypedDataExchangeProxyMetaTransactionAsync( - supportedProvider, - transaction, - signerAddress, - ); - return signedTransaction; - } catch (err) { - // HACK: We are unable to handle specific errors thrown since provider is not an object - // under our control. It could be Metamask Web3, Ethers, or any general RPC provider. - // We check for a user denying the signature request in a way that supports Metamask and - // Coinbase Wallet. Unfortunately for signers with a different error message, - // they will receive two signature requests. - if (err.message.includes('User denied message signature')) { - throw err; - } - const transactionHash = getExchangeProxyMetaTransactionHash(transaction); - const signatureHex = await signatureUtils.ecSignHashAsync( - supportedProvider, - transactionHash, - signerAddress, - ); - const signedTransaction = { - ...transaction, - signature: signatureHex, - }; - return signedTransaction; - } - }, - /** - * Signs an Exchange Proxy meta-transaction using `eth_signTypedData` and - * returns a SignedZeroExTransaction. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param transaction The Exchange Proxy transaction to sign. - * @param signerAddress The hex encoded Ethereum address you wish - * to sign it with. This address must be available via the supplied Provider. - * @return A SignedExchangeProxyMetaTransaction containing the - * ExchangeProxyMetaTransaction and elliptic curve signature with Signature Type. - */ - async ecSignTypedDataExchangeProxyMetaTransactionAsync( - supportedProvider: SupportedProvider, - transaction: ExchangeProxyMetaTransaction, - signerAddress: string, - ): Promise { - const provider = providerUtils.standardizeOrThrow(supportedProvider); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.doesConformToSchema('transaction', transaction, schemas.exchangeProxyMetaTransactionSchema, [ - schemas.hexSchema, - ]); - const web3Wrapper = new Web3Wrapper(provider); - await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); - const normalizedSignerAddress = signerAddress.toLowerCase(); - const typedData = eip712Utils.createExchangeProxyMetaTransactionTypedData(transaction); - try { - const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData); - const ecSignatureRSV = parseSignatureHexAsRSV(signature); - const signatureHex = hexUtils.concat( - ecSignatureRSV.v, - ecSignatureRSV.r, - ecSignatureRSV.s, - SignatureType.EIP712, - ); - return { - ...transaction, - signature: signatureHex, - }; - } catch (err) { - // Detect if Metamask to transition users to the MetamaskSubprovider - if ((provider as any).isMetaMask) { - throw new Error(TypedDataError.InvalidMetamaskSigner); - } else { - throw err; - } - } - }, - /** - * Signs a hash using `eth_sign` and returns its elliptic curve signature and signature type. - * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param msgHash Hex encoded message to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address - * must be available via the supplied Provider. - * @return A hex encoded string containing the Elliptic curve signature generated by signing the msgHash and the Signature Type. - */ - async ecSignHashAsync( - supportedProvider: SupportedProvider, - msgHash: string, - signerAddress: string, - ): Promise { - const provider = providerUtils.standardizeOrThrow(supportedProvider); - assert.isHexString('msgHash', msgHash); - assert.isETHAddressHex('signerAddress', signerAddress); - const web3Wrapper = new Web3Wrapper(provider); - await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); - const normalizedSignerAddress = signerAddress.toLowerCase(); - const signature = await web3Wrapper.signMessageAsync(normalizedSignerAddress, msgHash); - const prefixedMsgHashHex = signatureUtils.addSignedMessagePrefix(msgHash); - - // HACK: There is no consensus on whether the signatureHex string should be formatted as - // v + r + s OR r + s + v, and different clients (even different versions of the same client) - // return the signature params in different orders. In order to support all client implementations, - // we parse the signature in both ways, and evaluate if either one is a valid signature. - // r + s + v is the most prevalent format from eth_sign, so we attempt this first. - // tslint:disable-next-line:custom-no-magic-numbers - const validVParamValues = [27, 28]; - const ecSignatureRSV = parseSignatureHexAsRSV(signature); - if (_.includes(validVParamValues, ecSignatureRSV.v)) { - const isValidRSVSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureRSV, normalizedSignerAddress); - if (isValidRSVSignature) { - const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(ecSignatureRSV); - return convertedSignatureHex; - } - } - const ecSignatureVRS = parseSignatureHexAsVRS(signature); - if (_.includes(validVParamValues, ecSignatureVRS.v)) { - const isValidVRSSignature = isValidECSignature(prefixedMsgHashHex, ecSignatureVRS, normalizedSignerAddress); - if (isValidVRSSignature) { - const convertedSignatureHex = signatureUtils.convertECSignatureToSignatureHex(ecSignatureVRS); - return convertedSignatureHex; - } - } - // Detect if Metamask to transition users to the MetamaskSubprovider - if ((provider as any).isMetaMask) { - throw new Error(TypedDataError.InvalidMetamaskSigner); - } else { - throw new Error(TypedDataError.InvalidSignature); - } - }, - /** - * Combines ECSignature with V,R,S and the EthSign signature type for use in 0x protocol - * @param ecSignature The ECSignature of the signed data - * @return Hex encoded string of signature (v,r,s) with Signature Type - */ - convertECSignatureToSignatureHex(ecSignature: ECSignature): string { - const signatureHex = hexUtils.concat(ecSignature.v, ecSignature.r, ecSignature.s); - const signatureWithType = signatureUtils.convertToSignatureWithType(signatureHex, SignatureType.EthSign); - return signatureWithType; - }, - /** - * Combines the signature proof and the Signature Type. - * @param signature The hex encoded signature proof - * @param signatureType The signature type, i.e EthSign, Wallet etc. - * @return Hex encoded string of signature proof with Signature Type - */ - convertToSignatureWithType(signature: string, signatureType: SignatureType): string { - const signatureBuffer = Buffer.concat([ethUtil.toBuffer(signature), ethUtil.toBuffer(signatureType)]); - const signatureHex = `0x${signatureBuffer.toString('hex')}`; - return signatureHex; - }, - /** - * Adds the relevant prefix to the message being signed. - * @param message Message to sign - * @return Prefixed message - */ - addSignedMessagePrefix(message: string): string { - assert.isString('message', message); - const msgBuff = ethUtil.toBuffer(message); - const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff); - const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); - return prefixedMsgHex; - }, - /** - * Parse a hex-encoded Validator signature into validator address and signature components - * @param signature A hex encoded Validator 0x Protocol signature - * @return A ValidatorSignature with validatorAddress and signature parameters - */ - parseValidatorSignature(signature: string): ValidatorSignature { - assert.isOneOfExpectedSignatureTypes(signature, [SignatureType.Validator]); - // tslint:disable:custom-no-magic-numbers - const validatorSignature = { - validatorAddress: `0x${signature.slice(-42, -2)}`, - signature: signature.slice(0, -42), - }; - // tslint:enable:custom-no-magic-numbers - return validatorSignature; - }, -}; - -/** - * Parses a signature hex string, which is assumed to be in the VRS format. - */ -export function parseSignatureHexAsVRS(signatureHex: string): ECSignature { - const signatureBuffer = ethUtil.toBuffer(signatureHex); - let v = signatureBuffer[0]; - // HACK: Sometimes v is returned as [0, 1] and sometimes as [27, 28] - // If it is returned as [0, 1], add 27 to both so it becomes [27, 28] - const lowestValidV = 27; - const isProperlyFormattedV = v >= lowestValidV; - if (!isProperlyFormattedV) { - v += lowestValidV; - } - // signatureBuffer contains vrs - const vEndIndex = 1; - const rsIndex = 33; - const r = signatureBuffer.slice(vEndIndex, rsIndex); - const sEndIndex = 65; - const s = signatureBuffer.slice(rsIndex, sEndIndex); - const ecSignature: ECSignature = { - v, - r: ethUtil.bufferToHex(r), - s: ethUtil.bufferToHex(s), - }; - return ecSignature; -} - -function parseSignatureHexAsRSV(signatureHex: string): ECSignature { - const { v, r, s } = ethUtil.fromRpcSig(signatureHex); - const ecSignature: ECSignature = { - v, - r: ethUtil.bufferToHex(r), - s: ethUtil.bufferToHex(s), - }; - return ecSignature; -} - -/** - * Checks if the supplied elliptic curve signature corresponds to signing `data` with - * the private key corresponding to `signerAddress` - * @param data The hex encoded data signed by the supplied signature. - * @param signature An object containing the elliptic curve signature parameters. - * @param signerAddress The hex encoded address that signed the data, producing the supplied signature. - * @return Whether the ECSignature is valid. - */ -export function isValidECSignature(data: string, signature: ECSignature, signerAddress: string): boolean { - assert.isHexString('data', data); - assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema); - assert.isETHAddressHex('signerAddress', signerAddress); - const normalizedSignerAddress = signerAddress.toLowerCase(); - - const msgHashBuff = ethUtil.toBuffer(data); - try { - const pubKey = ethUtil.ecrecover( - msgHashBuff, - signature.v, - ethUtil.toBuffer(signature.r), - ethUtil.toBuffer(signature.s), - ); - const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); - const normalizedRetrievedAddress = retrievedAddress.toLowerCase(); - return normalizedRetrievedAddress === normalizedSignerAddress; - } catch (err) { - return false; - } -} - -// tslint:disable:max-file-line-count diff --git a/packages/order-utils/src/sorting_utils.ts b/packages/order-utils/src/sorting_utils.ts deleted file mode 100644 index 1de24264f7..0000000000 --- a/packages/order-utils/src/sorting_utils.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { schemas } from '@0x/json-schemas'; -import { Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { assert } from './assert'; -import { constants } from './constants'; -import { rateUtils } from './rate_utils'; - -export const sortingUtils = { - /** - * Takes an array of orders and sorts them by takerAsset/makerAsset rate in ascending order (best rate first). - * Adjusts the rate of each order according to the feeRate and takerFee for that order. - * @param orders An array of objects that extend the Order interface. All orders should specify ZRX as - * the makerAsset and WETH as the takerAsset. - * @param feeRate The market rate of ZRX denominated in takerAssetAmount - * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) - * Defaults to 0 - * @return The input orders sorted by rate in ascending order - */ - sortOrdersByFeeAdjustedRate(orders: T[], feeRate: BigNumber = constants.ZERO_AMOUNT): T[] { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - assert.isBigNumber('feeRate', feeRate); - const rateCalculator = (order: Order) => rateUtils.getFeeAdjustedRateOfOrder(order, feeRate); - const sortedOrders = sortOrders(orders, rateCalculator); - return sortedOrders; - }, - /** - * Takes an array of fee orders (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) - * and sorts them by rate in ascending order (best rate first). Adjusts the rate according to the takerFee. - * @param feeOrders An array of objects that extend the Order interface. All orders should specify ZRX as - * the makerAsset and WETH as the takerAsset. - * @return The input orders sorted by rate in ascending order - */ - sortFeeOrdersByFeeAdjustedRate(feeOrders: T[]): T[] { - assert.doesConformToSchema('feeOrders', feeOrders, schemas.ordersSchema); - const rateCalculator = rateUtils.getFeeAdjustedRateOfFeeOrder.bind(rateUtils); - const sortedOrders = sortOrders(feeOrders, rateCalculator); - return sortedOrders; - }, -}; - -type RateCalculator = (order: Order) => BigNumber; - -// takes an array of orders, copies them, and sorts the copy based on the rate definition provided by rateCalculator -function sortOrders(orders: T[], rateCalculator: RateCalculator): T[] { - const copiedOrders = _.cloneDeep(orders); - copiedOrders.sort((firstOrder, secondOrder) => { - const firstOrderRate = rateCalculator(firstOrder); - const secondOrderRate = rateCalculator(secondOrder); - return firstOrderRate.comparedTo(secondOrderRate); - }); - return copiedOrders; -} diff --git a/packages/order-utils/src/transaction_hash_utils.ts b/packages/order-utils/src/transaction_hash_utils.ts deleted file mode 100644 index c5c73e8242..0000000000 --- a/packages/order-utils/src/transaction_hash_utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ZeroExTransaction } from '@0x/types'; -import { hexUtils, signTypedDataUtils } from '@0x/utils'; - -import { eip712Utils } from './eip712_utils'; - -export const transactionHashUtils = { - getTransactionHash: (tx: ZeroExTransaction): string => { - return hexUtils.toHex( - signTypedDataUtils.generateTypedDataHash(eip712Utils.createZeroExTransactionTypedData(tx)), - ); - }, -}; diff --git a/packages/order-utils/src/transformer_utils.ts b/packages/order-utils/src/transformer_utils.ts deleted file mode 100644 index 8891d3b58c..0000000000 --- a/packages/order-utils/src/transformer_utils.ts +++ /dev/null @@ -1,271 +0,0 @@ -import { Order } from '@0x/types'; -import { AbiEncoder, BigNumber } from '@0x/utils'; -import * as ethjs from 'ethereumjs-util'; - -import { constants } from './constants'; - -const { NULL_ADDRESS } = constants; - -const ORDER_ABI_COMPONENTS = [ - { name: 'makerAddress', type: 'address' }, - { name: 'takerAddress', type: 'address' }, - { name: 'feeRecipientAddress', type: 'address' }, - { name: 'senderAddress', type: 'address' }, - { name: 'makerAssetAmount', type: 'uint256' }, - { name: 'takerAssetAmount', type: 'uint256' }, - { name: 'makerFee', type: 'uint256' }, - { name: 'takerFee', type: 'uint256' }, - { name: 'expirationTimeSeconds', type: 'uint256' }, - { name: 'salt', type: 'uint256' }, - { name: 'makerAssetData', type: 'bytes' }, - { name: 'takerAssetData', type: 'bytes' }, - { name: 'makerFeeAssetData', type: 'bytes' }, - { name: 'takerFeeAssetData', type: 'bytes' }, -]; - -/** - * ABI encoder for `FillQuoteTransformer.TransformData` - */ -export const fillQuoteTransformerDataEncoder = AbiEncoder.create([ - { - name: 'data', - type: 'tuple', - components: [ - { name: 'side', type: 'uint8' }, - { name: 'sellToken', type: 'address' }, - { name: 'buyToken', type: 'address' }, - { - name: 'orders', - type: 'tuple[]', - components: ORDER_ABI_COMPONENTS, - }, - { name: 'signatures', type: 'bytes[]' }, - { name: 'maxOrderFillAmounts', type: 'uint256[]' }, - { name: 'fillAmount', type: 'uint256' }, - { name: 'refundReceiver', type: 'address' }, - { name: 'rfqtTakerAddress', type: 'address' }, - ], - }, -]); - -/** - * Market operation for `FillQuoteTransformerData`. - */ -export enum FillQuoteTransformerSide { - Sell, - Buy, -} - -/** - * `FillQuoteTransformer.TransformData` - */ -export interface FillQuoteTransformerData { - side: FillQuoteTransformerSide; - sellToken: string; - buyToken: string; - orders: Array>; - signatures: string[]; - maxOrderFillAmounts: BigNumber[]; - fillAmount: BigNumber; - refundReceiver: string; - rfqtTakerAddress: string; -} - -/** - * ABI-encode a `FillQuoteTransformer.TransformData` type. - */ -export function encodeFillQuoteTransformerData(data: FillQuoteTransformerData): string { - return fillQuoteTransformerDataEncoder.encode([data]); -} - -/** - * ABI-decode a `FillQuoteTransformer.TransformData` type. - */ -export function decodeFillQuoteTransformerData(encoded: string): FillQuoteTransformerData { - return fillQuoteTransformerDataEncoder.decode(encoded).data; -} - -/** - * ABI encoder for `WethTransformer.TransformData` - */ -export const wethTransformerDataEncoder = AbiEncoder.create([ - { - name: 'data', - type: 'tuple', - components: [ - { name: 'token', type: 'address' }, - { name: 'amount', type: 'uint256' }, - ], - }, -]); - -/** - * `WethTransformer.TransformData` - */ -export interface WethTransformerData { - token: string; - amount: BigNumber; -} - -/** - * ABI-encode a `WethTransformer.TransformData` type. - */ -export function encodeWethTransformerData(data: WethTransformerData): string { - return wethTransformerDataEncoder.encode([data]); -} - -/** - * ABI-decode a `WethTransformer.TransformData` type. - */ -export function decodeWethTransformerData(encoded: string): WethTransformerData { - return wethTransformerDataEncoder.decode(encoded).data; -} - -/** - * ABI encoder for `PayTakerTransformer.TransformData` - */ -export const payTakerTransformerDataEncoder = AbiEncoder.create([ - { - name: 'data', - type: 'tuple', - components: [ - { name: 'tokens', type: 'address[]' }, - { name: 'amounts', type: 'uint256[]' }, - ], - }, -]); - -/** - * `PayTakerTransformer.TransformData` - */ -export interface PayTakerTransformerData { - tokens: string[]; - amounts: BigNumber[]; -} - -/** - * ABI-encode a `PayTakerTransformer.TransformData` type. - */ -export function encodePayTakerTransformerData(data: PayTakerTransformerData): string { - return payTakerTransformerDataEncoder.encode([data]); -} - -/** - * ABI-decode a `PayTakerTransformer.TransformData` type. - */ -export function decodePayTakerTransformerData(encoded: string): PayTakerTransformerData { - return payTakerTransformerDataEncoder.decode(encoded).data; -} - -/** - * ABI encoder for `affiliateFeetransformer.TransformData` - */ -export const affiliateFeeTransformerDataEncoder = AbiEncoder.create({ - name: 'data', - type: 'tuple', - components: [ - { - name: 'fees', - type: 'tuple[]', - components: [ - { name: 'token', type: 'address' }, - { name: 'amount', type: 'uint256' }, - { name: 'recipient', type: 'address' }, - ], - }, - ], -}); - -/** - * `AffiliateFeeTransformer.TransformData` - */ -export interface AffiliateFeeTransformerData { - fees: Array<{ - token: string; - amount: BigNumber; - recipient: string; - }>; -} - -/** - * ABI-encode a `AffiliateFeeTransformer.TransformData` type. - */ -export function encodeAffiliateFeeTransformerData(data: AffiliateFeeTransformerData): string { - return affiliateFeeTransformerDataEncoder.encode(data); -} - -/** - * ABI-decode a `AffiliateFeeTransformer.TransformData` type. - */ -export function decodeAffiliateFeeTransformerData(encoded: string): AffiliateFeeTransformerData { - return affiliateFeeTransformerDataEncoder.decode(encoded); -} - -/** - * ABI encoder for `PositiveSlippageFeeTransformer.TransformData` - */ -export const positiveSlippageFeeTransformerDataEncoder = AbiEncoder.create({ - name: 'data', - type: 'tuple', - components: [ - { name: 'token', type: 'address' }, - { name: 'bestCaseAmount', type: 'uint256' }, - { name: 'recipient', type: 'address' }, - ], -}); - -/** - * `PositiveSlippageFeeTransformer.TransformData` - */ -export interface PositiveSlippageFeeTransformerData { - token: string; - bestCaseAmount: BigNumber; - recipient: string; -} - -/** - * ABI-encode a `PositiveSlippageFeeTransformer.TransformData` type. - */ -export function encodePositiveSlippageFeeTransformerData(data: PositiveSlippageFeeTransformerData): string { - return positiveSlippageFeeTransformerDataEncoder.encode(data); -} - -/** - * ABI-decode a `PositiveSlippageFeeTransformer.TransformData` type. - */ -export function decodePositiveSlippageFeeTransformerData(encoded: string): PositiveSlippageFeeTransformerData { - return positiveSlippageFeeTransformerDataEncoder.decode(encoded); -} - -/** - * Find the nonce for a transformer given its deployer. - * If `deployer` is the null address, zero will always be returned. - */ -export function findTransformerNonce( - transformer: string, - deployer: string = NULL_ADDRESS, - maxGuesses: number = 1024, -): number { - if (deployer === NULL_ADDRESS) { - return 0; - } - const lowercaseTransformer = transformer.toLowerCase(); - // Try to guess the nonce. - for (let nonce = 0; nonce < maxGuesses; ++nonce) { - const deployedAddress = getTransformerAddress(deployer, nonce); - if (deployedAddress === lowercaseTransformer) { - return nonce; - } - } - throw new Error(`${deployer} did not deploy ${transformer}!`); -} - -/** - * Compute the deployed address for a transformer given a deployer and nonce. - */ -export function getTransformerAddress(deployer: string, nonce: number): string { - return ethjs.bufferToHex( - // tslint:disable-next-line: custom-no-magic-numbers - ethjs.rlphash([deployer, nonce] as any).slice(12), - ); -} diff --git a/packages/order-utils/src/types.ts b/packages/order-utils/src/types.ts deleted file mode 100644 index 53380db4e7..0000000000 --- a/packages/order-utils/src/types.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export enum TypedDataError { - InvalidSignature = 'INVALID_SIGNATURE', - InvalidMetamaskSigner = "MetaMask provider must be wrapped in a MetamaskSubprovider (from the '@0x/subproviders' package) in order to work with this method.", -} - -export interface CreateOrderOpts { - takerAddress?: string; - senderAddress?: string; - makerFee?: BigNumber; - takerFee?: BigNumber; - feeRecipientAddress?: string; - salt?: BigNumber; - expirationTimeSeconds?: BigNumber; - makerFeeAssetData?: string; - takerFeeAssetData?: string; -} - -export interface ValidateOrderFillableOpts { - expectedFillTakerTokenAmount?: BigNumber; - validateRemainingOrderAmountIsFillable?: boolean; - simulationTakerAddress?: string; -} - -/** - * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. - * You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the orders param. - * slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills. - * Defaults to 0 - */ -export interface FindOrdersThatCoverMakerAssetFillAmountOpts { - remainingFillableMakerAssetAmounts?: BigNumber[]; - slippageBufferAmount?: BigNumber; -} - -/** - * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. - * You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the orders param. - * slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills. - * Defaults to 0 - */ -export interface FindOrdersThatCoverTakerAssetFillAmountOpts { - remainingFillableTakerAssetAmounts?: BigNumber[]; - slippageBufferAmount?: BigNumber; -} - -/** - * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. - * You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the orders param. - * remainingFillableFeeAmounts: An array of BigNumbers corresponding to the feeOrders parameter. - * You can use OrderStateUtils @0x/order-utils to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the feeOrders param. - * slippageBufferAmount: An additional amount of fee to be covered by the result in case of trade collisions or partial fills. - * Defaults to 0 - */ -export interface FindFeeOrdersThatCoverFeesForTargetOrdersOpts { - remainingFillableMakerAssetAmounts?: BigNumber[]; - remainingFillableFeeAmounts?: BigNumber[]; - slippageBufferAmount?: BigNumber; -} - -export interface FeeOrdersAndRemainingFeeAmount { - resultFeeOrders: T[]; - feeOrdersRemainingFillableMakerAssetAmounts: BigNumber[]; - remainingFeeAmount: BigNumber; -} - -export interface OrdersAndRemainingMakerFillAmount { - resultOrders: T[]; - ordersRemainingFillableMakerAssetAmounts: BigNumber[]; - remainingFillAmount: BigNumber; -} - -export interface OrdersAndRemainingTakerFillAmount { - resultOrders: T[]; - ordersRemainingFillableTakerAssetAmounts: BigNumber[]; - remainingFillAmount: BigNumber; -} diff --git a/packages/order-utils/src/utils.ts b/packages/order-utils/src/utils.ts deleted file mode 100644 index 64195dbedb..0000000000 --- a/packages/order-utils/src/utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export const utils = { - getSignatureTypeIndexIfExists(signature: string): number { - // tslint:disable-next-line:custom-no-magic-numbers - const signatureTypeHex = signature.slice(-2); - const base = 16; - const signatureTypeInt = parseInt(signatureTypeHex, base); - return signatureTypeInt; - }, - getCurrentUnixTimestampSec(): BigNumber { - const milisecondsInSecond = 1000; - return new BigNumber(Date.now() / milisecondsInSecond).integerValue(); - }, - getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { - const fillMakerTokenAmount = numerator - .multipliedBy(target) - .div(denominator) - .integerValue(0); - return fillMakerTokenAmount; - }, -}; diff --git a/packages/order-utils/test/artifacts/UntransferrableDummyERC20Token.ts b/packages/order-utils/test/artifacts/UntransferrableDummyERC20Token.ts deleted file mode 100644 index 7d30980e16..0000000000 --- a/packages/order-utils/test/artifacts/UntransferrableDummyERC20Token.ts +++ /dev/null @@ -1,409 +0,0 @@ -export const UntransferrableDummyERC20Token = { - schemaVersion: '2.0.0', - contractName: 'UntransferrableDummyERC20Token', - compilerOutput: { - abi: [ - { - constant: true, - inputs: [], - name: 'name', - outputs: [ - { - name: '', - type: 'string', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_spender', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'approve', - outputs: [ - { - name: '', - type: 'bool', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'totalSupply', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_from', - type: 'address', - }, - { - name: '_to', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'transferFrom', - outputs: [ - { - name: '', - type: 'bool', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'decimals', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '_owner', - type: 'address', - }, - ], - name: 'balanceOf', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'owner', - outputs: [ - { - name: '', - type: 'address', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'symbol', - outputs: [ - { - name: '', - type: 'string', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_value', - type: 'uint256', - }, - ], - name: 'mint', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_to', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'transfer', - outputs: [ - { - name: '', - type: 'bool', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '_owner', - type: 'address', - }, - { - name: '_spender', - type: 'address', - }, - ], - name: 'allowance', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_target', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'setBalance', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: 'newOwner', - type: 'address', - }, - ], - name: 'transferOwnership', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'MAX_MINT_AMOUNT', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - name: '_name', - type: 'string', - }, - { - name: '_symbol', - type: 'string', - }, - { - name: '_decimals', - type: 'uint256', - }, - { - name: '_totalSupply', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: '_from', - type: 'address', - }, - { - indexed: true, - name: '_to', - type: 'address', - }, - { - indexed: false, - name: '_value', - type: 'uint256', - }, - ], - name: 'Transfer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: '_owner', - type: 'address', - }, - { - indexed: true, - name: '_spender', - type: 'address', - }, - { - indexed: false, - name: '_value', - type: 'uint256', - }, - ], - name: 'Approval', - type: 'event', - }, - ], - evm: { - bytecode: { - linkReferences: {}, - object: - '0x60806040523480156200001157600080fd5b5060405162000e2738038062000e27833981018060405260808110156200003757600080fd5b8101908080516401000000008111156200005057600080fd5b820160208101848111156200006457600080fd5b81516401000000008111828201871017156200007f57600080fd5b505092919060200180516401000000008111156200009c57600080fd5b82016020810184811115620000b057600080fd5b8151640100000000811182820187101715620000cb57600080fd5b505060208083015160409093015160008054600160a060020a03191633179055865192955092935085918591859185916200010c9160049187019062000146565b5082516200012290600590602086019062000146565b506006919091553360009081526001602052604090205550620001eb945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200018957805160ff1916838001178555620001b9565b82800160010185558215620001b9579182015b82811115620001b95782518255916020019190600101906200019c565b50620001c7929150620001cb565b5090565b620001e891905b80821115620001c75760008155600101620001d2565b90565b610c2c80620001fb6000396000f3fe608060405234801561001057600080fd5b5060043610610107576000357c01000000000000000000000000000000000000000000000000000000009004806395d89b41116100a9578063dd62ed3e11610083578063dd62ed3e146102ff578063e30443bc1461033a578063f2fde38b14610373578063fa9b7018146103a657610107565b806395d89b411461029f578063a0712d68146102a7578063a9059cbb146102c657610107565b806323b872dd116100e557806323b872dd146101f0578063313ce5671461023357806370a082311461023b5780638da5cb5b1461026e57610107565b806306fdde031461010c578063095ea7b31461018957806318160ddd146101d6575b600080fd5b6101146103ae565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561014e578181015183820152602001610136565b50505050905090810190601f16801561017b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101c26004803603604081101561019f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561045a565b604080519115158252519081900360200190f35b6101de6104cd565b60408051918252519081900360200190f35b6101c26004803603606081101561020657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356104d3565b6101de61053c565b6101de6004803603602081101561025157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610542565b61027661056a565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b610114610586565b6102c4600480360360208110156102bd57600080fd5b50356105ff565b005b6101c2600480360360408110156102dc57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610685565b6101de6004803603604081101561031557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610814565b6102c46004803603604081101561035057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561084c565b6102c46004803603602081101561038957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610960565b6101de610a47565b6004805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156104525780601f1061042757610100808354040283529160200191610452565b820191906000526020600020905b81548152906001019060200180831161043557829003601f168201915b505050505081565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b60035490565b6000604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5452414e534645525f44495341424c4544000000000000000000000000000000604482015290519081900360640190fd5b60065481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205490565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6005805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156104525780601f1061042757610100808354040283529160200191610452565b69021e19e0c9bab240000081111561067857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f56414c55455f544f4f5f4c415247450000000000000000000000000000000000604482015290519081900360640190fd5b6106823382610a55565b50565b3360009081526001602052604081205482111561070357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054828101101561079957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b3360008181526001602090815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020908152604080832093909416825291909152205490565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108d257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020548082101561091d576109156003546109108385610b0e565b610b0e565b600355610936565b61093260035461092d8484610b0e565b610b85565b6003555b5073ffffffffffffffffffffffffffffffffffffffff909116600090815260016020526040902055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109e657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811615610682576000805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617905550565b69021e19e0c9bab240000081565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020526040902054610a86908290610b85565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902055600354610ab99082610b85565b60035560408051828152905173ffffffffffffffffffffffffffffffffffffffff8416916000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600082821115610b7f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f55494e543235365f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b50900390565b600082820183811015610bf957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b939250505056fea165627a7a723058204cebdef97829ef903902bc1f15ea8041119e2f2735acfe65aeda451b3f21c4f10029', - }, - }, - }, - sources: { - 'test/UntransferrableDummyERC20Token.sol': { - id: 5, - }, - 'test/DummyERC20Token.sol': { - id: 4, - }, - '@0x/contracts-utils/contracts/src/Ownable.sol': { - id: 6, - }, - '@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol': { - id: 8, - }, - 'src/MintableERC20Token.sol': { - id: 1, - }, - '@0x/contracts-utils/contracts/src/SafeMath.sol': { - id: 7, - }, - 'src/UnlimitedAllowanceERC20Token.sol': { - id: 2, - }, - 'src/ERC20Token.sol': { - id: 0, - }, - 'src/interfaces/IERC20Token.sol': { - id: 3, - }, - }, - sourceCodes: { - 'test/UntransferrableDummyERC20Token.sol': - '/*\n\n Copyright 2019 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport "./DummyERC20Token.sol";\n\n\n// solhint-disable no-empty-blocks\ncontract UntransferrableDummyERC20Token is\n DummyERC20Token\n{\n bool internal _paused;\n\n constructor (\n string memory _name,\n string memory _symbol,\n uint256 _decimals,\n uint256 _totalSupply\n )\n public\n DummyERC20Token(\n _name,\n _symbol,\n _decimals,\n _totalSupply\n )\n {}\n\n /// @dev send `value` token to `to` from `msg.sender`\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n function transfer(address _to, uint256 _value)\n external\n returns (bool)\n {\n require(\n false,\n "TRANSFER_DISABLED"\n );\n }\n\n /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`\n /// @param _from The address of the sender\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n )\n external\n returns (bool)\n {\n require(\n false,\n "TRANSFER_DISABLED"\n );\n }\n}\n\n', - 'test/DummyERC20Token.sol': - '/*\n\n Copyright 2019 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport "@0x/contracts-utils/contracts/src/Ownable.sol";\nimport "../src/MintableERC20Token.sol";\n\n\ncontract DummyERC20Token is \n Ownable,\n MintableERC20Token\n{\n string public name;\n string public symbol;\n uint256 public decimals;\n uint256 public constant MAX_MINT_AMOUNT = 10000000000000000000000;\n\n constructor (\n string memory _name,\n string memory _symbol,\n uint256 _decimals,\n uint256 _totalSupply\n )\n public\n {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n _totalSupply = _totalSupply;\n balances[msg.sender] = _totalSupply;\n }\n\n /// @dev Sets the balance of target address\n /// @param _target Address or which balance will be updated\n /// @param _value New balance of target address\n function setBalance(address _target, uint256 _value)\n external\n onlyOwner\n {\n uint256 currBalance = balances[_target];\n if (_value < currBalance) {\n _totalSupply = safeSub(_totalSupply, safeSub(currBalance, _value));\n } else {\n _totalSupply = safeAdd(_totalSupply, safeSub(_value, currBalance));\n }\n balances[_target] = _value;\n }\n\n /// @dev Mints new tokens for sender\n /// @param _value Amount of tokens to mint\n function mint(uint256 _value)\n external\n {\n require(\n _value <= MAX_MINT_AMOUNT,\n "VALUE_TOO_LARGE"\n );\n\n _mint(msg.sender, _value);\n }\n}\n', - '@0x/contracts-utils/contracts/src/Ownable.sol': - 'pragma solidity ^0.5.5;\n\nimport "./interfaces/IOwnable.sol";\n\n\ncontract Ownable is\n IOwnable\n{\n address public owner;\n\n constructor ()\n public\n {\n owner = msg.sender;\n }\n\n modifier onlyOwner() {\n require(\n msg.sender == owner,\n "ONLY_CONTRACT_OWNER"\n );\n _;\n }\n\n function transferOwnership(address newOwner)\n public\n onlyOwner\n {\n if (newOwner != address(0)) {\n owner = newOwner;\n }\n }\n}\n', - '@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol': - 'pragma solidity ^0.5.5;\n\n\ncontract IOwnable {\n\n function transferOwnership(address newOwner)\n public;\n}\n', - 'src/MintableERC20Token.sol': - '/*\n\n Copyright 2019 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport "@0x/contracts-utils/contracts/src/SafeMath.sol";\nimport "./UnlimitedAllowanceERC20Token.sol";\n\n\ncontract MintableERC20Token is \n SafeMath,\n UnlimitedAllowanceERC20Token\n{\n /// @dev Mints new tokens\n /// @param _to Address of the beneficiary that will own the minted token\n /// @param _value Amount of tokens to mint\n function _mint(address _to, uint256 _value)\n internal\n {\n balances[_to] = safeAdd(_value, balances[_to]);\n _totalSupply = safeAdd(_totalSupply, _value);\n\n emit Transfer(\n address(0),\n _to,\n _value\n );\n }\n\n /// @dev Mints new tokens\n /// @param _owner Owner of tokens that will be burned\n /// @param _value Amount of tokens to burn\n function _burn(address _owner, uint256 _value)\n internal\n {\n balances[_owner] = safeSub(balances[_owner], _value);\n _totalSupply = safeSub(_totalSupply, _value);\n\n emit Transfer(\n _owner,\n address(0),\n _value\n );\n }\n}\n', - '@0x/contracts-utils/contracts/src/SafeMath.sol': - 'pragma solidity ^0.5.5;\n\n\ncontract SafeMath {\n\n function safeMul(uint256 a, uint256 b)\n internal\n pure\n returns (uint256)\n {\n if (a == 0) {\n return 0;\n }\n uint256 c = a * b;\n require(\n c / a == b,\n "UINT256_OVERFLOW"\n );\n return c;\n }\n\n function safeDiv(uint256 a, uint256 b)\n internal\n pure\n returns (uint256)\n {\n uint256 c = a / b;\n return c;\n }\n\n function safeSub(uint256 a, uint256 b)\n internal\n pure\n returns (uint256)\n {\n require(\n b <= a,\n "UINT256_UNDERFLOW"\n );\n return a - b;\n }\n\n function safeAdd(uint256 a, uint256 b)\n internal\n pure\n returns (uint256)\n {\n uint256 c = a + b;\n require(\n c >= a,\n "UINT256_OVERFLOW"\n );\n return c;\n }\n\n function max64(uint64 a, uint64 b)\n internal\n pure\n returns (uint256)\n {\n return a >= b ? a : b;\n }\n\n function min64(uint64 a, uint64 b)\n internal\n pure\n returns (uint256)\n {\n return a < b ? a : b;\n }\n\n function max256(uint256 a, uint256 b)\n internal\n pure\n returns (uint256)\n {\n return a >= b ? a : b;\n }\n\n function min256(uint256 a, uint256 b)\n internal\n pure\n returns (uint256)\n {\n return a < b ? a : b;\n }\n}\n', - 'src/UnlimitedAllowanceERC20Token.sol': - '/*\n\n Copyright 2019 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport "./ERC20Token.sol";\n\n\ncontract UnlimitedAllowanceERC20Token is\n ERC20Token\n{\n uint256 constant internal MAX_UINT = 2**256 - 1;\n\n /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717\n /// @param _from Address to transfer from.\n /// @param _to Address to transfer to.\n /// @param _value Amount to transfer.\n /// @return Success of transfer.\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n )\n external\n returns (bool)\n {\n uint256 allowance = allowed[_from][msg.sender];\n require(\n balances[_from] >= _value,\n "ERC20_INSUFFICIENT_BALANCE"\n );\n require(\n allowance >= _value,\n "ERC20_INSUFFICIENT_ALLOWANCE"\n );\n require(\n balances[_to] + _value >= balances[_to],\n "UINT256_OVERFLOW"\n );\n\n balances[_to] += _value;\n balances[_from] -= _value;\n if (allowance < MAX_UINT) {\n allowed[_from][msg.sender] -= _value;\n }\n\n emit Transfer(\n _from,\n _to,\n _value\n );\n\n return true;\n }\n}\n', - 'src/ERC20Token.sol': - '/*\n\n Copyright 2019 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport "./interfaces/IERC20Token.sol";\n\n\ncontract ERC20Token is\n IERC20Token\n{\n mapping (address => uint256) internal balances;\n mapping (address => mapping (address => uint256)) internal allowed;\n\n uint256 internal _totalSupply;\n\n /// @dev send `value` token to `to` from `msg.sender`\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return True if transfer was successful\n function transfer(address _to, uint256 _value)\n external\n returns (bool)\n {\n require(\n balances[msg.sender] >= _value,\n "ERC20_INSUFFICIENT_BALANCE"\n );\n require(\n balances[_to] + _value >= balances[_to],\n "UINT256_OVERFLOW"\n );\n\n balances[msg.sender] -= _value;\n balances[_to] += _value;\n\n emit Transfer(\n msg.sender,\n _to,\n _value\n );\n\n return true;\n }\n\n /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`\n /// @param _from The address of the sender\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return True if transfer was successful\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n )\n external\n returns (bool)\n {\n require(\n balances[_from] >= _value,\n "ERC20_INSUFFICIENT_BALANCE"\n );\n require(\n allowed[_from][msg.sender] >= _value,\n "ERC20_INSUFFICIENT_ALLOWANCE"\n );\n require(\n balances[_to] + _value >= balances[_to],\n "UINT256_OVERFLOW"\n );\n\n balances[_to] += _value;\n balances[_from] -= _value;\n allowed[_from][msg.sender] -= _value;\n \n emit Transfer(\n _from,\n _to,\n _value\n );\n \n return true;\n }\n\n /// @dev `msg.sender` approves `_spender` to spend `_value` tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @param _value The amount of wei to be approved for transfer\n /// @return Always true if the call has enough gas to complete execution\n function approve(address _spender, uint256 _value)\n external\n returns (bool)\n {\n allowed[msg.sender][_spender] = _value;\n emit Approval(\n msg.sender,\n _spender,\n _value\n );\n return true;\n }\n\n /// @dev Query total supply of token\n /// @return Total supply of token\n function totalSupply()\n external\n view\n returns (uint256)\n {\n return _totalSupply;\n }\n\n /// @dev Query the balance of owner\n /// @param _owner The address from which the balance will be retrieved\n /// @return Balance of owner\n function balanceOf(address _owner)\n external\n view\n returns (uint256)\n {\n return balances[_owner];\n }\n\n /// @param _owner The address of the account owning tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @return Amount of remaining tokens allowed to spent\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256)\n {\n return allowed[_owner][_spender];\n }\n}\n', - 'src/interfaces/IERC20Token.sol': - '/*\n\n Copyright 2019 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract IERC20Token {\n\n // solhint-disable no-simple-event-func-name\n event Transfer(\n address indexed _from,\n address indexed _to,\n uint256 _value\n );\n\n event Approval(\n address indexed _owner,\n address indexed _spender,\n uint256 _value\n );\n\n /// @dev send `value` token to `to` from `msg.sender`\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return True if transfer was successful\n function transfer(address _to, uint256 _value)\n external\n returns (bool);\n\n /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`\n /// @param _from The address of the sender\n /// @param _to The address of the recipient\n /// @param _value The amount of token to be transferred\n /// @return True if transfer was successful\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n )\n external\n returns (bool);\n \n /// @dev `msg.sender` approves `_spender` to spend `_value` tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @param _value The amount of wei to be approved for transfer\n /// @return Always true if the call has enough gas to complete execution\n function approve(address _spender, uint256 _value)\n external\n returns (bool);\n\n /// @dev Query total supply of token\n /// @return Total supply of token\n function totalSupply()\n external\n view\n returns (uint256);\n \n /// @param _owner The address from which the balance will be retrieved\n /// @return Balance of owner\n function balanceOf(address _owner)\n external\n view\n returns (uint256);\n\n /// @param _owner The address of the account owning tokens\n /// @param _spender The address of the account able to transfer the tokens\n /// @return Amount of remaining tokens allowed to spent\n function allowance(address _owner, address _spender)\n external\n view\n returns (uint256);\n}\n', - }, - sourceTreeHashHex: '0x1fe42c8f253c28a74058cb82ccc63d561a91271e813cb576ee4f2a43175b0f3f', - compiler: { - name: 'solc', - version: '0.5.6+commit.b259423e.Linux.g++', - settings: { - optimizer: { - enabled: true, - runs: 1000000, - details: { - yul: true, - deduplicate: true, - cse: true, - constantOptimizer: true, - }, - }, - outputSelection: { - '*': { - '*': [ - 'abi', - 'evm.bytecode.object', - 'evm.bytecode.sourceMap', - 'evm.deployedBytecode.object', - 'evm.deployedBytecode.sourceMap', - ], - }, - }, - evmVersion: 'byzantium', - remappings: [ - '@0x/contracts-utils=/Users/jacob/projects/ethdev/0x/0x.js/contracts/erc20/node_modules/@0x/contracts-utils', - ], - }, - }, - networks: {}, -}; diff --git a/packages/order-utils/test/assert_test.ts b/packages/order-utils/test/assert_test.ts deleted file mode 100644 index 6319717876..0000000000 --- a/packages/order-utils/test/assert_test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as chai from 'chai'; -import 'mocha'; - -import { assert } from '../src/assert'; - -import { chaiSetup } from './utils/chai_setup'; -import { web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('Assertion library', () => { - describe('#isSenderAddressHexAsync', () => { - it('throws when address is invalid', async () => { - const address = '0xdeadbeef'; - const varName = 'address'; - return expect(assert.isSenderAddressAsync(varName, address, web3Wrapper)).to.be.rejectedWith( - `Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`, - ); - }); - it('throws when address is unavailable', async () => { - const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42'; - const varName = 'address'; - return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, web3Wrapper)).to.be.rejectedWith( - `Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`, - ); - }); - it("doesn't throw if address is available", async () => { - const availableAddress = (await web3Wrapper.getAvailableAddressesAsync())[0]; - const varName = 'address'; - return expect(assert.isSenderAddressAsync(varName, availableAddress, web3Wrapper)).to.become(undefined); - }); - }); -}); diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts deleted file mode 100644 index a989377580..0000000000 --- a/packages/order-utils/test/asset_data_utils_test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import * as chai from 'chai'; - -import { AssetProxyId, ERC1155AssetData, ERC20AssetData, ERC721AssetData, MultiAssetData } from '@0x/types'; -import { BigNumber } from '@0x/utils'; - -import { assetDataUtils } from '../src/asset_data_utils'; - -import { chaiSetup } from './utils/chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -const KNOWN_ERC20_ENCODING = { - address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', - assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48', -}; -const KNOWN_ERC721_ENCODING = { - address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', - tokenId: new BigNumber(1), - assetData: - '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', -}; -const KNOWN_ERC1155_ENCODING = { - tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', - tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)], - tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)], - callbackData: - '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', - assetData: - '0xa7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', -}; -const KNOWN_MULTI_ASSET_ENCODING = { - amounts: [new BigNumber(70), new BigNumber(1), new BigNumber(18)], - nestedAssetData: [ - KNOWN_ERC20_ENCODING.assetData, - KNOWN_ERC721_ENCODING.assetData, - KNOWN_ERC1155_ENCODING.assetData, - ], - assetData: - '0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', -}; - -describe('assetDataUtils', () => { - it('should encode ERC20', () => { - const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address); - expect(assetData).to.equal(KNOWN_ERC20_ENCODING.assetData); - }); - it('should decode ERC20', () => { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow( - KNOWN_ERC20_ENCODING.assetData, - ) as ERC20AssetData; // tslint:disable-line:no-unnecessary-type-assertion - expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); - expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC20); - }); - it('should encode ERC721', () => { - const assetData = assetDataUtils.encodeERC721AssetData( - KNOWN_ERC721_ENCODING.address, - KNOWN_ERC721_ENCODING.tokenId, - ); - expect(assetData).to.equal(KNOWN_ERC721_ENCODING.assetData); - }); - it('should decode ERC721', () => { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow( - KNOWN_ERC721_ENCODING.assetData, - ) as ERC721AssetData; // tslint:disable-line:no-unnecessary-type-assertion - expect(decodedAssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); - expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721); - expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); - }); - it('should encode ERC1155', () => { - const assetData = assetDataUtils.encodeERC1155AssetData( - KNOWN_ERC1155_ENCODING.tokenAddress, - KNOWN_ERC1155_ENCODING.tokenIds, - KNOWN_ERC1155_ENCODING.tokenValues, - KNOWN_ERC1155_ENCODING.callbackData, - ); - expect(assetData).to.equal(KNOWN_ERC1155_ENCODING.assetData); - }); - it('should decode ERC1155', () => { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow( - KNOWN_ERC1155_ENCODING.assetData, - ) as ERC1155AssetData; // tslint:disable-line:no-unnecessary-type-assertion - expect(decodedAssetData.assetProxyId).to.be.equal(AssetProxyId.ERC1155); - expect(decodedAssetData.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress); - expect(decodedAssetData.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues); - expect(decodedAssetData.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); - expect(decodedAssetData.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); - }); - it('should encode ERC20, ERC721 and ERC1155 multiAssetData', () => { - const assetData = assetDataUtils.encodeMultiAssetData( - KNOWN_MULTI_ASSET_ENCODING.amounts, - KNOWN_MULTI_ASSET_ENCODING.nestedAssetData, - ); - expect(assetData).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData); - }); - it('should decode ERC20, ERC721 and ERC1155 multiAssetData', () => { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow( - KNOWN_MULTI_ASSET_ENCODING.assetData, - ) as MultiAssetData; // tslint:disable-line:no-unnecessary-type-assertion - expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); - expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts); - expect(decodedAssetData.nestedAssetData).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.nestedAssetData); - }); - it('should recursively decode ERC20 and ERC721 multiAssetData', () => { - const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(KNOWN_MULTI_ASSET_ENCODING.assetData); - expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); - expect(decodedAssetData.amounts).to.deep.equal(KNOWN_MULTI_ASSET_ENCODING.amounts); - expect(decodedAssetData.nestedAssetData.length).to.equal(3); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc20AssetData = decodedAssetData.nestedAssetData[0] as ERC20AssetData; - expect(decodedErc20AssetData.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); - expect(decodedErc20AssetData.assetProxyId).to.equal(AssetProxyId.ERC20); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc721AssetData = decodedAssetData.nestedAssetData[1] as ERC721AssetData; - expect(decodedErc721AssetData.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); - expect(decodedErc721AssetData.assetProxyId).to.equal(AssetProxyId.ERC721); - expect(decodedErc721AssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc1155AssetData = decodedAssetData.nestedAssetData[2] as ERC1155AssetData; - expect(decodedErc1155AssetData.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress); - expect(decodedErc1155AssetData.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues); - expect(decodedErc1155AssetData.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); - expect(decodedErc1155AssetData.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); - }); - it('should recursively decode nested assetData within multiAssetData', () => { - // setup test parameters - const erc20Amount = new BigNumber(1); - const erc721Amount = new BigNumber(1); - const erc1155Amount = new BigNumber(15); - const nestedAssetsAmount = new BigNumber(2); - const amounts = [erc20Amount, erc721Amount, erc1155Amount, nestedAssetsAmount]; - const nestedAssetData = [ - KNOWN_ERC20_ENCODING.assetData, - KNOWN_ERC721_ENCODING.assetData, - KNOWN_ERC1155_ENCODING.assetData, - KNOWN_MULTI_ASSET_ENCODING.assetData, - ]; - const assetData = assetDataUtils.encodeMultiAssetData(amounts, nestedAssetData); - // execute test - const decodedAssetData = assetDataUtils.decodeMultiAssetDataRecursively(assetData); - // validate asset data - expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.MultiAsset); - const expectedAmounts = [ - erc20Amount, - erc721Amount, - erc1155Amount, - KNOWN_MULTI_ASSET_ENCODING.amounts[0].times(nestedAssetsAmount), - KNOWN_MULTI_ASSET_ENCODING.amounts[1].times(nestedAssetsAmount), - KNOWN_MULTI_ASSET_ENCODING.amounts[2].times(nestedAssetsAmount), - ]; - expect(decodedAssetData.amounts).to.deep.equal(expectedAmounts); - const expectedNestedAssetDataLength = 6; - expect(decodedAssetData.nestedAssetData.length).to.be.equal(expectedNestedAssetDataLength); - // validate nested asset data (outer) - let nestedAssetDataIndex = 0; - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc20AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC20AssetData; - expect(decodedErc20AssetData1.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); - expect(decodedErc20AssetData1.assetProxyId).to.equal(AssetProxyId.ERC20); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc721AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC721AssetData; - expect(decodedErc721AssetData1.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); - expect(decodedErc721AssetData1.assetProxyId).to.equal(AssetProxyId.ERC721); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc1155AssetData1 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC1155AssetData; - expect(decodedErc1155AssetData1.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress); - expect(decodedErc1155AssetData1.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues); - expect(decodedErc1155AssetData1.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); - expect(decodedErc1155AssetData1.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); - // validate nested asset data (inner) - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc20AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC20AssetData; - expect(decodedErc20AssetData2.tokenAddress).to.equal(KNOWN_ERC20_ENCODING.address); - expect(decodedErc20AssetData2.assetProxyId).to.equal(AssetProxyId.ERC20); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc721AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC721AssetData; - expect(decodedErc721AssetData2.tokenAddress).to.equal(KNOWN_ERC721_ENCODING.address); - expect(decodedErc721AssetData2.assetProxyId).to.equal(AssetProxyId.ERC721); - // tslint:disable-next-line:no-unnecessary-type-assertion - const decodedErc1155AssetData2 = decodedAssetData.nestedAssetData[nestedAssetDataIndex++] as ERC1155AssetData; - expect(decodedErc1155AssetData2.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress); - expect(decodedErc1155AssetData2.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues); - expect(decodedErc1155AssetData2.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); - expect(decodedErc1155AssetData2.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); - }); -}); diff --git a/packages/order-utils/test/eip712_utils_test.ts b/packages/order-utils/test/eip712_utils_test.ts deleted file mode 100644 index 984c187e3e..0000000000 --- a/packages/order-utils/test/eip712_utils_test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { constants } from '../src/constants'; -import { eip712Utils } from '../src/eip712_utils'; - -import { chaiSetup } from './utils/chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('EIP712 Utils', () => { - const CHAIN_ID = 1337; - - describe('createTypedData', () => { - it('adds in the EIP712DomainSeparator with default values', () => { - const primaryType = 'Test'; - const typedData = eip712Utils.createTypedData( - primaryType, - { Test: [{ name: 'testValue', type: 'uint256' }] }, - { testValue: '1' }, - { chainId: CHAIN_ID, verifyingContract: constants.NULL_ADDRESS }, - ); - expect(typedData.domain).to.not.be.undefined(); - expect(typedData.types.EIP712Domain).to.not.be.undefined(); - const domainObject = typedData.domain; - expect(domainObject.name).to.eq(constants.EXCHANGE_DOMAIN_NAME); - expect(domainObject.version).to.eq(constants.EXCHANGE_DOMAIN_VERSION); - expect(domainObject.verifyingContract).to.eq(constants.NULL_ADDRESS); - expect(typedData.primaryType).to.eq(primaryType); - }); - it('adds in the EIP712DomainSeparator without default values', () => { - const primaryType = 'Test'; - const domainName = 'testDomain'; - const domainVersion = 'testVersion'; - const typedData = eip712Utils.createTypedData( - primaryType, - { Test: [{ name: 'testValue', type: 'uint256' }] }, - { testValue: '1' }, - { - name: domainName, - version: domainVersion, - chainId: CHAIN_ID, - verifyingContract: constants.NULL_ADDRESS, - }, - ); - expect(typedData.domain).to.not.be.undefined(); - expect(typedData.types.EIP712Domain).to.not.be.undefined(); - const domainObject = typedData.domain; - expect(domainObject.name).to.eq(domainName); - expect(domainObject.version).to.eq(domainVersion); - expect(domainObject.verifyingContract).to.eq(constants.NULL_ADDRESS); - expect(typedData.primaryType).to.eq(primaryType); - }); - }); - describe('createZeroExTransactionTypedData', () => { - it('adds in the EIP712DomainSeparator', () => { - const typedData = eip712Utils.createZeroExTransactionTypedData({ - salt: new BigNumber(0), - expirationTimeSeconds: new BigNumber(0), - gasPrice: new BigNumber(0), - data: constants.NULL_BYTES, - signerAddress: constants.NULL_ADDRESS, - domain: { - verifyingContract: constants.NULL_ADDRESS, - chainId: CHAIN_ID, - }, - }); - expect(typedData.primaryType).to.eq(constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name); - expect(typedData.types.EIP712Domain).to.not.be.undefined(); - const domainObject = typedData.domain; - expect(domainObject.name).to.eq(constants.EXCHANGE_DOMAIN_NAME); - expect(domainObject.version).to.eq(constants.EXCHANGE_DOMAIN_VERSION); - expect(domainObject.verifyingContract).to.eq(constants.NULL_ADDRESS); - }); - }); -}); diff --git a/packages/order-utils/test/market_utils_test.ts b/packages/order-utils/test/market_utils_test.ts deleted file mode 100644 index b1853d2922..0000000000 --- a/packages/order-utils/test/market_utils_test.ts +++ /dev/null @@ -1,396 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { marketUtils } from '../src'; -import { constants } from '../src/constants'; - -import { chaiSetup } from './utils/chai_setup'; -import { testOrderFactory } from './utils/test_order_factory'; - -chaiSetup.configure(); -const expect = chai.expect; - -// tslint:disable: no-unused-expression -describe('marketUtils', () => { - describe('#findOrdersThatCoverTakerAssetFillAmount', () => { - describe('no orders', () => { - it('returns empty and unchanged remainingFillAmount', async () => { - const fillAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - [], - fillAmount, - ); - expect(resultOrders).to.be.empty; - expect(remainingFillAmount).to.be.bignumber.equal(fillAmount); - }); - }); - describe('orders are completely fillable', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - const takerAssetAmount = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - takerAssetAmount, - }, - 3, - ); - it('returns input orders and zero remainingFillAmount when input exactly matches requested fill amount', async () => { - // try to fill 20 units of makerAsset - // include 10 units of slippageBufferAmount - const fillAmount = new BigNumber(20); - const slippageBufferAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - { - slippageBufferAmount, - }, - ); - expect(resultOrders).to.be.deep.equal(inputOrders); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('returns input orders and zero remainingFillAmount when input has more than requested fill amount', async () => { - // try to fill 15 units of makerAsset - // include 10 units of slippageBufferAmount - const fillAmount = new BigNumber(15); - const slippageBufferAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - { - slippageBufferAmount, - }, - ); - expect(resultOrders).to.be.deep.equal(inputOrders); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('returns input orders and non-zero remainingFillAmount when input has less than requested fill amount', async () => { - // try to fill 30 units of makerAsset - // include 5 units of slippageBufferAmount - const fillAmount = new BigNumber(30); - const slippageBufferAmount = new BigNumber(5); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - { - slippageBufferAmount, - }, - ); - expect(resultOrders).to.be.deep.equal(inputOrders); - expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(5)); - }); - it('returns first order and zero remainingFillAmount when requested fill amount is exactly covered by the first order', async () => { - // try to fill 10 units of makerAsset - const fillAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[0]]); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('returns first two orders and zero remainingFillAmount when requested fill amount is over covered by the first two order', async () => { - // try to fill 15 units of makerAsset - const fillAmount = new BigNumber(15); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('orders are partially fillable', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - const takerAssetAmount = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - takerAssetAmount, - }, - 3, - ); - // generate remainingFillableMakerAssetAmounts that cover different partial fill scenarios - // 1. order is completely filled already - // 2. order is partially fillable - // 3. order is completely fillable - const remainingFillableTakerAssetAmounts = [constants.ZERO_AMOUNT, new BigNumber(5), takerAssetAmount]; - it('returns last two orders and non-zero remainingFillAmount when trying to fill original takerAssetAmounts', async () => { - // try to fill 30 units of takerAsset - const fillAmount = new BigNumber(30); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - { - remainingFillableTakerAssetAmounts, - }, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]); - expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(15)); - }); - it('returns last two orders and zero remainingFillAmount when trying to fill exactly takerAssetAmounts remaining', async () => { - // try to fill 15 units of takerAsset - const fillAmount = new BigNumber(15); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverTakerAssetFillAmount( - inputOrders, - fillAmount, - { - remainingFillableTakerAssetAmounts, - }, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]); - expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(0)); - }); - }); - }); - describe('#findOrdersThatCoverMakerAssetFillAmount', () => { - describe('no orders', () => { - it('returns empty and unchanged remainingFillAmount', async () => { - const fillAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - [], - fillAmount, - ); - expect(resultOrders).to.be.empty; - expect(remainingFillAmount).to.be.bignumber.equal(fillAmount); - }); - }); - describe('orders are completely fillable', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - const makerAssetAmount = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - }, - 3, - ); - it('returns input orders and zero remainingFillAmount when input exactly matches requested fill amount', async () => { - // try to fill 20 units of makerAsset - // include 10 units of slippageBufferAmount - const fillAmount = new BigNumber(20); - const slippageBufferAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - inputOrders, - fillAmount, - { - slippageBufferAmount, - }, - ); - expect(resultOrders).to.be.deep.equal(inputOrders); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('returns input orders and zero remainingFillAmount when input has more than requested fill amount', async () => { - // try to fill 15 units of makerAsset - // include 10 units of slippageBufferAmount - const fillAmount = new BigNumber(15); - const slippageBufferAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - inputOrders, - fillAmount, - { - slippageBufferAmount, - }, - ); - expect(resultOrders).to.be.deep.equal(inputOrders); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('returns input orders and non-zero remainingFillAmount when input has less than requested fill amount', async () => { - // try to fill 30 units of makerAsset - // include 5 units of slippageBufferAmount - const fillAmount = new BigNumber(30); - const slippageBufferAmount = new BigNumber(5); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - inputOrders, - fillAmount, - { - slippageBufferAmount, - }, - ); - expect(resultOrders).to.be.deep.equal(inputOrders); - expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(5)); - }); - it('returns first order and zero remainingFillAmount when requested fill amount is exactly covered by the first order', async () => { - // try to fill 10 units of makerAsset - const fillAmount = new BigNumber(10); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - inputOrders, - fillAmount, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[0]]); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('returns first two orders and zero remainingFillAmount when requested fill amount is over covered by the first two order', async () => { - // try to fill 15 units of makerAsset - const fillAmount = new BigNumber(15); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - inputOrders, - fillAmount, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]); - expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('orders are partially fillable', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - const makerAssetAmount = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - }, - 3, - ); - // generate remainingFillableMakerAssetAmounts that cover different partial fill scenarios - // 1. order is completely filled already - // 2. order is partially fillable - // 3. order is completely fillable - const remainingFillableMakerAssetAmounts = [constants.ZERO_AMOUNT, new BigNumber(5), makerAssetAmount]; - it('returns last two orders and non-zero remainingFillAmount when trying to fill original makerAssetAmounts', async () => { - // try to fill 30 units of makerAsset - const fillAmount = new BigNumber(30); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - inputOrders, - fillAmount, - { - remainingFillableMakerAssetAmounts, - }, - ); - expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]); - expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(15)); - }); - }); - }); - describe('#findFeeOrdersThatCoverFeesForTargetOrders', () => { - // generate three signed fee orders each with 10 units of ZRX, 30 total - const zrxAmount = new BigNumber(10); - const inputFeeOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount: zrxAmount, - }, - 3, - ); - describe('no target orders', () => { - it('returns empty and zero remainingFeeAmount', async () => { - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - [], - inputFeeOrders, - ); - expect(resultFeeOrders).to.be.empty; - expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('no fee orders', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - // each signed order requires 10 units of takerFee - const makerAssetAmount = new BigNumber(10); - const takerFee = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerFee, - }, - 3, - ); - // generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount - const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount]; - it('returns empty and non-zero remainingFeeAmount', async () => { - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - inputOrders, - [], - { - remainingFillableMakerAssetAmounts, - }, - ); - expect(resultFeeOrders).to.be.empty; - expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30)); - }); - }); - describe('target orders have no fees', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - const makerAssetAmount = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - }, - 3, - ); - it('returns empty and zero remainingFeeAmount', async () => { - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - inputOrders, - inputFeeOrders, - ); - expect(resultFeeOrders).to.be.empty; - expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('target orders require fees and are completely fillable', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - // each signed order requires 10 units of takerFee - const makerAssetAmount = new BigNumber(10); - const takerFee = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerFee, - }, - 3, - ); - it('returns input fee orders and zero remainingFeeAmount', async () => { - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - inputOrders, - inputFeeOrders, - ); - expect(resultFeeOrders).to.be.deep.equal(inputFeeOrders); - expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('target orders require fees and are partially fillable', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - // each signed order requires 10 units of takerFee - const makerAssetAmount = new BigNumber(10); - const takerFee = new BigNumber(10); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerFee, - }, - 3, - ); - // generate remainingFillableMakerAssetAmounts that cover different partial fill scenarios - // 1. order is completely filled already - // 2. order is partially fillable - // 3. order is completely fillable - const remainingFillableMakerAssetAmounts = [constants.ZERO_AMOUNT, new BigNumber(5), makerAssetAmount]; - it('returns first two input fee orders and zero remainingFeeAmount', async () => { - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - inputOrders, - inputFeeOrders, - { - remainingFillableMakerAssetAmounts, - }, - ); - expect(resultFeeOrders).to.be.deep.equal([inputFeeOrders[0], inputFeeOrders[1]]); - expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); - }); - }); - describe('target orders require more fees than available', () => { - // generate three signed orders each with 10 units of makerAsset, 30 total - // each signed order requires 20 units of takerFee - const makerAssetAmount = new BigNumber(10); - const takerFee = new BigNumber(20); - const inputOrders = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerFee, - }, - 3, - ); - it('returns input fee orders and non-zero remainingFeeAmount', async () => { - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - inputOrders, - inputFeeOrders, - ); - expect(resultFeeOrders).to.be.deep.equal(inputFeeOrders); - expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30)); - }); - }); - }); -}); diff --git a/packages/order-utils/test/rate_utils_test.ts b/packages/order-utils/test/rate_utils_test.ts deleted file mode 100644 index b13878bb59..0000000000 --- a/packages/order-utils/test/rate_utils_test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { rateUtils } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { testOrderFactory } from './utils/test_order_factory'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('rateUtils', () => { - const testOrder = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(100), - takerFee: new BigNumber(20), - }); - describe('#getFeeAdjustedRateOfOrder', () => { - it('throws when feeRate is less than zero', async () => { - const feeRate = new BigNumber(-1); - expect(() => rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate)).to.throw( - 'Expected feeRate: -1 to be greater than or equal to 0', - ); - }); - it('correctly calculates fee adjusted rate when feeRate is provided', async () => { - const feeRate = new BigNumber(2); // ZRX costs 2 units of takerAsset per 1 unit of ZRX - const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate); - // the order actually takes 100 + (2 * 20) takerAsset units to fill 100 units of makerAsset - expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.4)); - }); - it('correctly calculates fee adjusted rate when no feeRate is provided', async () => { - const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder); - // because no feeRate was provided we just assume 0 fees - // the order actually takes 100 takerAsset units to fill 100 units of makerAsset - expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1)); - }); - }); - describe('#getFeeAdjustedRateOfFeeOrder', () => { - it('throws when takerFee exceeds makerAssetAmount', async () => { - const badOrder = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerFee: new BigNumber(101), - }); - expect(() => rateUtils.getFeeAdjustedRateOfFeeOrder(badOrder)).to.throw( - 'Expected takerFee: "101" to be less than makerAssetAmount: "100"', - ); - }); - it('correctly calculates fee adjusted rate', async () => { - const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfFeeOrder(testOrder); - // the order actually takes 100 takerAsset units to fill (100 - 20) units of makerAsset - expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.25)); - }); - }); -}); diff --git a/packages/order-utils/test/remaining_fillable_calculator_test.ts b/packages/order-utils/test/remaining_fillable_calculator_test.ts deleted file mode 100644 index c04b38e015..0000000000 --- a/packages/order-utils/test/remaining_fillable_calculator_test.ts +++ /dev/null @@ -1,252 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import 'mocha'; - -import { RemainingFillableCalculator } from '../src/remaining_fillable_calculator'; - -import { chaiSetup } from './utils/chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('RemainingFillableCalculator', () => { - let calculator: RemainingFillableCalculator; - let signedOrder: SignedOrder; - let transferrableMakeAssetAmount: BigNumber; - let transferrableMakerFeeTokenAmount: BigNumber; - let remainingMakeAssetAmount: BigNumber; - let makerAmount: BigNumber; - let takerAmount: BigNumber; - let makerFeeAmount: BigNumber; - let isPercentageFee: boolean; - const makerAssetData: string = '0x1'; - const takerAssetData: string = '0x2'; - const makerFeeAssetData: string = '0x03'; - const takerFeeAssetData: string = '0x04'; - const decimals: number = 4; - const zero: BigNumber = new BigNumber(0); - const chainId: number = 1337; - const zeroAddress = '0x0'; - const signature: string = - '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403'; - beforeEach(async () => { - [makerAmount, takerAmount, makerFeeAmount] = [ - Web3Wrapper.toBaseUnitAmount(new BigNumber(50), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(1), decimals), - ]; - [transferrableMakeAssetAmount, transferrableMakerFeeTokenAmount] = [ - Web3Wrapper.toBaseUnitAmount(new BigNumber(50), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals), - ]; - }); - function buildSignedOrder(): SignedOrder { - return { - signature, - feeRecipientAddress: zeroAddress, - senderAddress: zeroAddress, - makerAddress: zeroAddress, - takerAddress: zeroAddress, - makerFee: makerFeeAmount, - takerFee: zero, - makerAssetAmount: makerAmount, - takerAssetAmount: takerAmount, - makerAssetData, - takerAssetData, - makerFeeAssetData, - takerFeeAssetData, - salt: zero, - expirationTimeSeconds: zero, - exchangeAddress: zeroAddress, - chainId, - }; - } - describe('Maker asset is not fee asset', () => { - before(async () => { - isPercentageFee = false; - }); - it('calculates the correct amount when unfilled and funds available', () => { - signedOrder = buildSignedOrder(); - remainingMakeAssetAmount = signedOrder.makerAssetAmount; - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(remainingMakeAssetAmount); - }); - it('calculates the correct amount when partially filled and funds available', () => { - signedOrder = buildSignedOrder(); - remainingMakeAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), decimals); - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(remainingMakeAssetAmount); - }); - it('calculates the amount to be 0 when all fee funds are transferred', () => { - signedOrder = buildSignedOrder(); - transferrableMakerFeeTokenAmount = zero; - remainingMakeAssetAmount = signedOrder.makerAssetAmount; - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(zero); - }); - it('calculates the correct amount when balance is less than remaining fillable', () => { - signedOrder = buildSignedOrder(); - const partiallyFilledAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - remainingMakeAssetAmount = signedOrder.makerAssetAmount.minus(partiallyFilledAmount); - transferrableMakeAssetAmount = remainingMakeAssetAmount.minus(partiallyFilledAmount); - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(transferrableMakeAssetAmount); - }); - describe('Order to Fee Ratio is < 1', () => { - beforeEach(async () => { - [makerAmount, takerAmount, makerFeeAmount] = [ - Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(6), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(6), decimals), - ]; - }); - it('calculates the correct amount when funds unavailable', () => { - signedOrder = buildSignedOrder(); - remainingMakeAssetAmount = signedOrder.makerAssetAmount; - const transferredAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - transferrableMakeAssetAmount = remainingMakeAssetAmount.minus(transferredAmount); - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(transferrableMakeAssetAmount); - }); - }); - describe('Ratio is not evenly divisible', () => { - beforeEach(async () => { - [makerAmount, takerAmount, makerFeeAmount] = [ - Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(7), decimals), - Web3Wrapper.toBaseUnitAmount(new BigNumber(7), decimals), - ]; - }); - it('calculates the correct amount when funds unavailable', () => { - signedOrder = buildSignedOrder(); - remainingMakeAssetAmount = signedOrder.makerAssetAmount; - const transferredAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - transferrableMakeAssetAmount = remainingMakeAssetAmount.minus(transferredAmount); - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - const calculatedFillableAmount = calculator.computeRemainingFillable(); - expect(calculatedFillableAmount.isLessThanOrEqualTo(transferrableMakeAssetAmount)).to.be.true(); - expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0)); - const orderToFeeRatio = signedOrder.makerAssetAmount.dividedBy(signedOrder.makerFee); - const calculatedFeeAmount = calculatedFillableAmount.dividedBy(orderToFeeRatio); - expect(calculatedFeeAmount).to.be.bignumber.lessThan(transferrableMakerFeeTokenAmount); - }); - }); - }); - describe('Maker asset is fee asset', () => { - before(async () => { - isPercentageFee = true; - }); - it('calculates the correct amount when unfilled and funds available', () => { - signedOrder = buildSignedOrder(); - transferrableMakeAssetAmount = makerAmount.plus(makerFeeAmount); - transferrableMakerFeeTokenAmount = transferrableMakeAssetAmount; - remainingMakeAssetAmount = signedOrder.makerAssetAmount; - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(remainingMakeAssetAmount); - }); - it('calculates the correct amount when partially filled and funds available', () => { - signedOrder = buildSignedOrder(); - remainingMakeAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), decimals); - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(remainingMakeAssetAmount); - }); - it('calculates the amount to be 0 when all fee funds are transferred', () => { - signedOrder = buildSignedOrder(); - transferrableMakeAssetAmount = zero; - transferrableMakerFeeTokenAmount = zero; - remainingMakeAssetAmount = signedOrder.makerAssetAmount; - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - expect(calculator.computeRemainingFillable()).to.be.bignumber.equal(zero); - }); - it('calculates the correct amount when balance is less than remaining fillable', () => { - signedOrder = buildSignedOrder(); - const partiallyFilledAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - remainingMakeAssetAmount = signedOrder.makerAssetAmount.minus(partiallyFilledAmount); - transferrableMakeAssetAmount = remainingMakeAssetAmount.minus(partiallyFilledAmount); - transferrableMakerFeeTokenAmount = transferrableMakeAssetAmount; - - const orderToFeeRatio = signedOrder.makerAssetAmount.dividedToIntegerBy(signedOrder.makerFee); - const expectedFillableAmount = new BigNumber(450980); - calculator = new RemainingFillableCalculator( - signedOrder.makerFee, - signedOrder.makerAssetAmount, - isPercentageFee, - transferrableMakeAssetAmount, - transferrableMakerFeeTokenAmount, - remainingMakeAssetAmount, - ); - const calculatedFillableAmount = calculator.computeRemainingFillable(); - const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio); - const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio); - expect(calculatedFillableAmountPlusFees).to.be.bignumber.lessThan(transferrableMakeAssetAmount); - expect(calculatedFillableAmountPlusFees).to.be.bignumber.lessThan(remainingMakeAssetAmount); - expect(calculatedFillableAmount).to.be.bignumber.equal(expectedFillableAmount); - expect(numberOfFillsInRatio.decimalPlaces()).to.be.equal(0); - }); - }); -}); diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts deleted file mode 100644 index 987dfe4813..0000000000 --- a/packages/order-utils/test/signature_utils_test.ts +++ /dev/null @@ -1,384 +0,0 @@ -import { assert } from '@0x/assert'; -import { Order, SignatureType, ZeroExTransaction } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import { JSONRPCErrorCallback, JSONRPCRequestPayload } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; -import 'mocha'; - -import { generatePseudoRandomSalt } from '../src'; -import { constants } from '../src/constants'; -import { orderHashUtils } from '../src/order_hash_utils'; -import { isValidECSignature, signatureUtils } from '../src/signature_utils'; -import { transactionHashUtils } from '../src/transaction_hash_utils'; - -import { chaiSetup } from './utils/chai_setup'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('Signature utils', () => { - let makerAddress: string; - const fakeExchangeContractAddress = '0x1dc4c1cefef38a777b15aa20260a54e584b16c48'; - const fakeChainId = 1337; - let order: Order; - let transaction: ZeroExTransaction; - before(async () => { - const availableAddreses = await web3Wrapper.getAvailableAddressesAsync(); - makerAddress = availableAddreses[0]; - order = { - makerAddress, - takerAddress: constants.NULL_ADDRESS, - senderAddress: constants.NULL_ADDRESS, - feeRecipientAddress: constants.NULL_ADDRESS, - makerAssetData: constants.NULL_ADDRESS, - takerAssetData: constants.NULL_ADDRESS, - makerFeeAssetData: constants.NULL_ADDRESS, - takerFeeAssetData: constants.NULL_ADDRESS, - salt: new BigNumber(0), - makerFee: new BigNumber(0), - takerFee: new BigNumber(0), - makerAssetAmount: new BigNumber(0), - takerAssetAmount: new BigNumber(0), - expirationTimeSeconds: new BigNumber(0), - exchangeAddress: fakeExchangeContractAddress, - chainId: fakeChainId, - }; - transaction = { - domain: { - verifyingContract: fakeExchangeContractAddress, - chainId: fakeChainId, - }, - salt: generatePseudoRandomSalt(), - signerAddress: makerAddress, - data: '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0', - expirationTimeSeconds: new BigNumber(0), - gasPrice: new BigNumber(0), - }; - }); - describe('#isValidECSignature', () => { - const signature = { - v: 27, - r: '0xaca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d64393', - s: '0x46b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf2', - }; - const data = '0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad'; - const address = '0x0e5cb767cce09a7f3ca594df118aa519be5e2b5a'; - - it("should return false if the data doesn't pertain to the signature & address", async () => { - expect(isValidECSignature('0x0', signature, address)).to.be.false(); - }); - it("should return false if the address doesn't pertain to the signature & data", async () => { - const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; - expect(isValidECSignature(data, signature, validUnrelatedAddress)).to.be.false(); - }); - it("should return false if the signature doesn't pertain to the data & address", async () => { - const wrongSignature = _.assign({}, signature, { v: 28 }); - expect(isValidECSignature(data, wrongSignature, address)).to.be.false(); - }); - it('should return true if the signature does pertain to the data & address', async () => { - const isValidSignatureLocal = isValidECSignature(data, signature, address); - expect(isValidSignatureLocal).to.be.true(); - }); - }); - describe('#generateSalt', () => { - it('generates different salts', () => { - const isEqual = generatePseudoRandomSalt().eq(generatePseudoRandomSalt()); - expect(isEqual).to.be.false(); - }); - it('generates salt in range [0..2^256)', () => { - const salt = generatePseudoRandomSalt(); - expect(salt.isGreaterThanOrEqualTo(0)).to.be.true(); - // tslint:disable-next-line:custom-no-magic-numbers - const twoPow256 = new BigNumber(2).pow(256); - expect(salt.isLessThan(twoPow256)).to.be.true(); - }); - }); - describe('#parseValidatorSignature', () => { - const ethSignSignature = - '0x1c3582f06356a1314dbf1c0e534c4d8e92e59b056ee607a7ff5a825f5f2cc5e6151c5cc7fdd420f5608e4d5bef108e42ad90c7a4b408caef32e24374cf387b0d7603'; - const validatorAddress = '0x63ac26ad9477d6be19a5fabe394bcc4886057c53'; - const signature = `${ethSignSignature}${validatorAddress.substr(2)}05`; - it('throws if signature type is not Validator type signature', () => { - expect(signatureUtils.parseValidatorSignature.bind(null, ethSignSignature)).to.throw( - 'Unexpected signatureType: 3. Valid signature types: 5', - ); - }); - it('extracts signature and validator address', () => { - const validatorSignature = signatureUtils.parseValidatorSignature(signature); - - expect(validatorSignature.validatorAddress).to.equal(validatorAddress); - expect(validatorSignature.signature).to.equal(ethSignSignature); - }); - }); - describe('#ecSignOrderAsync', () => { - it('should default to eth_sign if eth_signTypedData is unavailable', async () => { - const expectedSignature = - '0x1bea7883d76c4d8d0cd5915ec613f8dedf3b5f03e6a1f74aa171e700b0becdc8b47ade1ede08a5496ff31e34715bc6ac5da5aba709d3d8989a48127c18ef2f56d503'; - - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method.startsWith('eth_signTypedData')) { - callback(new Error('Internal RPC Error')); - } else if (payload.method === 'eth_sign') { - const [address, message] = payload.params; - const signature = await web3Wrapper.signMessageAsync(address, message); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - const signedOrder = await signatureUtils.ecSignOrderAsync(fakeProvider, order, makerAddress); - expect(signedOrder.signature).to.equal(expectedSignature); - }); - it('should throw if the user denies the signing request', async () => { - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method.startsWith('eth_signTypedData')) { - callback(new Error('User denied message signature')); - } else if (payload.method === 'eth_sign') { - const [address, message] = payload.params; - const signature = await web3Wrapper.signMessageAsync(address, message); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - expect(signatureUtils.ecSignOrderAsync(fakeProvider, order, makerAddress)).to.to.be.rejectedWith( - 'User denied message signature', - ); - }); - }); - describe('#ecSignTransactionAsync', () => { - it('should default to eth_sign if eth_signTypedData is unavailable', async () => { - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method.startsWith('eth_signTypedData')) { - callback(new Error('Internal RPC Error')); - } else if (payload.method === 'eth_sign') { - const [address, message] = payload.params; - const signature = await web3Wrapper.signMessageAsync(address, message); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - const signedTransaction = await signatureUtils.ecSignTransactionAsync( - fakeProvider, - transaction, - makerAddress, - ); - assert.isHexString('signedTransaction.signature', signedTransaction.signature); - }); - it('should throw if the user denies the signing request', async () => { - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method.startsWith('eth_signTypedData')) { - callback(new Error('User denied message signature')); - } else if (payload.method === 'eth_sign') { - const [address, message] = payload.params; - const signature = await web3Wrapper.signMessageAsync(address, message); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - expect( - signatureUtils.ecSignTransactionAsync(fakeProvider, transaction, makerAddress), - ).to.to.be.rejectedWith('User denied message signature'); - }); - }); - describe('#ecSignHashAsync', () => { - before(async () => { - const availableAddreses = await web3Wrapper.getAvailableAddressesAsync(); - makerAddress = availableAddreses[0]; - }); - it('should return the correct Signature', async () => { - const orderHash = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0'; - const expectedSignature = - '0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403'; - const ecSignature = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress); - expect(ecSignature).to.equal(expectedSignature); - }); - it('should return the correct Signature for signatureHex concatenated as R + S + V', async () => { - const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004'; - const expectedSignature = - '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03'; - - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method === 'eth_sign') { - const [address, message] = payload.params; - expect(message).to.equal(orderHash); - const signature = await web3Wrapper.signMessageAsync(address, message); - // tslint:disable-next-line:custom-no-magic-numbers - const rsvHex = `0x${signature.substr(130)}${signature.substr(2, 128)}`; - callback(null, { - id: 42, - jsonrpc: '2.0', - result: rsvHex, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - const ecSignature = await signatureUtils.ecSignHashAsync(fakeProvider, orderHash, makerAddress); - expect(ecSignature).to.equal(expectedSignature); - }); - it('should return the correct Signature for signatureHex concatenated as V + R + S', async () => { - const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004'; - const expectedSignature = - '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03'; - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method === 'eth_sign') { - const [address, message] = payload.params; - const signature = await web3Wrapper.signMessageAsync(address, message); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - - const ecSignature = await signatureUtils.ecSignHashAsync(fakeProvider, orderHash, makerAddress); - expect(ecSignature).to.equal(expectedSignature); - }); - it('should return a valid signature', async () => { - const expectedSignature = - '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03'; - - const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004'; - const ecSignature = await signatureUtils.ecSignHashAsync(provider, orderHash, makerAddress); - expect(ecSignature).to.equal(expectedSignature); - }); - }); - describe('#ecSignTypedDataOrderAsync', () => { - it('should result in the same signature as signing the order hash without an ethereum message prefix', async () => { - // Note: Since order hash is an EIP712 hash the result of a valid EIP712 signature - // of order hash is the same as signing the order without the Ethereum Message prefix. - const orderHashHex = orderHashUtils.getOrderHash(order); - const sig = ethUtil.ecsign( - ethUtil.toBuffer(orderHashHex), - Buffer.from('F2F48EE19680706196E2E339E5DA3491186E0C4C5030670656B0E0164837257D', 'hex'), - ); - const signatureBuffer = Buffer.concat([ - ethUtil.toBuffer(sig.v), - ethUtil.toBuffer(sig.r), - ethUtil.toBuffer(sig.s), - ethUtil.toBuffer(SignatureType.EIP712), - ]); - const signatureHex = `0x${signatureBuffer.toString('hex')}`; - const signedOrder = await signatureUtils.ecSignTypedDataOrderAsync(provider, order, makerAddress); - expect(signatureHex).to.eq(signedOrder.signature); - }); - it('should return the correct signature for signatureHex concatenated as R + S + V', async () => { - const expectedSignature = - '0x1b65b7b6205a4511cc81ec8f1b3eb475b398d60985089a3041c74735109f207e99542c7f0f81b0a988317e89b8280ec72829c8532a04c376f1f1236589c911545002'; - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method.startsWith('eth_signTypedData')) { - const [address, typedData] = payload.params; - const signature = await web3Wrapper.signTypedDataAsync(address, JSON.parse(typedData)); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - const signedOrder = await signatureUtils.ecSignTypedDataOrderAsync(fakeProvider, order, makerAddress); - expect(signedOrder.signature).to.equal(expectedSignature); - }); - }); - describe('#ecSignTypedDataTransactionAsync', () => { - it('should result in the same signature as signing the order hash without an ethereum message prefix', async () => { - // Note: Since order hash is an EIP712 hash the result of a valid EIP712 signature - // of order hash is the same as signing the order without the Ethereum Message prefix. - const transactionHashHex = transactionHashUtils.getTransactionHash(transaction); - const sig = ethUtil.ecsign( - ethUtil.toBuffer(transactionHashHex), - Buffer.from('F2F48EE19680706196E2E339E5DA3491186E0C4C5030670656B0E0164837257D', 'hex'), - ); - const signatureBuffer = Buffer.concat([ - ethUtil.toBuffer(sig.v), - ethUtil.toBuffer(sig.r), - ethUtil.toBuffer(sig.s), - ethUtil.toBuffer(SignatureType.EIP712), - ]); - const signatureHex = `0x${signatureBuffer.toString('hex')}`; - const signedTransaction = await signatureUtils.ecSignTypedDataTransactionAsync( - provider, - transaction, - makerAddress, - ); - expect(signatureHex).to.eq(signedTransaction.signature); - }); - it('should return the correct Signature for signatureHex concatenated as R + S + V', async () => { - const fakeProvider = { - async sendAsync(payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback): Promise { - if (payload.method.startsWith('eth_signTypedData')) { - const [address, typedData] = payload.params; - const signature = await web3Wrapper.signTypedDataAsync(address, JSON.parse(typedData)); - callback(null, { - id: 42, - jsonrpc: '2.0', - result: signature, - }); - } else { - callback(null, { id: 42, jsonrpc: '2.0', result: [makerAddress] }); - } - }, - }; - const signedTransaction = await signatureUtils.ecSignTypedDataTransactionAsync( - fakeProvider, - transaction, - makerAddress, - ); - assert.isHexString('signedTransaction.signature', signedTransaction.signature); - }); - }); - describe('#convertECSignatureToSignatureHex', () => { - const ecSignature: ECSignature = { - v: 27, - r: '0xaca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d64393', - s: '0x46b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf2', - }; - it('should concatenate v,r,s and append the EthSign signature type', async () => { - const expectedSignatureWithSignatureType = - '0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf203'; - const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex(ecSignature); - expect(signatureWithSignatureType).to.equal(expectedSignatureWithSignatureType); - }); - }); -}); diff --git a/packages/order-utils/test/sorting_utils_test.ts b/packages/order-utils/test/sorting_utils_test.ts deleted file mode 100644 index 0b8757496b..0000000000 --- a/packages/order-utils/test/sorting_utils_test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { sortingUtils } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { testOrderFactory } from './utils/test_order_factory'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('sortingUtils', () => { - describe('#sortOrdersByFeeAdjustedRate', () => { - const feeRate = new BigNumber(1); // ZRX costs 1 unit of takerAsset per 1 unit of ZRX - // rate: 2 takerAsset / makerAsset - const testOrder1 = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(200), - }); - // rate: 1 takerAsset / makerAsset - const testOrder2 = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(100), - }); - // rate: 2.5 takerAsset / makerAsset - const testOrder3 = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(200), - takerFee: new BigNumber(50), - }); - it('correctly sorts by fee adjusted rate when feeRate is Provided', async () => { - const orders = [testOrder1, testOrder2, testOrder3]; - const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate(orders, feeRate); - expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); - }); - it('correctly sorts by fee adjusted rate when no feeRate is Provided', async () => { - const orders = [testOrder1, testOrder2, testOrder3]; - const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate(orders); - expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); - }); - }); - describe('#sortFeeOrdersByFeeAdjustedRate', () => { - // rate: 200 takerAsset / makerAsset - const testOrder1 = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(200), - takerFee: new BigNumber(99), - }); - // rate: 1 takerAsset / makerAsset - const testOrder2 = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(100), - }); - // rate: 4 takerAsset / makerAsset - const testOrder3 = testOrderFactory.generateTestSignedOrder({ - makerAssetAmount: new BigNumber(100), - takerAssetAmount: new BigNumber(200), - takerFee: new BigNumber(50), - }); - it('correctly sorts by fee adjusted rate', async () => { - const orders = [testOrder1, testOrder2, testOrder3]; - const sortedOrders = sortingUtils.sortFeeOrdersByFeeAdjustedRate(orders); - expect(sortedOrders).to.deep.equal([testOrder2, testOrder3, testOrder1]); - }); - }); -}); diff --git a/packages/order-utils/test/utils/chai_setup.ts b/packages/order-utils/test/utils/chai_setup.ts deleted file mode 100644 index e721397b28..0000000000 --- a/packages/order-utils/test/utils/chai_setup.ts +++ /dev/null @@ -1 +0,0 @@ -export { chaiSetup } from '@0x/dev-utils'; diff --git a/packages/order-utils/test/utils/test_order_factory.ts b/packages/order-utils/test/utils/test_order_factory.ts deleted file mode 100644 index 990b2d1f90..0000000000 --- a/packages/order-utils/test/utils/test_order_factory.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Order, SignedOrder } from '@0x/types'; -import * as _ from 'lodash'; - -import { constants } from '../../src/constants'; -import { orderFactory } from '../../src/order_factory'; - -const CHAIN_ID = 1337; -const BASE_TEST_ORDER: Order = orderFactory.createOrder( - constants.NULL_ADDRESS, - constants.ZERO_AMOUNT, - constants.NULL_ERC20_ASSET_DATA, - constants.ZERO_AMOUNT, - constants.NULL_ERC20_ASSET_DATA, - constants.NULL_ADDRESS, - CHAIN_ID, -); -const BASE_TEST_SIGNED_ORDER: SignedOrder = { - ...BASE_TEST_ORDER, - signature: constants.NULL_BYTES, -}; - -export const testOrderFactory = { - generateTestSignedOrder(partialOrder: Partial): SignedOrder { - return transformObject(BASE_TEST_SIGNED_ORDER, partialOrder); - }, - generateTestSignedOrders(partialOrder: Partial, numOrders: number): SignedOrder[] { - const baseTestOrders = _.map(_.range(numOrders), () => BASE_TEST_SIGNED_ORDER); - return _.map(baseTestOrders, order => transformObject(order, partialOrder)); - }, -}; - -function transformObject(input: T, transformation: Partial): T { - const copy = _.cloneDeep(input); - return _.assign(copy, transformation); -} diff --git a/packages/order-utils/test/utils/web3_wrapper.ts b/packages/order-utils/test/utils/web3_wrapper.ts deleted file mode 100644 index 32f8543267..0000000000 --- a/packages/order-utils/test/utils/web3_wrapper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { web3Factory } from '@0x/dev-utils'; -import { Web3ProviderEngine } from '@0x/subproviders'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -const provider: Web3ProviderEngine = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true }); -const web3Wrapper = new Web3Wrapper(provider); - -export { provider, web3Wrapper }; diff --git a/packages/order-utils/tsconfig.json b/packages/order-utils/tsconfig.json deleted file mode 100644 index 718e623c74..0000000000 --- a/packages/order-utils/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "." - }, - "include": ["src/**/*", "test/**/*"] -} diff --git a/packages/order-utils/tslint.json b/packages/order-utils/tslint.json deleted file mode 100644 index dd9053357e..0000000000 --- a/packages/order-utils/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["@0x/tslint-config"] -} diff --git a/packages/order-utils/typedoc-tsconfig.json b/packages/order-utils/typedoc-tsconfig.json deleted file mode 100644 index b9c6b36f30..0000000000 --- a/packages/order-utils/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["src/**/*", "test/**/*"] -} diff --git a/tsconfig.json b/tsconfig.json index 435518b3fe..1b2ba3223d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,29 +15,17 @@ "declarationMap": true, "sourceMap": true }, - // These are not working right now - "exclude": ["./contracts/extensions/**/*"], + "exclude": [], // The root of the project is just a list of references and does not contain // any top-level TypeScript code. "include": [], "references": [ - { "path": "./contracts/asset-proxy" }, { "path": "./contracts/erc20" }, - { "path": "./contracts/erc721" }, - { "path": "./contracts/exchange" }, - { "path": "./contracts/coordinator" }, - { "path": "./contracts/exchange-forwarder" }, - { "path": "./contracts/exchange-libs" }, - // { "path": "./contracts/extensions" }, - { "path": "./contracts/multisig" }, { "path": "./contracts/test-utils" }, { "path": "./contracts/utils" }, - { "path": "./contracts/dev-utils" }, - { "path": "./contracts/integrations" }, { "path": "./packages/contract-addresses" }, { "path": "./packages/contract-artifacts" }, { "path": "./packages/contract-wrappers" }, - { "path": "./packages/migrations" }, - { "path": "./packages/order-utils" } + { "path": "./packages/migrations" } ] } diff --git a/yarn.lock b/yarn.lock index a3af48b37e..7a306a5ba8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -665,17 +665,6 @@ toposort "^2.0.2" yargs "^10.0.3" -"@0x/assert@^3.0.1", "@0x/assert@^3.0.17": - version "3.0.17" - resolved "https://registry.yarnpkg.com/@0x/assert/-/assert-3.0.17.tgz#dc15d038ed085744cb375044218285368f0cbfa8" - dependencies: - "@0x/json-schemas" "^5.3.3" - "@0x/typescript-typings" "^5.1.5" - "@0x/utils" "^6.1.0" - "@types/node" "12.12.54" - lodash "^4.17.11" - valid-url "^1.0.9" - "@0x/assert@^3.0.27": version "3.0.27" resolved "https://registry.yarnpkg.com/@0x/assert/-/assert-3.0.27.tgz#a4e54e5c1703c276689a21c935ecd24b2be292b9" @@ -715,14 +704,150 @@ js-sha3 "^0.7.0" uuid "^3.3.2" -"@0x/contract-addresses@^4.0.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-4.12.0.tgz#2adb0bcde763ad13437f782adf25c403107ff428" +"@0x/contract-addresses@^6.6.0": + version "6.6.0" + resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-6.6.0.tgz#8525697a02a765e998211fb45814b4247ce7d820" + +"@0x/contract-wrappers@^13.17.4": + version "13.17.4" + resolved "https://registry.yarnpkg.com/@0x/contract-wrappers/-/contract-wrappers-13.17.4.tgz#79c4964705e0a6d6eef8312901d897c13a7977e9" + dependencies: + "@0x/assert" "^3.0.27" + "@0x/base-contract" "^6.4.0" + "@0x/contract-addresses" "^6.6.0" + "@0x/json-schemas" "^6.1.3" + "@0x/types" "^3.3.3" + "@0x/utils" "^6.4.3" + "@0x/web3-wrapper" "^7.5.3" + ethereum-types "^3.5.0" + ethers "~4.0.4" + +"@0x/contracts-asset-proxy@^3.7.17": + version "3.7.18" + resolved "https://registry.yarnpkg.com/@0x/contracts-asset-proxy/-/contracts-asset-proxy-3.7.18.tgz#d0a031ccf32d3266b5ec86c07f538b3fbb66ccc1" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-erc1155" "^2.1.36" + "@0x/contracts-erc20" "^3.3.15" + "@0x/contracts-erc721" "^3.1.36" + "@0x/contracts-exchange-libs" "^4.3.36" + "@0x/order-utils" "^10.4.28" + "@0x/types" "^3.3.3" + "@0x/typescript-typings" "^5.2.0" + "@0x/utils" "^6.4.3" + "@0x/web3-wrapper" "^7.5.3" + ethereum-types "^3.5.0" + lodash "^4.17.11" + +"@0x/contracts-coordinator@^3.1.36": + version "3.1.36" + resolved "https://registry.yarnpkg.com/@0x/contracts-coordinator/-/contracts-coordinator-3.1.36.tgz#fad0ce622546365498c5b5a8033154a571386162" + dependencies: + "@0x/assert" "^3.0.27" + "@0x/base-contract" "^6.4.0" + "@0x/contract-addresses" "^6.5.0" + "@0x/contracts-exchange" "^3.2.36" + "@0x/contracts-test-utils" "^5.4.6" + "@0x/contracts-utils" "^4.7.14" + "@0x/json-schemas" "^6.1.3" + "@0x/types" "^3.3.3" + "@0x/typescript-typings" "^5.2.0" + "@0x/utils" "^6.4.3" + ethereum-types "^3.5.0" + http-status-codes "^1.3.2" + +"@0x/contracts-dev-utils@^1.3.34": + version "1.3.34" + resolved "https://registry.yarnpkg.com/@0x/contracts-dev-utils/-/contracts-dev-utils-1.3.34.tgz#be755bb5a6da75c3e06887a3d0c5159ca7f1468c" + dependencies: + "@0x/base-contract" "^6.4.0" + "@types/node" "12.12.54" + +"@0x/contracts-erc1155@^2.1.35": + version "2.1.35" + resolved "https://registry.yarnpkg.com/@0x/contracts-erc1155/-/contracts-erc1155-2.1.35.tgz#a3e2ce36b428b8b9b21c41afc6ef2817081b9f4e" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-test-utils" "^5.4.6" + "@0x/utils" "^6.4.3" + "@0x/web3-wrapper" "^7.5.3" + lodash "^4.17.11" + +"@0x/contracts-erc1155@^2.1.36": + version "2.1.36" + resolved "https://registry.yarnpkg.com/@0x/contracts-erc1155/-/contracts-erc1155-2.1.36.tgz#ed744dc6f947e2cd82b10758316c7aeb75d1322b" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-test-utils" "^5.4.7" + "@0x/utils" "^6.4.3" + "@0x/web3-wrapper" "^7.5.3" + lodash "^4.17.11" + +"@0x/contracts-erc20@^3.3.15": + version "3.3.15" + resolved "https://registry.yarnpkg.com/@0x/contracts-erc20/-/contracts-erc20-3.3.15.tgz#386c4ea50f64399e46e1b4de0d8a6186a6be2410" + dependencies: + "@0x/base-contract" "^6.4.0" + ethers "~4.0.4" + +"@0x/contracts-erc721@^3.1.35": + version "3.1.35" + resolved "https://registry.yarnpkg.com/@0x/contracts-erc721/-/contracts-erc721-3.1.35.tgz#de9d7ddce0708f1262e724757b8d7e7785cd0e84" + dependencies: + "@0x/base-contract" "^6.4.0" + +"@0x/contracts-erc721@^3.1.36": + version "3.1.36" + resolved "https://registry.yarnpkg.com/@0x/contracts-erc721/-/contracts-erc721-3.1.36.tgz#fd858757f36e9c2b6698f3ae0883395895c1ac93" + dependencies: + "@0x/base-contract" "^6.4.0" + +"@0x/contracts-exchange-forwarder@^4.2.36": + version "4.2.36" + resolved "https://registry.yarnpkg.com/@0x/contracts-exchange-forwarder/-/contracts-exchange-forwarder-4.2.36.tgz#396416b7aa5b4e95d9af601fde8c88087f780c78" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/typescript-typings" "^5.2.0" + ethereum-types "^3.5.0" + +"@0x/contracts-exchange-libs@^4.3.35", "@0x/contracts-exchange-libs@^4.3.36": + version "4.3.36" + resolved "https://registry.yarnpkg.com/@0x/contracts-exchange-libs/-/contracts-exchange-libs-4.3.36.tgz#7bf7a01a68886d901850be39af5612cd0713e205" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-test-utils" "^5.4.7" + "@0x/contracts-utils" "^4.7.15" + "@0x/order-utils" "^10.4.28" + "@0x/types" "^3.3.3" + "@0x/typescript-typings" "^5.2.0" + "@0x/utils" "^6.4.3" + ethereum-types "^3.5.0" + +"@0x/contracts-exchange@^3.2.36": + version "3.2.36" + resolved "https://registry.yarnpkg.com/@0x/contracts-exchange/-/contracts-exchange-3.2.36.tgz#3b014d196ee65c37563a1ad8687800845acd712c" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-dev-utils" "^1.3.34" + "@0x/contracts-erc1155" "^2.1.35" + "@0x/contracts-erc20" "^3.3.14" + "@0x/contracts-erc721" "^3.1.35" + "@0x/order-utils" "^10.4.27" + "@0x/utils" "^6.4.3" + lodash "^4.17.11" + +"@0x/contracts-extensions@^6.2.30": + version "6.2.30" + resolved "https://registry.yarnpkg.com/@0x/contracts-extensions/-/contracts-extensions-6.2.30.tgz#75d81234f4b2c3236a7c6a024ce60d8ebe9209fb" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-test-utils" "^5.4.6" + "@0x/typescript-typings" "^5.2.0" + ethereum-types "^3.5.0" "@0x/contracts-gen@^2.0.38": version "2.0.38" resolved "https://registry.yarnpkg.com/@0x/contracts-gen/-/contracts-gen-2.0.38.tgz#6f2977e2bcb299b5e8a32f45d7eca73d19e34c50" - integrity sha512-SIvfwGIjlZgL979q8iohBVVFH09kJdNCn8ozFEKxMs67GCBEWQFWOAcvyadKGPgyvMkPSOh10WBUHO9wRf18wg== dependencies: "@0x/sol-compiler" "^4.7.3" "@0x/sol-resolver" "^3.1.8" @@ -736,37 +861,75 @@ prettier "^1.16.3" to-snake-case "^1.0.0" -"@0x/coordinator-server@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-1.0.5.tgz#3fda0d5f2af45f0baa7663ad0a5e8465b4161081" +"@0x/contracts-multisig@^4.1.36": + version "4.1.37" + resolved "https://registry.yarnpkg.com/@0x/contracts-multisig/-/contracts-multisig-4.1.37.tgz#081cacf4217cf50202ddb5ecdb41a47695b41cb2" dependencies: - "@0x/assert" "^3.0.1" - "@0x/contract-addresses" "^4.0.0" - "@0x/contract-wrappers" "^13.1.0" - "@0x/json-schemas" "^5.0.1" - "@0x/order-utils" "^10.0.0" - "@0x/subproviders" "^6.0.1" - "@0x/types" "^3.1.0" - "@0x/typescript-typings" "^5.0.0" - "@0x/utils" "^5.1.0" - "@babel/polyfill" "^7.0.0" - body-parser "^1.18.3" - cors "^2.8.5" - express "^4.16.3" - express-async-handler "^1.1.4" - forever "^0.15.3" - http-status-codes "^1.3.0" - jsonschema "^1.2.4" + "@0x/base-contract" "^6.4.0" + "@0x/typescript-typings" "^5.2.0" + ethereum-types "^3.5.0" + +"@0x/contracts-staking@^2.0.43": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@0x/contracts-staking/-/contracts-staking-2.0.44.tgz#8bfca27012e44e281cb0acc02da5549bfd32919c" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/contracts-test-utils" "^5.4.7" + "@0x/typescript-typings" "^5.2.0" + "@0x/utils" "^6.4.3" + ethereum-types "^3.5.0" + ethereumjs-util "^7.0.10" + +"@0x/contracts-test-utils@^5.4.7": + version "5.4.7" + resolved "https://registry.yarnpkg.com/@0x/contracts-test-utils/-/contracts-test-utils-5.4.7.tgz#2bd007ddcf95ec211642f1c656043b79046737df" + dependencies: + "@0x/assert" "^3.0.27" + "@0x/base-contract" "^6.4.0" + "@0x/contract-addresses" "^6.6.0" + "@0x/dev-utils" "^4.2.7" + "@0x/json-schemas" "^6.1.3" + "@0x/order-utils" "^10.4.28" + "@0x/sol-coverage" "^4.0.37" + "@0x/sol-profiler" "^4.1.27" + "@0x/sol-trace" "^3.0.37" + "@0x/subproviders" "^6.5.3" + "@0x/types" "^3.3.3" + "@0x/typescript-typings" "^5.2.0" + "@0x/utils" "^6.4.3" + "@0x/web3-wrapper" "^7.5.3" + "@types/bn.js" "^4.11.0" + "@types/js-combinatorics" "^0.5.29" + "@types/lodash" "4.14.104" + "@types/mocha" "^5.2.7" + "@types/node" "12.12.54" + bn.js "^4.11.8" + chai "^4.0.1" + chai-as-promised "^7.1.0" + chai-bignumber "^3.0.0" + decimal.js "^10.2.0" + dirty-chai "^2.0.1" + ethereum-types "^3.5.0" + ethereumjs-util "^7.0.10" + ethers "~4.0.4" + js-combinatorics "^0.5.3" lodash "^4.17.11" - reflect-metadata "^0.1.10" - sqlite3 "^4.0.2" - typeorm "0.2.7" - websocket "^1.0.25" + make-promises-safe "^1.1.0" + mocha "^6.2.0" + +"@0x/contracts-utils@^4.7.15": + version "4.7.15" + resolved "https://registry.yarnpkg.com/@0x/contracts-utils/-/contracts-utils-4.7.15.tgz#f3f150b190b78c99f45caa34edcff98f6c002d1c" + dependencies: + "@0x/base-contract" "^6.4.0" + "@0x/typescript-typings" "^5.2.0" + "@0x/utils" "^6.4.3" + bn.js "^4.11.8" + ethereum-types "^3.5.0" "@0x/dev-utils@^4.2.7": version "4.2.7" resolved "https://registry.yarnpkg.com/@0x/dev-utils/-/dev-utils-4.2.7.tgz#9c85a134cace5a423a75221241fd687df81f3bbc" - integrity sha512-jblw/3Hpfw5E2cHTyJxbRcHsCYSCLsTOMvitbo+f/SX61HOvjXGO+T0sxy7l2d3HPu8lXaDywoZTt56ooF5EiQ== dependencies: "@0x/subproviders" "^6.5.3" "@0x/types" "^3.3.3" @@ -783,15 +946,6 @@ lodash "^4.17.11" web3-provider-engine "14.0.6" -"@0x/json-schemas@^5.0.1", "@0x/json-schemas@^5.3.3": - version "5.3.3" - resolved "https://registry.yarnpkg.com/@0x/json-schemas/-/json-schemas-5.3.3.tgz#4b9de100385ca23b0cd58a454165df2e9758e453" - dependencies: - "@0x/typescript-typings" "^5.1.5" - "@types/node" "12.12.54" - jsonschema "^1.2.0" - lodash.values "^4.3.0" - "@0x/json-schemas@^5.4.1": version "5.4.1" resolved "https://registry.yarnpkg.com/@0x/json-schemas/-/json-schemas-5.4.1.tgz#488cae01fbb7f37fa9043e426f52ff32de69f6e0" @@ -825,7 +979,6 @@ "@0x/monorepo-scripts@^3.1.7": version "3.1.7" resolved "https://registry.yarnpkg.com/@0x/monorepo-scripts/-/monorepo-scripts-3.1.7.tgz#17e719b9e26875958562532ed705cd770d107a43" - integrity sha512-Us3Rn77cIFWXTkenJFoMA71TXW0WaHIcypwGZ5KaGAtItAm9sEy/DUwYTCc0Wyb1C+5QdOTwL5Cmif0N3C2f9w== dependencies: "@0x/types" "^3.3.3" "@0x/utils" "^6.4.3" @@ -850,10 +1003,23 @@ typedoc "~0.16.11" yargs "^10.0.3" +"@0x/order-utils@^10.2.4", "@0x/order-utils@^10.4.27", "@0x/order-utils@^10.4.28": + version "10.4.28" + resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-10.4.28.tgz#c7b2f7d87a7f9834f9aa6186fbac68f32a05a81d" + dependencies: + "@0x/assert" "^3.0.27" + "@0x/contract-addresses" "^6.6.0" + "@0x/contract-wrappers" "^13.17.4" + "@0x/json-schemas" "^6.1.3" + "@0x/utils" "^6.4.3" + "@0x/web3-wrapper" "^7.5.3" + ethereumjs-util "^7.0.10" + ethers "~4.0.4" + lodash "^4.17.11" + "@0x/quote-server@^6.0.2": version "6.0.2" resolved "https://registry.yarnpkg.com/@0x/quote-server/-/quote-server-6.0.2.tgz#cb99e00c737e0f97a2a32bc7e7be6db65243c3af" - integrity sha512-SS5LfAgKSRjEszWVZl5UtRDBkrsqAvYn/lPB4hxtKky8XitClUYFQ2pSnrFuyQSVft3tFxH4p7eC65YQN5wkcA== dependencies: "@0x/json-schemas" "^6.0.1" "@0x/order-utils" "^10.2.4" @@ -867,7 +1033,6 @@ "@0x/sol-compiler@^4.7.3": version "4.7.3" resolved "https://registry.yarnpkg.com/@0x/sol-compiler/-/sol-compiler-4.7.3.tgz#d994661bc9c06a0a63b0e2f77ee6511d3cef488e" - integrity sha512-JNbdD9BgVDMFUvLX4Lb8JLLukF5svLoqk0WNaNz3LmOiZv7yPHOkI1XugR8XmG6Mr/YUEfCGk6u/VQF+1rCo5w== dependencies: "@0x/assert" "^3.0.27" "@0x/json-schemas" "^6.1.3" @@ -896,7 +1061,6 @@ "@0x/sol-coverage@^4.0.37": version "4.0.37" resolved "https://registry.yarnpkg.com/@0x/sol-coverage/-/sol-coverage-4.0.37.tgz#951363f1497cc65edf9bc76f37ac7824667e2c2b" - integrity sha512-TgluveJKVXbi+V5ib+0VX0n5tJN6V9g3V8GriwXwVK4HqCFBvAWqXs8CpFcmQr7OQxXy7T2EKfD4tvNdlloqJA== dependencies: "@0x/sol-tracing-utils" "^7.2.3" "@0x/subproviders" "^6.5.3" @@ -911,7 +1075,6 @@ "@0x/sol-profiler@^4.1.27": version "4.1.27" resolved "https://registry.yarnpkg.com/@0x/sol-profiler/-/sol-profiler-4.1.27.tgz#2bd14882dd204a7465b494149877daa16d86208d" - integrity sha512-5pDdQC1WMnpaObfuWo8kQuQ0UTb6VhlD1nuflHarI7F/AsH6M4DRGrrcRw904q1ZOpyODrGuvgpY8qxXqcQRRQ== dependencies: "@0x/sol-tracing-utils" "^7.2.3" "@0x/subproviders" "^6.5.3" @@ -935,7 +1098,6 @@ "@0x/sol-trace@^3.0.37": version "3.0.37" resolved "https://registry.yarnpkg.com/@0x/sol-trace/-/sol-trace-3.0.37.tgz#915a1c7c4869f9a95994fdb24878997d5bc39450" - integrity sha512-o7tkp3uoEWM9cT4PLiQKysmT285TEpMKLCup1uIjGutUNtWOTeLel8Lr5Z5KweuHqIolwLVpHyCwV2MbWp0DFg== dependencies: "@0x/sol-tracing-utils" "^7.2.3" "@0x/subproviders" "^6.5.3" @@ -951,7 +1113,6 @@ "@0x/sol-tracing-utils@^7.2.3": version "7.2.3" resolved "https://registry.yarnpkg.com/@0x/sol-tracing-utils/-/sol-tracing-utils-7.2.3.tgz#2a24969943315af4f86ceab12ad8bc34433069e5" - integrity sha512-htXf69MXo6gZ5+LK/2VkoitJyZ88e+zkR3OH+DkoIiPCOhAh+72m9Vw7Ozkb8pqXuxENllBHB/s1ZmNsXJimNg== dependencies: "@0x/dev-utils" "^4.2.7" "@0x/sol-compiler" "^4.7.3" @@ -976,38 +1137,9 @@ solc "^0.5.5" solidity-parser-antlr "^0.4.2" -"@0x/subproviders@^6.0.1": - version "6.1.9" - resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.1.9.tgz#9cf4f57576ba03c2c077d0d32816baa20c191a13" - dependencies: - "@0x/assert" "^3.0.17" - "@0x/types" "^3.3.0" - "@0x/typescript-typings" "^5.1.5" - "@0x/utils" "^6.1.0" - "@0x/web3-wrapper" "^7.2.8" - "@ledgerhq/hw-app-eth" "^4.3.0" - "@ledgerhq/hw-transport-u2f" "4.24.0" - "@types/hdkey" "^0.7.0" - "@types/node" "12.12.54" - "@types/web3-provider-engine" "^14.0.0" - bip39 "^2.5.0" - bn.js "^4.11.8" - ethereum-types "^3.3.3" - ethereumjs-tx "^1.3.5" - ethereumjs-util "^5.1.1" - ganache-core "^2.10.2" - hdkey "^0.7.1" - json-rpc-error "2.0.0" - lodash "^4.17.11" - semaphore-async-await "^1.5.1" - web3-provider-engine "14.0.6" - optionalDependencies: - "@ledgerhq/hw-transport-node-hid" "^4.3.0" - "@0x/subproviders@^6.5.3": version "6.5.3" resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.5.3.tgz#aec86903527c8f972beec1bc2fbda5fdba361235" - integrity sha512-Qg1T7NaiMiEU+mIOojcSCRM2aQKrVB4pc6ghfoBtIkLE1Bv9Tnnxu7EQmvLPoa43rZsZ98j9q1AGEt2kOlaD4w== dependencies: "@0x/assert" "^3.0.27" "@0x/types" "^3.3.3" @@ -1058,14 +1190,6 @@ tslint-react "^3.2.0" tsutils "3.0.0" -"@0x/types@^3.1.0", "@0x/types@^3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@0x/types/-/types-3.3.0.tgz#98c5ee91b66c7cc1719cfece6c3e5477c90bf9c5" - dependencies: - "@types/node" "12.12.54" - bignumber.js "~9.0.0" - ethereum-types "^3.3.3" - "@0x/types@^3.1.2", "@0x/types@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@0x/types/-/types-3.3.1.tgz#24f3f805d89c1235602abbef12bbeb7e92db9d63" @@ -1074,6 +1198,14 @@ bignumber.js "~9.0.0" ethereum-types "^3.4.0" +"@0x/types@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@0x/types/-/types-3.3.0.tgz#98c5ee91b66c7cc1719cfece6c3e5477c90bf9c5" + dependencies: + "@types/node" "12.12.54" + bignumber.js "~9.0.0" + ethereum-types "^3.3.3" + "@0x/types@^3.3.3": version "3.3.3" resolved "https://registry.yarnpkg.com/@0x/types/-/types-3.3.3.tgz#5df4ec381bba9f62441474b0e54309ddb2fccd17" @@ -1082,7 +1214,7 @@ bignumber.js "~9.0.0" ethereum-types "^3.5.0" -"@0x/typescript-typings@^5.0.0", "@0x/typescript-typings@^5.0.1", "@0x/typescript-typings@^5.1.5": +"@0x/typescript-typings@^5.0.1", "@0x/typescript-typings@^5.1.5": version "5.1.5" resolved "https://registry.yarnpkg.com/@0x/typescript-typings/-/typescript-typings-5.1.5.tgz#dd0ad20ef42dad9d054886fd1da72839145b5863" dependencies: @@ -1115,7 +1247,7 @@ ethereum-types "^3.5.0" popper.js "1.14.3" -"@0x/utils@^5.1.0", "@0x/utils@^5.1.1", "@0x/utils@^5.4.0", "@0x/utils@^5.4.1": +"@0x/utils@^5.1.1", "@0x/utils@^5.4.0", "@0x/utils@^5.4.1": version "5.6.4" resolved "https://registry.yarnpkg.com/@0x/utils/-/utils-5.6.4.tgz#0158ec3243bbee444d90afbd79981321d19ccdfd" dependencies: @@ -1133,24 +1265,6 @@ js-sha3 "^0.7.0" lodash "^4.17.11" -"@0x/utils@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@0x/utils/-/utils-6.1.0.tgz#df5750927d8e2b82f6709d666e7fcfca0f33f66e" - dependencies: - "@0x/types" "^3.3.0" - "@0x/typescript-typings" "^5.1.5" - "@types/node" "12.12.54" - abortcontroller-polyfill "^1.1.9" - bignumber.js "~9.0.0" - chalk "^2.3.0" - detect-node "2.0.3" - ethereum-types "^3.3.3" - ethereumjs-util "^5.1.1" - ethers "~4.0.4" - isomorphic-fetch "2.2.1" - js-sha3 "^0.7.0" - lodash "^4.17.11" - "@0x/utils@^6.2.0": version "6.2.0" resolved "https://registry.yarnpkg.com/@0x/utils/-/utils-6.2.0.tgz#07708d87691ac260163c01713ffac7a7f8e4c795" @@ -1188,20 +1302,6 @@ js-sha3 "^0.7.0" lodash "^4.17.11" -"@0x/web3-wrapper@^7.2.8": - version "7.2.8" - resolved "https://registry.yarnpkg.com/@0x/web3-wrapper/-/web3-wrapper-7.2.8.tgz#7df4c52e358594338f8dbe76b1490a5c4c423633" - dependencies: - "@0x/assert" "^3.0.17" - "@0x/json-schemas" "^5.3.3" - "@0x/typescript-typings" "^5.1.5" - "@0x/utils" "^6.1.0" - "@types/node" "12.12.54" - ethereum-types "^3.3.3" - ethereumjs-util "^5.1.1" - ethers "~4.0.4" - lodash "^4.17.11" - "@0x/web3-wrapper@^7.5.3": version "7.5.3" resolved "https://registry.yarnpkg.com/@0x/web3-wrapper/-/web3-wrapper-7.5.3.tgz#f36c3a2e5ffcbca2b3deef1a15e7485eb91dba7e" @@ -1222,10 +1322,6 @@ dependencies: npm-registry-client "7.0.9" -"@azure/core-asynciterator-polyfill@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz#dcccebb88406e5c76e0e1d52e8cc4c43a68b3ee7" - "@babel/code-frame@^7.0.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" @@ -1244,13 +1340,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/polyfill@^7.0.0": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" - dependencies: - core-js "^2.6.5" - regenerator-runtime "^0.13.4" - "@babel/runtime@7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205" @@ -1639,7 +1728,6 @@ "@jest/types@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^1.1.1" @@ -2592,19 +2680,16 @@ "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" - integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== "@types/istanbul-lib-report@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^1.1.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" @@ -2633,12 +2718,6 @@ version "5.2.7" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" -"@types/nock@^10.0.3": - version "10.0.3" - resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.3.tgz#dab1d18ffbccfbf2db811dab9584304eeb6e1c4c" - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@>= 8": version "14.14.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.6.tgz#146d3da57b3c636cc0d1769396ce1cfa8991147f" @@ -2704,10 +2783,6 @@ dependencies: "@types/node" "*" -"@types/seedrandom@^2.4.28": - version "2.4.28" - resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.28.tgz#9ce8fa048c1e8c85cb71d7fe4d704e000226036f" - "@types/serve-static@*": version "1.13.6" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.6.tgz#866b1b8dec41c36e28c7be40ac725b88be43c5c1" @@ -2736,7 +2811,6 @@ "@types/yargs-parser@*": version "20.2.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" - integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA== "@types/yargs@^11.0.0": version "11.1.7" @@ -2745,7 +2819,6 @@ "@types/yargs@^13.0.0": version "13.0.11" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.11.tgz#def2f0c93e4bdf2c61d7e34899b17e34be28d3b1" - integrity sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ== dependencies: "@types/yargs-parser" "*" @@ -2926,13 +2999,6 @@ any-promise@1.3.0, any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - anymatch@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" @@ -2944,10 +3010,6 @@ app-module-path@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" -app-root-path@^2.0.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" - append-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" @@ -3015,10 +3077,6 @@ array-differ@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-2.1.0.tgz#4b9c1c3f14b906757082925769e8ab904f4801b1" -array-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" - array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -3107,10 +3165,6 @@ async-child-process@^1.1.1: dependencies: babel-runtime "^6.11.6" -async-each@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - async-eventemitter@^0.2.2: version "0.2.4" resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" @@ -3121,14 +3175,6 @@ async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" -async@0.2.9: - version "0.2.9" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.9.tgz#df63060fbf3d33286a76aaf6d55a2986d9ff8619" - -async@0.2.x, async@~0.2.9: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - async@1.x, async@^1.4.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -3165,12 +3211,6 @@ atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" -available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" - dependencies: - array-filter "^1.0.0" - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -3725,10 +3765,6 @@ bignumber.js@~4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - binary-extensions@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" @@ -3810,7 +3846,7 @@ bn.js@^5.1.1, bn.js@^5.1.2: version "5.1.3" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" -body-parser@1.19.0, body-parser@^1.16.0, body-parser@^1.18.3: +body-parser@1.19.0, body-parser@^1.16.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" dependencies: @@ -3861,24 +3897,10 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" -broadway@~0.3.2, broadway@~0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/broadway/-/broadway-0.3.6.tgz#7dbef068b954b7907925fd544963b578a902ba7a" - dependencies: - cliff "0.1.9" - eventemitter2 "0.4.14" - nconf "0.6.9" - utile "0.2.1" - winston "0.8.0" - brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" -browser-stdout@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" - browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -4012,7 +4034,7 @@ buffer-xor@^2.0.1: dependencies: safe-buffer "^5.1.1" -buffer@^5.0.5, buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: version "5.7.0" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.0.tgz#88afbd29fc89fa7b58e82b39206f31f2cf34feed" dependencies: @@ -4141,12 +4163,6 @@ caller-path@^2.0.0: dependencies: caller-callsite "^2.0.0" -caller@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/caller/-/caller-0.0.1.tgz#f37a1d6ea10e829d94721ae29a90bb4fb52ab767" - dependencies: - tape "~2.3.2" - callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" @@ -4215,7 +4231,7 @@ chai-bignumber@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/chai-bignumber/-/chai-bignumber-3.0.0.tgz#e90cf1f468355bbb11a9acd051222586cd2648a9" -chai@^4.0.1, chai@^4.1.2: +chai@^4.0.1: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" dependencies: @@ -4226,7 +4242,7 @@ chai@^4.0.1, chai@^4.1.2: pathval "^1.1.0" type-detect "^4.0.5" -chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -4236,7 +4252,7 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" dependencies: @@ -4309,21 +4325,6 @@ chokidar@3.4.2: optionalDependencies: fsevents "~2.1.2" -chokidar@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - chokidar@^3.0.2: version "3.4.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" @@ -4402,16 +4403,6 @@ cli-format@^3.0.9: dependencies: string-width "^1.0.1" -cli-highlight@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-1.2.3.tgz#b200f97ed0e43d24633e89de0f489a48bb87d2bf" - dependencies: - chalk "^2.3.0" - highlight.js "^9.6.0" - mz "^2.4.0" - parse5 "^3.0.3" - yargs "^10.0.3" - cli-spinners@^1.0.1: version "1.3.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" @@ -4424,22 +4415,6 @@ cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" -cliff@0.1.9: - version "0.1.9" - resolved "https://registry.yarnpkg.com/cliff/-/cliff-0.1.9.tgz#a211e09c6a3de3ba1af27d049d301250d18812bc" - dependencies: - colors "0.x.x" - eyes "0.1.x" - winston "0.8.x" - -cliff@~0.1.9: - version "0.1.10" - resolved "https://registry.yarnpkg.com/cliff/-/cliff-0.1.10.tgz#53be33ea9f59bec85609ee300ac4207603e52013" - dependencies: - colors "~1.0.3" - eyes "~0.1.8" - winston "0.8.x" - cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -4547,11 +4522,7 @@ color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" -colors@0.6.x, colors@0.x.x, colors@~0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - -colors@1.0.x, colors@~1.0.3: +colors@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" @@ -4600,10 +4571,6 @@ command-line-usage@^6.1.0: table-layout "^1.0.1" typical "^5.2.0" -commander@2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - commander@2.18.0: version "2.18.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" @@ -4802,7 +4769,7 @@ core-js-pure@^3.0.1: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" -core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: +core-js@^2.4.0, core-js@^2.5.0: version "2.6.11" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" @@ -4810,7 +4777,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cors@^2.8.1, cors@^2.8.5: +cors@^2.8.1: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" dependencies: @@ -4908,7 +4875,6 @@ cross-fetch@^2.1.0, cross-fetch@^2.1.1: cross-fetch@^3.0.6: version "3.1.4" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" - integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== dependencies: node-fetch "2.6.1" @@ -5010,7 +4976,7 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@3.2.6, debug@^3.1.0, debug@^3.2.6: +debug@3.2.6, debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" dependencies: @@ -5028,7 +4994,7 @@ debug@4.1.1: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0: +debug@^4.0.1: version "4.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" dependencies: @@ -5127,26 +5093,11 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" -deep-equal@*: - version "2.0.4" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.4.tgz#6b0b407a074666033169df3acaf128e1c6f3eab6" - dependencies: - es-abstract "^1.18.0-next.1" - es-get-iterator "^1.1.0" - is-arguments "^1.0.4" - is-date-object "^1.0.2" - is-regex "^1.1.1" - isarray "^2.0.5" - object-is "^1.1.3" - object-keys "^1.1.1" - object.assign "^4.1.1" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.3" - which-boxed-primitive "^1.0.1" - which-collection "^1.0.1" - which-typed-array "^1.1.2" +deep-equal@~0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" -deep-equal@^1.0.0, deep-equal@~1.1.1: +deep-equal@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" dependencies: @@ -5157,14 +5108,6 @@ deep-equal@^1.0.0, deep-equal@~1.1.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" -deep-equal@~0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.1.2.tgz#b246c2b80a570a47c11be1d9bd1070ec878b87ce" - -deep-equal@~0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" - deep-extend@^0.6.0, deep-extend@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -5227,10 +5170,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" - defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -5283,7 +5222,7 @@ detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" -detect-libc@^1.0.2, detect-libc@^1.0.3: +detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" @@ -5298,10 +5237,6 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -diff@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" - diff@3.5.0, diff@^3.1.0, diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -5328,10 +5263,6 @@ dir-to-object@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dir-to-object/-/dir-to-object-2.0.0.tgz#29723e9bd1c3e58e4f307bd04ff634c0370c8f8a" -director@1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/director/-/director-1.2.7.tgz#bfd3741075fd7fb1a5b2e13658c5f4bec77736f3" - dirty-chai@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-2.0.1.tgz#6b2162ef17f7943589da840abc96e75bda01aff3" @@ -5371,10 +5302,6 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" -dotenv@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" - dotignore@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" @@ -5542,7 +5469,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.17.5: +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4: version "1.17.7" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" dependencies: @@ -5579,7 +5506,7 @@ es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" -es-get-iterator@^1.0.2, es-get-iterator@^1.1.0: +es-get-iterator@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8" dependencies: @@ -5873,17 +5800,6 @@ eth-sig-util@^1.4.2: ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" ethereumjs-util "^5.1.1" -eth-sig-util@^2.0.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-2.5.3.tgz#6938308b38226e0b3085435474900b03036abcbe" - dependencies: - buffer "^5.2.1" - elliptic "^6.4.0" - ethereumjs-abi "0.6.5" - ethereumjs-util "^5.1.1" - tweetnacl "^1.0.0" - tweetnacl-util "^0.15.0" - eth-tx-summary@^3.1.2: version "3.2.4" resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" @@ -6051,7 +5967,7 @@ ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.1, ethereumjs-tx@^2.1.2: ethereumjs-common "^1.5.0" ethereumjs-util "^6.0.0" -ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3, ethereumjs-tx@^1.3.5: +ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3: version "1.3.7" resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" dependencies: @@ -6126,6 +6042,17 @@ ethereumjs-util@^7.0.2: ethjs-util "0.1.6" rlp "^2.2.4" +ethereumjs-util@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz#e2b43a30bfcdbcb432a4eb42bd5f2393209b3fd5" + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.4" + ethereumjs-vm@4.2.0, ethereumjs-vm@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.2.0.tgz#e885e861424e373dbc556278f7259ff3fca5edab" @@ -6219,16 +6146,6 @@ ethjs-util@0.1.6, ethjs-util@^0.1.3: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" -event-stream@~0.5: - version "0.5.3" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-0.5.3.tgz#b77b9309f7107addfeab63f0c0eafd8db0bd8c1c" - dependencies: - optimist "0.2" - -eventemitter2@0.4.14, eventemitter2@~0.4.14: - version "0.4.14" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" - eventemitter3@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -6316,7 +6233,7 @@ express-async-handler@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/express-async-handler/-/express-async-handler-1.1.4.tgz#225a84908df63b35ae9df94b6f0f1af061266426" -express@^4.14.0, express@^4.16.3, express@^4.17.1: +express@^4.14.0, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" dependencies: @@ -6411,7 +6328,6 @@ extract-comments@^1.1.0: extract-files@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" - integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== extsprintf@1.3.0: version "1.3.0" @@ -6421,7 +6337,7 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" -eyes@0.1.x, eyes@~0.1.8: +eyes@0.1.x: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" @@ -6482,10 +6398,6 @@ figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" -figlet@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.0.tgz#2db4d00a584e5155a96080632db919213c3e003c" - figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -6629,15 +6541,6 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" -flatiron@~0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/flatiron/-/flatiron-0.4.3.tgz#248cf79a3da7d7dc379e2a11c92a2719cbb540f6" - dependencies: - broadway "~0.3.2" - director "1.2.7" - optimist "0.6.0" - prompt "0.2.14" - flatted@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" @@ -6673,10 +6576,6 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - foreground-child@^1.5.3, foreground-child@^1.5.6: version "1.5.6" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" @@ -6688,40 +6587,9 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" -forever-monitor@~1.7.0: - version "1.7.2" - resolved "https://registry.yarnpkg.com/forever-monitor/-/forever-monitor-1.7.2.tgz#ea8aad548eaab4a7e1fd193da80a4d577e4b29ee" - dependencies: - broadway "~0.3.6" - chokidar "^1.7.0" - minimatch "~3.0.2" - ps-tree "0.0.x" - utile "^0.3.0" - -forever@^0.15.3: - version "0.15.3" - resolved "https://registry.yarnpkg.com/forever/-/forever-0.15.3.tgz#77d9d7e15fd2f511ad9d84a110c7dd8fc8ecebc2" - dependencies: - cliff "~0.1.9" - clone "^1.0.2" - colors "~0.6.2" - flatiron "~0.4.2" - forever-monitor "~1.7.0" - nconf "~0.6.9" - nssocket "~0.5.1" - object-assign "^3.0.0" - optimist "~0.6.0" - path-is-absolute "~1.0.0" - prettyjson "^1.1.2" - shush "^1.0.0" - timespan "~2.3.0" - utile "~0.2.1" - winston "~0.8.1" - form-data@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -6826,13 +6694,6 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - fsevents@~2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" @@ -6853,42 +6714,6 @@ ganache-cli@6.8.0-istanbul.0: source-map-support "0.5.12" yargs "13.2.4" -ganache-core@^2.10.2: - version "2.13.1" - resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.13.1.tgz#bf60399a2dd084e1090db91cbbc7ed3885dc01e4" - dependencies: - abstract-leveldown "3.0.0" - async "2.6.2" - bip39 "2.5.0" - cachedown "1.0.0" - clone "2.1.2" - debug "3.2.6" - encoding-down "5.0.4" - eth-sig-util "^2.0.0" - ethereumjs-abi "0.6.8" - ethereumjs-account "3.0.0" - ethereumjs-block "2.2.2" - ethereumjs-common "1.5.0" - ethereumjs-tx "2.1.2" - ethereumjs-util "6.2.1" - ethereumjs-vm "4.2.0" - heap "0.2.6" - keccak "3.0.1" - level-sublevel "6.6.4" - levelup "3.1.1" - lodash "4.17.20" - lru-cache "5.1.1" - merkle-patricia-tree "3.0.0" - patch-package "6.2.2" - seedrandom "3.0.1" - source-map-support "0.5.12" - tmp "0.1.0" - web3-provider-engine "14.2.1" - websocket "1.0.32" - optionalDependencies: - ethereumjs-wallet "0.6.5" - web3 "1.2.11" - ganache-core@^2.13.2: version "2.13.2" resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.13.2.tgz#27e6fc5417c10e6e76e2e646671869d7665814a3" @@ -7145,17 +6970,6 @@ glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" -glob@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -7268,7 +7082,6 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.1 graphql-request@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.4.0.tgz#3a400cd5511eb3c064b1873afb059196bbea9c2b" - integrity sha512-acrTzidSlwAj8wBNO7Q/UQHS8T+z5qRGquCQRv9J1InwR01BBWV9ObnoE+JS5nCCEj8wSGS0yrDXVDoRiKZuOg== dependencies: cross-fetch "^3.0.6" extract-files "^9.0.0" @@ -7277,11 +7090,6 @@ graphql-request@^3.4.0: graphql@^15.4.0: version "15.5.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5" - integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA== - -growl@1.10.3: - version "1.10.3" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" growl@1.10.5: version "1.10.5" @@ -7323,10 +7131,6 @@ has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -7415,10 +7219,6 @@ hdkey@^0.7.1: coinstring "^2.0.0" secp256k1 "^3.0.1" -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -7438,7 +7238,7 @@ heartbeats@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/heartbeats/-/heartbeats-5.0.1.tgz#c0d476151982e707faac49345143b9582de40cae" -highlight.js@^9.17.1, highlight.js@^9.6.0: +highlight.js@^9.17.1: version "9.18.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634" @@ -7508,7 +7308,7 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http-status-codes@^1.3.0, http-status-codes@^1.3.2, http-status-codes@^1.4.0: +http-status-codes@^1.3.2, http-status-codes@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" @@ -7543,7 +7343,7 @@ i@0.3.x: version "0.3.6" resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -7649,7 +7449,7 @@ inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@1.x.x, ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -7759,26 +7559,12 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e" - is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -7815,7 +7601,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1, is-date-object@^1.0.2: +is-date-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" @@ -7937,10 +7723,6 @@ is-negative-zero@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" -is-number-object@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -8063,15 +7845,6 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" -is-typed-array@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" - dependencies: - available-typed-arrays "^1.0.0" - es-abstract "^1.17.4" - foreach "^2.0.5" - has-symbols "^1.0.1" - is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -8100,14 +7873,6 @@ is-valid-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - -is-weakset@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" - is-windows@^1.0.0, is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -8243,7 +8008,6 @@ iterate-value@^1.0.0: jest-changed-files@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" - integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== dependencies: "@jest/types" "^24.9.0" execa "^1.0.0" @@ -8284,7 +8048,7 @@ js-yaml@3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@3.14.0, js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.7.0: +js-yaml@3.14.0, js-yaml@3.x, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.7.0: version "3.14.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" dependencies: @@ -8382,7 +8146,7 @@ jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" -jsonschema@^1.2.0, jsonschema@^1.2.4: +jsonschema@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" @@ -8457,10 +8221,6 @@ kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" -lazy@~1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" - lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -8772,7 +8532,7 @@ lodash.values@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" -lodash@4.17.20, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1: +lodash@4.17.20, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" @@ -9111,7 +8871,7 @@ methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.11: +micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -9202,7 +8962,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -9223,18 +8983,10 @@ minimist-options@^3.0.1: arrify "^1.0.1" is-plain-obj "^1.1.0" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@~1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -9297,12 +9049,6 @@ mkdirp@*, mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" -mkdirp@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - mkdirp@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" @@ -9345,21 +9091,6 @@ mocha@8.1.2: yargs-parser "13.1.2" yargs-unparser "1.6.1" -mocha@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" - dependencies: - browser-stdout "1.3.0" - commander "2.11.0" - debug "3.1.0" - diff "3.3.1" - escape-string-regexp "1.0.5" - glob "7.1.2" - growl "1.10.3" - he "1.1.1" - mkdirp "0.5.1" - supports-color "4.4.0" - mocha@^6.2.0: version "6.2.3" resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" @@ -9475,7 +9206,7 @@ mute-stream@0.0.8, mute-stream@~0.0.4: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" -mz@^2.4.0, mz@^2.5.0: +mz@^2.5.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" dependencies: @@ -9487,7 +9218,7 @@ nan@2.13.2: version "2.13.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" -nan@^2.12.1, nan@^2.13.2, nan@^2.14.0, nan@^2.2.1: +nan@^2.13.2, nan@^2.14.0, nan@^2.2.1: version "2.14.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" @@ -9519,30 +9250,10 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -nconf@0.6.9, nconf@~0.6.9: - version "0.6.9" - resolved "https://registry.yarnpkg.com/nconf/-/nconf-0.6.9.tgz#9570ef15ed6f9ae6b2b3c8d5e71b66d3193cd661" - dependencies: - async "0.2.9" - ini "1.x.x" - optimist "0.6.0" - -ncp@0.4.x: - version "0.4.2" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.4.2.tgz#abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574" - ncp@1.0.x: version "1.0.1" resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" -needle@^2.2.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.5.2.tgz#cf1a8fce382b5a280108bba90a14993c00e4010a" - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -9594,20 +9305,6 @@ no-case@^2.2.0, no-case@^2.3.2: dependencies: lower-case "^1.1.1" -nock@^10.0.6: - version "10.0.6" - resolved "https://registry.yarnpkg.com/nock/-/nock-10.0.6.tgz#e6d90ee7a68b8cfc2ab7f6127e7d99aa7d13d111" - dependencies: - chai "^4.1.2" - debug "^4.1.0" - deep-equal "^1.0.0" - json-stringify-safe "^5.0.1" - lodash "^4.17.5" - mkdirp "^0.5.0" - propagate "^1.0.0" - qs "^6.5.1" - semver "^5.5.0" - node-abi@^2.7.0: version "2.19.1" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.19.1.tgz#6aa32561d0a5e2fdb6810d8c25641b657a8cea85" @@ -9680,21 +9377,6 @@ node-hid@^0.7.9: nan "^2.13.2" prebuild-install "^5.3.0" -node-pre-gyp@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - noop-logger@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" @@ -9727,7 +9409,7 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -9790,7 +9472,7 @@ npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: semver "^5.6.0" validate-npm-package-name "^3.0.0" -npm-packlist@^1.1.6, npm-packlist@^1.4.4: +npm-packlist@^1.4.4: version "1.4.8" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" dependencies: @@ -9845,7 +9527,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2: +npmlog@^4.0.1, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -9862,13 +9544,6 @@ npmlog@~2.0.0: are-we-there-yet "~1.1.2" gauge "~1.2.5" -nssocket@~0.5.1: - version "0.5.3" - resolved "https://registry.yarnpkg.com/nssocket/-/nssocket-0.5.3.tgz#883ca2ec605f5ed64a4d5190b2625401928f8f8d" - dependencies: - eventemitter2 "~0.4.14" - lazy "~1.0.11" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -9916,10 +9591,6 @@ oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -9940,7 +9611,7 @@ object-inspect@~1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" -object-is@^1.0.1, object-is@^1.1.3: +object-is@^1.0.1: version "1.1.3" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81" dependencies: @@ -10033,26 +9704,6 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -optimist@0.2: - version "0.2.8" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.2.8.tgz#e981ab7e268b457948593b55674c099a815cac31" - dependencies: - wordwrap ">=0.0.1 <0.1.0" - -optimist@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.0.tgz#69424826f3405f79f142e6fc3d9ae58d4dbb9200" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -optimist@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - optionator@^0.8.1, optionator@^0.8.2: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -10251,10 +9902,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parent-require@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" - parse-asn1@^5.0.0, parse-asn1@^5.1.5: version "5.1.6" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" @@ -10324,12 +9971,6 @@ parse-url@^5.0.0: parse-path "^4.0.0" protocols "^1.4.0" -parse5@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" - dependencies: - "@types/node" "*" - parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -10386,7 +10027,7 @@ path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1, path-is-absolute@~1.0.0: +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -10582,7 +10223,6 @@ prettier-plugin-solidity@^1.0.0-alpha.4: prettier@1.19.1, prettier@^1.14.3, prettier@^1.16.3: version "1.19.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== prettier@^2.0.5: version "2.1.2" @@ -10595,13 +10235,6 @@ pretty-bytes@^1.0.4: get-stdin "^4.0.1" meow "^3.1.0" -prettyjson@^1.1.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" - dependencies: - colors "^1.1.2" - minimist "^1.2.0" - printj@~1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" @@ -10667,16 +10300,6 @@ promisify-child-process@^3.1.1: dependencies: "@babel/runtime" "^7.1.5" -prompt@0.2.14: - version "0.2.14" - resolved "https://registry.yarnpkg.com/prompt/-/prompt-0.2.14.tgz#57754f64f543fd7b0845707c818ece618f05ffdc" - dependencies: - pkginfo "0.x.x" - read "1.0.x" - revalidator "0.1.x" - utile "0.2.x" - winston "0.8.x" - prompt@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" @@ -10701,10 +10324,6 @@ promzard@^0.3.0: dependencies: read "1" -propagate@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/propagate/-/propagate-1.0.0.tgz#00c2daeedda20e87e3782b344adba1cddd6ad709" - proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -10730,12 +10349,6 @@ prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" -ps-tree@0.0.x: - version "0.0.3" - resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-0.0.3.tgz#dbf8d752a7fe22fa7d58635689499610e9276ddc" - dependencies: - event-stream "~0.5" - pseudomap@^1.0.1, pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -10859,10 +10472,6 @@ qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" -qs@^6.5.1: - version "6.9.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" - qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -11031,7 +10640,7 @@ read@1, read@1.0.x, read@~1.0.1, read@~1.0.5: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" dependencies: @@ -11078,14 +10687,6 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" -readdirp@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - readdirp@~3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" @@ -11129,10 +10730,6 @@ reduce-flatten@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" -reflect-metadata@^0.1.10, reflect-metadata@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - regenerate@^1.2.1: version "1.4.1" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" @@ -11166,7 +10763,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: +regexp.prototype.flags@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" dependencies: @@ -11449,10 +11046,6 @@ samsam@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50" -sax@>=0.6.0, sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - scrypt-js@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" @@ -11500,10 +11093,6 @@ seedrandom@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" -seedrandom@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" - seek-bzip@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" @@ -11687,13 +11276,6 @@ shelljs@^0.8.3: interpret "^1.0.0" rechoir "^0.6.2" -shush@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shush/-/shush-1.0.0.tgz#c27415a9e458f2fed39b27cf8eb37c003782b431" - dependencies: - caller "~0.0.1" - strip-json-comments "~0.1.1" - shx@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/shx/-/shx-0.2.2.tgz#0a304d020b0edf1306ad81570e80f0346df58a39" @@ -11702,13 +11284,6 @@ shx@^0.2.2: minimist "^1.2.0" shelljs "^0.7.3" -side-channel@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3" - dependencies: - es-abstract "^1.18.0-next.0" - object-inspect "^1.8.0" - signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -11977,13 +11552,6 @@ sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" -sqlite3@^4.0.2: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.2.0.tgz#49026d665e9fc4f922e56fb9711ba5b4c85c4901" - dependencies: - nan "^2.12.1" - node-pre-gyp "^0.11.0" - sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -12208,10 +11776,6 @@ strip-json-comments@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" -strip-json-comments@~0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-0.1.3.tgz#164c64e370a8a3cc00c9e01b539e569823f0ee54" - strong-log-transformer@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" @@ -12220,12 +11784,6 @@ strong-log-transformer@^2.0.0: minimist "^1.2.0" through "^2.3.4" -supports-color@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" - dependencies: - has-flag "^2.0.0" - supports-color@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" @@ -12338,17 +11896,6 @@ tape@^4.4.0, tape@^4.6.3: string.prototype.trim "~1.2.1" through "~2.3.8" -tape@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tape/-/tape-2.3.3.tgz#2e7ce0a31df09f8d6851664a71842e0ca5057af7" - dependencies: - deep-equal "~0.1.0" - defined "~0.0.0" - inherits "~2.0.1" - jsonify "~0.0.0" - resumer "~0.0.0" - through "~2.3.4" - tar-fs@^1.15.3: version "1.16.3" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" @@ -12389,7 +11936,7 @@ tar-stream@^2.0.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4, tar@^4.0.2, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: +tar@^4.0.2, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" dependencies: @@ -12508,10 +12055,6 @@ timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" -timespan@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" - title-case@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa" @@ -12827,24 +12370,6 @@ typemoq@^2.1.0: lodash "^4.17.4" postinstall-build "^5.0.1" -typeorm@0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.7.tgz#4bbbace80dc91b1303be13f42d44ebf01d1b2558" - dependencies: - app-root-path "^2.0.1" - buffer "^5.1.0" - chalk "^2.3.2" - cli-highlight "^1.2.3" - debug "^3.1.0" - dotenv "^5.0.1" - glob "^7.1.2" - js-yaml "^3.11.0" - mkdirp "^0.5.1" - reflect-metadata "^0.1.12" - xml2js "^0.4.17" - yargonaut "^1.1.2" - yargs "^11.1.0" - typescript@3.7.x: version "3.7.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" @@ -13071,18 +12596,7 @@ util.promisify@^1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.0" -utile@0.2.1, utile@0.2.x, utile@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/utile/-/utile-0.2.1.tgz#930c88e99098d6220834c356cbd9a770522d90d7" - dependencies: - async "~0.2.9" - deep-equal "*" - i "0.3.x" - mkdirp "0.x.x" - ncp "0.4.x" - rimraf "2.x.x" - -utile@0.3.x, utile@^0.3.0: +utile@0.3.x: version "0.3.0" resolved "https://registry.yarnpkg.com/utile/-/utile-0.3.0.tgz#1352c340eb820e4d8ddba039a4fbfaa32ed4ef3a" dependencies: @@ -13796,7 +13310,7 @@ webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" -websocket@1.0.32, websocket@^1.0.25, websocket@^1.0.31: +websocket@1.0.32, websocket@^1.0.31: version "1.0.32" resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.32.tgz#1f16ddab3a21a2d929dec1687ab21cfdc6d3dbb1" dependencies: @@ -13848,25 +13362,6 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" -which-boxed-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1" - dependencies: - is-bigint "^1.0.0" - is-boolean-object "^1.0.0" - is-number-object "^1.0.3" - is-string "^1.0.4" - is-symbol "^1.0.2" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -13875,17 +13370,6 @@ which-pm-runs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" -which-typed-array@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" - dependencies: - available-typed-arrays "^1.0.2" - es-abstract "^1.17.5" - foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" - which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -13910,29 +13394,6 @@ windows-release@^3.1.0: dependencies: execa "^1.0.0" -winston@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/winston/-/winston-0.8.0.tgz#61d0830fa699706212206b0a2b5ca69a93043668" - dependencies: - async "0.2.x" - colors "0.6.x" - cycle "1.0.x" - eyes "0.1.x" - pkginfo "0.3.x" - stack-trace "0.0.x" - -winston@0.8.x, winston@~0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/winston/-/winston-0.8.3.tgz#64b6abf4cd01adcaefd5009393b1d8e8bec19db0" - dependencies: - async "0.2.x" - colors "0.6.x" - cycle "1.0.x" - eyes "0.1.x" - isstream "0.1.x" - pkginfo "0.3.x" - stack-trace "0.0.x" - winston@2.1.x: version "2.1.1" resolved "https://registry.yarnpkg.com/winston/-/winston-2.1.1.tgz#3c9349d196207fd1bdff9d4bc43ef72510e3a12e" @@ -13949,10 +13410,6 @@ word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" -"wordwrap@>=0.0.1 <0.1.0", wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -14059,7 +13516,6 @@ ws@^5.1.1: wsrun@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-5.2.4.tgz#6eb6c3ccd3327721a8df073a5e3578fb0dea494e" - integrity sha512-akv3WtKBohdHsD/5uqhYRHw6GXeCXe87FsSg28Szq+2cpoqRW2SY4yPfm1D0za1cS6MgNy5hPgzS5SqYJaGUxg== dependencies: bluebird "^3.5.1" chalk "^2.3.0" @@ -14104,17 +13560,6 @@ xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: parse-headers "^2.0.0" xtend "^4.0.0" -xml2js@^0.4.17: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - xmlhttprequest@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" @@ -14153,14 +13598,6 @@ yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" -yargonaut@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" - dependencies: - chalk "^1.1.1" - figlet "^1.1.1" - parent-require "^1.0.0" - yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" @@ -14261,7 +13698,6 @@ yargs@13.2.4: yargs@13.3.2, yargs@^13.0.0, yargs@^13.3.0: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== dependencies: cliui "^5.0.0" find-up "^3.0.0" @@ -14291,23 +13727,6 @@ yargs@^10.0.3: y18n "^3.2.1" yargs-parser "^8.1.0" -yargs@^11.1.0: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766" - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^3.1.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^9.0.2" - yargs@^12.0.1: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"