Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Calling Balance_of (or get_balance) from CameLIGO test #99

Open
egarson opened this issue Jan 9, 2023 · 10 comments
Open

Calling Balance_of (or get_balance) from CameLIGO test #99

egarson opened this issue Jan 9, 2023 · 10 comments

Comments

@egarson
Copy link

egarson commented Jan 9, 2023

Hello,
I want to call the Balance_of entrypoint for a standard FA2 contract in a CameLIGO unit test (or it's "implementation" get_balance).
I am trying to formulate the correct balance_of_request.callback parameter, but the continuation-passing style is giving me trouble - I cannot conjure up the correct incantation.
Below is the test in development. Notice that I typed all the parameters, and broke everything down completely, to isolate completely the error.
The problem I have is only with the callback parameter ("Cannot unify ..."). I have tried a number of things, but I cannot get the right incantation.
My last effort has been trying to pass a fun to the callback, because I thought it might require a fun going from balance_of_response list to contract. It is a unique signature amongst all the other ones with which I have successfully worked.

let test_call_get_balance =
    let addr,_,_ = Test.originate main {initial_storage with admin = admin} 0tez in
    let contract = (Test.to_contract addr) in
    let balance_request: balance_of_request = {owner = alice; token_id = 0n} in
    let requests: balance_of_request list = [balance_request] in
    // OR: let requests: balance_of_request list = [{owner = alice; token_id = 0n}] in
    // !!Trying to formulate balance_of_request.callback parameter here!!
    // This is "just" another attempt, I am not sure how to reconcile this with CPS
    let callback = fun(l: balance_of_response list): contract ->
        let _printList = Test.log("Got list: ", l) in
        contract
    in
    let balance_param: balance_of_param = ({ requests = requests; callback = callback}) in
    // And finally call get_balance (alternatively the Balance_of entrypoint)
    let balance_of_response: balance_of_response = get_balance(requests) in
    Test.log("Alice's balance is:", balance_of_response.balance)

What is the correct incantation such that I can get the above to pass? You can see what I'm trying to do, I hope?
I will also take this opportunity to thank you very much for the significant value I have derived from this repository.
Cheers!
Edward Garson
Developer Evangelist @ ECAD Labs

@emishur
Copy link
Collaborator

emishur commented Jan 9, 2023

The callback type required is not a function but an other contract entry point balance_of_response list contract.
You probably would need to originate yet another "balance inspector contract" (see inspector.mligo ); get its %response entry point using Ligo's Test.to_entrypoint to create a callback.

But I am not sure how Ligo test framework works with multi-contract tests. If it does not help you may ask Ligo team

@egarson
Copy link
Author

egarson commented Jan 9, 2023

Thank you very much for your speedy response. I will look into this.
I missed inspector.mligo, to my surprise!

@egarson
Copy link
Author

egarson commented Jan 23, 2023

Hello,
(Back at this after a short hiatus).
I am unable to get the callback contract to work but I don't (yet) think it's a multi-contract problem.
I am unsure how to wire up inspector and my contract, and I'm unable to get a handle to the %response entrypoint.
I have copied the code to do so from inspector.mligo. The compiler allows me to assign to the variable inspector_contract, but when I run I get the error, Type "inspector_contract" not found at the line, let cb_opt: balance_of_response inspector_contract = .
If I comment out from that line to the end of the test, and write Test.log("Inspector contract", inspector_contract) as the last line of the test, I can compile, and if I ligo run test I see the output ("Inspector contract", KT1address(None)). (Why is "(None)" appearing in my output? This may be the problem!).
Here is what I've got now:

let test_call_get_balance =
    let main_addr,_,_ = Test.originate main {initial_storage with admin = admin} 0tez in
    let main_contract = Test.to_contract main_addr in
    let balance_request: balance_of_request = {owner = alice; token_id = 0n} in
    // Setup the inspector callback contract to receive (balance_of_response list)
    let inspector_storage: inspector_storage = (State []) in
    // Contract is imported as: `#import "inspector.mligo" "INSPECTOR"`
    let inspector_addr,_,_ = Test.originate INSPECTOR.main inspector_storage 0tez in
    // Ok: we get a bona fide address
    let _ = Test.log("Inspector addr", inspector_addr) in
    // And this assignment succeeds
    let inspector_contract = Test.to_contract inspector_addr in
    // This emits ("Inspector contract" , KT1AYqMzvqtZb4jNfDd1Wqdzd8JgD9pk2Rv3(None))" // N.B. (None)
    let _ = Test.log("Inspector contract", inspector_contract) in
    // Get a handle to the callback entrypoint in `inspector_contract`
    // Error! `Type "inspector_contract" not found`
    let cb_opt: balance_of_response list inspector_contract option =
        Tezos.get_entrypoint_opt "%response" inspector_contract in
    let cb = match cb_opt with
        | None -> (failwith "NO_RESPONSES_ENTRYPOINT")
        | Some callback_entrypoint -> callback_entrypoint
    in
    let bp: balance_of_param = ({ requests = requests; callback = cb}) in
    let q_op = match fa2 with
        | None -> (failwith "NO_BALANCE_OF_ENTRYPOINT" : operation)
        | Some balance -> Tezos.transaction bp 0mutez callback_entrypoint
    in
    Test.log("Alice's balance is:", balance)

I have added you as a collaborator to this private repository in case you need to see more information.
I appreciate any help you may be able to offer to get the above test to pass!
Cheers
Edward

@emishur
Copy link
Collaborator

emishur commented Jan 23, 2023

let cb_opt: balance_of_response list inspector_contract option =
        Tezos.get_entrypoint_opt "%response" inspector_contract

it. looks like wrong callback type. Shouldn't it be

let cb_opt: balance_of_response list contract option =
        Tezos.get_entrypoint_opt "%response" inspector_contract

?

@egarson
Copy link
Author

egarson commented Jan 23, 2023

Hmm, with that change I get, Cannot unify "contract (INSPECTOR.inspector_parameter) with "address"

@emishur
Copy link
Collaborator

emishur commented Jan 23, 2023

Tezos.get_entrypoint_opt accepts an address as second parameter, not the contract reference.
I guess the following should work:

let cb_opt: balance_of_response list contract option =
        Tezos.get_entrypoint_opt "%response" inspector_addr

@egarson
Copy link
Author

egarson commented Jan 23, 2023

With that change, I get Cannot unify "typed_address (INSPECTOR.inspector_parameter , INSPECTOR.inspector_storage)" with "address".

@egarson
Copy link
Author

egarson commented Jan 23, 2023

The new Marigold tutorial has a callback example at https://github.com/ligolang/contract-catalogue/blob/main/test/fa2/single_asset.test.mligo which I will try just now.

@emishur
Copy link
Collaborator

emishur commented Jan 23, 2023

I think you cannot mix Test and Tezos modules in your test code.
Try to use Test.to_entrypoint (which has signature string -> ('param, 'storage) typed_address -> 'e contract) instead of Tezos.get_entrypoint_opt

@egarson
Copy link
Author

egarson commented Jan 23, 2023

Ah... I will try that, thank you

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants