import {providers, ContractFactory, Signer, Wallet, Contract} from 'ethers'; import {ContractJSON, isStandard, hasByteCode} from './ContractJSON'; type Newable = { new(...args: any): T }; type ContractFactoryOrJSON = Newable | ContractJSON; type ContractTypeOf = T extends Newable ? (U extends ContractFactory ? ReturnType : never) : Contract; type DeployArgumentsOf = T extends Newable ? (U extends ContractFactory ? Parameters : never) : any[]; const isFactory = (contract: ContractFactoryOrJSON): contract is Newable => 'call' in contract; export async function deployContract( wallet: Wallet | Signer, factoryOrContractJson: T, args: DeployArgumentsOf = [] as any, overrideOptions: providers.TransactionRequest = {} ): Promise> { if (isFactory(factoryOrContractJson)) { const Factory = factoryOrContractJson; const contractFactory = new Factory(wallet); const contract = await contractFactory.deploy(...args, overrideOptions); await contract.deployed(); return contract as any; } else { const contract = await deployFromJson(wallet, factoryOrContractJson, args, overrideOptions); return contract as any; } } async function deployFromJson( wallet: Signer, contractJson: ContractJSON, args: any[], overrideOptions: providers.TransactionRequest) { const bytecode = isStandard(contractJson) ? contractJson.evm.bytecode : contractJson.bytecode; if (!hasByteCode(bytecode)) { throw new Error('Cannot deploy contract with empty bytecode'); } const factory = new ContractFactory( contractJson.abi, bytecode, wallet ); const contract = await factory.deploy(...args, { ...overrideOptions }); await contract.deployed(); return contract; }