diff --git a/packages/abi-gen/templates/TypeScript/contract.handlebars b/packages/abi-gen/templates/TypeScript/contract.handlebars index f85a7f6dd4..7a5ba5ead9 100644 --- a/packages/abi-gen/templates/TypeScript/contract.handlebars +++ b/packages/abi-gen/templates/TypeScript/contract.handlebars @@ -130,12 +130,9 @@ export class {{contractName}}Contract extends BaseContract { txDefaults ); const bytecode = linkLibrariesInBytecode( - artifact.compilerOutput.evm.bytecode, + artifact, libraryAddresses, ); - if (!hexUtils.isHex(bytecode)) { - throw new Error(`Bytecode for "${artifact.contractName}" was not fully linked.`); - } return {{contractName}}Contract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly, {{> params inputs=ctor.inputs}}); } @@ -236,12 +233,9 @@ export class {{contractName}}Contract extends BaseContract { ); // Deploy this library. const linkedLibraryBytecode = linkLibrariesInBytecode( - libraryArtifact.compilerOutput.evm.bytecode, + libraryArtifact, libraryAddresses, ); - if (!hexUtils.isHex(linkedLibraryBytecode)) { - throw new Error(`Bytecode for library "${libraryArtifact.contractName}" was not fully linked.`); - } const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( { data: linkedLibraryBytecode, diff --git a/packages/abi-gen/test-cli/output/typescript/abi_gen_dummy.ts b/packages/abi-gen/test-cli/output/typescript/abi_gen_dummy.ts index 33d31834c4..b443443c88 100644 --- a/packages/abi-gen/test-cli/output/typescript/abi_gen_dummy.ts +++ b/packages/abi-gen/test-cli/output/typescript/abi_gen_dummy.ts @@ -119,10 +119,7 @@ export class AbiGenDummyContract extends BaseContract { new Web3Wrapper(provider), txDefaults, ); - const bytecode = linkLibrariesInBytecode(artifact.compilerOutput.evm.bytecode, libraryAddresses); - if (!hexUtils.isHex(bytecode)) { - throw new Error(`Bytecode for "${artifact.contractName}" was not fully linked.`); - } + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); return AbiGenDummyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } @@ -933,13 +930,7 @@ export class AbiGenDummyContract extends BaseContract { libraryAddresses, ); // Deploy this library. - const linkedLibraryBytecode = linkLibrariesInBytecode( - libraryArtifact.compilerOutput.evm.bytecode, - libraryAddresses, - ); - if (!hexUtils.isHex(linkedLibraryBytecode)) { - throw new Error(`Bytecode for library "${libraryArtifact.contractName}" was not fully linked.`); - } + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( { data: linkedLibraryBytecode, diff --git a/packages/abi-gen/test-cli/output/typescript/lib_dummy.ts b/packages/abi-gen/test-cli/output/typescript/lib_dummy.ts index 2db785da85..b76c5771e5 100644 --- a/packages/abi-gen/test-cli/output/typescript/lib_dummy.ts +++ b/packages/abi-gen/test-cli/output/typescript/lib_dummy.ts @@ -98,10 +98,7 @@ export class LibDummyContract extends BaseContract { new Web3Wrapper(provider), txDefaults, ); - const bytecode = linkLibrariesInBytecode(artifact.compilerOutput.evm.bytecode, libraryAddresses); - if (!hexUtils.isHex(bytecode)) { - throw new Error(`Bytecode for "${artifact.contractName}" was not fully linked.`); - } + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); return LibDummyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } @@ -180,13 +177,7 @@ export class LibDummyContract extends BaseContract { libraryAddresses, ); // Deploy this library. - const linkedLibraryBytecode = linkLibrariesInBytecode( - libraryArtifact.compilerOutput.evm.bytecode, - libraryAddresses, - ); - if (!hexUtils.isHex(linkedLibraryBytecode)) { - throw new Error(`Bytecode for library "${libraryArtifact.contractName}" was not fully linked.`); - } + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( { data: linkedLibraryBytecode, diff --git a/packages/abi-gen/test-cli/output/typescript/test_lib_dummy.ts b/packages/abi-gen/test-cli/output/typescript/test_lib_dummy.ts index 7cc875574d..95306317ac 100644 --- a/packages/abi-gen/test-cli/output/typescript/test_lib_dummy.ts +++ b/packages/abi-gen/test-cli/output/typescript/test_lib_dummy.ts @@ -99,10 +99,7 @@ export class TestLibDummyContract extends BaseContract { new Web3Wrapper(provider), txDefaults, ); - const bytecode = linkLibrariesInBytecode(artifact.compilerOutput.evm.bytecode, libraryAddresses); - if (!hexUtils.isHex(bytecode)) { - throw new Error(`Bytecode for "${artifact.contractName}" was not fully linked.`); - } + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); return TestLibDummyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } @@ -220,13 +217,7 @@ export class TestLibDummyContract extends BaseContract { libraryAddresses, ); // Deploy this library. - const linkedLibraryBytecode = linkLibrariesInBytecode( - libraryArtifact.compilerOutput.evm.bytecode, - libraryAddresses, - ); - if (!hexUtils.isHex(linkedLibraryBytecode)) { - throw new Error(`Bytecode for library "${libraryArtifact.contractName}" was not fully linked.`); - } + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( { data: linkedLibraryBytecode, diff --git a/packages/base-contract/src/utils.ts b/packages/base-contract/src/utils.ts index cd99e86d55..0f6bda3246 100644 --- a/packages/base-contract/src/utils.ts +++ b/packages/base-contract/src/utils.ts @@ -1,5 +1,5 @@ import { AbiEncoder } from '@0x/utils'; -import { DataItem, EvmBytecodeOutput, MethodAbi } from 'ethereum-types'; +import { ContractArtifact, DataItem, MethodAbi } from 'ethereum-types'; // tslint:disable-next-line:completed-docs export function formatABIDataItem(abi: DataItem, value: any, formatter: (type: string, value: any) => any): any { @@ -40,19 +40,24 @@ export function methodAbiToFunctionSignature(methodAbi: MethodAbi): string { } /** - * Replaces unliked library references in bytecode with real addresses - * and returns the bytecode. + * Replaces unliked library references in the bytecode of a contract artifact + * with real addresses and returns the bytecode. */ export function linkLibrariesInBytecode( - bytecodeArtifact: EvmBytecodeOutput, + artifact: ContractArtifact, libraryAddresses: { [libraryName: string]: string }, ): string { + const bytecodeArtifact = artifact.compilerOutput.evm.bytecode; let bytecode = bytecodeArtifact.object.substr(2); for (const link of Object.values(bytecodeArtifact.linkReferences)) { for (const [libraryName, libraryRefs] of Object.entries(link)) { const libraryAddress = libraryAddresses[libraryName]; if (!libraryAddress) { - continue; + throw new Error( + `${ + artifact.contractName + } has an unlinked reference library ${libraryName} but no addresses was provided'.`, + ); } for (const ref of libraryRefs) { bytecode = [ diff --git a/packages/contract-wrappers/src/generated-wrappers/coordinator.ts b/packages/contract-wrappers/src/generated-wrappers/coordinator.ts index fdc8ae55df..048fcfc7aa 100644 --- a/packages/contract-wrappers/src/generated-wrappers/coordinator.ts +++ b/packages/contract-wrappers/src/generated-wrappers/coordinator.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'; @@ -78,6 +79,50 @@ export class CoordinatorContract extends BaseContract { chainId, ); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + exchange: string, + chainId: BigNumber, + ): 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 CoordinatorContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return CoordinatorContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + exchange, + chainId, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -456,12 +501,58 @@ export class CoordinatorContract 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 CoordinatorContract._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 = CoordinatorContract.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 CoordinatorContract; @@ -469,6 +560,7 @@ export class CoordinatorContract 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 CoordinatorContract; @@ -476,6 +568,7 @@ export class CoordinatorContract 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 CoordinatorContract; @@ -688,7 +781,15 @@ export class CoordinatorContract extends BaseContract { }> > { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue< @@ -840,7 +941,15 @@ export class CoordinatorContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); diff --git a/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts b/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts index bb24dc4a88..1346b79e5c 100644 --- a/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts +++ b/packages/contract-wrappers/src/generated-wrappers/dev_utils.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'; @@ -78,6 +79,50 @@ export class DevUtilsContract extends BaseContract { _chaiBridge, ); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + _exchange: string, + _chaiBridge: 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 DevUtilsContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return DevUtilsContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _exchange, + _chaiBridge, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -1666,12 +1711,58 @@ export class DevUtilsContract 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 DevUtilsContract._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 = DevUtilsContract.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 DevUtilsContract; @@ -1679,6 +1770,7 @@ export class DevUtilsContract 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 DevUtilsContract; @@ -1686,6 +1778,7 @@ export class DevUtilsContract 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 DevUtilsContract; @@ -1729,7 +1822,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[number, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[number, string, string]>(rawCallResult); @@ -1752,7 +1853,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string]>(rawCallResult); @@ -1776,7 +1885,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -1802,7 +1919,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, string]>(rawCallResult); @@ -1828,7 +1953,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, string, string]>(rawCallResult); @@ -1857,7 +1990,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, BigNumber[], BigNumber[], string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, BigNumber[], BigNumber[], string]>( @@ -1882,7 +2023,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string]>(rawCallResult); @@ -1909,7 +2058,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, string, string]>(rawCallResult); @@ -1936,7 +2093,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, BigNumber]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, BigNumber]>(rawCallResult); @@ -1962,7 +2127,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[number, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[number, string, string]>(rawCallResult); @@ -1985,7 +2158,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[number, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[number, string]>(rawCallResult); @@ -2011,7 +2192,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[number, BigNumber, BigNumber]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[number, BigNumber, BigNumber]>(rawCallResult); @@ -2037,7 +2226,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, BigNumber[], string[]]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, BigNumber[], string[]]>(rawCallResult); @@ -2060,7 +2257,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string]>(rawCallResult); @@ -2086,7 +2291,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, BigNumber]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, BigNumber]>(rawCallResult); @@ -2109,7 +2322,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[string, number]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, number]>(rawCallResult); @@ -2135,7 +2356,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[number, string, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[number, string, string, string]>(rawCallResult); @@ -2158,7 +2387,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string]>(rawCallResult); @@ -2184,7 +2421,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, string, string]>(rawCallResult); @@ -2211,7 +2456,15 @@ export class DevUtilsContract extends BaseContract { defaultBlock?: BlockParam, ): Promise<[string, string, string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string, string, string]>(rawCallResult); @@ -2234,7 +2487,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[number, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[number, string]>(rawCallResult); @@ -2257,7 +2518,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[string, string]> { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue<[string, string]>(rawCallResult); @@ -2293,7 +2562,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -2322,7 +2599,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -2348,7 +2633,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -2374,7 +2667,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -2407,7 +2708,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -2819,7 +3128,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -3273,7 +3590,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); @@ -3350,7 +3675,15 @@ export class DevUtilsContract extends BaseContract { return { async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue(rawCallResult); diff --git a/packages/contract-wrappers/src/generated-wrappers/erc20_token.ts b/packages/contract-wrappers/src/generated-wrappers/erc20_token.ts index 419c4c21ef..02f831b38b 100644 --- a/packages/contract-wrappers/src/generated-wrappers/erc20_token.ts +++ b/packages/contract-wrappers/src/generated-wrappers/erc20_token.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -89,6 +90,40 @@ export class ERC20TokenContract extends BaseContract { } return ERC20TokenContract.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 ERC20TokenContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ERC20TokenContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -314,12 +349,58 @@ export class ERC20TokenContract 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 ERC20TokenContract._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 = ERC20TokenContract.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 ERC20TokenContract; @@ -327,6 +408,7 @@ export class ERC20TokenContract 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 ERC20TokenContract; @@ -334,6 +416,7 @@ export class ERC20TokenContract 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 ERC20TokenContract; @@ -608,6 +691,7 @@ export class ERC20TokenContract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -615,12 +699,14 @@ export class ERC20TokenContract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The ERC20Token contract event you would like to subscribe to. @@ -646,6 +732,7 @@ export class ERC20TokenContract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider, diff --git a/packages/contract-wrappers/src/generated-wrappers/erc721_token.ts b/packages/contract-wrappers/src/generated-wrappers/erc721_token.ts index 1a7996d3c3..e51818dc2b 100644 --- a/packages/contract-wrappers/src/generated-wrappers/erc721_token.ts +++ b/packages/contract-wrappers/src/generated-wrappers/erc721_token.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -99,6 +100,40 @@ export class ERC721TokenContract extends BaseContract { } return ERC721TokenContract.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 ERC721TokenContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ERC721TokenContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -404,12 +439,58 @@ export class ERC721TokenContract 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 ERC721TokenContract._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 = ERC721TokenContract.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 ERC721TokenContract; @@ -417,6 +498,7 @@ export class ERC721TokenContract 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 ERC721TokenContract; @@ -424,6 +506,7 @@ export class ERC721TokenContract 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 ERC721TokenContract; @@ -868,6 +951,7 @@ export class ERC721TokenContract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -875,12 +959,14 @@ export class ERC721TokenContract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The ERC721Token contract event you would like to subscribe to. @@ -906,6 +992,7 @@ export class ERC721TokenContract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider, diff --git a/packages/contract-wrappers/src/generated-wrappers/exchange.ts b/packages/contract-wrappers/src/generated-wrappers/exchange.ts index f044bb0e09..a39c898884 100644 --- a/packages/contract-wrappers/src/generated-wrappers/exchange.ts +++ b/packages/contract-wrappers/src/generated-wrappers/exchange.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -156,6 +157,41 @@ export class ExchangeContract extends BaseContract { } return ExchangeContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly, chainId); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + chainId: BigNumber, + ): 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 ExchangeContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ExchangeContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly, chainId); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -3113,12 +3149,58 @@ export class ExchangeContract 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 ExchangeContract._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 = ExchangeContract.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 ExchangeContract; @@ -3126,6 +3208,7 @@ export class ExchangeContract 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 ExchangeContract; @@ -3133,6 +3216,7 @@ export class ExchangeContract 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 ExchangeContract; @@ -5879,6 +5963,7 @@ export class ExchangeContract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -5886,12 +5971,14 @@ export class ExchangeContract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The Exchange contract event you would like to subscribe to. @@ -5917,6 +6004,7 @@ export class ExchangeContract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider, diff --git a/packages/contract-wrappers/src/generated-wrappers/forwarder.ts b/packages/contract-wrappers/src/generated-wrappers/forwarder.ts index 5f12fccbc1..1c602bc852 100644 --- a/packages/contract-wrappers/src/generated-wrappers/forwarder.ts +++ b/packages/contract-wrappers/src/generated-wrappers/forwarder.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -93,6 +94,52 @@ export class ForwarderContract extends BaseContract { _weth, ); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + _exchange: string, + _exchangeV2: 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 ForwarderContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ForwarderContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _exchange, + _exchangeV2, + _weth, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -459,12 +506,58 @@ export class ForwarderContract 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 ForwarderContract._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 = ForwarderContract.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 ForwarderContract; @@ -472,6 +565,7 @@ export class ForwarderContract 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 ForwarderContract; @@ -479,6 +573,7 @@ export class ForwarderContract 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 ForwarderContract; @@ -903,6 +998,7 @@ export class ForwarderContract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -910,12 +1006,14 @@ export class ForwarderContract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The Forwarder contract event you would like to subscribe to. @@ -941,6 +1039,7 @@ export class ForwarderContract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider, diff --git a/packages/contract-wrappers/src/generated-wrappers/i_asset_data.ts b/packages/contract-wrappers/src/generated-wrappers/i_asset_data.ts index bbe382d072..4be8521cf0 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_asset_data.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_asset_data.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'; @@ -67,6 +68,40 @@ export class IAssetDataContract extends BaseContract { } return IAssetDataContract.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 IAssetDataContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return IAssetDataContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -237,12 +272,58 @@ export class IAssetDataContract 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 IAssetDataContract._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 = IAssetDataContract.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 IAssetDataContract; @@ -250,6 +331,7 @@ export class IAssetDataContract 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 IAssetDataContract; @@ -257,6 +339,7 @@ export class IAssetDataContract 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 IAssetDataContract; diff --git a/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts b/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts index ee08395fbe..802bd42e58 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.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'; @@ -73,6 +74,46 @@ export class IERC20BridgeSamplerContract extends BaseContract { 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 IERC20BridgeSamplerContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return IERC20BridgeSamplerContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -731,12 +772,58 @@ export class IERC20BridgeSamplerContract 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 IERC20BridgeSamplerContract._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 = IERC20BridgeSamplerContract.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 IERC20BridgeSamplerContract; @@ -744,6 +831,7 @@ export class IERC20BridgeSamplerContract 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 IERC20BridgeSamplerContract; @@ -751,6 +839,7 @@ export class IERC20BridgeSamplerContract 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 IERC20BridgeSamplerContract; @@ -852,25 +941,33 @@ export class IERC20BridgeSamplerContract extends BaseContract { }, }; } + /** + * Query batches of native orders and sample buy quotes on multiple DEXes at once. + * @param orders Batches of Native orders to query. + * @param orderSignatures Batches of Signatures for each respective order in + * `orders`. + * @param sources Address of each DEX. Passing in an unsupported DEX will + * throw. + * @param makerTokenAmounts Batches of Maker token sell amount for each sample. + * @returns ordersAndSamples How much taker asset can be filled by each order in `orders`. Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index + */ public queryBatchOrdersAndSampleBuys( - orders: Array< - Array<{ - makerAddress: string; - takerAddress: string; - feeRecipientAddress: string; - senderAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - expirationTimeSeconds: BigNumber; - salt: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; - }> - >, + orders: Array>, orderSignatures: string[][], sources: string[], makerTokenAmounts: BigNumber[][], @@ -894,6 +991,7 @@ export class IERC20BridgeSamplerContract extends BaseContract { defaultBlock, ); const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue< Array<{ orderFillableAssetAmounts: BigNumber[]; tokenAmountsBySource: BigNumber[][] }> >(rawCallResult); @@ -908,25 +1006,33 @@ export class IERC20BridgeSamplerContract extends BaseContract { }, }; } + /** + * Query batches of native orders and sample sell quotes on multiple DEXes at once. + * @param orders Batches of Native orders to query. + * @param orderSignatures Batches of Signatures for each respective order in + * `orders`. + * @param sources Address of each DEX. Passing in an unsupported DEX will + * throw. + * @param takerTokenAmounts Batches of Taker token sell amount for each sample. + * @returns ordersAndSamples How much taker asset can be filled by each order in `orders`. Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index. + */ public queryBatchOrdersAndSampleSells( - orders: Array< - Array<{ - makerAddress: string; - takerAddress: string; - feeRecipientAddress: string; - senderAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - expirationTimeSeconds: BigNumber; - salt: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; - }> - >, + orders: Array>, orderSignatures: string[][], sources: string[], takerTokenAmounts: BigNumber[][], @@ -950,6 +1056,7 @@ export class IERC20BridgeSamplerContract extends BaseContract { defaultBlock, ); const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue< Array<{ orderFillableAssetAmounts: BigNumber[]; tokenAmountsBySource: BigNumber[][] }> >(rawCallResult); diff --git a/packages/contract-wrappers/src/generated-wrappers/lib_transaction_decoder.ts b/packages/contract-wrappers/src/generated-wrappers/lib_transaction_decoder.ts index 009ced047d..ea9b0ebe19 100644 --- a/packages/contract-wrappers/src/generated-wrappers/lib_transaction_decoder.ts +++ b/packages/contract-wrappers/src/generated-wrappers/lib_transaction_decoder.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'; @@ -74,6 +75,46 @@ export class LibTransactionDecoderContract extends BaseContract { 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 LibTransactionDecoderContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return LibTransactionDecoderContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -213,12 +254,58 @@ export class LibTransactionDecoderContract 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 LibTransactionDecoderContract._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 = LibTransactionDecoderContract.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 LibTransactionDecoderContract; @@ -226,6 +313,7 @@ export class LibTransactionDecoderContract 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 LibTransactionDecoderContract; @@ -233,6 +321,7 @@ export class LibTransactionDecoderContract 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 LibTransactionDecoderContract; @@ -303,7 +392,15 @@ export class LibTransactionDecoderContract extends BaseContract { ] > { BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + let rawCallResult; + if (self._deployedBytecodeIfExists) { + rawCallResult = await self._evmExecAsync(this.getABIEncodedTransactionData()); + } else { + rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + } const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); return abiEncoder.strictDecodeReturnValue< diff --git a/packages/contract-wrappers/src/generated-wrappers/staking.ts b/packages/contract-wrappers/src/generated-wrappers/staking.ts index 585af60e1e..83c3d1ea04 100644 --- a/packages/contract-wrappers/src/generated-wrappers/staking.ts +++ b/packages/contract-wrappers/src/generated-wrappers/staking.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -200,6 +201,40 @@ export class StakingContract extends BaseContract { } return StakingContract.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 StakingContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return StakingContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -1583,12 +1618,58 @@ export class StakingContract 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 StakingContract._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 = StakingContract.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 StakingContract; @@ -1596,6 +1677,7 @@ export class StakingContract 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 StakingContract; @@ -1603,6 +1685,7 @@ export class StakingContract 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 StakingContract; @@ -3430,6 +3513,7 @@ export class StakingContract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -3437,12 +3521,14 @@ export class StakingContract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The Staking contract event you would like to subscribe to. @@ -3468,6 +3554,7 @@ export class StakingContract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider, diff --git a/packages/contract-wrappers/src/generated-wrappers/staking_proxy.ts b/packages/contract-wrappers/src/generated-wrappers/staking_proxy.ts index 4c962c3771..bdd59569f8 100644 --- a/packages/contract-wrappers/src/generated-wrappers/staking_proxy.ts +++ b/packages/contract-wrappers/src/generated-wrappers/staking_proxy.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -114,6 +115,48 @@ export class StakingProxyContract extends BaseContract { _stakingContract, ); } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + _stakingContract: 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 StakingProxyContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return StakingProxyContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _stakingContract, + ); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -702,12 +745,58 @@ export class StakingProxyContract 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 StakingProxyContract._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 = StakingProxyContract.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 StakingProxyContract; @@ -715,6 +804,7 @@ export class StakingProxyContract 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 StakingProxyContract; @@ -722,6 +812,7 @@ export class StakingProxyContract 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 StakingProxyContract; @@ -1546,6 +1637,7 @@ export class StakingProxyContract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -1553,12 +1645,14 @@ export class StakingProxyContract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The StakingProxy contract event you would like to subscribe to. @@ -1584,6 +1678,7 @@ export class StakingProxyContract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider, diff --git a/packages/contract-wrappers/src/generated-wrappers/weth9.ts b/packages/contract-wrappers/src/generated-wrappers/weth9.ts index 1a6d7cf648..e99fc2651e 100644 --- a/packages/contract-wrappers/src/generated-wrappers/weth9.ts +++ b/packages/contract-wrappers/src/generated-wrappers/weth9.ts @@ -10,6 +10,7 @@ import { SubscriptionManager, PromiseWithTransactionHash, methodAbiToFunctionSignature, + linkLibrariesInBytecode, } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { @@ -27,7 +28,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'; @@ -105,6 +106,40 @@ export class WETH9Contract extends BaseContract { } return WETH9Contract.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 WETH9Contract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return WETH9Contract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); + } + public static async deployAsync( bytecode: string, abi: ContractAbi, @@ -438,12 +473,58 @@ export class WETH9Contract 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 WETH9Contract._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 = WETH9Contract.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 WETH9Contract; @@ -451,6 +532,7 @@ export class WETH9Contract 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 WETH9Contract; @@ -458,6 +540,7 @@ export class WETH9Contract 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 WETH9Contract; @@ -857,6 +940,7 @@ export class WETH9Contract extends BaseContract { ); return subscriptionToken; } + /** * Cancel a subscription * @param subscriptionToken Subscription token returned by `subscribe()` @@ -864,12 +948,14 @@ export class WETH9Contract extends BaseContract { public unsubscribe(subscriptionToken: string): void { this._subscriptionManager.unsubscribe(subscriptionToken); } + /** * Cancels all existing subscriptions */ public unsubscribeAll(): void { this._subscriptionManager.unsubscribeAll(); } + /** * Gets historical logs without creating a subscription * @param eventName The WETH9 contract event you would like to subscribe to. @@ -895,6 +981,7 @@ export class WETH9Contract extends BaseContract { ); return logs; } + constructor( address: string, supportedProvider: SupportedProvider,