Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More examples or better explanation on how to make contract calls #116

Closed
acemasterjb opened this issue Oct 12, 2021 · 9 comments
Closed
Labels

Comments

@acemasterjb
Copy link

I'm at a total loss as to how make a contract call, and the only way to make a transaction from what I can tell is to use withAccount with withParam which according to the docs is not the only option.

How can you use call or send? What params are needed? The docs state that

Functions above can be run in account context only and transaction parameters should be set before.

But what does that mean, how can we set the account context, how do you se the transaction parameters before invoking call and send?

@akru
Copy link
Member

akru commented Oct 13, 2021

Hi, thank you for the feedback.

So, if you have contract ABI then library will generate required wrappers for call and send functions that suits for your contract.

As example please check https://github.com/airalab/hs-web3/blob/master/examples/erc20/Main.hs#L17

And here is wrapping module that generates functions from contract ABI: https://github.com/airalab/hs-web3/blob/master/examples/erc20/ERC20.hs

@akru akru added the question label Oct 13, 2021
@acemasterjb
Copy link
Author

Thanks for getting back to me @akru, I am aware of this method of making function calls, however, I am unable to do a

main = do
    result <- runWeb3 $
        withAccount () $
            withParam -- ...

and by extension, only this works for me

main = do
    result <- runWeb3 $
        withAccount (LocalKey ... ) $ -- or Personal, though I am unable to make txs this way
            withParam -- ...

but it creates a tx when I would like to only make a call/run a getter function.

I do not have issues with constants, like in your example when using withAccount (LocalKey ...). Only calls.

@akru
Copy link
Member

akru commented Oct 14, 2021

So, https://hackage.haskell.org/package/web3-0.9.1.0/docs/Network-Ethereum-Account.html
This is account abstraction docs. As you can see call functions used for call getters (view or constant in terms of solidity), but send used for sending transactions. Calldata could be defined by user or prepared by wrapper function, automatically generated from contract ABI.

@acemasterjb
Copy link
Author

acemasterjb commented Oct 14, 2021

Yes, I've read this doc, but again I am unsure of how to use this call function for a view function.

With web3.py, web3.js and ethers.js it is:

# web3.py
erc20.functions.allowance(owner.address, spender.address).call()
// ethers.js
await erc20.allowance(owner.address, spender.address)

where allowance is the standard ERC20 view function that returns a uint256. I'm asking how would you do this for hs-web3 because it is not clear to me based on the docs.

Can you provide an example of doing this allowance call in web3-hs?

When I use the method in the example, it makes a transaction that is logged in etherscan, which should not happen.

@akru
Copy link
Member

akru commented Oct 14, 2021

Generally, developer don’t use call/send functions directly. Developer uses wrappers created for specified contract ABI: template in https://github.com/airalab/hs-web3/blob/master/examples/erc20/ERC20.hs will generate allowance function for you. All you need is just use it in your code.

runWeb3 $
        withAccount () $
            withParam (to .~ "0xA2f4FCb0FDe2dD59f7a1873e121bc5623e3164Eb") $ allowance alice bob

@acemasterjb
Copy link
Author

Sorry for the late reply @akru, I have been a bit preoccupied.

It turns out the abi was the issue when using the method wrappers. Related to #98, I had to add constant to the abi when in other web3 projects I did not have to, prior to that, my hs-web3 project would not even compile.

I mistakenly added constant: false for my call method. setting to true fixed it.


Now I have a question about extracting data from its return value.

If the return value is a primitive data type, getting the return value is straight forward as the examples show.

If the return type is a composite data type such as a struct or an array of structs, then how do you obtain that value?

E.g. this is the return type of the method I'm using

returnValue :: ((UIntN 256, Text, UIntN 256), UIntN 256, UIntN 256, UIntN 256)

if I do something like

snd' ((_, _, _), a, _, _) = a

then

case result of
        Left err   -> print err
        Right info -> putStrLn ("Success: " ++ show(fromEnum $ snd' returnValue))

I get

too few bytes
From:   demandInput

When I do a stack run --nix... not sure what I'm doing wrong here

@akru
Copy link
Member

akru commented Oct 24, 2021

Solidity library in hs-web3 uses Generics to drive abi encoding.

https://github.com/airalab/hs-web3/blob/master/packages/solidity/src/Data/Solidity/Abi/Generic.hs

This approach applicable as for tuples in your case as same for production type structures (tuple also production type structure).

TH wrapper automatically generates function outputs according to contract abi.

From other side you can set output type manually for call function, but output should contains enough data for decoding.

@acemasterjb
Copy link
Author

acemasterjb commented Oct 24, 2021

Okay, so you're saying that I shouldn't need anything else besides

case result of
        Left err   -> print err
        Right info -> print info

to get the return value... so I'm doing something wrong.


I changed a value in the input of my function and suddenly it started working.

However its strange, the logic when I use web3.py and hs-web3 is exactly the same; the input takes in a value of 1. When I give this same function the value 2 it started working.

@acemasterjb
Copy link
Author

Going to close this issue, as you've provided some much needed clarification. Thank you @akru for your help 😄

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

No branches or pull requests

2 participants