zksync-sdk / zksync2-go

zksync2-go is a geth library adapted to work with the zkSync Era.
Apache License 2.0
87 stars 36 forks source link

How to read contract use go-sdk?I cannot find the way to call read function. #8

Closed KillerJi closed 8 months ago

KillerJi commented 1 year ago

Does it use github.com/zksync-sdk/zksync2-go/ContractDeployer? but I got err when go mod tidy : github.com/zksync-sdk/zksync2-go/ContractDeployer: module github.com/zksync-sdk/zksync2-go@latest found (v0.1.1), but does not contain package github.com/zksync-sdk/zksync2-go/ContractDeploye

KillerJi commented 1 year ago

Every time I call the method of reading the contract, an error will be reported, panic: failed to EstimateGas: failed to query eth_estimateGas: Failed to submit transaction: cannot estimate gas

danijelTxFusion commented 1 year ago

The examples for go sdk (including smart contract deployment) are available here.

danijelTxFusion commented 1 year ago

Every time I call the method of reading the contract, an error will be reported, panic: failed to EstimateGas: failed to query eth_estimateGas: Failed to submit transaction: cannot estimate gas

There was a bug on zkSync node related on gas estimation. The bug has been patched and has been deployed on test nad mainnet

KillerJi commented 1 year ago

The examples for go sdk (including smart contract deployment) are available here.

hello sir What I need is an example of reading contract variables, not examples of transaction transfer and execution contracts. I have read the examples you mentioned, but they are not what I need. For example, I deploy a contract and I need to read the value of the B variable.What should I do? What I need is this example.

danijelTxFusion commented 1 year ago

I you want to read the data from smart contract just call the appropriate get function (example of get function, and how it's called in program) . In case where public modifier for some variable is used, abigen generates method with exact same name as the variable. Here's the example of smart contract that has public modifier for owner variable:

contract ToDo {

    address public  owner;

    constructor(){
        owner = msg.sender;
    }
}

In order to get owner value in program, do the following:

todoContract, err := todo.NewTodo(common.HexToAddress(Contract), zp.Client)
if err != nil {
    log.Panic(err)
}

owner, err := todoContract.Owner(nil)
if err != nil {
    log.Panic(err)
}
fmt.Println("Owner address: ", owner)
KillerJi commented 1 year ago
zkSyncProvider, err := zksync2.NewDefaultProvider("https://zksync2-mainnet.zksync.io/")
if err != nil {
    log.Fatal(err)
}
add := common.HexToAddress("0x621425a1Ef6abE91058E9712575dcc4258F8d091")
q, _ := pool.NewPool(add, zkSyncProvider.Client)
a, err := q.GetReserves(nil)
if err != nil {
    log.Fatal(err)
}

yes i'm using this way but always getting log error “execution reverted”, above is my code i don't know what's wrong,This is a code to read the balance of the currency pair pool, but it always reports an error

Have you tried the read action of the mainnet node?

danijelTxFusion commented 1 year ago

Read on mainnet network does work. In following example decimals() method of USDC token is called:

zp, _ := zksync2.NewDefaultProvider("https://mainnet.era.zksync.io/")
address := common.HexToAddress("3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4")

data, err := zp.CallContract(
    context.Background(),
    ethereum.CallMsg{
        From: *new(common.Address),
        To:   &address,
        Data: crypto.Keccak256([]byte("decimals()"))[:4],
    },
    nil)
if err != nil {
    log.Panic(err)
}
decimals := new(big.Int)
decimals.SetBytes(data)
fmt.Println("Decimals:", decimals) // Decimals: 6

But when I try to execute your example I get the same error as you: execution reverted.

zp, _ := zksync2.NewDefaultProvider("https://mainnet.era.zksync.io/")
add := common.HexToAddress("621425a1Ef6abE91058E9712575dcc4258F8d091")

value, err := zp.CallContract(
    context.Background(),
    ethereum.CallMsg{
        From: *new(common.Address),
        To:   &add,
        Data: crypto.Keccak256([]byte("getReserves()"))[:4],
    },
    nil)
if err != nil {
    log.Panic(err) // execution reverted
}

fmt.Println("Value:", value)

I guess error is related to smart contract it self, perhaps getReserves() does not exist on smart contract. Or version of ABI does not match with deployed smart contract.

Have you tried to execute other methods from smart contracts?

KillerJi commented 1 year ago

https://zksync2-mainnet.zksync.io/"

Thank you for your example. I changed the contract address and it can be successfully read. I still have two questions. 1. Is it possible to obtain the gas estimate for executing the transaction? 2 If it is available, does it support modifying the gas limit?

danijelTxFusion commented 1 year ago
  1. Gas estimation currently does not work on mainnet (works on testnet).
  2. Specifying gas limit is supported:

    
    // Create instance of Storage smart contract
    storageContract, err := storage.NewStorage(contractAddress, zp.Client)
    if err != nil {
    log.Panic(err)
    }
    
    // Read the private key
    privateKey, err := crypto.ToECDSA(common.Hex2Bytes(PrivateKey))
    if err != nil {
    log.Panic(err)
    }

// Start configuring transaction parameters opts, err := bind.NewKeyedTransactorWithChainID(privateKey, w.GetEthSigner().GetDomain().ChainId) if err != nil { log.Panic(err) } // GasLimit opts.GasLimit = 30_000

// GasTipCap is required to be set, otherwise following error occurs: Method not found !!! opts.GasTipCap = big.NewInt(300)

// Execute Set method from storage smart contract with configured transaction parameters tx, err := storageContract.Set(opts, big.NewInt(200)) if err != nil { log.Panic(err) }

KillerJi commented 1 year ago

thanks.May I ask in the next go version update, will there be an operation to add this estimated gas? Without this method, it is meaningless to modify the gas limit

danijelTxFusion commented 1 year ago

SDK already supports gas limit estimation. When opts.GasLimit is not specified, the SDK calls eth_estimateGas RPC endpoint to fetch gas limit. The problem is that eth_estimateGas does not work on mainnet. Temporary solution whould be to run gas estimation on testnet and use it on mainnet.

KillerJi commented 11 months ago

I think this needs to be fixed, because the network is different and the gas is not the same, do you have a plan to fix it?

danijelTxFusion commented 8 months ago

This has been fixed for a while on both networks (mainnet, testnet)

I executed the example of smart contract deployment using smart contracts generated with abigen on mainnet:

I have tested the gas estimation using the following code with the v0.3.1 version on mainnet and testnet.

var (
    PrivateKey                 = os.Getenv("PRIVATE_KEY")
    ZkSyncEraProvider  = "https://zksync2-mainnet.zksync.io"
    //ZkSyncEraProvider = "https://testnet.era.zksync.dev"
       contractAddress       = common.HexToAddress("0x99B4da9890d62eC523851A345e2b216f1216EDB4")
)

client, err := clients.Dial(ZkSyncEraProvider)
if err != nil {
    log.Panic(err)
}
defer client.Close()

wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, nil)
if err != nil {
    log.Panic(err)
}

abi, err := storage.StorageMetaData.GetAbi()
if err != nil {
    log.Panic(err)
}
setArguments, err := abi.Pack("set", big.NewInt(700))
if err != nil {
    log.Panic(err)
}
gas, err := client.EstimateGasL2(context.Background(), types.CallMsg{
    CallMsg: ethereum.CallMsg{
        To:   &contractAddress,
        From: wallet.Address(),
        Data: setArguments,
    },
})
if err != nil {
    log.Panic(err)
}
fmt.Println("Gas: ", gas)

result, err := wallet.CallContract(context.Background(), accounts.CallMsg{
    To:   &contractAddress,
    Data: setArguments,
}, nil)
if err != nil {
    log.Panic(err)
}
fmt.Println("Result: ", result)

Output:

Gas:  558302
Result:  []