qtumproject/qtumjs

Wrap contract deployment

Opened this issue · 6 comments

Contract deployment is a (relatively) common use case for front-end applications, especially contract generators/factories. It makes sense to wrap createcontract and replicate the functionality of web3's Contract.new().

I therefore propose Contract.deploy(params: any[] = [], opts: IRPCCreateContractRequest = {}): Promise<IRPCCreateContractResult>.

IRPCCreateContractRequest is defined as:

export interface IRPCCreateContractRequest {
  /**
   * Bytecode of the contract to deploy
   */
  bytecode?: string
  
  /**
   * gasLimit, default: 200000, max: 40000000
   */
  gasLimit?: number

  /**
   * Qtum price per gas unit, default: 0.00000001, min:0.00000001
   */
  gasPrice?: number | string
  
  /**
   * The quantum address that will be used as sender.
   */
  senderAddress?: string;
}

and IRPCCreateContractResult is defined as:

export interface IRPCCreateContractResult extends IRPCSendToContractResult {
  /**
   * Address of the deployed contract.
   */
  address: string
}

In order to facilitate this, I also propose a function encodeConstructorParams in abi.ts similar to https://github.com/ethereum/web3.js/blob/2fba1d2f2b4c5c0afb286e30b6b756d33faf9c8a/lib/web3/contract.js#L36:

export function encodeConstructorParams(contract: IABIMethod[], params: any[] = []): string {
  const types = contract.filter((method) => {
    return method.type === "constructor" && method.inputs.length === params.length
  }).map((method: IABIMethod) => {
    return method.inputs.map((input) => {
      return input.type
    })
  })[0] || ''
  const calldata = encodeParams(types, params)
  return calldata
}

This is implemented and tested in https://github.com/kfichter/qtumjs/commit/b0de48c6a4a5b20f06f9b0e412e006926363e0a8.

My only question is whether to implement Contract.deploy() such that it sets the instance address to the address of the newly deployed contract. That's how Web3 handles this and I think it makes sense.

The implementation in https://github.com/kfichter/qtumjs/commit/b0de48c6a4a5b20f06f9b0e412e006926363e0a8 looks good.

However, I think deploy being an instance method of Contract makes the semantic rather strange.

I think a nicer API is to put this method on the Qtum object (this object knows about all the ABI information):

class Qtum extends QtumRPC
/**
   * Read ABI and bytecode from `this.repo`, and call `createcontract`
   * RPC call, and return an instantiated Contract.
   *
   * @param name The name of the contract definition.
   */
  public deploy(name: string, opts: { sender?: string } = {}): Contract {
     // call rpc to deploy the contract
  }
}

And we add definitions to IContractsRepoData to contain ABI and bytecode.

The ContractsRepo is able to instantiate a Contract with a logDecoder that knows about all event types.

Agreed. I pretty much just ripped that deployment syntax from web3 but I think you're right. I'll make those changes.

Thanks!

Btw, sorry for the slow response. I didn't get the GitHub notification (I wasn't a repo watcher and I didn't realize that) ☹️

Haha, no worries. Just trying to help out where I can.

@kfichter @hayeah any news about that functionality? Really needed! Can I help you in any manner?