500 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			500 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import {
 | |
|     artifacts as assetProxyArtifacts,
 | |
|     ERC1155ProxyContract,
 | |
|     ERC20ProxyContract,
 | |
|     ERC721ProxyContract,
 | |
|     MultiAssetProxyContract,
 | |
|     StaticCallProxyContract,
 | |
| } from '@0x/contracts-asset-proxy';
 | |
| import { DevUtilsContract } from '@0x/contracts-dev-utils';
 | |
| import { artifacts as ERC1155Artifacts, ERC1155MintableContract } from '@0x/contracts-erc1155';
 | |
| import { artifacts as ERC20Artifacts, DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
 | |
| import { artifacts as ERC721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
 | |
| import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
 | |
| import { artifacts as multisigArtifacts, ZeroExGovernorContract } from '@0x/contracts-multisig';
 | |
| import {
 | |
|     artifacts as stakingArtifacts,
 | |
|     StakingProxyContract,
 | |
|     TestStakingContract,
 | |
|     ZrxVaultContract,
 | |
| } from '@0x/contracts-staking';
 | |
| import { BlockchainTestsEnvironment, constants } from '@0x/contracts-test-utils';
 | |
| import { BigNumber } from '@0x/utils';
 | |
| import { TxData } from 'ethereum-types';
 | |
| import * as _ from 'lodash';
 | |
| 
 | |
| import { AssetProxyDispatcher, Authorizable, Ownable } from './wrapper_interfaces';
 | |
| 
 | |
| /**
 | |
|  * Adds a batch of authorities to a list of authorizable contracts.
 | |
|  * @param owner The owner of the authorizable contracts.
 | |
|  * @param authorizers The authorizable contracts.
 | |
|  * @param authorities A list of addresses to authorize in each authorizer contract.
 | |
|  */
 | |
| async function batchAddAuthorizedAddressAsync(
 | |
|     owner: string,
 | |
|     authorizers: Authorizable[],
 | |
|     authorities: string[],
 | |
| ): Promise<void> {
 | |
|     for (const authorizer of authorizers) {
 | |
|         for (const authority of authorities) {
 | |
|             await authorizer.addAuthorizedAddress(authority).awaitTransactionSuccessAsync({ from: owner });
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Batch registers asset proxies in a list of registry contracts.
 | |
|  * @param owner The owner of the registry accounts.
 | |
|  * @param registries The registries that the asset proxies should be registered in.
 | |
|  * @param proxies A list of proxy contracts to register.
 | |
|  */
 | |
| async function batchRegisterAssetProxyAsync(
 | |
|     owner: string,
 | |
|     registries: AssetProxyDispatcher[],
 | |
|     proxies: string[],
 | |
| ): Promise<void> {
 | |
|     for (const registry of registries) {
 | |
|         for (const proxy of proxies) {
 | |
|             await registry.registerAssetProxy(proxy).awaitTransactionSuccessAsync({ from: owner });
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Transfers ownership of several contracts from one address to another.
 | |
|  * @param owner The address that currently owns the contract instances.
 | |
|  * @param newOwner The address that will be given ownership of the contract instances.
 | |
|  * @param ownedContracts The contracts whose ownership will be transferred.
 | |
|  */
 | |
| async function batchTransferOwnershipAsync(
 | |
|     owner: string,
 | |
|     newOwner: ZeroExGovernorContract,
 | |
|     ownedContracts: Ownable[],
 | |
| ): Promise<void> {
 | |
|     for (const ownedContract of ownedContracts) {
 | |
|         await ownedContract.transferOwnership(newOwner.address).awaitTransactionSuccessAsync({ from: owner });
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Contract wrappers for all of the asset proxies
 | |
| interface AssetProxyContracts {
 | |
|     erc20Proxy: ERC20ProxyContract;
 | |
|     erc721Proxy: ERC721ProxyContract;
 | |
|     erc1155Proxy: ERC1155ProxyContract;
 | |
|     multiAssetProxy: MultiAssetProxyContract;
 | |
|     staticCallProxy: StaticCallProxyContract;
 | |
| }
 | |
| 
 | |
| // Contract wrappers for all of the staking contracts
 | |
| interface StakingContracts {
 | |
|     stakingLogic: TestStakingContract;
 | |
|     stakingProxy: StakingProxyContract;
 | |
|     stakingWrapper: TestStakingContract;
 | |
|     zrxVault: ZrxVaultContract;
 | |
| }
 | |
| 
 | |
| // Contract wrappers for tokens.
 | |
| interface TokenContracts {
 | |
|     erc20: DummyERC20TokenContract[];
 | |
|     erc721: DummyERC721TokenContract[];
 | |
|     erc1155: ERC1155MintableContract[];
 | |
|     weth: WETH9Contract;
 | |
|     zrx: DummyERC20TokenContract;
 | |
| }
 | |
| 
 | |
| // Options to be passed to `deployAsync`
 | |
| export interface DeploymentOptions {
 | |
|     owner: string;
 | |
|     numErc1155TokensToDeploy: number;
 | |
|     numErc20TokensToDeploy: number;
 | |
|     numErc721TokensToDeploy: number;
 | |
| }
 | |
| 
 | |
| export class DeploymentManager {
 | |
|     public static readonly protocolFeeMultiplier = new BigNumber(150000);
 | |
|     public static readonly gasPrice = new BigNumber(1e9); // 1 Gwei
 | |
|     public static readonly protocolFee = DeploymentManager.gasPrice.times(DeploymentManager.protocolFeeMultiplier);
 | |
| 
 | |
|     /**
 | |
|      * Fully deploy the 0x exchange and staking contracts and configure the system with the
 | |
|      * asset proxy owner multisig.
 | |
|      * @param environment A blockchain test environment to use for contracts deployment.
 | |
|      * @param options Specifies the owner address and number of tokens to deploy.
 | |
|      */
 | |
|     public static async deployAsync(
 | |
|         environment: BlockchainTestsEnvironment,
 | |
|         options: Partial<DeploymentOptions> = {},
 | |
|     ): Promise<DeploymentManager> {
 | |
|         const chainId = await environment.getChainIdAsync();
 | |
|         const accounts = await environment.getAccountAddressesAsync();
 | |
| 
 | |
|         const owner = options.owner || (await environment.getAccountAddressesAsync())[0];
 | |
|         const txDefaults = {
 | |
|             ...environment.txDefaults,
 | |
|             from: owner,
 | |
|             gasPrice: DeploymentManager.gasPrice,
 | |
|         };
 | |
| 
 | |
|         // Deploy the contracts using the same owner and environment.
 | |
|         const assetProxies = await DeploymentManager._deployAssetProxyContractsAsync(environment, txDefaults);
 | |
|         const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
 | |
|             exchangeArtifacts.Exchange,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             { ...ERC20Artifacts, ...exchangeArtifacts, ...stakingArtifacts },
 | |
|             new BigNumber(chainId),
 | |
|         );
 | |
|         const governor = await ZeroExGovernorContract.deployFrom0xArtifactAsync(
 | |
|             multisigArtifacts.ZeroExGovernor,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             multisigArtifacts,
 | |
|             [],
 | |
|             [],
 | |
|             [],
 | |
|             [owner],
 | |
|             new BigNumber(1),
 | |
|             constants.ZERO_AMOUNT,
 | |
|         );
 | |
|         const tokens = await DeploymentManager._deployTokenContractsAsync(environment, txDefaults, options);
 | |
|         const staking = await DeploymentManager._deployStakingContractsAsync(
 | |
|             environment,
 | |
|             owner,
 | |
|             txDefaults,
 | |
|             tokens,
 | |
|             assetProxies,
 | |
|         );
 | |
| 
 | |
|         // Configure the asset proxies with the exchange and the exchange with the staking contracts.
 | |
|         await DeploymentManager._configureAssetProxiesWithExchangeAsync(assetProxies, exchange, owner);
 | |
|         await DeploymentManager._configureExchangeWithStakingAsync(exchange, staking, owner);
 | |
| 
 | |
|         // Authorize the asset-proxy owner in the staking proxy and in the zrx vault.
 | |
|         await staking.stakingProxy.addAuthorizedAddress(governor.address).awaitTransactionSuccessAsync({
 | |
|             from: owner,
 | |
|         });
 | |
|         await staking.zrxVault.addAuthorizedAddress(governor.address).awaitTransactionSuccessAsync({
 | |
|             from: owner,
 | |
|         });
 | |
| 
 | |
|         // Remove authorization for the original owner address.
 | |
|         await staking.stakingProxy.removeAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner });
 | |
|         await staking.zrxVault.removeAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner });
 | |
| 
 | |
|         // Transfer complete ownership of the system to the asset proxy owner.
 | |
|         await batchTransferOwnershipAsync(owner, governor, [
 | |
|             assetProxies.erc20Proxy,
 | |
|             assetProxies.erc721Proxy,
 | |
|             assetProxies.erc1155Proxy,
 | |
|             assetProxies.multiAssetProxy,
 | |
|             exchange,
 | |
|             staking.stakingProxy,
 | |
|         ]);
 | |
| 
 | |
|         const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, environment.provider);
 | |
| 
 | |
|         return new DeploymentManager(
 | |
|             assetProxies,
 | |
|             governor,
 | |
|             exchange,
 | |
|             staking,
 | |
|             tokens,
 | |
|             chainId,
 | |
|             accounts,
 | |
|             txDefaults,
 | |
|             devUtils,
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Configures a set of asset proxies with an exchange contract.
 | |
|      * @param assetProxies A set of asset proxies to be configured.
 | |
|      * @param exchange An exchange contract to configure with the asset proxies.
 | |
|      * @param owner An owner address to use when configuring the asset proxies.
 | |
|      */
 | |
|     protected static async _configureAssetProxiesWithExchangeAsync(
 | |
|         assetProxies: AssetProxyContracts,
 | |
|         exchange: ExchangeContract,
 | |
|         owner: string,
 | |
|     ): Promise<void> {
 | |
|         // Register the asset proxies in the exchange contract.
 | |
|         await batchRegisterAssetProxyAsync(
 | |
|             owner,
 | |
|             [exchange],
 | |
|             [
 | |
|                 assetProxies.erc20Proxy.address,
 | |
|                 assetProxies.erc721Proxy.address,
 | |
|                 assetProxies.erc1155Proxy.address,
 | |
|                 assetProxies.multiAssetProxy.address,
 | |
|                 assetProxies.staticCallProxy.address,
 | |
|             ],
 | |
|         );
 | |
| 
 | |
|         // Register the asset proxies in the multi-asset proxy.
 | |
|         await batchRegisterAssetProxyAsync(
 | |
|             owner,
 | |
|             [assetProxies.multiAssetProxy],
 | |
|             [
 | |
|                 assetProxies.erc20Proxy.address,
 | |
|                 assetProxies.erc721Proxy.address,
 | |
|                 assetProxies.erc1155Proxy.address,
 | |
|                 assetProxies.staticCallProxy.address,
 | |
|             ],
 | |
|         );
 | |
| 
 | |
|         // Add the multi-asset proxy as an authorized address of the token proxies.
 | |
|         await batchAddAuthorizedAddressAsync(
 | |
|             owner,
 | |
|             [assetProxies.erc20Proxy, assetProxies.erc721Proxy, assetProxies.erc1155Proxy],
 | |
|             [assetProxies.multiAssetProxy.address],
 | |
|         );
 | |
| 
 | |
|         // Add the exchange as an authorized address in all of the proxies.
 | |
|         await batchAddAuthorizedAddressAsync(
 | |
|             owner,
 | |
|             [
 | |
|                 assetProxies.erc20Proxy,
 | |
|                 assetProxies.erc721Proxy,
 | |
|                 assetProxies.erc1155Proxy,
 | |
|                 assetProxies.multiAssetProxy,
 | |
|             ],
 | |
|             [exchange.address],
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Configures an exchange contract with staking contracts
 | |
|      * @param exchange The Exchange contract.
 | |
|      * @param staking The Staking contracts.
 | |
|      * @param owner An owner address to use when configuring the asset proxies.
 | |
|      */
 | |
|     protected static async _configureExchangeWithStakingAsync(
 | |
|         exchange: ExchangeContract,
 | |
|         staking: StakingContracts,
 | |
|         owner: string,
 | |
|     ): Promise<void> {
 | |
|         // Configure the exchange for staking.
 | |
|         await exchange.setProtocolFeeCollectorAddress(staking.stakingProxy.address).awaitTransactionSuccessAsync({
 | |
|             from: owner,
 | |
|         });
 | |
|         await exchange.setProtocolFeeMultiplier(DeploymentManager.protocolFeeMultiplier).awaitTransactionSuccessAsync();
 | |
| 
 | |
|         // Register the exchange contract in staking.
 | |
|         await staking.stakingWrapper.addExchangeAddress(exchange.address).awaitTransactionSuccessAsync({ from: owner });
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Deploy a set of asset proxy contracts.
 | |
|      * @param environment The blockchain environment to use.
 | |
|      * @param txDefaults Defaults to use when deploying the asset proxies.
 | |
|      */
 | |
|     protected static async _deployAssetProxyContractsAsync(
 | |
|         environment: BlockchainTestsEnvironment,
 | |
|         txDefaults: Partial<TxData>,
 | |
|     ): Promise<AssetProxyContracts> {
 | |
|         const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
 | |
|             assetProxyArtifacts.ERC20Proxy,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             assetProxyArtifacts,
 | |
|         );
 | |
|         const erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
 | |
|             assetProxyArtifacts.ERC721Proxy,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             assetProxyArtifacts,
 | |
|         );
 | |
|         const erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
 | |
|             assetProxyArtifacts.ERC1155Proxy,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             assetProxyArtifacts,
 | |
|         );
 | |
|         const multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
 | |
|             assetProxyArtifacts.MultiAssetProxy,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             assetProxyArtifacts,
 | |
|         );
 | |
|         const staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync(
 | |
|             assetProxyArtifacts.StaticCallProxy,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             assetProxyArtifacts,
 | |
|         );
 | |
|         return {
 | |
|             erc20Proxy,
 | |
|             erc721Proxy,
 | |
|             erc1155Proxy,
 | |
|             multiAssetProxy,
 | |
|             staticCallProxy,
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Deploy a set of staking contracts.
 | |
|      * @param environment The blockchain environment to use.
 | |
|      * @param owner An owner address to use when configuring the asset proxies.
 | |
|      * @param txDefaults Defaults to use when deploying the asset proxies.
 | |
|      * @param tokens A set of token contracts to use during deployment of the staking contracts.
 | |
|      * @param assetProxies A set of asset proxies to use with the staking contracts.
 | |
|      */
 | |
|     protected static async _deployStakingContractsAsync(
 | |
|         environment: BlockchainTestsEnvironment,
 | |
|         owner: string,
 | |
|         txDefaults: Partial<TxData>,
 | |
|         tokens: TokenContracts,
 | |
|         assetProxies: AssetProxyContracts,
 | |
|     ): Promise<StakingContracts> {
 | |
|         const zrxVault = await ZrxVaultContract.deployFrom0xArtifactAsync(
 | |
|             stakingArtifacts.ZrxVault,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             stakingArtifacts,
 | |
|             assetProxies.erc20Proxy.address,
 | |
|             tokens.zrx.address,
 | |
|         );
 | |
|         const stakingLogic = await TestStakingContract.deployFrom0xArtifactAsync(
 | |
|             stakingArtifacts.TestStaking,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             stakingArtifacts,
 | |
|             tokens.weth.address,
 | |
|             zrxVault.address,
 | |
|         );
 | |
|         const stakingProxy = await StakingProxyContract.deployFrom0xArtifactAsync(
 | |
|             stakingArtifacts.StakingProxy,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             stakingArtifacts,
 | |
|             stakingLogic.address,
 | |
|         );
 | |
| 
 | |
|         const stakingWrapper = new TestStakingContract(stakingProxy.address, environment.provider, txDefaults);
 | |
| 
 | |
|         // Add the zrx vault and the weth contract to the staking proxy.
 | |
|         await stakingWrapper.setWethContract(tokens.weth.address).awaitTransactionSuccessAsync({ from: owner });
 | |
|         await stakingWrapper.setZrxVault(zrxVault.address).awaitTransactionSuccessAsync({ from: owner });
 | |
| 
 | |
|         // Authorize the owner address in the staking proxy and the zrx vault.
 | |
|         await stakingProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner });
 | |
|         await zrxVault.addAuthorizedAddress(owner).awaitTransactionSuccessAsync({ from: owner });
 | |
| 
 | |
|         // Authorize the zrx vault in the erc20 proxy
 | |
|         await assetProxies.erc20Proxy.addAuthorizedAddress(zrxVault.address).awaitTransactionSuccessAsync({
 | |
|             from: owner,
 | |
|         });
 | |
| 
 | |
|         // Configure the zrx vault and the staking contract.
 | |
|         await zrxVault.setStakingProxy(stakingProxy.address).awaitTransactionSuccessAsync({ from: owner });
 | |
| 
 | |
|         return {
 | |
|             stakingLogic,
 | |
|             stakingProxy,
 | |
|             stakingWrapper,
 | |
|             zrxVault,
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Deploy a set of token contracts.
 | |
|      * @param environment The blockchain environment to use.
 | |
|      * @param txDefaults Defaults to use when deploying the asset proxies.
 | |
|      * @param options Specifies how many tokens of each standard to deploy.
 | |
|      */
 | |
|     protected static async _deployTokenContractsAsync(
 | |
|         environment: BlockchainTestsEnvironment,
 | |
|         txDefaults: Partial<TxData>,
 | |
|         options: Partial<DeploymentOptions>,
 | |
|     ): Promise<TokenContracts> {
 | |
|         const numErc20TokensToDeploy =
 | |
|             options.numErc20TokensToDeploy !== undefined
 | |
|                 ? options.numErc20TokensToDeploy
 | |
|                 : constants.NUM_DUMMY_ERC20_TO_DEPLOY;
 | |
|         const numErc721TokensToDeploy =
 | |
|             options.numErc721TokensToDeploy !== undefined
 | |
|                 ? options.numErc721TokensToDeploy
 | |
|                 : constants.NUM_DUMMY_ERC721_TO_DEPLOY;
 | |
|         const numErc1155TokensToDeploy =
 | |
|             options.numErc1155TokensToDeploy !== undefined
 | |
|                 ? options.numErc1155TokensToDeploy
 | |
|                 : constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY;
 | |
| 
 | |
|         const erc20 = await Promise.all(
 | |
|             _.times(numErc20TokensToDeploy, async () =>
 | |
|                 DummyERC20TokenContract.deployFrom0xArtifactAsync(
 | |
|                     ERC20Artifacts.DummyERC20Token,
 | |
|                     environment.provider,
 | |
|                     txDefaults,
 | |
|                     ERC20Artifacts,
 | |
|                     constants.DUMMY_TOKEN_NAME,
 | |
|                     constants.DUMMY_TOKEN_SYMBOL,
 | |
|                     constants.DUMMY_TOKEN_DECIMALS,
 | |
|                     constants.DUMMY_TOKEN_TOTAL_SUPPLY,
 | |
|                 ),
 | |
|             ),
 | |
|         );
 | |
|         const erc721 = await Promise.all(
 | |
|             _.times(numErc721TokensToDeploy, async () =>
 | |
|                 DummyERC721TokenContract.deployFrom0xArtifactAsync(
 | |
|                     ERC721Artifacts.DummyERC721Token,
 | |
|                     environment.provider,
 | |
|                     txDefaults,
 | |
|                     ERC721Artifacts,
 | |
|                     constants.DUMMY_TOKEN_NAME,
 | |
|                     constants.DUMMY_TOKEN_SYMBOL,
 | |
|                 ),
 | |
|             ),
 | |
|         );
 | |
|         const erc1155 = await Promise.all(
 | |
|             _.times(numErc1155TokensToDeploy, async () =>
 | |
|                 ERC1155MintableContract.deployFrom0xArtifactAsync(
 | |
|                     ERC1155Artifacts.ERC1155Mintable,
 | |
|                     environment.provider,
 | |
|                     txDefaults,
 | |
|                     ERC1155Artifacts,
 | |
|                 ),
 | |
|             ),
 | |
|         );
 | |
| 
 | |
|         const weth = await WETH9Contract.deployFrom0xArtifactAsync(
 | |
|             ERC20Artifacts.WETH9,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             ERC20Artifacts,
 | |
|         );
 | |
|         const zrx = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
 | |
|             ERC20Artifacts.DummyERC20Token,
 | |
|             environment.provider,
 | |
|             txDefaults,
 | |
|             ERC20Artifacts,
 | |
|             constants.DUMMY_TOKEN_NAME,
 | |
|             constants.DUMMY_TOKEN_SYMBOL,
 | |
|             constants.DUMMY_TOKEN_DECIMALS,
 | |
|             constants.DUMMY_TOKEN_TOTAL_SUPPLY,
 | |
|         );
 | |
| 
 | |
|         return {
 | |
|             erc20,
 | |
|             erc721,
 | |
|             erc1155,
 | |
|             weth,
 | |
|             zrx,
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     protected constructor(
 | |
|         public assetProxies: AssetProxyContracts,
 | |
|         public governor: ZeroExGovernorContract,
 | |
|         public exchange: ExchangeContract,
 | |
|         public staking: StakingContracts,
 | |
|         public tokens: TokenContracts,
 | |
|         public chainId: number,
 | |
|         public accounts: string[],
 | |
|         public txDefaults: Partial<TxData>,
 | |
|         public devUtils: DevUtilsContract,
 | |
|     ) {}
 | |
| }
 | |
| // tslint:disable:max-file-line-count
 |