@0x/contracts-zero-ex: bootstrap() is now a temporary feature, registered in the ZeroEx constructor.
				
					
				
			`@0x/contracts-zero-ex`: `bootstrap()` de-registers itself and self-destructs once it's called. `@0x/contracts-zero-ex`: `bootstrap()` now takes arbitrary call data, but the callee is fixed in an immutable. `@0x/contracts-zero-ex`: `bootstrap()` caller is fixed in an immutable. `@0x/contracts-zero-ex`: `bootstrap()` only calls a single target. `@0x/contracts-zero-ex`: Renamed `BasicMigration` to `InitialMigration`. `@0x/contracts-zero-ex`: `InitialMigration` is now the bootstrap target and multiplexes to the initial features. `@0x/contracts-zero-ex`: Add `Migrate` feature and tests. `@0x/contracts-zero-ex`: Re-organize contract locatins (remove `interfaces` folder).
This commit is contained in:
		| @@ -20,7 +20,8 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; | ||||
| import "./interfaces/IZeroExBootstrapper.sol"; | ||||
| import "./migrations/LibBootstrap.sol"; | ||||
| import "./features/Bootstrap.sol"; | ||||
| import "./storage/LibProxyStorage.sol"; | ||||
| import "./errors/LibProxyRichErrors.sol"; | ||||
|  | ||||
| @@ -28,17 +29,23 @@ 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; | ||||
|     /// @dev Magic bytes returned by the bootstrapper to indicate success. | ||||
|     bytes4 internal constant BOOTSTRAP_SUCCESS = 0xd150751b; | ||||
|  | ||||
|     /// @dev Construct this contract and set the bootstrap migration contract. | ||||
|     ///      After constructing this contract, `bootstrap()` should be called | ||||
|     ///      to seed the initial feature set. | ||||
|     /// @param bootstrapper The bootstrap migration contract. | ||||
|     constructor(address bootstrapper) public { | ||||
|         // Temporarily create and register the bootstrap feature. | ||||
|         // It will deregister itself after `bootstrap()` has been called. | ||||
|         Bootstrap bootstrap = new Bootstrap(msg.sender, bootstrapper); | ||||
|         LibProxyStorage.getStorage().impls[bootstrap.bootstrap.selector] = | ||||
|             address(bootstrap); | ||||
|     } | ||||
|  | ||||
|     // solhint-disable state-visibility | ||||
| @@ -63,40 +70,6 @@ contract ZeroEx { | ||||
|  | ||||
|     // 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. | ||||
|   | ||||
| @@ -17,17 +17,31 @@ | ||||
| */ | ||||
| 
 | ||||
| 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); | ||||
| library LibMigrateRichErrors { | ||||
| 
 | ||||
|     // solhint-disable func-name-mixedcase | ||||
| 
 | ||||
|     function AlreadyMigratingError() | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("AlreadyMigratingError()")) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     function MigrateCallFailedError(address target, bytes memory resultData) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("MigrateCallFailedError(address,bytes)")), | ||||
|             target, | ||||
|             resultData | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -34,25 +34,39 @@ library LibProxyRichErrors { | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function AlreadyBootstrappedError() | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("AlreadyBootstrappedError()")) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidBootstrapCallerError(address caller, address expectedCaller) | ||||
|     function InvalidBootstrapCallerError(address actual, address expected) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("InvalidBootstrapCallerError(address,address)")), | ||||
|             caller, | ||||
|             expectedCaller | ||||
|             actual, | ||||
|             expected | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidDieCallerError(address actual, address expected) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("InvalidDieCallerError(address,address)")), | ||||
|             actual, | ||||
|             expected | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function BootstrapCallFailedError(address target, bytes memory resultData) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("BootstrapCallFailedError(address,bytes)")), | ||||
|             target, | ||||
|             resultData | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										87
									
								
								contracts/zero-ex/contracts/src/features/Bootstrap.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								contracts/zero-ex/contracts/src/features/Bootstrap.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  | ||||
|   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 "../migrations/LibBootstrap.sol"; | ||||
| import "../fixins/FixinCommon.sol"; | ||||
| import "../storage/LibProxyStorage.sol"; | ||||
| import "./IBootstrap.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Detachable `bootstrap()` feature. | ||||
| contract Bootstrap is | ||||
|     IBootstrap, | ||||
|     FixinCommon | ||||
| { | ||||
|     // solhint-disable state-visibility,indent | ||||
|     /// @dev The ZeroEx contract. | ||||
|     ///      This has to be immutable to persist across delegatecalls. | ||||
|     address immutable private _deployer; | ||||
|     /// @dev The implementation address of this contract. | ||||
|     ///      This has to be immutable to persist across delegatecalls. | ||||
|     address immutable private _implementation; | ||||
|     /// @dev The deployer. | ||||
|     ///      This has to be immutable to persist across delegatecalls. | ||||
|     address immutable private _bootstrapCaller; | ||||
|     /// @dev The bootstrap migrator. | ||||
|     ///      This has to be immutable to persist across delegatecalls. | ||||
|     address immutable private _bootstrapper; | ||||
|     // solhint-enable state-visibility,indent | ||||
|  | ||||
|     /// @dev Construct this contract and set the bootstrap migration contract. | ||||
|     ///      After constructing this contract, `bootstrap()` should be called | ||||
|     ///      to seed the initial feature set. | ||||
|     /// @param bootstrapCaller The allowed caller of `bootstrap()`. | ||||
|     /// @param bootstrapper The bootstrap migration contract. | ||||
|     constructor(address bootstrapCaller, address bootstrapper) public { | ||||
|         _deployer = msg.sender; | ||||
|         _implementation = address(this); | ||||
|         _bootstrapCaller = bootstrapCaller; | ||||
|         _bootstrapper = bootstrapper; | ||||
|     } | ||||
|  | ||||
|     /// @dev Bootstrap the initial feature set of this contract by delegatecalling | ||||
|     ///      into `_bootstrapper`. Before exiting the `bootstrap()` function will | ||||
|     ///      deregister itself from the proxy to prevent being called again. | ||||
|     /// @param callData The call data to execute on `_bootstrapper`. | ||||
|     function bootstrap(bytes calldata callData) external override { | ||||
|         // Only the bootstrap caller can call this function. | ||||
|         if (msg.sender != _bootstrapCaller) { | ||||
|             _rrevert(LibProxyRichErrors.InvalidBootstrapCallerError( | ||||
|                 msg.sender, | ||||
|                 _bootstrapCaller | ||||
|             )); | ||||
|         } | ||||
|         LibBootstrap.delegatecallBootstrapFunction(_bootstrapper, callData); | ||||
|         // Deregister. | ||||
|         LibProxyStorage.getStorage().impls[this.bootstrap.selector] = address(0); | ||||
|         // Self-destruct. | ||||
|         Bootstrap(_implementation).die(); | ||||
|     } | ||||
|  | ||||
|     /// @dev Self-destructs this contract. | ||||
|     ///      Can only be called by the ZeroEx contract. | ||||
|     function die() external { | ||||
|         if (msg.sender != _deployer) { | ||||
|             _rrevert(LibProxyRichErrors.InvalidDieCallerError(msg.sender, _deployer)); | ||||
|         } | ||||
|         selfdestruct(msg.sender); | ||||
|     } | ||||
| } | ||||
| @@ -20,13 +20,12 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| 
 | ||||
| /// @dev Interface for a bootstrapping contract that the `ZeroEx` proxy. | ||||
| interface IZeroExBootstrapper { | ||||
| /// @dev Detachable `bootstrap()` feature. | ||||
| interface IBootstrap { | ||||
| 
 | ||||
|     /// @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; | ||||
|     /// @dev Bootstrap the initial feature set of this contract by delegatecalling | ||||
|     ///      into `_bootstrapper`. Before exiting the `bootstrap()` function will | ||||
|     ///      deregister itself from the proxy to prevent being called again. | ||||
|     /// @param callData The call data to execute on `_bootstrapper`. | ||||
|     function bootstrap(bytes calldata callData) external; | ||||
| } | ||||
							
								
								
									
										43
									
								
								contracts/zero-ex/contracts/src/features/IMigrate.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								contracts/zero-ex/contracts/src/features/IMigrate.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -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 Migration features. | ||||
| interface IMigrate { | ||||
|  | ||||
|     /// @dev Emitted when `migrate()` is called. | ||||
|     /// @param caller The caller of `migrate()`. | ||||
|     /// @param migrator The migration contract. | ||||
|     event Migrated(address caller, address migrator); | ||||
|  | ||||
|     /// @dev Execute a migration function in the context of the ZeroEx contract. | ||||
|     ///      The result of the function being called should be the magic bytes | ||||
|     ///      0x2c64c5ef. Only callable by the owner. | ||||
|     ///      The owner will be temporarily set to `address(this)` inside the call. | ||||
|     ///      The original owner can be retrieved through `getMigrationOwner()`.` | ||||
|     /// @param target The migrator contract address. | ||||
|     /// @param data The call data. | ||||
|     function migrate(address target, bytes calldata data) external; | ||||
|  | ||||
|     /// @dev Get the true owner of this contract during a migration. | ||||
|     /// @return owner The true owner of this contract. | ||||
|     function getMigrationOwner() external view returns (address owner); | ||||
| } | ||||
| @@ -19,8 +19,6 @@ | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| import "../interfaces/IZeroExBootstrapper.sol"; | ||||
| 
 | ||||
| 
 | ||||
| /// @dev Basic registry management features. | ||||
| interface ISimpleFunctionRegistry { | ||||
| @@ -41,12 +39,6 @@ interface ISimpleFunctionRegistry { | ||||
|     /// @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; | ||||
| 
 | ||||
|     /// @dev Retrieve the length of the rollback history for a function. | ||||
|     /// @param selector The function selector. | ||||
|     /// @return rollbackLength The number of items in the rollback history for | ||||
							
								
								
									
										94
									
								
								contracts/zero-ex/contracts/src/features/Migrate.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								contracts/zero-ex/contracts/src/features/Migrate.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| /* | ||||
|  | ||||
|   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 "../errors/LibOwnableRichErrors.sol"; | ||||
| import "../storage/LibOwnableStorage.sol"; | ||||
| import "../storage/LibMigrateStorage.sol"; | ||||
| import "../migrations/LibMigrate.sol"; | ||||
| import "../migrations/LibBootstrap.sol"; | ||||
| import "./IFeature.sol"; | ||||
| import "./IMigrate.sol"; | ||||
| import "./ISimpleFunctionRegistry.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Migration features. | ||||
| contract Migrate is | ||||
|     IFeature, | ||||
|     IMigrate, | ||||
|     FixinOwnable | ||||
| { | ||||
|     // solhint-disable const-name-snakecase | ||||
|  | ||||
|     /// @dev Name of this feature. | ||||
|     string constant public override FEATURE_NAME = "Migrate"; | ||||
|     /// @dev Version of this feature. | ||||
|     uint256 constant public override FEATURE_VERSION = (1 << 64) | (0 << 32) | (0); | ||||
|  | ||||
|     /// @dev Initializes this feature. | ||||
|     /// @param impl The actual address of this feature contract. | ||||
|     /// @return success Magic bytes if successful. | ||||
|     function bootstrap(address impl) external returns (bytes4 success) { | ||||
|         // Register feature functions. | ||||
|         ISimpleFunctionRegistry(address(this)).extend(this.migrate.selector, impl); | ||||
|         ISimpleFunctionRegistry(address(this)).extend(this.getMigrationOwner.selector, impl); | ||||
|         return LibBootstrap.BOOTSTRAP_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev Execute a migration function in the context of the ZeroEx contract. | ||||
|     ///      The result of the function being called should be the magic bytes | ||||
|     ///      0x2c64c5ef. Only callable by the owner. | ||||
|     ///      The owner will be temporarily set to `address(this)` inside the call. | ||||
|     ///      The original owner can be retrieved through `getMigrationOwner()`.` | ||||
|     /// @param target The migrator contract address. | ||||
|     /// @param data The call data. | ||||
|     function migrate(address target, bytes calldata data) | ||||
|         external | ||||
|         override | ||||
|         onlyOwner | ||||
|     { | ||||
|         LibOwnableStorage.Storage storage ownableStor = LibOwnableStorage.getStorage(); | ||||
|         LibMigrateStorage.Storage storage stor = LibMigrateStorage.getStorage(); | ||||
|         address prevOwner = ownableStor.owner; | ||||
|         if (prevOwner == address(this)) { | ||||
|             // If the owner is already set to ourselves then we've reentered. | ||||
|             _rrevert(LibMigrateRichErrors.AlreadyMigratingError()); | ||||
|         } | ||||
|         // Temporarily set the owner to ourselves. | ||||
|         ownableStor.owner = address(this); | ||||
|         stor.migrationOwner = prevOwner; | ||||
|  | ||||
|         // Perform the migration. | ||||
|         LibMigrate.delegatecallMigrateFunction(target, data); | ||||
|  | ||||
|         // Restore the owner. | ||||
|         ownableStor.owner = prevOwner; | ||||
|         stor.migrationOwner = address(0); | ||||
|  | ||||
|         emit Migrated(msg.sender, target); | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the true owner of this contract during a migration. | ||||
|     /// @return owner The true owner of this contract. | ||||
|     function getMigrationOwner() external override view returns (address owner) { | ||||
|         return LibMigrateStorage.getStorage().migrationOwner; | ||||
|     } | ||||
| } | ||||
| @@ -20,19 +20,18 @@ 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"; | ||||
| import "../migrations/LibBootstrap.sol"; | ||||
| import "./IFeature.sol"; | ||||
| import "./IOwnable.sol"; | ||||
| import "./ISimpleFunctionRegistry.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Owner management features. | ||||
| contract Ownable is | ||||
|     IFeature, | ||||
|     IOwnable, | ||||
|     IZeroExBootstrapper, | ||||
|     FixinOwnable | ||||
| { | ||||
|     // solhint-disable const-name-snakecase | ||||
| @@ -42,15 +41,20 @@ contract Ownable is | ||||
|     /// @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 { | ||||
|     /// @dev Initializes this feature. The intial owner will be set to this (ZeroEx) | ||||
|     ///      to allow the bootstrappers to call `extend()`. Ownership should be | ||||
|     ///      transferred to the real owner by the bootstrapper after | ||||
|     ///      bootstrapping is complete. | ||||
|     /// @param impl the actual address of this feature contract. | ||||
|     /// @return success Magic bytes if successful. | ||||
|     function bootstrap(address impl) external returns (bytes4 success) { | ||||
|         // Set the owner. | ||||
|         LibOwnableStorage.getStorage().owner = msg.sender; | ||||
|         LibOwnableStorage.getStorage().owner = address(this); | ||||
|  | ||||
|         // Register feature functions. | ||||
|         ISimpleFunctionRegistry(address(this)).extendSelf(this.transferOwnership.selector, impl); | ||||
|         ISimpleFunctionRegistry(address(this)).extendSelf(this.getOwner.selector, impl); | ||||
|         ISimpleFunctionRegistry(address(this)).extend(this.transferOwnership.selector, impl); | ||||
|         ISimpleFunctionRegistry(address(this)).extend(this.getOwner.selector, impl); | ||||
|         return LibBootstrap.BOOTSTRAP_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev Change the owner of this contract. | ||||
|   | ||||
| @@ -19,20 +19,19 @@ | ||||
| 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"; | ||||
| import "../migrations/LibBootstrap.sol"; | ||||
| import "./IFeature.sol"; | ||||
| import "./ISimpleFunctionRegistry.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Basic registry management features. | ||||
| contract SimpleFunctionRegistry is | ||||
|     IFeature, | ||||
|     ISimpleFunctionRegistry, | ||||
|     IZeroExBootstrapper, | ||||
|     FixinOwnable | ||||
| { | ||||
|     // solhint-disable const-name-snakecase | ||||
| @@ -42,17 +41,18 @@ contract SimpleFunctionRegistry is | ||||
|     /// @dev Version of this feature. | ||||
|     uint256 constant public override FEATURE_VERSION = (1 << 64) | (0 << 32) | (0); | ||||
|  | ||||
|     /// @dev Initializes the feature implementation registry. | ||||
|     /// @dev Initializes this feature. | ||||
|     /// @param impl The actual address of this feature contract. | ||||
|     function bootstrap(address impl) external override { | ||||
|     /// @return success Magic bytes if successful. | ||||
|     function bootstrap(address impl) external returns (bytes4 success) { | ||||
|         // 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); | ||||
|         // Register getters. | ||||
|         _extend(this.getRollbackLength.selector, impl); | ||||
|         _extend(this.getRollbackEntryAtIndex.selector, impl); | ||||
|         return LibBootstrap.BOOTSTRAP_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /// @dev Roll back to a prior implementation of a function. | ||||
| @@ -108,18 +108,6 @@ contract SimpleFunctionRegistry is | ||||
|         _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 Retrieve the length of the rollback history for a function. | ||||
|     /// @param selector The function selector. | ||||
|     /// @return rollbackLength The number of items in the rollback history for | ||||
|   | ||||
| @@ -1,70 +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; | ||||
| 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, address(0)); | ||||
|  | ||||
|         // 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. | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  | ||||
|   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/IBootstrap.sol"; | ||||
| import "../features/SimpleFunctionRegistry.sol"; | ||||
| import "../features/Ownable.sol"; | ||||
| import "../features/Migrate.sol"; | ||||
| import "./LibBootstrap.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev A contract for deploying and configuring a minimal ZeroEx contract. | ||||
| contract InitialMigration { | ||||
|     /// @dev The deployed ZereEx instance. | ||||
|     ZeroEx private _zeroEx; | ||||
|  | ||||
|     /// @dev Deploy the `ZeroEx` contract with the minimum feature set, | ||||
|     ///      transfers ownership to `owner`, then self-destructs. | ||||
|     /// @param owner The owner of the contract. | ||||
|     /// @return zeroEx The deployed and configured `ZeroEx` contract. | ||||
|     function deploy(address owner) public virtual returns (ZeroEx zeroEx) { | ||||
|         // Must not have already been run. | ||||
|         require(address(_zeroEx) == address(0), "InitialMigration/ALREADY_DEPLOYED"); | ||||
|  | ||||
|         // Deploy the ZeroEx contract, setting ourselves as the bootstrapper. | ||||
|         zeroEx = _zeroEx = new ZeroEx(address(this)); | ||||
|  | ||||
|         // Bootstrap the initial feature set. | ||||
|         IBootstrap(address(zeroEx)).bootstrap(abi.encodeWithSelector( | ||||
|             this.bootstrap.selector, | ||||
|             owner | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     /// @dev Sets up the initial state of the `ZeroEx` contract. | ||||
|     ///      The `ZeroEx` contract will delegatecall into this function. | ||||
|     /// @param owner The new owner of the ZeroEx contract. | ||||
|     /// @return success Magic bytes if successful. | ||||
|     function bootstrap(address owner) public virtual returns (bytes4 success) { | ||||
|         // Deploy and migrate the initial features. | ||||
|         // Order matters here. | ||||
|  | ||||
|         // Initialize Registry. | ||||
|         SimpleFunctionRegistry registry = new SimpleFunctionRegistry(); | ||||
|         LibBootstrap.delegatecallBootstrapFunction( | ||||
|             address(registry), | ||||
|             abi.encodeWithSelector(registry.bootstrap.selector, address(registry)) | ||||
|         ); | ||||
|  | ||||
|         // Initialize Ownable. | ||||
|         Ownable ownable = new Ownable(); | ||||
|         LibBootstrap.delegatecallBootstrapFunction( | ||||
|             address(ownable), | ||||
|             abi.encodeWithSelector(ownable.bootstrap.selector, address(ownable)) | ||||
|         ); | ||||
|  | ||||
|         // Initialize Migrate. | ||||
|         Migrate migrate = new Migrate(); | ||||
|         LibBootstrap.delegatecallBootstrapFunction( | ||||
|             address(migrate), | ||||
|             abi.encodeWithSelector(migrate.bootstrap.selector, address(migrate)) | ||||
|         ); | ||||
|  | ||||
|         // Transfer ownership to the real owner. | ||||
|         Ownable(address(this)).transferOwnership(owner); | ||||
|  | ||||
|         success = LibBootstrap.BOOTSTRAP_SUCCESS; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										50
									
								
								contracts/zero-ex/contracts/src/migrations/LibBootstrap.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								contracts/zero-ex/contracts/src/migrations/LibBootstrap.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -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 "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; | ||||
| import "../errors/LibProxyRichErrors.sol"; | ||||
|  | ||||
|  | ||||
| library LibBootstrap { | ||||
|  | ||||
|     /// @dev Magic bytes returned by the bootstrapper to indicate success. | ||||
|     bytes4 internal constant BOOTSTRAP_SUCCESS = 0xd150751b; | ||||
|  | ||||
|     /// @dev Perform a delegatecall and ensure it returns the magic bytes. | ||||
|     /// @param target The call target. | ||||
|     /// @param data The call data. | ||||
|     function delegatecallBootstrapFunction( | ||||
|         address target, | ||||
|         bytes memory data | ||||
|     ) | ||||
|         internal | ||||
|     { | ||||
|         (bool success, bytes memory resultData) = target.delegatecall(data); | ||||
|         if (!success || | ||||
|             resultData.length != 32 || | ||||
|             abi.decode(resultData, (bytes4)) != BOOTSTRAP_SUCCESS) | ||||
|         { | ||||
|             LibRichErrorsV06.rrevert( | ||||
|                 LibProxyRichErrors.BootstrapCallFailedError(target, resultData) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										50
									
								
								contracts/zero-ex/contracts/src/migrations/LibMigrate.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								contracts/zero-ex/contracts/src/migrations/LibMigrate.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -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 "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; | ||||
| import "../errors/LibMigrateRichErrors.sol"; | ||||
|  | ||||
|  | ||||
| library LibMigrate { | ||||
|  | ||||
|     /// @dev Magic bytes returned by a migrator to indicate success. | ||||
|     bytes4 internal constant MIGRATE_SUCCESS = 0x2c64c5ef; | ||||
|  | ||||
|     /// @dev Perform a delegatecall and ensure it returns the magic bytes. | ||||
|     /// @param target The call target. | ||||
|     /// @param data The call data. | ||||
|     function delegatecallMigrateFunction( | ||||
|         address target, | ||||
|         bytes memory data | ||||
|     ) | ||||
|         internal | ||||
|     { | ||||
|         (bool success, bytes memory resultData) = target.delegatecall(data); | ||||
|         if (!success || | ||||
|             resultData.length != 32 || | ||||
|             abi.decode(resultData, (bytes4)) != MIGRATE_SUCCESS) | ||||
|         { | ||||
|             LibRichErrorsV06.rrevert( | ||||
|                 LibMigrateRichErrors.MigrateCallFailedError(target, resultData) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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 `Migrate` feature. | ||||
| library LibMigrateStorage { | ||||
|  | ||||
|     /// @dev Globally unique offset for the storage bucket. | ||||
|     bytes32 constant internal STORAGE_ID = | ||||
|         0x0ed67b719caa0e9bebb7147a4de9fdb6f1c82a984b2297d741a9888432214d5c; | ||||
|  | ||||
|     /// @dev Storage bucket for this feature. | ||||
|     struct Storage { | ||||
|         // The owner of this contract prior to the `migrate()` call. | ||||
|         address migrationOwner; | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the storage bucket for this contract. | ||||
|     function getStorage() internal pure returns (Storage storage stor) { | ||||
|         bytes32 storageId = STORAGE_ID; | ||||
|         assembly { stor_slot := storageId } | ||||
|     } | ||||
| } | ||||
| @@ -29,8 +29,6 @@ library LibProxyStorage { | ||||
|  | ||||
|     /// @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; | ||||
|     } | ||||
|   | ||||
							
								
								
									
										46
									
								
								contracts/zero-ex/contracts/test/TestInitialMigration.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								contracts/zero-ex/contracts/test/TestInitialMigration.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| /* | ||||
|  | ||||
|   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/ZeroEx.sol"; | ||||
| import "../src/features/IBootstrap.sol"; | ||||
| import "../src/migrations/InitialMigration.sol"; | ||||
|  | ||||
|  | ||||
| contract TestInitialMigration is | ||||
|     InitialMigration | ||||
| { | ||||
|     address public bootstrapFeature; | ||||
|  | ||||
|     function callBootstrap(ZeroEx zeroEx) external { | ||||
|         IBootstrap(address(zeroEx)).bootstrap(new bytes(0)); | ||||
|     } | ||||
|  | ||||
|     function getCodeSizeOf(address target) external view returns (uint256 codeSize) { | ||||
|         assembly { codeSize := extcodesize(target) } | ||||
|     } | ||||
|  | ||||
|     function bootstrap(address owner) public override returns (bytes4 success) { | ||||
|         success = InitialMigration.bootstrap(owner); | ||||
|         // Snoop the bootstrap feature contract. | ||||
|         bootstrapFeature = ZeroEx(address(uint160(address(this)))) | ||||
|             .getFunctionImplementation(IBootstrap.bootstrap.selector); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										55
									
								
								contracts/zero-ex/contracts/test/TestMigrator.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								contracts/zero-ex/contracts/test/TestMigrator.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  | ||||
|   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/LibMigrate.sol"; | ||||
| import "../src/features/IOwnable.sol"; | ||||
| import "../src/features/IMigrate.sol"; | ||||
|  | ||||
|  | ||||
| contract TestMigrator { | ||||
|     event TestMigrateCalled( | ||||
|         bytes callData, | ||||
|         address owner, | ||||
|         address actualOwner | ||||
|     ); | ||||
|  | ||||
|     function succeedingMigrate() external returns (bytes4 success) { | ||||
|         emit TestMigrateCalled( | ||||
|             msg.data, | ||||
|             IOwnable(address(this)).getOwner(), | ||||
|             IMigrate(address(this)).getMigrationOwner() | ||||
|         ); | ||||
|         return LibMigrate.MIGRATE_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     function failingMigrate() external returns (bytes4 success) { | ||||
|         emit TestMigrateCalled( | ||||
|             msg.data, | ||||
|             IOwnable(address(this)).getOwner(), | ||||
|             IMigrate(address(this)).getMigrationOwner() | ||||
|         ); | ||||
|         return 0xdeadbeef; | ||||
|     } | ||||
|  | ||||
|     function revertingMigrate() external pure { | ||||
|         revert("OOPSIE"); | ||||
|     } | ||||
| } | ||||
| @@ -38,9 +38,9 @@ | ||||
|         "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" | ||||
|     }, | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "ZeroEx,IOwnable,ISimpleFunctionRegistry", | ||||
|         "publicInterfaceContracts": "ZeroEx,IMigrate,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" | ||||
|         "abis": "./test/generated-artifacts/@(Bootstrap|FixinCommon|FixinOwnable|IBootstrap|IFeature|IMigrate|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|InitialMigration|LibBootstrap|LibCommonRichErrors|LibMigrate|LibMigrateRichErrors|LibMigrateStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|Migrate|Ownable|SimpleFunctionRegistry|TestInitialMigration|TestMigrator|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestZeroExFeature|ZeroEx).json" | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| @@ -5,11 +5,13 @@ | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as IMigrate from '../generated-artifacts/IMigrate.json'; | ||||
| 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, | ||||
|     IMigrate: IMigrate as ContractArtifact, | ||||
|     IOwnable: IOwnable as ContractArtifact, | ||||
|     ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, | ||||
| }; | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|  * Warning: This file is auto-generated by contracts-gen. Don't edit manually. | ||||
|  * ----------------------------------------------------------------------------- | ||||
|  */ | ||||
| export * from '../generated-wrappers/i_migrate'; | ||||
| export * from '../generated-wrappers/i_ownable'; | ||||
| export * from '../generated-wrappers/i_simple_function_registry'; | ||||
| export * from '../generated-wrappers/zero_ex'; | ||||
|   | ||||
| @@ -5,24 +5,32 @@ | ||||
|  */ | ||||
| import { ContractArtifact } from 'ethereum-types'; | ||||
|  | ||||
| import * as BasicMigration from '../test/generated-artifacts/BasicMigration.json'; | ||||
| import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json'; | ||||
| import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json'; | ||||
| import * as FixinOwnable from '../test/generated-artifacts/FixinOwnable.json'; | ||||
| import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json'; | ||||
| import * as IFeature from '../test/generated-artifacts/IFeature.json'; | ||||
| import * as IMigrate from '../test/generated-artifacts/IMigrate.json'; | ||||
| import * as InitialMigration from '../test/generated-artifacts/InitialMigration.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 LibBootstrap from '../test/generated-artifacts/LibBootstrap.json'; | ||||
| import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json'; | ||||
| import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json'; | ||||
| import * as LibMigrateRichErrors from '../test/generated-artifacts/LibMigrateRichErrors.json'; | ||||
| import * as LibMigrateStorage from '../test/generated-artifacts/LibMigrateStorage.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 Migrate from '../test/generated-artifacts/Migrate.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 TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json'; | ||||
| import * as TestMigrator from '../test/generated-artifacts/TestMigrator.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'; | ||||
| @@ -30,23 +38,31 @@ import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json'; | ||||
| export const artifacts = { | ||||
|     ZeroEx: ZeroEx as ContractArtifact, | ||||
|     LibCommonRichErrors: LibCommonRichErrors as ContractArtifact, | ||||
|     LibMigrateRichErrors: LibMigrateRichErrors as ContractArtifact, | ||||
|     LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, | ||||
|     LibProxyRichErrors: LibProxyRichErrors as ContractArtifact, | ||||
|     LibSimpleFunctionRegistryRichErrors: LibSimpleFunctionRegistryRichErrors as ContractArtifact, | ||||
|     Bootstrap: Bootstrap as ContractArtifact, | ||||
|     IBootstrap: IBootstrap as ContractArtifact, | ||||
|     IFeature: IFeature as ContractArtifact, | ||||
|     IMigrate: IMigrate as ContractArtifact, | ||||
|     IOwnable: IOwnable as ContractArtifact, | ||||
|     ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, | ||||
|     Migrate: Migrate 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, | ||||
|     InitialMigration: InitialMigration as ContractArtifact, | ||||
|     LibBootstrap: LibBootstrap as ContractArtifact, | ||||
|     LibMigrate: LibMigrate as ContractArtifact, | ||||
|     LibMigrateStorage: LibMigrateStorage as ContractArtifact, | ||||
|     LibOwnableStorage: LibOwnableStorage as ContractArtifact, | ||||
|     LibProxyStorage: LibProxyStorage as ContractArtifact, | ||||
|     LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact, | ||||
|     ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, | ||||
|     TestBasicMigration: TestBasicMigration as ContractArtifact, | ||||
|     TestInitialMigration: TestInitialMigration as ContractArtifact, | ||||
|     TestMigrator: TestMigrator as ContractArtifact, | ||||
|     TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact, | ||||
|     TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact, | ||||
|     TestZeroExFeature: TestZeroExFeature as ContractArtifact, | ||||
|   | ||||
| @@ -1,62 +0,0 @@ | ||||
| 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()); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										94
									
								
								contracts/zero-ex/test/features/migrate_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								contracts/zero-ex/test/features/migrate_test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| import { blockchainTests, expect, LogDecoder, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils'; | ||||
| import { hexUtils, OwnableRevertErrors, StringRevertError, ZeroExRevertErrors } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts } from '../artifacts'; | ||||
| import { initialMigrateAsync } from '../utils/migration'; | ||||
| import { IMigrateContract, IOwnableContract, TestMigratorContract, TestMigratorEvents } from '../wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Migrate feature', env => { | ||||
|     let owner: string; | ||||
|     let ownable: IOwnableContract; | ||||
|     let migrate: IMigrateContract; | ||||
|     let testMigrator: TestMigratorContract; | ||||
|     let succeedingMigrateFnCallData: string; | ||||
|     let failingMigrateFnCallData: string; | ||||
|     let revertingMigrateFnCallData: string; | ||||
|     let logDecoder: LogDecoder; | ||||
|  | ||||
|     before(async () => { | ||||
|         logDecoder = new LogDecoder(env.web3Wrapper, artifacts); | ||||
|         [owner] = await env.getAccountAddressesAsync(); | ||||
|         const zeroEx = await initialMigrateAsync(owner, env.provider, env.txDefaults); | ||||
|         ownable = new IOwnableContract(zeroEx.address, env.provider, env.txDefaults); | ||||
|         migrate = new IMigrateContract(zeroEx.address, env.provider, env.txDefaults); | ||||
|         testMigrator = await TestMigratorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestMigrator, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         succeedingMigrateFnCallData = testMigrator.succeedingMigrate().getABIEncodedTransactionData(); | ||||
|         failingMigrateFnCallData = testMigrator.failingMigrate().getABIEncodedTransactionData(); | ||||
|         revertingMigrateFnCallData = testMigrator.revertingMigrate().getABIEncodedTransactionData(); | ||||
|     }); | ||||
|  | ||||
|     describe('migrate()', () => { | ||||
|         it('non-owner cannot call migrate()', async () => { | ||||
|             const notOwner = randomAddress(); | ||||
|             const tx = migrate | ||||
|                 .migrate(testMigrator.address, succeedingMigrateFnCallData) | ||||
|                 .awaitTransactionSuccessAsync({ from: notOwner }); | ||||
|             return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner, owner)); | ||||
|         }); | ||||
|  | ||||
|         it('can successfully execute a migration', async () => { | ||||
|             const receipt = await migrate | ||||
|                 .migrate(testMigrator.address, succeedingMigrateFnCallData) | ||||
|                 .awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const { logs } = logDecoder.decodeReceiptLogs(receipt); | ||||
|             verifyEventsFromLogs( | ||||
|                 logs, | ||||
|                 [ | ||||
|                     { | ||||
|                         callData: succeedingMigrateFnCallData, | ||||
|                         owner: migrate.address, | ||||
|                         actualOwner: owner, | ||||
|                     }, | ||||
|                 ], | ||||
|                 TestMigratorEvents.TestMigrateCalled, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('owner is restored after a migration', async () => { | ||||
|             await migrate | ||||
|                 .migrate(testMigrator.address, succeedingMigrateFnCallData) | ||||
|                 .awaitTransactionSuccessAsync({ from: owner }); | ||||
|             const currentOwner = await ownable.getOwner().callAsync(); | ||||
|             expect(currentOwner).to.eq(owner); | ||||
|         }); | ||||
|  | ||||
|         it('failing migration reverts', async () => { | ||||
|             const tx = migrate | ||||
|                 .migrate(testMigrator.address, failingMigrateFnCallData) | ||||
|                 .awaitTransactionSuccessAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith( | ||||
|                 new ZeroExRevertErrors.Migrate.MigrateCallFailedError( | ||||
|                     testMigrator.address, | ||||
|                     hexUtils.rightPad('0xdeadbeef'), | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('reverting migration reverts', async () => { | ||||
|             const tx = migrate | ||||
|                 .migrate(testMigrator.address, revertingMigrateFnCallData) | ||||
|                 .awaitTransactionSuccessAsync({ from: owner }); | ||||
|             return expect(tx).to.revertWith( | ||||
|                 new ZeroExRevertErrors.Migrate.MigrateCallFailedError( | ||||
|                     testMigrator.address, | ||||
|                     new StringRevertError('OOPSIE').encode(), | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -1,30 +1,30 @@ | ||||
| import { blockchainTests, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils'; | ||||
| import { OwnableRevertErrors } from '@0x/utils'; | ||||
|  | ||||
| import { basicMigrateAsync } from '../utils/migration'; | ||||
| import { initialMigrateAsync } from '../utils/migration'; | ||||
| import { IOwnableContract, IOwnableEvents } from '../wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Ownable feature', env => { | ||||
|     const notOwner = randomAddress(); | ||||
|     let owner: string; | ||||
|     let auth: IOwnableContract; | ||||
|     let ownable: 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); | ||||
|         const zeroEx = await initialMigrateAsync(owner, env.provider, env.txDefaults); | ||||
|         ownable = 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 }); | ||||
|             const tx = ownable.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 }); | ||||
|             const receipt = await ownable.transferOwnership(newOwner).awaitTransactionSuccessAsync({ from: owner }); | ||||
|             verifyEventsFromLogs( | ||||
|                 receipt.logs, | ||||
|                 [ | ||||
| @@ -35,7 +35,7 @@ blockchainTests.resets('Ownable feature', env => { | ||||
|                 ], | ||||
|                 IOwnableEvents.OwnershipTransferred, | ||||
|             ); | ||||
|             expect(await auth.getOwner().callAsync()).to.eq(newOwner); | ||||
|             expect(await ownable.getOwner().callAsync()).to.eq(newOwner); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs | ||||
| import { BigNumber, hexUtils, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts } from '../artifacts'; | ||||
| import { basicMigrateAsync } from '../utils/migration'; | ||||
| import { initialMigrateAsync } from '../utils/migration'; | ||||
| import { | ||||
|     ISimpleFunctionRegistryContract, | ||||
|     ISimpleFunctionRegistryEvents, | ||||
| @@ -25,7 +25,7 @@ blockchainTests.resets('SimpleFunctionRegistry feature', env => { | ||||
|  | ||||
|     before(async () => { | ||||
|         [owner] = await env.getAccountAddressesAsync(); | ||||
|         zeroEx = await basicMigrateAsync(owner, env.provider, env.txDefaults); | ||||
|         zeroEx = await initialMigrateAsync(owner, env.provider, env.txDefaults); | ||||
|         registry = new ISimpleFunctionRegistryContract(zeroEx.address, env.provider, { | ||||
|             ...env.txDefaults, | ||||
|             from: owner, | ||||
|   | ||||
							
								
								
									
										57
									
								
								contracts/zero-ex/test/initial_migration_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								contracts/zero-ex/test/initial_migration_test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| import { blockchainTests, expect } from '@0x/contracts-test-utils'; | ||||
| import { ZeroExRevertErrors } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { IBootstrapContract, IOwnableContract, TestInitialMigrationContract, ZeroExContract } from './wrappers'; | ||||
|  | ||||
| blockchainTests.resets('Initial migration', env => { | ||||
|     let owner: string; | ||||
|     let zeroEx: ZeroExContract; | ||||
|     let migrator: TestInitialMigrationContract; | ||||
|     let bootstrapFeature: IBootstrapContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         [owner] = await env.getAccountAddressesAsync(); | ||||
|         migrator = await TestInitialMigrationContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.TestInitialMigration, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|         bootstrapFeature = new IBootstrapContract( | ||||
|             await migrator.bootstrapFeature().callAsync(), | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             {}, | ||||
|         ); | ||||
|         const deployCall = migrator.deploy(owner); | ||||
|         zeroEx = new ZeroExContract(await deployCall.callAsync(), env.provider, env.txDefaults); | ||||
|         await deployCall.awaitTransactionSuccessAsync(); | ||||
|     }); | ||||
|  | ||||
|     describe('bootstrapping', () => { | ||||
|         it('Migrator cannot call bootstrap() again', async () => { | ||||
|             const tx = migrator.callBootstrap(zeroEx.address).awaitTransactionSuccessAsync(); | ||||
|             const selector = bootstrapFeature.getSelector('bootstrap'); | ||||
|             return expect(tx).to.revertWith(new ZeroExRevertErrors.Proxy.NotImplementedError(selector)); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     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); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     it('bootstrap feature self destructs after deployment', async () => { | ||||
|         const codeSize = await migrator.getCodeSizeOf(bootstrapFeature.address).callAsync(); | ||||
|         expect(codeSize).to.bignumber.eq(0); | ||||
|     }); | ||||
| }); | ||||
| @@ -2,22 +2,22 @@ import { SupportedProvider } from '@0x/subproviders'; | ||||
| import { TxData } from 'ethereum-types'; | ||||
|  | ||||
| import { artifacts } from '../artifacts'; | ||||
| import { BasicMigrationContract, ZeroExContract } from '../wrappers'; | ||||
| import { InitialMigrationContract, ZeroExContract } from '../wrappers'; | ||||
|  | ||||
| // tslint:disable: completed-docs | ||||
| export async function basicMigrateAsync( | ||||
| export async function initialMigrateAsync( | ||||
|     owner: string, | ||||
|     provider: SupportedProvider, | ||||
|     txDefaults: Partial<TxData>, | ||||
| ): Promise<ZeroExContract> { | ||||
|     const migrator = await BasicMigrationContract.deployFrom0xArtifactAsync( | ||||
|         artifacts.BasicMigration, | ||||
|     const migrator = await InitialMigrationContract.deployFrom0xArtifactAsync( | ||||
|         artifacts.InitialMigration, | ||||
|         provider, | ||||
|         txDefaults, | ||||
|         artifacts, | ||||
|     ); | ||||
|     const migrateCall = migrator.migrate(owner); | ||||
|     const zeroEx = new ZeroExContract(await migrateCall.callAsync(), provider, {}); | ||||
|     await migrateCall.awaitTransactionSuccessAsync(); | ||||
|     const deployCall = migrator.deploy(owner); | ||||
|     const zeroEx = new ZeroExContract(await deployCall.callAsync(), provider, {}); | ||||
|     await deployCall.awaitTransactionSuccessAsync(); | ||||
|     return zeroEx; | ||||
| } | ||||
|   | ||||
| @@ -3,24 +3,32 @@ | ||||
|  * 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/bootstrap'; | ||||
| export * from '../test/generated-wrappers/fixin_common'; | ||||
| export * from '../test/generated-wrappers/fixin_ownable'; | ||||
| export * from '../test/generated-wrappers/i_bootstrap'; | ||||
| export * from '../test/generated-wrappers/i_feature'; | ||||
| export * from '../test/generated-wrappers/i_migrate'; | ||||
| 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/initial_migration'; | ||||
| export * from '../test/generated-wrappers/lib_bootstrap'; | ||||
| export * from '../test/generated-wrappers/lib_common_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_migrate'; | ||||
| export * from '../test/generated-wrappers/lib_migrate_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_migrate_storage'; | ||||
| 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/migrate'; | ||||
| 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_initial_migration'; | ||||
| export * from '../test/generated-wrappers/test_migrator'; | ||||
| 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'; | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/co | ||||
| import { BigNumber, ZeroExRevertErrors } from '@0x/utils'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { basicMigrateAsync } from './utils/migration'; | ||||
| import { initialMigrateAsync } from './utils/migration'; | ||||
| import { | ||||
|     IFeatureContract, | ||||
|     IOwnableContract, | ||||
| @@ -21,7 +21,7 @@ blockchainTests.resets('ZeroEx contract', env => { | ||||
|  | ||||
|     before(async () => { | ||||
|         [owner] = await env.getAccountAddressesAsync(); | ||||
|         zeroEx = await basicMigrateAsync(owner, env.provider, env.txDefaults); | ||||
|         zeroEx = await initialMigrateAsync(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); | ||||
|   | ||||
| @@ -3,27 +3,36 @@ | ||||
|     "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, | ||||
|     "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], | ||||
|     "files": [ | ||||
|         "generated-artifacts/IMigrate.json", | ||||
|         "generated-artifacts/IOwnable.json", | ||||
|         "generated-artifacts/ISimpleFunctionRegistry.json", | ||||
|         "generated-artifacts/ZeroEx.json", | ||||
|         "test/generated-artifacts/BasicMigration.json", | ||||
|         "test/generated-artifacts/Bootstrap.json", | ||||
|         "test/generated-artifacts/FixinCommon.json", | ||||
|         "test/generated-artifacts/FixinOwnable.json", | ||||
|         "test/generated-artifacts/IBootstrap.json", | ||||
|         "test/generated-artifacts/IFeature.json", | ||||
|         "test/generated-artifacts/IMigrate.json", | ||||
|         "test/generated-artifacts/IOwnable.json", | ||||
|         "test/generated-artifacts/ISimpleFunctionRegistry.json", | ||||
|         "test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json", | ||||
|         "test/generated-artifacts/IZeroExBootstrapper.json", | ||||
|         "test/generated-artifacts/InitialMigration.json", | ||||
|         "test/generated-artifacts/LibBootstrap.json", | ||||
|         "test/generated-artifacts/LibCommonRichErrors.json", | ||||
|         "test/generated-artifacts/LibMigrate.json", | ||||
|         "test/generated-artifacts/LibMigrateRichErrors.json", | ||||
|         "test/generated-artifacts/LibMigrateStorage.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/Migrate.json", | ||||
|         "test/generated-artifacts/Ownable.json", | ||||
|         "test/generated-artifacts/SimpleFunctionRegistry.json", | ||||
|         "test/generated-artifacts/TestBasicMigration.json", | ||||
|         "test/generated-artifacts/TestInitialMigration.json", | ||||
|         "test/generated-artifacts/TestMigrator.json", | ||||
|         "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json", | ||||
|         "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json", | ||||
|         "test/generated-artifacts/TestZeroExFeature.json", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user