diff --git a/contracts/zero-ex/.npmignore b/contracts/zero-ex/.npmignore new file mode 100644 index 0000000000..bdf2b8acbe --- /dev/null +++ b/contracts/zero-ex/.npmignore @@ -0,0 +1,10 @@ +# Blacklist all files +.* +* +# Whitelist lib +!lib/**/* +# Whitelist Solidity contracts +!contracts/src/**/* +# Blacklist tests in lib +/lib/test/* +# Package specific ignore diff --git a/contracts/zero-ex/CHANGELOG.json b/contracts/zero-ex/CHANGELOG.json new file mode 100644 index 0000000000..c6d63cc417 --- /dev/null +++ b/contracts/zero-ex/CHANGELOG.json @@ -0,0 +1,11 @@ +[ + { + "version": "0.1.0", + "changes": [ + { + "note": "Create this package", + "pr": 2540 + } + ] + } +] diff --git a/contracts/zero-ex/CHANGELOG.md b/contracts/zero-ex/CHANGELOG.md new file mode 100644 index 0000000000..1004e94271 --- /dev/null +++ b/contracts/zero-ex/CHANGELOG.md @@ -0,0 +1,6 @@ + + +CHANGELOG diff --git a/contracts/zero-ex/DEPLOYS.json b/contracts/zero-ex/DEPLOYS.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/contracts/zero-ex/DEPLOYS.json @@ -0,0 +1 @@ +[] diff --git a/contracts/zero-ex/README.md b/contracts/zero-ex/README.md new file mode 100644 index 0000000000..253807b3c7 --- /dev/null +++ b/contracts/zero-ex/README.md @@ -0,0 +1,65 @@ +## ERC20BridgeSampler + +This package contains contracts contracts for the ZeroEx extensible contract architecture. + +## Installation + +**Install** + +```bash +npm install @0x/contracts-zero-ex --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-zero-ex yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0x/contracts-zero-ex yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/contracts/zero-ex/compiler.json b/contracts/zero-ex/compiler.json new file mode 100644 index 0000000000..20f8637f21 --- /dev/null +++ b/contracts/zero-ex/compiler.json @@ -0,0 +1,27 @@ +{ + "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/zero-ex/contracts/src/ZeroEx.sol b/contracts/zero-ex/contracts/src/ZeroEx.sol new file mode 100644 index 0000000000..ed3965abe9 --- /dev/null +++ b/contracts/zero-ex/contracts/src/ZeroEx.sol @@ -0,0 +1,122 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; +import "./interfaces/IZeroExBootstrapper.sol"; +import "./storage/LibProxyStorage.sol"; +import "./errors/LibProxyRichErrors.sol"; + + +/// @dev An extensible proxy contract that serves as a universal entry point for +/// interacting with the 0x protocol. +contract ZeroEx { + + // solhint-disable separate-by-one-line-in-contract,indent,var-name-mixedcase + + using LibBytesV06 for bytes; + + /// @dev Construct this contract. + /// After constructing this contract, the deployer should call + /// `bootstrap()` to seed the initial feature set. + constructor() public { + // Set the `bootstrap()` caller to the deployer. + LibProxyStorage.getStorage().bootstrapCaller = msg.sender; + } + + // solhint-disable state-visibility + + /// @dev Forwards calls to the appropriate implementation contract. + fallback() external payable { + bytes4 selector = msg.data.readBytes4(0); + address impl = getFunctionImplementation(selector); + if (impl == address(0)) { + _revertWithData(LibProxyRichErrors.NotImplementedError(selector)); + } + + (bool success, bytes memory resultData) = impl.delegatecall(msg.data); + if (!success) { + _revertWithData(resultData); + } + _returnWithData(resultData); + } + + /// @dev Fallback for just receiving ether. + receive() external payable {} + + // solhint-enable state-visibility + + /// @dev Bootstrap the initial feature set of this contract. + /// This can only be called once by the deployer of this contract. + /// @param bootstrappers Array of bootstrapping contracts to delegatecall into. + function bootstrap(IZeroExBootstrapper[] calldata bootstrappers) external { + LibProxyStorage.Storage storage stor = LibProxyStorage.getStorage(); + + // If `bootstrapCaller` is zero, the contract has already been bootstrapped. + address bootstrapCaller = stor.bootstrapCaller; + if (bootstrapCaller == address(0)) { + _revertWithData(LibProxyRichErrors.AlreadyBootstrappedError()); + } + // Only the deployer caller can call this function. + if (bootstrapCaller != msg.sender) { + _revertWithData( + LibProxyRichErrors.InvalidBootstrapCallerError(msg.sender, bootstrapCaller) + ); + } + // Prevent calling `bootstrap()` again. + stor.bootstrapCaller = address(0); + + // Call the bootstrap contracts. + for (uint256 i = 0; i < bootstrappers.length; ++i) { + // Delegatecall into the bootstrap contract. + (bool success, bytes memory resultData) = address(bootstrappers[i]) + .delegatecall(abi.encodeWithSelector( + IZeroExBootstrapper.bootstrap.selector, + address(bootstrappers[i]) + )); + if (!success) { + _revertWithData(resultData); + } + } + } + + /// @dev Get the implementation contract of a registered function. + /// @param selector The function selector. + /// @return impl The implementation contract address. + function getFunctionImplementation(bytes4 selector) + public + view + returns (address impl) + { + return LibProxyStorage.getStorage().impls[selector]; + } + + /// @dev Revert with arbitrary bytes. + /// @param data Revert data. + function _revertWithData(bytes memory data) private pure { + assembly { revert(add(data, 32), mload(data)) } + } + + /// @dev Return with arbitrary bytes. + /// @param data Return data. + function _returnWithData(bytes memory data) private pure { + assembly { return(add(data, 32), mload(data)) } + } +} diff --git a/contracts/zero-ex/contracts/src/errors/LibCommonRichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibCommonRichErrors.sol new file mode 100644 index 0000000000..a0314db2ad --- /dev/null +++ b/contracts/zero-ex/contracts/src/errors/LibCommonRichErrors.sol @@ -0,0 +1,36 @@ +/* + + 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; + + +library LibCommonRichErrors { + + // solhint-disable func-name-mixedcase + + function OnlyCallableBySelfError(address sender) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("OnlyCallableBySelfError(address)")), + sender + ); + } +} diff --git a/contracts/zero-ex/contracts/src/errors/LibOwnableRichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibOwnableRichErrors.sol new file mode 100644 index 0000000000..6cb47072e6 --- /dev/null +++ b/contracts/zero-ex/contracts/src/errors/LibOwnableRichErrors.sol @@ -0,0 +1,50 @@ +/* + + 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; + + +library LibOwnableRichErrors { + + // solhint-disable func-name-mixedcase + + function OnlyOwnerError( + address sender, + address owner + ) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("OnlyOwnerError(address,address)")), + sender, + owner + ); + } + + function TransferOwnerToZeroError() + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("TransferOwnerToZeroError()")) + ); + } +} diff --git a/contracts/zero-ex/contracts/src/errors/LibProxyRichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibProxyRichErrors.sol new file mode 100644 index 0000000000..062e325ab5 --- /dev/null +++ b/contracts/zero-ex/contracts/src/errors/LibProxyRichErrors.sol @@ -0,0 +1,58 @@ +/* + + 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; + + +library LibProxyRichErrors { + + // solhint-disable func-name-mixedcase + + function NotImplementedError(bytes4 selector) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("NotImplementedError(bytes4)")), + selector + ); + } + + function AlreadyBootstrappedError() + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("AlreadyBootstrappedError()")) + ); + } + + function InvalidBootstrapCallerError(address caller, address expectedCaller) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("InvalidBootstrapCallerError(address,address)")), + caller, + expectedCaller + ); + } +} diff --git a/contracts/zero-ex/contracts/src/errors/LibSimpleFunctionRegistryRichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibSimpleFunctionRegistryRichErrors.sol new file mode 100644 index 0000000000..43117adfcb --- /dev/null +++ b/contracts/zero-ex/contracts/src/errors/LibSimpleFunctionRegistryRichErrors.sol @@ -0,0 +1,38 @@ +/* + + 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; + + +library LibSimpleFunctionRegistryRichErrors { + + // solhint-disable func-name-mixedcase + + function NoRollbackHistoryError( + bytes4 selector + ) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + bytes4(keccak256("NoRollbackHistoryError(bytes4)")), + selector + ); + } +} diff --git a/contracts/zero-ex/contracts/src/features/Ownable.sol b/contracts/zero-ex/contracts/src/features/Ownable.sol new file mode 100644 index 0000000000..5a77ba7b56 --- /dev/null +++ b/contracts/zero-ex/contracts/src/features/Ownable.sol @@ -0,0 +1,79 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../fixins/FixinOwnable.sol"; +import "../interfaces/IFeature.sol"; +import "../interfaces/IOwnable.sol"; +import "../interfaces/ISimpleFunctionRegistry.sol"; +import "../interfaces/IZeroExBootstrapper.sol"; +import "../errors/LibOwnableRichErrors.sol"; +import "../storage/LibOwnableStorage.sol"; + + +/// @dev Owner management features. +contract Ownable is + IFeature, + IOwnable, + IZeroExBootstrapper, + FixinOwnable +{ + // solhint-disable const-name-snakecase + + /// @dev Name of this feature. + string constant public override FEATURE_NAME = "Ownable"; + /// @dev Version of this feature. + uint256 constant public override FEATURE_VERSION = (1 << 64) | (0 << 32) | (0); + + /// @dev Initializes the authority feature. + /// @param impl The actual address of this feature contract. + function bootstrap(address impl) external override { + // Set the owner. + LibOwnableStorage.getStorage().owner = msg.sender; + + // Register feature functions. + ISimpleFunctionRegistry(address(this)).extendSelf(this.transferOwnership.selector, impl); + ISimpleFunctionRegistry(address(this)).extendSelf(this.getOwner.selector, impl); + } + + /// @dev Change the owner of this contract. + /// Only directly callable by the owner. + /// @param newOwner New owner address. + function transferOwnership(address newOwner) + external + override + onlyOwner + { + LibOwnableStorage.Storage storage proxyStor = LibOwnableStorage.getStorage(); + + if (newOwner == address(0)) { + _rrevert(LibOwnableRichErrors.TransferOwnerToZeroError()); + } else { + proxyStor.owner = newOwner; + emit OwnershipTransferred(msg.sender, newOwner); + } + } + + /// @dev Get the owner of this contract. + /// @return owner_ The owner of this contract. + function getOwner() external override view returns (address owner_) { + return LibOwnableStorage.getStorage().owner; + } +} diff --git a/contracts/zero-ex/contracts/src/features/SimpleFunctionRegistry.sol b/contracts/zero-ex/contracts/src/features/SimpleFunctionRegistry.sol new file mode 100644 index 0000000000..736d5f08ae --- /dev/null +++ b/contracts/zero-ex/contracts/src/features/SimpleFunctionRegistry.sol @@ -0,0 +1,139 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../interfaces/IFeature.sol"; +import "../interfaces/ISimpleFunctionRegistry.sol"; +import "../interfaces/IZeroExBootstrapper.sol"; +import "../fixins/FixinOwnable.sol"; +import "../storage/LibProxyStorage.sol"; +import "../storage/LibSimpleFunctionRegistryStorage.sol"; +import "../errors/LibSimpleFunctionRegistryRichErrors.sol"; + + +/// @dev Basic registry management features. +contract SimpleFunctionRegistry is + IFeature, + ISimpleFunctionRegistry, + IZeroExBootstrapper, + FixinOwnable +{ + // solhint-disable const-name-snakecase + + /// @dev Name of this feature. + string constant public override FEATURE_NAME = "SimpleFunctionRegistry"; + /// @dev Version of this feature. + uint256 constant public override FEATURE_VERSION = (1 << 64) | (0 << 32) | (0); + + /// @dev Initializes the feature implementation registry. + /// @param impl The actual address of this feature contract. + function bootstrap(address impl) external override { + // Register the registration functions (inception vibes). + _extend(this.extend.selector, impl); + _extend(this.extendSelf.selector, impl); + // Register the rollback function. + _extend(this.rollback.selector, impl); + } + + /// @dev Roll back to the last implementation of a function. + /// Only directly callable by an authority. + /// @param selector The function selector. + function rollback(bytes4 selector) + external + override + onlyOwner + { + ( + LibSimpleFunctionRegistryStorage.Storage storage stor, + LibProxyStorage.Storage storage proxyStor + ) = _getStorages(); + + address[] storage history = stor.implHistory[selector]; + if (history.length == 0) { + _rrevert( + LibSimpleFunctionRegistryRichErrors.NoRollbackHistoryError(selector) + ); + } + address impl = history[history.length - 1]; + address oldImpl = proxyStor.impls[selector]; + proxyStor.impls[selector] = impl; + history.pop(); + emit ProxyFunctionUpdated(selector, oldImpl, impl); + } + + /// @dev Register or replace a function. + /// Only directly callable by an authority. + /// @param selector The function selector. + /// @param impl The implementation contract for the function. + function extend(bytes4 selector, address impl) + external + override + onlyOwner + { + _extend(selector, impl); + } + + /// @dev Register or replace a function. + /// Only callable from within. + /// @param selector The function selector. + /// @param impl The implementation contract for the function. + function extendSelf(bytes4 selector, address impl) + external + override + onlySelf + { + _extend(selector, impl); + } + + /// @dev Register or replace a function. + /// @param selector The function selector. + /// @param impl The implementation contract for the function. + function _extend(bytes4 selector, address impl) + private + { + ( + LibSimpleFunctionRegistryStorage.Storage storage stor, + LibProxyStorage.Storage storage proxyStor + ) = _getStorages(); + + address oldImpl = proxyStor.impls[selector]; + address[] storage history = stor.implHistory[selector]; + history.push(oldImpl); + proxyStor.impls[selector] = impl; + emit ProxyFunctionUpdated(selector, oldImpl, impl); + } + + /// @dev Get the storage buckets for this feature and the proxy. + /// @return stor Storage bucket for this feature. + /// @return proxyStor age bucket for the proxy. + function _getStorages() + private + pure + returns ( + LibSimpleFunctionRegistryStorage.Storage storage stor, + LibProxyStorage.Storage storage proxyStor + ) + { + return ( + LibSimpleFunctionRegistryStorage.getStorage(), + LibProxyStorage.getStorage() + ); + } +} diff --git a/contracts/zero-ex/contracts/src/fixins/FixinCommon.sol b/contracts/zero-ex/contracts/src/fixins/FixinCommon.sol new file mode 100644 index 0000000000..d389e4280d --- /dev/null +++ b/contracts/zero-ex/contracts/src/fixins/FixinCommon.sol @@ -0,0 +1,43 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; +import "../storage/LibProxyStorage.sol"; +import "../errors/LibCommonRichErrors.sol"; + + +/// @dev Common utilities. +contract FixinCommon { + + /// @dev The caller must be this contract. + modifier onlySelf() { + if (msg.sender != address(this)) { + _rrevert(LibCommonRichErrors.OnlyCallableBySelfError(msg.sender)); + } + _; + } + + /// @dev Reverts with arbitrary data `errorData`. + /// @param errorData ABI encoded error data. + function _rrevert(bytes memory errorData) internal pure { + LibRichErrorsV06.rrevert(errorData); + } +} diff --git a/contracts/zero-ex/contracts/src/fixins/FixinOwnable.sol b/contracts/zero-ex/contracts/src/fixins/FixinOwnable.sol new file mode 100644 index 0000000000..e784d7883f --- /dev/null +++ b/contracts/zero-ex/contracts/src/fixins/FixinOwnable.sol @@ -0,0 +1,50 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../errors/LibOwnableRichErrors.sol"; +import "../storage/LibOwnableStorage.sol"; +import "./FixinCommon.sol"; + + +/// @dev A feature mixin for restricting callers to owners. +contract FixinOwnable is + FixinCommon +{ + /// @dev The caller of this function must be the owner. + modifier onlyOwner() { + { + address owner = _getOwner(); + if (msg.sender != owner) { + _rrevert(LibOwnableRichErrors.OnlyOwnerError( + msg.sender, + owner + )); + } + } + _; + } + + /// @dev Get the owner of this contract. + /// @return owner The owner of this contract. + function _getOwner() internal view returns (address owner) { + return LibOwnableStorage.getStorage().owner; + } +} diff --git a/contracts/zero-ex/contracts/src/interfaces/IFeature.sol b/contracts/zero-ex/contracts/src/interfaces/IFeature.sol new file mode 100644 index 0000000000..261f7708c4 --- /dev/null +++ b/contracts/zero-ex/contracts/src/interfaces/IFeature.sol @@ -0,0 +1,35 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../interfaces/IZeroExBootstrapper.sol"; + + +/// @dev Basic interface for a feature contract. +interface IFeature { + + // solhint-disable func-name-mixedcase + + /// @dev The name of this feature set. + function FEATURE_NAME() external view returns (string memory name); + + /// @dev The version of this feature set. + function FEATURE_VERSION() external view returns (uint256 version); +} diff --git a/contracts/zero-ex/contracts/src/interfaces/IOwnable.sol b/contracts/zero-ex/contracts/src/interfaces/IOwnable.sol new file mode 100644 index 0000000000..5f8ab8cb38 --- /dev/null +++ b/contracts/zero-ex/contracts/src/interfaces/IOwnable.sol @@ -0,0 +1,29 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-utils/contracts/src/v06/interfaces/IOwnableV06.sol"; + + +// solhint-disable no-empty-blocks +/// @dev Owner management features. +interface IOwnable is + IOwnableV06 +{} diff --git a/contracts/zero-ex/contracts/src/interfaces/ISimpleFunctionRegistry.sol b/contracts/zero-ex/contracts/src/interfaces/ISimpleFunctionRegistry.sol new file mode 100644 index 0000000000..5a769ec39f --- /dev/null +++ b/contracts/zero-ex/contracts/src/interfaces/ISimpleFunctionRegistry.sol @@ -0,0 +1,48 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../interfaces/IZeroExBootstrapper.sol"; + + +/// @dev Basic registry management features. +interface ISimpleFunctionRegistry { + + /// @dev A function implementation was updated via `extend()` or `rollback()`. + /// @param selector The function selector. + /// @param oldImpl The implementation contract address being replaced. + /// @param newImpl The replacement implementation contract address. + event ProxyFunctionUpdated(bytes4 indexed selector, address oldImpl, address newImpl); + + /// @dev Roll back to the last implementation of a function. + /// @param selector The function selector. + function rollback(bytes4 selector) external; + + /// @dev Register or replace a function. + /// @param selector The function selector. + /// @param impl The implementation contract for the function. + function extend(bytes4 selector, address impl) external; + + /// @dev Register or replace a function. + /// Only callable from within. + /// @param selector The function selector. + /// @param impl The implementation contract for the function. + function extendSelf(bytes4 selector, address impl) external; +} diff --git a/contracts/zero-ex/contracts/src/interfaces/IZeroExBootstrapper.sol b/contracts/zero-ex/contracts/src/interfaces/IZeroExBootstrapper.sol new file mode 100644 index 0000000000..4965ce22e9 --- /dev/null +++ b/contracts/zero-ex/contracts/src/interfaces/IZeroExBootstrapper.sol @@ -0,0 +1,32 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + + +/// @dev Interface for a bootstrapping contract that the `ZeroEx` proxy. +interface IZeroExBootstrapper { + + /// @dev Sets up the initial state of the `ZeroEx` contract. + /// The `ZeroEx` contract will delegatecall this function so the + /// bootstrapper should use this function to register initial + /// features. + /// @param impl The implementation contract. + function bootstrap(address impl) external; +} diff --git a/contracts/zero-ex/contracts/src/migrations/BasicMigration.sol b/contracts/zero-ex/contracts/src/migrations/BasicMigration.sol new file mode 100644 index 0000000000..27e7ef2094 --- /dev/null +++ b/contracts/zero-ex/contracts/src/migrations/BasicMigration.sol @@ -0,0 +1,70 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../ZeroEx.sol"; +import "../features/SimpleFunctionRegistry.sol"; +import "../features/Ownable.sol"; +import "../interfaces/IOwnable.sol"; +import "../interfaces/IZeroExBootstrapper.sol"; +import "../interfaces/ISimpleFunctionRegistry.sol"; + + +/// @dev A contract for deploying and configuring a minimal ZeroEx contract. +contract BasicMigration { + + /// @dev Deploy the `ZeroEx` contract with the minimum feature set. + /// @param owner The owner of the contract. + /// @return zeroEx The deployed and configured `ZeroEx` contract. + function migrate(address owner) external returns (ZeroEx zeroEx) { + // Deploy the ZeroEx contract. + zeroEx = new ZeroEx(); + + // Bootstrap the initial feature set. + zeroEx.bootstrap(_createBootstrappers()); + + // Disable the `extendSelf()` function by rolling it back to zero. + ISimpleFunctionRegistry(address(zeroEx)) + .rollback(ISimpleFunctionRegistry.extendSelf.selector); + + // Call the _postInitialize hook. + _postInitialize(zeroEx); + + // Transfer ownership. + if (owner != address(this)) { + IOwnable(address(zeroEx)).transferOwnership(owner); + } + } + + function _createBootstrappers() + internal + virtual + returns (IZeroExBootstrapper[] memory bootstrappers) + { + bootstrappers = new IZeroExBootstrapper[](2); + bootstrappers[0] = IZeroExBootstrapper(address(new SimpleFunctionRegistry())); + bootstrappers[1] = IZeroExBootstrapper(address(new Ownable())); + } + + // solhint-disable no-empty-blocks + function _postInitialize(ZeroEx zeroEx) internal virtual { + // Override me. + } +} diff --git a/contracts/zero-ex/contracts/src/storage/LibOwnableStorage.sol b/contracts/zero-ex/contracts/src/storage/LibOwnableStorage.sol new file mode 100644 index 0000000000..40f7159337 --- /dev/null +++ b/contracts/zero-ex/contracts/src/storage/LibOwnableStorage.sol @@ -0,0 +1,41 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + + +/// @dev Storage helpers for the `Ownable` feature. +library LibOwnableStorage { + + /// @dev Globally unique offset for the storage bucket. + bytes32 constant internal STORAGE_ID = + 0xeef73acb590dd70cb88ccc8e9832ea7f198de2f3c87ff92d610497d647795b3c; + + /// @dev Storage bucket for this feature. + struct Storage { + // The owner of this contract. + address owner; + } + + /// @dev Get the storage bucket for this contract. + function getStorage() internal pure returns (Storage storage stor) { + bytes32 storageId = STORAGE_ID; + assembly { stor_slot := storageId } + } +} diff --git a/contracts/zero-ex/contracts/src/storage/LibProxyStorage.sol b/contracts/zero-ex/contracts/src/storage/LibProxyStorage.sol new file mode 100644 index 0000000000..c579f3af1a --- /dev/null +++ b/contracts/zero-ex/contracts/src/storage/LibProxyStorage.sol @@ -0,0 +1,43 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + + +/// @dev Storage helpers for the proxy contract. +library LibProxyStorage { + + /// @dev Globally unique offset for the storage bucket. + bytes32 constant internal STORAGE_ID = + 0xd7434ab6df6fb6431870c66fc3fc3d21ddd20b029595942d9e0ffc950ce32f66; + + /// @dev Storage bucket for proxy contract. + struct Storage { + // The allowed caller for `bootstrap()`. + address bootstrapCaller; + // Mapping of function selector -> function implementation + mapping(bytes4 => address) impls; + } + + /// @dev Get the storage bucket for this contract. + function getStorage() internal pure returns (Storage storage stor) { + bytes32 storageId = STORAGE_ID; + assembly { stor_slot := storageId } + } +} diff --git a/contracts/zero-ex/contracts/src/storage/LibSimpleFunctionRegistryStorage.sol b/contracts/zero-ex/contracts/src/storage/LibSimpleFunctionRegistryStorage.sol new file mode 100644 index 0000000000..e288ed277c --- /dev/null +++ b/contracts/zero-ex/contracts/src/storage/LibSimpleFunctionRegistryStorage.sol @@ -0,0 +1,41 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + + +/// @dev Storage helpers for the `SimpleFunctionRegistry` feature. +library LibSimpleFunctionRegistryStorage { + + /// @dev Globally unique offset for the storage bucket. + bytes32 constant internal STORAGE_ID = + 0x9817e79514d088041d4834d6eb535f4fa107927bddb0f3c55c3e6b2bfe43daa5; + + /// @dev Storage bucket for this feature. + struct Storage { + // Mapping of function selector -> implementation history. + mapping(bytes4 => address[]) implHistory; + } + + /// @dev Get the storage bucket for this contract. + function getStorage() internal pure returns (Storage storage stor) { + bytes32 storageId = STORAGE_ID; + assembly { stor_slot := storageId } + } +} diff --git a/contracts/zero-ex/contracts/test/ITestSimpleFunctionRegistryFeature.sol b/contracts/zero-ex/contracts/test/ITestSimpleFunctionRegistryFeature.sol new file mode 100644 index 0000000000..f2fb4d7f96 --- /dev/null +++ b/contracts/zero-ex/contracts/test/ITestSimpleFunctionRegistryFeature.sol @@ -0,0 +1,25 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + + +interface ITestSimpleFunctionRegistryFeature { + function testFn() external view returns (uint256 id); +} diff --git a/contracts/zero-ex/contracts/test/TestBasicMigration.sol b/contracts/zero-ex/contracts/test/TestBasicMigration.sol new file mode 100644 index 0000000000..2a7a4e2229 --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestBasicMigration.sol @@ -0,0 +1,33 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../src/migrations/BasicMigration.sol"; +import "../src/interfaces/IZeroExBootstrapper.sol"; + + +contract TestBasicMigration is + BasicMigration +{ + function callBootstrap(ZeroEx zeroEx) external { + IZeroExBootstrapper[] memory bootstrappers; + zeroEx.bootstrap(bootstrappers); + } +} diff --git a/contracts/zero-ex/contracts/test/TestSimpleFunctionRegistryFeatureImpl1.sol b/contracts/zero-ex/contracts/test/TestSimpleFunctionRegistryFeatureImpl1.sol new file mode 100644 index 0000000000..30f64ae52a --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestSimpleFunctionRegistryFeatureImpl1.sol @@ -0,0 +1,35 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../src/fixins/FixinCommon.sol"; + + +contract TestSimpleFunctionRegistryFeatureImpl1 is + FixinCommon +{ + function testFn() + external + pure + returns (uint256 id) + { + return 1337; + } +} diff --git a/contracts/zero-ex/contracts/test/TestSimpleFunctionRegistryFeatureImpl2.sol b/contracts/zero-ex/contracts/test/TestSimpleFunctionRegistryFeatureImpl2.sol new file mode 100644 index 0000000000..ae8bc3e60c --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestSimpleFunctionRegistryFeatureImpl2.sol @@ -0,0 +1,35 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../src/fixins/FixinCommon.sol"; + + +contract TestSimpleFunctionRegistryFeatureImpl2 is + FixinCommon +{ + function testFn() + external + pure + returns (uint256 id) + { + return 1338; + } +} diff --git a/contracts/zero-ex/contracts/test/TestZeroExFeature.sol b/contracts/zero-ex/contracts/test/TestZeroExFeature.sol new file mode 100644 index 0000000000..65e5f128e6 --- /dev/null +++ b/contracts/zero-ex/contracts/test/TestZeroExFeature.sol @@ -0,0 +1,54 @@ +/* + + 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; +pragma experimental ABIEncoderV2; + +import "../src/fixins/FixinCommon.sol"; +import "../src/ZeroEx.sol"; + + +contract TestZeroExFeature is + FixinCommon +{ + event PayableFnCalled(uint256 value); + event NotPayableFnCalled(); + + function payableFn() + external + payable + { + emit PayableFnCalled(msg.value); + } + + function notPayableFn() + external + { + emit NotPayableFnCalled(); + } + + // solhint-disable no-empty-blocks + function unimplmentedFn() + external + {} + + function internalFn() + external + onlySelf + {} +} diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json new file mode 100644 index 0000000000..75b856a79e --- /dev/null +++ b/contracts/zero-ex/package.json @@ -0,0 +1,84 @@ +{ + "name": "@0x/contracts-zero-ex", + "version": "0.1.0", + "engines": { + "node": ">=6.12" + }, + "description": "Extensible contracts for interacting 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 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": "ZeroEx,IOwnable,ISimpleFunctionRegistry", + "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", + "abis": "./test/generated-artifacts/@(BasicMigration|FixinCommon|FixinOwnable|IFeature|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|IZeroExBootstrapper|LibCommonRichErrors|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|Ownable|SimpleFunctionRegistry|TestBasicMigration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestZeroExFeature|ZeroEx).json" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x-monorepo.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x-monorepo/issues" + }, + "homepage": "https://github.com/0xProject/0x-monorepo/contracts/zero-ex/README.md", + "devDependencies": { + "@0x/abi-gen": "^5.2.2", + "@0x/contracts-gen": "^2.0.8", + "@0x/contracts-test-utils": "^5.3.2", + "@0x/dev-utils": "^3.2.1", + "@0x/sol-compiler": "^4.0.8", + "@0x/subproviders": "^6.0.8", + "@0x/ts-doc-gen": "^0.0.22", + "@0x/tslint-config": "^4.0.0", + "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", + "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.15.0", + "typescript": "3.0.1" + }, + "dependencies": { + "@0x/base-contract": "^6.2.1", + "@0x/types": "^3.1.2", + "@0x/typescript-typings": "^5.0.2", + "@0x/utils": "^5.4.1", + "ethereum-types": "^3.1.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/contracts/zero-ex/src/artifacts.ts b/contracts/zero-ex/src/artifacts.ts new file mode 100644 index 0000000000..aa3ab07a57 --- /dev/null +++ b/contracts/zero-ex/src/artifacts.ts @@ -0,0 +1,15 @@ +/* + * ----------------------------------------------------------------------------- + * Warning: This file is auto-generated by contracts-gen. Don't edit manually. + * ----------------------------------------------------------------------------- + */ +import { ContractArtifact } from 'ethereum-types'; + +import * as IOwnable from '../generated-artifacts/IOwnable.json'; +import * as ISimpleFunctionRegistry from '../generated-artifacts/ISimpleFunctionRegistry.json'; +import * as ZeroEx from '../generated-artifacts/ZeroEx.json'; +export const artifacts = { + ZeroEx: ZeroEx as ContractArtifact, + IOwnable: IOwnable as ContractArtifact, + ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, +}; diff --git a/contracts/zero-ex/src/index.ts b/contracts/zero-ex/src/index.ts new file mode 100644 index 0000000000..9e2650968f --- /dev/null +++ b/contracts/zero-ex/src/index.ts @@ -0,0 +1,38 @@ +export { artifacts } from './artifacts'; +export { + IOwnableContract, + IOwnableEvents, + ISimpleFunctionRegistryContract, + ISimpleFunctionRegistryEvents, + ZeroExContract, +} from './wrappers'; +export { ZeroExRevertErrors } 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/zero-ex/src/wrappers.ts b/contracts/zero-ex/src/wrappers.ts new file mode 100644 index 0000000000..b7b12cc29d --- /dev/null +++ b/contracts/zero-ex/src/wrappers.ts @@ -0,0 +1,8 @@ +/* + * ----------------------------------------------------------------------------- + * Warning: This file is auto-generated by contracts-gen. Don't edit manually. + * ----------------------------------------------------------------------------- + */ +export * from '../generated-wrappers/i_ownable'; +export * from '../generated-wrappers/i_simple_function_registry'; +export * from '../generated-wrappers/zero_ex'; diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts new file mode 100644 index 0000000000..f11d91e878 --- /dev/null +++ b/contracts/zero-ex/test/artifacts.ts @@ -0,0 +1,53 @@ +/* + * ----------------------------------------------------------------------------- + * Warning: This file is auto-generated by contracts-gen. Don't edit manually. + * ----------------------------------------------------------------------------- + */ +import { ContractArtifact } from 'ethereum-types'; + +import * as BasicMigration from '../test/generated-artifacts/BasicMigration.json'; +import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json'; +import * as FixinOwnable from '../test/generated-artifacts/FixinOwnable.json'; +import * as IFeature from '../test/generated-artifacts/IFeature.json'; +import * as IOwnable from '../test/generated-artifacts/IOwnable.json'; +import * as ISimpleFunctionRegistry from '../test/generated-artifacts/ISimpleFunctionRegistry.json'; +import * as ITestSimpleFunctionRegistryFeature from '../test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json'; +import * as IZeroExBootstrapper from '../test/generated-artifacts/IZeroExBootstrapper.json'; +import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json'; +import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json'; +import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json'; +import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErrors.json'; +import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.json'; +import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json'; +import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json'; +import * as Ownable from '../test/generated-artifacts/Ownable.json'; +import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json'; +import * as TestBasicMigration from '../test/generated-artifacts/TestBasicMigration.json'; +import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json'; +import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json'; +import * as TestZeroExFeature from '../test/generated-artifacts/TestZeroExFeature.json'; +import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json'; +export const artifacts = { + ZeroEx: ZeroEx as ContractArtifact, + LibCommonRichErrors: LibCommonRichErrors as ContractArtifact, + LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, + LibProxyRichErrors: LibProxyRichErrors as ContractArtifact, + LibSimpleFunctionRegistryRichErrors: LibSimpleFunctionRegistryRichErrors as ContractArtifact, + Ownable: Ownable as ContractArtifact, + SimpleFunctionRegistry: SimpleFunctionRegistry as ContractArtifact, + FixinCommon: FixinCommon as ContractArtifact, + FixinOwnable: FixinOwnable as ContractArtifact, + IFeature: IFeature as ContractArtifact, + IOwnable: IOwnable as ContractArtifact, + ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, + IZeroExBootstrapper: IZeroExBootstrapper as ContractArtifact, + BasicMigration: BasicMigration as ContractArtifact, + LibOwnableStorage: LibOwnableStorage as ContractArtifact, + LibProxyStorage: LibProxyStorage as ContractArtifact, + LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact, + ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, + TestBasicMigration: TestBasicMigration as ContractArtifact, + TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact, + TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact, + TestZeroExFeature: TestZeroExFeature as ContractArtifact, +}; diff --git a/contracts/zero-ex/test/basic_migration_test.ts b/contracts/zero-ex/test/basic_migration_test.ts new file mode 100644 index 0000000000..66a9fb92c4 --- /dev/null +++ b/contracts/zero-ex/test/basic_migration_test.ts @@ -0,0 +1,62 @@ +import { blockchainTests, expect, randomAddress } from '@0x/contracts-test-utils'; +import { hexUtils, ZeroExRevertErrors } from '@0x/utils'; + +import { artifacts } from './artifacts'; +import { + IOwnableContract, + ISimpleFunctionRegistryContract, + TestBasicMigrationContract, + ZeroExContract, +} from './wrappers'; + +blockchainTests.resets('Basic migration', env => { + let owner: string; + let zeroEx: ZeroExContract; + let migrator: TestBasicMigrationContract; + + before(async () => { + [owner] = await env.getAccountAddressesAsync(); + migrator = await TestBasicMigrationContract.deployFrom0xArtifactAsync( + artifacts.TestBasicMigration, + env.provider, + env.txDefaults, + artifacts, + ); + const migrateCall = migrator.migrate(owner); + zeroEx = new ZeroExContract(await migrateCall.callAsync(), env.provider, env.txDefaults); + await migrateCall.awaitTransactionSuccessAsync(); + }); + + describe('bootstrapping', () => { + it('Migrator cannot call bootstrap() again', async () => { + const tx = migrator.callBootstrap(zeroEx.address).awaitTransactionSuccessAsync(); + return expect(tx).to.revertWith(new ZeroExRevertErrors.Proxy.AlreadyBootstrappedError()); + }); + }); + + describe('Ownable feature', () => { + let ownable: IOwnableContract; + + before(async () => { + ownable = new IOwnableContract(zeroEx.address, env.provider, env.txDefaults); + }); + + it('has the correct owner', async () => { + const actualOwner = await ownable.getOwner().callAsync(); + expect(actualOwner).to.eq(owner); + }); + }); + + describe('Registry feature', () => { + let registry: ISimpleFunctionRegistryContract; + + before(async () => { + registry = new ISimpleFunctionRegistryContract(zeroEx.address, env.provider, env.txDefaults); + }); + + it('`extendSelf()` is unregistered', async () => { + const tx = registry.extendSelf(hexUtils.random(4), randomAddress()).callAsync(); + return expect(tx).to.revertWith(new ZeroExRevertErrors.Proxy.NotImplementedError()); + }); + }); +}); diff --git a/contracts/zero-ex/test/features/ownable_test.ts b/contracts/zero-ex/test/features/ownable_test.ts new file mode 100644 index 0000000000..2e68b5116a --- /dev/null +++ b/contracts/zero-ex/test/features/ownable_test.ts @@ -0,0 +1,41 @@ +import { blockchainTests, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils'; +import { OwnableRevertErrors } from '@0x/utils'; + +import { basicMigrateAsync } from '../utils/migration'; +import { IOwnableContract, IOwnableEvents } from '../wrappers'; + +blockchainTests.resets('Ownable feature', env => { + const notOwner = randomAddress(); + let owner: string; + let auth: IOwnableContract; + + before(async () => { + [owner] = await env.getAccountAddressesAsync(); + const zeroEx = await basicMigrateAsync(owner, env.provider, env.txDefaults); + auth = new IOwnableContract(zeroEx.address, env.provider, env.txDefaults); + }); + + describe('transferOwnership()', () => { + it('non-owner cannot transfer ownership', async () => { + const newOwner = randomAddress(); + const tx = auth.transferOwnership(newOwner).callAsync({ from: notOwner }); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner, owner)); + }); + + it('owner can transfer ownership', async () => { + const newOwner = randomAddress(); + const receipt = await auth.transferOwnership(newOwner).awaitTransactionSuccessAsync({ from: owner }); + verifyEventsFromLogs( + receipt.logs, + [ + { + previousOwner: owner, + newOwner, + }, + ], + IOwnableEvents.OwnershipTransferred, + ); + expect(await auth.getOwner().callAsync()).to.eq(newOwner); + }); + }); +}); diff --git a/contracts/zero-ex/test/features/simple_function_registry_test.ts b/contracts/zero-ex/test/features/simple_function_registry_test.ts new file mode 100644 index 0000000000..54a1dcfe82 --- /dev/null +++ b/contracts/zero-ex/test/features/simple_function_registry_test.ts @@ -0,0 +1,118 @@ +import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils'; +import { hexUtils, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils'; + +import { artifacts } from '../artifacts'; +import { basicMigrateAsync } from '../utils/migration'; +import { + ISimpleFunctionRegistryContract, + ISimpleFunctionRegistryEvents, + ITestSimpleFunctionRegistryFeatureContract, + TestSimpleFunctionRegistryFeatureImpl1Contract, + TestSimpleFunctionRegistryFeatureImpl2Contract, +} from '../wrappers'; + +blockchainTests.resets('SimpleFunctionRegistry feature', env => { + const { NULL_ADDRESS } = constants; + const notOwner = randomAddress(); + let owner: string; + let registry: ISimpleFunctionRegistryContract; + let testFnSelector: string; + let testFeature: ITestSimpleFunctionRegistryFeatureContract; + let testFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1Contract; + let testFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2Contract; + + before(async () => { + [owner] = await env.getAccountAddressesAsync(); + const zeroEx = await basicMigrateAsync(owner, env.provider, env.txDefaults); + registry = new ISimpleFunctionRegistryContract(zeroEx.address, env.provider, { + ...env.txDefaults, + from: owner, + }); + testFeature = new ITestSimpleFunctionRegistryFeatureContract(zeroEx.address, env.provider, env.txDefaults); + testFnSelector = testFeature.getSelector('testFn'); + testFeatureImpl1 = await TestSimpleFunctionRegistryFeatureImpl1Contract.deployFrom0xArtifactAsync( + artifacts.TestSimpleFunctionRegistryFeatureImpl1, + env.provider, + env.txDefaults, + artifacts, + ); + testFeatureImpl2 = await TestSimpleFunctionRegistryFeatureImpl2Contract.deployFrom0xArtifactAsync( + artifacts.TestSimpleFunctionRegistryFeatureImpl2, + env.provider, + env.txDefaults, + artifacts, + ); + }); + + it('`extend()` cannot be called by a non-owner', async () => { + const tx = registry.extend(hexUtils.random(4), randomAddress()).callAsync({ from: notOwner }); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner, owner)); + }); + + it('`rollback()` cannot be called by a non-owner', async () => { + const tx = registry.rollback(hexUtils.random(4)).callAsync({ from: notOwner }); + return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner, owner)); + }); + + it('`rollback()` reverts for unregistered function', async () => { + const tx = registry.rollback(testFnSelector).awaitTransactionSuccessAsync(); + return expect(tx).to.revertWith( + new ZeroExRevertErrors.SimpleFunctionRegistry.NoRollbackHistoryError(testFnSelector), + ); + }); + + it('owner can add a new function with `extend()`', async () => { + const { logs } = await registry.extend(testFnSelector, testFeatureImpl1.address).awaitTransactionSuccessAsync(); + verifyEventsFromLogs( + logs, + [{ selector: testFnSelector, oldImpl: NULL_ADDRESS, newImpl: testFeatureImpl1.address }], + ISimpleFunctionRegistryEvents.ProxyFunctionUpdated, + ); + const r = await testFeature.testFn().callAsync(); + expect(r).to.bignumber.eq(1337); + }); + + it('owner can replace add a function with `extend()`', async () => { + await registry.extend(testFnSelector, testFeatureImpl1.address).awaitTransactionSuccessAsync(); + await registry.extend(testFnSelector, testFeatureImpl2.address).awaitTransactionSuccessAsync(); + const r = await testFeature.testFn().callAsync(); + expect(r).to.bignumber.eq(1338); + }); + + it('owner can unset a function with `extend()`', async () => { + await registry.extend(testFnSelector, testFeatureImpl1.address).awaitTransactionSuccessAsync(); + await registry.extend(testFnSelector, constants.NULL_ADDRESS).awaitTransactionSuccessAsync(); + return expect(testFeature.testFn().callAsync()).to.revertWith( + new ZeroExRevertErrors.Proxy.NotImplementedError(testFnSelector), + ); + }); + + it('owner can rollback a new function to unset', async () => { + await registry.extend(testFnSelector, testFeatureImpl1.address).awaitTransactionSuccessAsync(); + const { logs } = await registry.rollback(testFnSelector).awaitTransactionSuccessAsync(); + verifyEventsFromLogs( + logs, + [{ selector: testFnSelector, oldImpl: testFeatureImpl1.address, newImpl: NULL_ADDRESS }], + ISimpleFunctionRegistryEvents.ProxyFunctionUpdated, + ); + return expect(testFeature.testFn().callAsync()).to.revertWith( + new ZeroExRevertErrors.Proxy.NotImplementedError(testFnSelector), + ); + }); + + it('owner can rollback a function to a previous version', async () => { + await registry.extend(testFnSelector, testFeatureImpl1.address).awaitTransactionSuccessAsync(); + await registry.extend(testFnSelector, testFeatureImpl2.address).awaitTransactionSuccessAsync(); + await registry.rollback(testFnSelector).awaitTransactionSuccessAsync(); + const r = await testFeature.testFn().callAsync(); + expect(r).to.bignumber.eq(1337); + }); + + it('owner can rollback an unset function to a previous version', async () => { + await registry.extend(testFnSelector, testFeatureImpl1.address).awaitTransactionSuccessAsync(); + await registry.extend(testFnSelector, constants.NULL_ADDRESS).awaitTransactionSuccessAsync(); + await registry.rollback(testFnSelector).awaitTransactionSuccessAsync(); + const r = await testFeature.testFn().callAsync(); + expect(r).to.bignumber.eq(1337); + }); +}); diff --git a/contracts/zero-ex/test/utils/migration.ts b/contracts/zero-ex/test/utils/migration.ts new file mode 100644 index 0000000000..8612b55b02 --- /dev/null +++ b/contracts/zero-ex/test/utils/migration.ts @@ -0,0 +1,23 @@ +import { SupportedProvider } from '@0x/subproviders'; +import { TxData } from 'ethereum-types'; + +import { artifacts } from '../artifacts'; +import { BasicMigrationContract, ZeroExContract } from '../wrappers'; + +// tslint:disable: completed-docs +export async function basicMigrateAsync( + owner: string, + provider: SupportedProvider, + txDefaults: Partial, +): Promise { + const migrator = await BasicMigrationContract.deployFrom0xArtifactAsync( + artifacts.BasicMigration, + provider, + txDefaults, + artifacts, + ); + const migrateCall = migrator.migrate(owner); + const zeroEx = new ZeroExContract(await migrateCall.callAsync(), provider, {}); + await migrateCall.awaitTransactionSuccessAsync(); + return zeroEx; +} diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts new file mode 100644 index 0000000000..9da5bfd0b8 --- /dev/null +++ b/contracts/zero-ex/test/wrappers.ts @@ -0,0 +1,27 @@ +/* + * ----------------------------------------------------------------------------- + * Warning: This file is auto-generated by contracts-gen. Don't edit manually. + * ----------------------------------------------------------------------------- + */ +export * from '../test/generated-wrappers/basic_migration'; +export * from '../test/generated-wrappers/fixin_common'; +export * from '../test/generated-wrappers/fixin_ownable'; +export * from '../test/generated-wrappers/i_feature'; +export * from '../test/generated-wrappers/i_ownable'; +export * from '../test/generated-wrappers/i_simple_function_registry'; +export * from '../test/generated-wrappers/i_test_simple_function_registry_feature'; +export * from '../test/generated-wrappers/i_zero_ex_bootstrapper'; +export * from '../test/generated-wrappers/lib_common_rich_errors'; +export * from '../test/generated-wrappers/lib_ownable_rich_errors'; +export * from '../test/generated-wrappers/lib_ownable_storage'; +export * from '../test/generated-wrappers/lib_proxy_rich_errors'; +export * from '../test/generated-wrappers/lib_proxy_storage'; +export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors'; +export * from '../test/generated-wrappers/lib_simple_function_registry_storage'; +export * from '../test/generated-wrappers/ownable'; +export * from '../test/generated-wrappers/simple_function_registry'; +export * from '../test/generated-wrappers/test_basic_migration'; +export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl1'; +export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl2'; +export * from '../test/generated-wrappers/test_zero_ex_feature'; +export * from '../test/generated-wrappers/zero_ex'; diff --git a/contracts/zero-ex/test/zero_ex_test.ts b/contracts/zero-ex/test/zero_ex_test.ts new file mode 100644 index 0000000000..50bc0d0e2a --- /dev/null +++ b/contracts/zero-ex/test/zero_ex_test.ts @@ -0,0 +1,95 @@ +import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils'; +import { BigNumber, ZeroExRevertErrors } from '@0x/utils'; + +import { artifacts } from './artifacts'; +import { basicMigrateAsync } from './utils/migration'; +import { + IFeatureContract, + IOwnableContract, + ISimpleFunctionRegistryContract, + TestZeroExFeatureContract, + TestZeroExFeatureEvents, + ZeroExContract, +} from './wrappers'; + +blockchainTests.resets('ZeroEx contract', env => { + let owner: string; + let zeroEx: ZeroExContract; + let ownable: IOwnableContract; + let registry: ISimpleFunctionRegistryContract; + let testFeature: TestZeroExFeatureContract; + + before(async () => { + [owner] = await env.getAccountAddressesAsync(); + zeroEx = await basicMigrateAsync(owner, env.provider, env.txDefaults); + ownable = new IOwnableContract(zeroEx.address, env.provider, env.txDefaults); + registry = new ISimpleFunctionRegistryContract(zeroEx.address, env.provider, env.txDefaults); + testFeature = new TestZeroExFeatureContract(zeroEx.address, env.provider, env.txDefaults); + // Register test features. + const testFeatureImpl = await TestZeroExFeatureContract.deployFrom0xArtifactAsync( + artifacts.TestZeroExFeature, + env.provider, + env.txDefaults, + artifacts, + ); + for (const fn of ['payableFn', 'notPayableFn', 'internalFn']) { + await registry + .extend(testFeature.getSelector(fn), testFeatureImpl.address) + .awaitTransactionSuccessAsync({ from: owner }); + } + }); + + it('can receive ether', async () => { + const txHash = await env.web3Wrapper.sendTransactionAsync({ + from: owner, + to: zeroEx.address, + data: constants.NULL_BYTES, + value: 1, + }); + await env.web3Wrapper.awaitTransactionSuccessAsync(txHash); + }); + + it('can attach ether to a call', async () => { + const wei = Math.floor(Math.random() * 100); + const receipt = await testFeature.payableFn().awaitTransactionSuccessAsync({ value: wei }); + verifyEventsFromLogs(receipt.logs, [{ value: new BigNumber(wei) }], TestZeroExFeatureEvents.PayableFnCalled); + }); + + it('reverts when attaching ether to a non-payable function', async () => { + const wei = Math.floor(Math.random() * 100); + const tx = testFeature.notPayableFn().awaitTransactionSuccessAsync({ value: wei }); + // This will cause an empty revert. + return expect(tx).to.be.rejectedWith('revert'); + }); + + it('reverts when calling an unimplmented function', async () => { + const selector = testFeature.getSelector('unimplmentedFn'); + const tx = testFeature.unimplmentedFn().awaitTransactionSuccessAsync(); + return expect(tx).to.revertWith(new ZeroExRevertErrors.Proxy.NotImplementedError(selector)); + }); + + it('reverts when calling an internal function', async () => { + const tx = testFeature.internalFn().awaitTransactionSuccessAsync({ from: owner }); + return expect(tx).to.revertWith(new ZeroExRevertErrors.Common.OnlyCallableBySelfError(owner)); + }); + + describe('getFunctionImplementation()', () => { + it('returns the correct implementations of the initial features', async () => { + const ownableSelectors = [ownable.getSelector('transferOwnership')]; + const registrySelectors = [ + registry.getSelector('rollback'), + registry.getSelector('extend'), + // registry.getSelector('extendSelf'), + ]; + const selectors = [...ownableSelectors, ...registrySelectors]; + const impls = await Promise.all(selectors.map(s => zeroEx.getFunctionImplementation(s).callAsync())); + for (let i = 0; i < impls.length; ++i) { + const selector = selectors[i]; + const impl = impls[i]; + const feat = new IFeatureContract(impl, env.provider, env.txDefaults); + const featName = ownableSelectors.includes(selector) ? 'Ownable' : 'SimpleFunctionRegistry'; + expect(await feat.FEATURE_NAME().callAsync()).to.eq(featName); + } + }); + }); +}); diff --git a/contracts/zero-ex/truffle-config.js b/contracts/zero-ex/truffle-config.js new file mode 100644 index 0000000000..a9ef3b858b --- /dev/null +++ b/contracts/zero-ex/truffle-config.js @@ -0,0 +1,96 @@ +/** + * 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.6.5', + settings: { + evmVersion: 'istanbul', + optimizer: { + enabled: true, + runs: 1000000, + details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true }, + }, + }, + }, + }, +}; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json new file mode 100644 index 0000000000..f1364e47ae --- /dev/null +++ b/contracts/zero-ex/tsconfig.json @@ -0,0 +1,33 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, + "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], + "files": [ + "generated-artifacts/IOwnable.json", + "generated-artifacts/ISimpleFunctionRegistry.json", + "generated-artifacts/ZeroEx.json", + "test/generated-artifacts/BasicMigration.json", + "test/generated-artifacts/FixinCommon.json", + "test/generated-artifacts/FixinOwnable.json", + "test/generated-artifacts/IFeature.json", + "test/generated-artifacts/IOwnable.json", + "test/generated-artifacts/ISimpleFunctionRegistry.json", + "test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json", + "test/generated-artifacts/IZeroExBootstrapper.json", + "test/generated-artifacts/LibCommonRichErrors.json", + "test/generated-artifacts/LibOwnableRichErrors.json", + "test/generated-artifacts/LibOwnableStorage.json", + "test/generated-artifacts/LibProxyRichErrors.json", + "test/generated-artifacts/LibProxyStorage.json", + "test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json", + "test/generated-artifacts/LibSimpleFunctionRegistryStorage.json", + "test/generated-artifacts/Ownable.json", + "test/generated-artifacts/SimpleFunctionRegistry.json", + "test/generated-artifacts/TestBasicMigration.json", + "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json", + "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json", + "test/generated-artifacts/TestZeroExFeature.json", + "test/generated-artifacts/ZeroEx.json" + ], + "exclude": ["./deploy/solc/solc_bin"] +} diff --git a/contracts/zero-ex/tslint.json b/contracts/zero-ex/tslint.json new file mode 100644 index 0000000000..91bb1bec78 --- /dev/null +++ b/contracts/zero-ex/tslint.json @@ -0,0 +1,10 @@ +{ + "extends": ["@0x/tslint-config"], + "rules": { + "custom-no-magic-numbers": false, + "max-file-line-count": false + }, + "linterOptions": { + "exclude": ["src/artifacts.ts", "test/artifacts.ts"] + } +}