From 6f5bf9d146368fe21d8dd7a8609cc3d04d3b9f8a Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Thu, 5 Mar 2020 10:53:02 -0800 Subject: [PATCH] Add artifacts, wrappers, and addresses --- packages/contract-addresses/CHANGELOG.json | 9 + packages/contract-addresses/addresses.json | 15 +- packages/contract-addresses/src/index.ts | 1 + packages/contract-artifacts/CHANGELOG.json | 9 + .../artifacts/MaximumGasPrice.json | 70 ++++ packages/contract-wrappers/CHANGELOG.json | 13 + packages/contract-wrappers/package.json | 2 +- .../src/generated-wrappers/broker.ts | 96 ++++- .../gods_unchained_validator.ts | 94 ++++- .../generated-wrappers/maximum_gas_price.ts | 334 ++++++++++++++++++ packages/migrations/src/migration.ts | 1 + 11 files changed, 636 insertions(+), 8 deletions(-) create mode 100644 packages/contract-artifacts/artifacts/MaximumGasPrice.json create mode 100644 packages/contract-wrappers/src/generated-wrappers/maximum_gas_price.ts diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index 77d26c7c86..58a7cdb4f3 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "4.10.0", + "changes": [ + { + "note": "Added MaximumGasPrice addresses", + "pr": 2511 + } + ] + }, { "version": "4.9.0", "changes": [ diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index c2cabef7b1..ba27501e82 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -28,7 +28,8 @@ "godsUnchainedValidator": "0x09A379Ef7218BCFD8913fAa8B281ebc5A2E0bC04", "broker": "0xd4690a51044db77D91d7Aa8f7a3a5ad5dA331Af0", "chainlinkStopLimit": "0xeb27220f95f364e1d9531992c48613f231839f53", - "curveBridge": "0xe335bdd1fb0ee30f9a9a434f18f8b118dec32df7" + "curveBridge": "0xe335bdd1fb0ee30f9a9a434f18f8b118dec32df7", + "maximumGasPrice": "0xe2bfd35306495d11e3c9db0d8de390cda24563cf" }, "3": { "erc20Proxy": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa", @@ -59,7 +60,8 @@ "godsUnchainedValidator": "0xd4690a51044db77D91d7Aa8f7a3a5ad5dA331Af0", "broker": "0x4Aa817C6f383C8e8aE77301d18Ce48efb16Fd2BE", "chainlinkStopLimit": "0x67a094cf028221ffdd93fc658f963151d05e2a74", - "curveBridge": "0x0000000000000000000000000000000000000000" + "curveBridge": "0x0000000000000000000000000000000000000000", + "maximumGasPrice": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a" }, "4": { "exchangeV2": "0xbff9493f92a3df4b0429b6d00743b3cfb4c85831", @@ -90,7 +92,8 @@ "godsUnchainedValidator": "0x0000000000000000000000000000000000000000", "broker": "0x0000000000000000000000000000000000000000", "chainlinkStopLimit": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a", - "curveBridge": "0x0000000000000000000000000000000000000000" + "curveBridge": "0x0000000000000000000000000000000000000000", + "maximumGasPrice": "0x47697b44bd89051e93b4d5857ba8e024800a74ac" }, "42": { "erc20Proxy": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e", @@ -121,7 +124,8 @@ "godsUnchainedValidator": "0x0000000000000000000000000000000000000000", "broker": "0x0000000000000000000000000000000000000000", "chainlinkStopLimit": "0x0000000000000000000000000000000000000000", - "curveBridge": "0x0000000000000000000000000000000000000000" + "curveBridge": "0x0000000000000000000000000000000000000000", + "maximumGasPrice": "0x67a094cf028221ffdd93fc658f963151d05e2a74" }, "1337": { "erc20Proxy": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48", @@ -152,6 +156,7 @@ "godsUnchainedValidator": "0x0000000000000000000000000000000000000000", "broker": "0x0000000000000000000000000000000000000000", "chainlinkStopLimit": "0x0000000000000000000000000000000000000000", - "curveBridge": "0x0000000000000000000000000000000000000000" + "curveBridge": "0x0000000000000000000000000000000000000000", + "maximumGasPrice": "0x0000000000000000000000000000000000000000" } } diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts index 0229f9ebe2..a9d519b586 100644 --- a/packages/contract-addresses/src/index.ts +++ b/packages/contract-addresses/src/index.ts @@ -30,6 +30,7 @@ export interface ContractAddresses { godsUnchainedValidator: string; broker: string; chainlinkStopLimit: string; + maximumGasPrice: string; } export enum ChainId { diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json index 3e957ec2b8..58e3d872c5 100644 --- a/packages/contract-artifacts/CHANGELOG.json +++ b/packages/contract-artifacts/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "3.7.0", + "changes": [ + { + "note": "Added `MaximumGasPrice` artifact", + "pr": 2511 + } + ] + }, { "timestamp": 1582623685, "version": "3.6.1", diff --git a/packages/contract-artifacts/artifacts/MaximumGasPrice.json b/packages/contract-artifacts/artifacts/MaximumGasPrice.json new file mode 100644 index 0000000000..3ccdc90cf2 --- /dev/null +++ b/packages/contract-artifacts/artifacts/MaximumGasPrice.json @@ -0,0 +1,70 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "MaximumGasPrice", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [], + "name": "checkGasPrice", + "outputs": [], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "uint256", "name": "maxGasPrice", "type": "uint256" }], + "name": "checkGasPrice", + "outputs": [], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "methods": { + "checkGasPrice()": { + "details": "Checks that the current transaction's gas price is less than the default maximum value of 20 Gwei." + }, + "checkGasPrice(uint256)": { + "details": "Checks that the current transaction's gas price is less than the specified maximum value.", + "params": { "maxGasPrice": "The maximum gas price allowed for the current transaction." } + } + } + }, + "evm": { + "bytecode": { + "object": "0x608060405234801561001057600080fd5b506101a5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063d728f5b71461003b578063da5b166a14610045575b600080fd5b610043610062565b005b6100436004803603602081101561005b57600080fd5b50356100c2565b6404a817c8003a11156100c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806101486029913960400191505060405180910390fd5b565b803a111561011b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061011f6029913960400191505060405180910390fd5b5056fe4d6178696d756d47617350726963652f4741535f50524943455f455843454544535f4d4158494d554d4d6178696d756d47617350726963652f4741535f50524943455f455843454544535f32305f47574549a265627a7a72315820b735b9a3a2024167c985358b7c43d479b1e6d937ae2375ccb506b2092c0c20e564736f6c63430005100032" + }, + "deployedBytecode": { + "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063d728f5b71461003b578063da5b166a14610045575b600080fd5b610043610062565b005b6100436004803603602081101561005b57600080fd5b50356100c2565b6404a817c8003a11156100c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806101486029913960400191505060405180910390fd5b565b803a111561011b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061011f6029913960400191505060405180910390fd5b5056fe4d6178696d756d47617350726963652f4741535f50524943455f455843454544535f4d4158494d554d4d6178696d756d47617350726963652f4741535f50524943455f455843454544535f32305f47574549a265627a7a72315820b735b9a3a2024167c985358b7c43d479b1e6d937ae2375ccb506b2092c0c20e564736f6c63430005100032" + } + } + }, + "compiler": { + "name": "solc", + "version": "soljson-v0.5.16+commit.9c3226ce.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "devdoc", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "istanbul" + } + }, + "chains": {} +} diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index d3e4f2dce9..abd74491da 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,17 @@ [ + { + "version": "13.7.0", + "changes": [ + { + "note": "Regenerated wrappers for Broker and GodsUnchainedValidator", + "pr": 2511 + }, + { + "note": "Added wrapper for MaximumGasPrice", + "pr": 2511 + } + ] + }, { "timestamp": 1583220306, "version": "13.6.3", diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index a10ec452f7..da155a0289 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -31,7 +31,7 @@ "wrappers:generate": "abi-gen --abis ${npm_package_config_abis} --output src/generated-wrappers --backend ethers" }, "config": { - "abis": "../contract-artifacts/artifacts/@(DevUtils|ERC20Token|ERC721Token|Exchange|Forwarder|IAssetData|LibTransactionDecoder|WETH9|Coordinator|Staking|StakingProxy|IERC20BridgeSampler|GodsUnchainedValidator|Broker).json" + "abis": "../contract-artifacts/artifacts/@(DevUtils|ERC20Token|ERC721Token|Exchange|Forwarder|IAssetData|LibTransactionDecoder|WETH9|Coordinator|Staking|StakingProxy|IERC20BridgeSampler|GodsUnchainedValidator|Broker|MaximumGasPrice).json" }, "repository": { "type": "git", diff --git a/packages/contract-wrappers/src/generated-wrappers/broker.ts b/packages/contract-wrappers/src/generated-wrappers/broker.ts index 2efeafabc1..06ae217df9 100644 --- a/packages/contract-wrappers/src/generated-wrappers/broker.ts +++ b/packages/contract-wrappers/src/generated-wrappers/broker.ts @@ -9,6 +9,7 @@ import { BaseContract, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -25,7 +26,7 @@ import { TxDataPayable, SupportedProvider, } from 'ethereum-types'; -import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils'; +import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { assert } from '@0x/assert'; @@ -33,6 +34,7 @@ import * as ethers from 'ethers'; // tslint:enable:no-unused-variable /* istanbul ignore next */ +// tslint:disable:array-type // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class BrokerContract extends BaseContract { @@ -77,6 +79,50 @@ export class BrokerContract extends BaseContract { weth, ); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + exchange: string, + weth: string, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + const libraryAddresses = await BrokerContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return BrokerContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + exchange, + weth, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -432,12 +478,58 @@ export class BrokerContract extends BaseContract { return abi; } + protected static async _deployLibrariesAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + web3Wrapper: Web3Wrapper, + txDefaults: Partial, + libraryAddresses: { [libraryName: string]: string } = {}, + ): Promise<{ [libraryName: string]: string }> { + const links = artifact.compilerOutput.evm.bytecode.linkReferences; + // Go through all linked libraries, recursively deploying them if necessary. + for (const link of Object.values(links)) { + for (const libraryName of Object.keys(link)) { + if (!libraryAddresses[libraryName]) { + // Library not yet deployed. + const libraryArtifact = libraryArtifacts[libraryName]; + if (!libraryArtifact) { + throw new Error(`Missing artifact for linked library "${libraryName}"`); + } + // Deploy any dependent libraries used by this library. + await BrokerContract._deployLibrariesAsync( + libraryArtifact, + libraryArtifacts, + web3Wrapper, + txDefaults, + libraryAddresses, + ); + // Deploy this library. + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: linkedLibraryBytecode, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); + libraryAddresses[libraryArtifact.contractName] = contractAddress as string; + } + } + } + return libraryAddresses; + } + public getFunctionSignature(methodName: string): string { const index = this._methodABIIndex[methodName]; const methodAbi = BrokerContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion const functionSignature = methodAbiToFunctionSignature(methodAbi); return functionSignature; } + public getABIDecodedTransactionData(methodName: string, callData: string): T { const functionSignature = this.getFunctionSignature(methodName); const self = (this as any) as BrokerContract; @@ -445,6 +537,7 @@ export class BrokerContract extends BaseContract { const abiDecodedCallData = abiEncoder.strictDecode(callData); return abiDecodedCallData; } + public getABIDecodedReturnData(methodName: string, callData: string): T { const functionSignature = this.getFunctionSignature(methodName); const self = (this as any) as BrokerContract; @@ -452,6 +545,7 @@ export class BrokerContract extends BaseContract { const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); return abiDecodedCallData; } + public getSelector(methodName: string): string { const functionSignature = this.getFunctionSignature(methodName); const self = (this as any) as BrokerContract; diff --git a/packages/contract-wrappers/src/generated-wrappers/gods_unchained_validator.ts b/packages/contract-wrappers/src/generated-wrappers/gods_unchained_validator.ts index cfacae76af..67ed233daf 100644 --- a/packages/contract-wrappers/src/generated-wrappers/gods_unchained_validator.ts +++ b/packages/contract-wrappers/src/generated-wrappers/gods_unchained_validator.ts @@ -9,6 +9,7 @@ import { BaseContract, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -25,7 +26,7 @@ import { TxDataPayable, SupportedProvider, } from 'ethereum-types'; -import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils'; +import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { assert } from '@0x/assert'; @@ -33,6 +34,7 @@ import * as ethers from 'ethers'; // tslint:enable:no-unused-variable /* istanbul ignore next */ +// tslint:disable:array-type // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class GodsUnchainedValidatorContract extends BaseContract { @@ -75,6 +77,48 @@ export class GodsUnchainedValidatorContract extends BaseContract { _godsUnchained, ); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + _godsUnchained: string, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + const libraryAddresses = await GodsUnchainedValidatorContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return GodsUnchainedValidatorContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _godsUnchained, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -160,12 +204,58 @@ export class GodsUnchainedValidatorContract extends BaseContract { return abi; } + protected static async _deployLibrariesAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + web3Wrapper: Web3Wrapper, + txDefaults: Partial, + libraryAddresses: { [libraryName: string]: string } = {}, + ): Promise<{ [libraryName: string]: string }> { + const links = artifact.compilerOutput.evm.bytecode.linkReferences; + // Go through all linked libraries, recursively deploying them if necessary. + for (const link of Object.values(links)) { + for (const libraryName of Object.keys(link)) { + if (!libraryAddresses[libraryName]) { + // Library not yet deployed. + const libraryArtifact = libraryArtifacts[libraryName]; + if (!libraryArtifact) { + throw new Error(`Missing artifact for linked library "${libraryName}"`); + } + // Deploy any dependent libraries used by this library. + await GodsUnchainedValidatorContract._deployLibrariesAsync( + libraryArtifact, + libraryArtifacts, + web3Wrapper, + txDefaults, + libraryAddresses, + ); + // Deploy this library. + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: linkedLibraryBytecode, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); + libraryAddresses[libraryArtifact.contractName] = contractAddress as string; + } + } + } + return libraryAddresses; + } + public getFunctionSignature(methodName: string): string { const index = this._methodABIIndex[methodName]; const methodAbi = GodsUnchainedValidatorContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion const functionSignature = methodAbiToFunctionSignature(methodAbi); return functionSignature; } + public getABIDecodedTransactionData(methodName: string, callData: string): T { const functionSignature = this.getFunctionSignature(methodName); const self = (this as any) as GodsUnchainedValidatorContract; @@ -173,6 +263,7 @@ export class GodsUnchainedValidatorContract extends BaseContract { const abiDecodedCallData = abiEncoder.strictDecode(callData); return abiDecodedCallData; } + public getABIDecodedReturnData(methodName: string, callData: string): T { const functionSignature = this.getFunctionSignature(methodName); const self = (this as any) as GodsUnchainedValidatorContract; @@ -180,6 +271,7 @@ export class GodsUnchainedValidatorContract extends BaseContract { const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); return abiDecodedCallData; } + public getSelector(methodName: string): string { const functionSignature = this.getFunctionSignature(methodName); const self = (this as any) as GodsUnchainedValidatorContract; diff --git a/packages/contract-wrappers/src/generated-wrappers/maximum_gas_price.ts b/packages/contract-wrappers/src/generated-wrappers/maximum_gas_price.ts new file mode 100644 index 0000000000..0a8b09e012 --- /dev/null +++ b/packages/contract-wrappers/src/generated-wrappers/maximum_gas_price.ts @@ -0,0 +1,334 @@ +// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming +// tslint:disable:whitespace no-unbound-method no-trailing-whitespace +// tslint:disable:no-unused-variable +import { + AwaitTransactionSuccessOpts, + ContractFunctionObj, + ContractTxFunctionObj, + SendTransactionOpts, + BaseContract, + PromiseWithTransactionHash, + methodAbiToFunctionSignature, + linkLibrariesInBytecode, +} from '@0x/base-contract'; +import { schemas } from '@0x/json-schemas'; +import { + BlockParam, + BlockParamLiteral, + BlockRange, + CallData, + ContractAbi, + ContractArtifact, + DecodedLogArgs, + MethodAbi, + TransactionReceiptWithDecodedLogs, + TxData, + TxDataPayable, + SupportedProvider, +} from 'ethereum-types'; +import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; +import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { assert } from '@0x/assert'; +import * as ethers from 'ethers'; +// tslint:enable:no-unused-variable + +/* istanbul ignore next */ +// tslint:disable:array-type +// tslint:disable:no-parameter-reassignment +// tslint:disable-next-line:class-name +export class MaximumGasPriceContract extends BaseContract { + /** + * @ignore + */ + public static deployedBytecode: string | undefined; + public static contractName = 'MaximumGasPrice'; + private readonly _methodABIIndex: { [name: string]: number } = {}; + public static async deployFrom0xArtifactAsync( + artifact: ContractArtifact | SimpleContractArtifact, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const bytecode = artifact.compilerOutput.evm.bytecode.object; + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return MaximumGasPriceContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + const libraryAddresses = await MaximumGasPriceContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return MaximumGasPriceContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + + public static async deployAsync( + bytecode: string, + abi: ContractAbi, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, + ): Promise { + assert.isHexString('bytecode', bytecode); + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const constructorAbi = BaseContract._lookupConstructorAbi(abi); + [] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString); + const iface = new ethers.utils.Interface(abi); + const deployInfo = iface.deployFunction; + const txData = deployInfo.encode(bytecode, []); + const web3Wrapper = new Web3Wrapper(provider); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: txData, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`MaximumGasPrice successfully deployed at ${txReceipt.contractAddress}`); + const contractInstance = new MaximumGasPriceContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); + contractInstance.constructorArgs = []; + return contractInstance; + } + + /** + * @returns The contract ABI + */ + public static ABI(): ContractAbi { + const abi = [ + { + constant: true, + inputs: [], + name: 'checkGasPrice', + outputs: [], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'maxGasPrice', + type: 'uint256', + }, + ], + name: 'checkGasPrice', + outputs: [], + payable: false, + stateMutability: 'view', + type: 'function', + }, + ] as ContractAbi; + return abi; + } + + protected static async _deployLibrariesAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + web3Wrapper: Web3Wrapper, + txDefaults: Partial, + libraryAddresses: { [libraryName: string]: string } = {}, + ): Promise<{ [libraryName: string]: string }> { + const links = artifact.compilerOutput.evm.bytecode.linkReferences; + // Go through all linked libraries, recursively deploying them if necessary. + for (const link of Object.values(links)) { + for (const libraryName of Object.keys(link)) { + if (!libraryAddresses[libraryName]) { + // Library not yet deployed. + const libraryArtifact = libraryArtifacts[libraryName]; + if (!libraryArtifact) { + throw new Error(`Missing artifact for linked library "${libraryName}"`); + } + // Deploy any dependent libraries used by this library. + await MaximumGasPriceContract._deployLibrariesAsync( + libraryArtifact, + libraryArtifacts, + web3Wrapper, + txDefaults, + libraryAddresses, + ); + // Deploy this library. + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: linkedLibraryBytecode, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); + libraryAddresses[libraryArtifact.contractName] = contractAddress as string; + } + } + } + return libraryAddresses; + } + + public getFunctionSignature(methodName: string): string { + const index = this._methodABIIndex[methodName]; + const methodAbi = MaximumGasPriceContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion + const functionSignature = methodAbiToFunctionSignature(methodAbi); + return functionSignature; + } + + public getABIDecodedTransactionData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as MaximumGasPriceContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + } + + public getABIDecodedReturnData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as MaximumGasPriceContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); + return abiDecodedCallData; + } + + public getSelector(methodName: string): string { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as MaximumGasPriceContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + return abiEncoder.getSelector(); + } + + /** + * Checks that the current transaction's gas price is less than + * the default maximum value of 20 Gwei. + */ + public checkGasPrice1(): ContractFunctionObj { + const self = (this as any) as MaximumGasPriceContract; + const functionSignature = 'checkGasPrice()'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, []); + }, + }; + } + /** + * Checks that the current transaction's gas price is less than + * the specified maximum value. + * @param maxGasPrice The maximum gas price allowed for the current + * transaction. + */ + public checkGasPrice2(maxGasPrice: BigNumber): ContractFunctionObj { + const self = (this as any) as MaximumGasPriceContract; + assert.isBigNumber('maxGasPrice', maxGasPrice); + const functionSignature = 'checkGasPrice(uint256)'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [maxGasPrice]); + }, + }; + } + + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + deployedBytecode: string | undefined = MaximumGasPriceContract.deployedBytecode, + ) { + super( + 'MaximumGasPrice', + MaximumGasPriceContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + deployedBytecode, + ); + classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + MaximumGasPriceContract.ABI().forEach((item, index) => { + if (item.type === 'function') { + const methodAbi = item as MethodAbi; + this._methodABIIndex[methodAbi.name] = index; + } + }); + } +} + +// tslint:disable:max-file-line-count +// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align +// tslint:enable:trailing-comma whitespace no-trailing-whitespace diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts index 5e5e8bd5db..42d4f4a6e7 100644 --- a/packages/migrations/src/migration.ts +++ b/packages/migrations/src/migration.ts @@ -307,6 +307,7 @@ export async function runMigrationsAsync( godsUnchainedValidator: constants.NULL_ADDRESS, broker: constants.NULL_ADDRESS, chainlinkStopLimit: constants.NULL_ADDRESS, + maximumGasPrice: constants.NULL_ADDRESS, }; return contractAddresses; }