factory.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { Interface } from "../abi/index.js";
  2. import { getCreateAddress } from "../address/index.js";
  3. import {
  4. concat, defineProperties, getBytes, hexlify,
  5. assert, assertArgument
  6. } from "../utils/index.js";
  7. import { BaseContract, copyOverrides, resolveArgs } from "./contract.js";
  8. import type { InterfaceAbi } from "../abi/index.js";
  9. import type { Addressable } from "../address/index.js";
  10. import type { ContractRunner } from "../providers/index.js";
  11. import type { BytesLike } from "../utils/index.js";
  12. import type {
  13. ContractInterface, ContractMethodArgs, ContractDeployTransaction,
  14. } from "./types.js";
  15. import type { ContractTransactionResponse } from "./wrappers.js";
  16. // A = Arguments to the constructor
  17. // I = Interface of deployed contracts
  18. /**
  19. * A **ContractFactory** is used to deploy a Contract to the blockchain.
  20. */
  21. export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract> {
  22. /**
  23. * The Contract Interface.
  24. */
  25. readonly interface!: Interface;
  26. /**
  27. * The Contract deployment bytecode. Often called the initcode.
  28. */
  29. readonly bytecode!: string;
  30. /**
  31. * The ContractRunner to deploy the Contract as.
  32. */
  33. readonly runner!: null | ContractRunner;
  34. /**
  35. * Create a new **ContractFactory** with %%abi%% and %%bytecode%%,
  36. * optionally connected to %%runner%%.
  37. *
  38. * The %%bytecode%% may be the ``bytecode`` property within the
  39. * standard Solidity JSON output.
  40. */
  41. constructor(abi: Interface | InterfaceAbi, bytecode: BytesLike | { object: string }, runner?: null | ContractRunner) {
  42. const iface = Interface.from(abi);
  43. // Dereference Solidity bytecode objects and allow a missing `0x`-prefix
  44. if (bytecode instanceof Uint8Array) {
  45. bytecode = hexlify(getBytes(bytecode));
  46. } else {
  47. if (typeof(bytecode) === "object") { bytecode = bytecode.object; }
  48. if (!bytecode.startsWith("0x")) { bytecode = "0x" + bytecode; }
  49. bytecode = hexlify(getBytes(bytecode));
  50. }
  51. defineProperties<ContractFactory>(this, {
  52. bytecode, interface: iface, runner: (runner || null)
  53. });
  54. }
  55. attach(target: string | Addressable): BaseContract & Omit<I, keyof BaseContract> {
  56. return new (<any>BaseContract)(target, this.interface, this.runner);
  57. }
  58. /**
  59. * Resolves to the transaction to deploy the contract, passing %%args%%
  60. * into the constructor.
  61. */
  62. async getDeployTransaction(...args: ContractMethodArgs<A>): Promise<ContractDeployTransaction> {
  63. let overrides: Omit<ContractDeployTransaction, "data"> = { };
  64. const fragment = this.interface.deploy;
  65. if (fragment.inputs.length + 1 === args.length) {
  66. overrides = await copyOverrides(args.pop());
  67. }
  68. if (fragment.inputs.length !== args.length) {
  69. throw new Error("incorrect number of arguments to constructor");
  70. }
  71. const resolvedArgs = await resolveArgs(this.runner, fragment.inputs, args);
  72. const data = concat([ this.bytecode, this.interface.encodeDeploy(resolvedArgs) ]);
  73. return Object.assign({ }, overrides, { data });
  74. }
  75. /**
  76. * Resolves to the Contract deployed by passing %%args%% into the
  77. * constructor.
  78. *
  79. * This will resolve to the Contract before it has been deployed to the
  80. * network, so the [[BaseContract-waitForDeployment]] should be used before
  81. * sending any transactions to it.
  82. */
  83. async deploy(...args: ContractMethodArgs<A>): Promise<BaseContract & { deploymentTransaction(): ContractTransactionResponse } & Omit<I, keyof BaseContract>> {
  84. const tx = await this.getDeployTransaction(...args);
  85. assert(this.runner && typeof(this.runner.sendTransaction) === "function",
  86. "factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
  87. operation: "sendTransaction" });
  88. const sentTx = await this.runner.sendTransaction(tx);
  89. const address = getCreateAddress(sentTx);
  90. return new (<any>BaseContract)(address, this.interface, this.runner, sentTx);
  91. }
  92. /**
  93. * Return a new **ContractFactory** with the same ABI and bytecode,
  94. * but connected to %%runner%%.
  95. */
  96. connect(runner: null | ContractRunner): ContractFactory<A, I> {
  97. return new ContractFactory(this.interface, this.bytecode, runner);
  98. }
  99. /**
  100. * Create a new **ContractFactory** from the standard Solidity JSON output.
  101. */
  102. static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
  103. assertArgument(output != null, "bad compiler output", "output", output);
  104. if (typeof(output) === "string") { output = JSON.parse(output); }
  105. const abi = output.abi;
  106. let bytecode = "";
  107. if (output.bytecode) {
  108. bytecode = output.bytecode;
  109. } else if (output.evm && output.evm.bytecode) {
  110. bytecode = output.evm.bytecode;
  111. }
  112. return new this(abi, bytecode, runner);
  113. }
  114. }