5

Contract A is not able to find the address of the contract created by contract.create. Tried adding the signature of B as well as it's complete definition in contract A but still, it doesn't solve the issue.

Contract A is as described below:

[%%version 0.9]

(* Contract A *)

(*Signature of contract B*)
  (*
    contract ContractB = struct
      type storage = nat 
      let%init storage (param : nat) = (param) 
      let%entry update_param
          (param : nat) (storage: storage) = [], storage 
    end*)

contract ContractB = struct 
  type storage = nat 
  let%init storage (param: nat) = (param) 
  let%entry update_param
      (param : nat) (storage: storage) = 
    let storage = param in 
    [], storage
end

(*Signature of contract A*)
contract ContractA = struct
  type storage = address 
  let%init storage (param : address) = (param) 
  let%entry create_InstanceB (param : nat) (storage: storage) = [], storage
  let%entry call_InstanceB (param : nat) (storage: storage) = [], storage 
end

type storage = address

let%init storage (param : address) = (param)

let%entry create_InstanceB (param : nat) (storage: storage) = 

  let mgr = tz1RYq8wjcCbRZykY7XH15WPkzK7TWwPvJJt in 
  (* Creating the instance of B *)
  let (op, b_addr) = 
    Contract.create 
      ~manager:mgr 
      ~delegate:None
      ~spendable:true 
      ~delegatable:true 
      ~amount:100tz
      (param) 
      (contract ContractB) 
  in
  let storage = b_addr in
  [], storage


let%entry call_InstanceB (param : nat) (storage: storage) = 
  let addr1 =  storage in
  let _contract = (Contract.at addr1 : ContractB.instance option)  in
  match _contract with 
  |None -> Current.failwith ("Not able to find contract B's instance.");
  |Some contract_ -> (*Current.failwith ("Found some contract's instance.");*)
      let op = Contract.call ~dest:contract_ ~amount:0tz ~entry:update_param ~parameter:(param) in
      [op], storage


Contract B is as below:

[%%version 0.9]

(* Contract B *)

(*Signature of contract B*)
contract ContractB = struct
  type storage = nat 
  let%init storage (param : nat) = (param) 
  let%entry update_param
      (param : nat) (storage: storage) = [], storage 
end

type storage = nat

let%init storage (param: nat) = (param)

let%entry update_param
    (param : nat) (storage: storage) = 
  let storage = param in 
  [], storage

First I have deployed the contract B and then A and then performed a call to entry point "create_and_call_InstanceB" of A but got the following Error:

Error
liquidity_buffer:58.11-58.72: Failed at runtime: in failed
Failed with "Not able to find contract B's instance."
Call to contract failed

If I don't perform the contract call and try getting the address of created contract and try performing call to one of it's entry points, I get the following error:

Error
Response error: in failed
- temporary: proto.003-PsddFKi3.contract.non_existing_contract
Call to contract failed

Seems like something very basic is missing here from conceptual point of view. Please explain the following:

a) Is it needed that contract B should be deployed first and then it's instance can be created by contract.create? If so, which prototype of contract B will be taken at the time of instantiation of contract B from contract.create?

b) If above is not the right way then how to create and deploy a contract from another contract and then perform a call to an entry point of a newly created contract?

c) How to create an instance of already deployed contract and perform a call to an entry point of that instance?

4

You cannot create a contract and call it immediately.

It goes like this, chronologically:

  • Your script is running. You invoke CREATE_CONTRACT or CREATE_ACCOUNT. An operation and address are returned and your script continues on. The operation will create the account after your script returns it. Right now, the account does not exist.
  • You now immediately try to CONTRACT p on the address, to get a contract p so that you can call TRANSFER_TOKENS. This fails, because the contract doesn't exist.

To work around this, you could either break the functionality into two top-level operations, or have the script transfer to itself (returning the create account operation, and then the transfer) in order to run more code after the account is created.

  • 1
    Oh. Sorry... The problem is that you are not returning the operation in contract A: you have [], storage instead of [op], storage. – Tom Apr 1 '19 at 10:37
  • Thanks for pointing out the mistakes. Edited and seems like call is working as expected now. I have one more question: How the implementation/Definition of contract B is decided based on its signature mentioned in contract A? Is it the case that last deployed contract matching the signature is taken for instantiation? – user_184 Apr 1 '19 at 14:01
  • It is the (contract ContractB) which defines the created contract. When you run Contract.create/CREATE_CONTRACT, you get an operation which will create the contract, and the address the contract will have, once created. Because you put the address in storage, in the next operation, the address refers to the (now) created instance of B, which has the correct type and expected code. – Tom Apr 1 '19 at 15:58
  • Yes, That's correct. Actually, the question I wanted to ask was how to instantiate an already deployed contract? For example, Let's B is already deployed and we need an instance of B in contract A which have a signature of contract B. How to do that? I think the address of deployed contract B will be used here. – user_184 Apr 1 '19 at 21:28
  • Yes, you need to get the address of the deployed contract... Hardcode it in the code as a literal address, put it in storage (like you did), or pass it as a parameter. Then write (Contract.at addr : ContractB.instance option) just like you did. Not sure where you are stuck. – Tom Apr 1 '19 at 21:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.