lmittmann / w3 Goto Github PK
View Code? Open in Web Editor NEWEnhanced Ethereum Integration for Go
Home Page: http://w3.cool
License: MIT License
Enhanced Ethereum Integration for Go
Home Page: http://w3.cool
License: MIT License
There's my case: I need make a call with many output (like slot0) and when I try something like c.Call(eth.CallFunc(w3.MustNewFunc("signature", "output fields"), address).Returns(&myStruct))
I receive an error
invalid type: can not copy *big.Int to *myStruct
But ok, I could then map fields into a structure, but the problems start when I need make a multicall one function and the number of calls can be dynamic. Example:
c.Call(
eth.CallFunc(w3.MustNewFunc("signature", "output fields"), address1).Returns(???),
eth.CallFunc(w3.MustNewFunc("signature", "output fields"), address2).Returns(???),
eth.CallFunc(w3.MustNewFunc("signature", "output fields"), address3).Returns(???),
)
How make the correct return? Do I understand correctly that such cases are left out yet in the library interface/unfinished?
Goal: reduce overall testdata size by storing contract codes only once.
I am trying to use w3.MustNewFunc
on a smart contract function with the following header:
function getPairsByIndexRange(UniswapV2Factory _uniswapFactory, uint256 _start, uint256 _stop) external view returns (address[3][] memory)
This is how I am calling w3.MustNewFunc
:
funcGetPairsByIndexRange := w3.MustNewFunc("getPairsByIndexRange(address, uint256, uint256)", "address[3][]")
I get the following error:
panic: w3: invalid ABI: unknown type ""
goroutine 1 [running]:
github.com/lmittmann/w3.MustNewFunc(...)
/home/user/go/pkg/mod/github.com/lmittmann/[email protected]/func.go:71
I think I am getting this because MustNewFunc is unable to parse 2d arrays, when I changed it to a one dimensional array it worked as expected.
Any idea how to fix or workaround this issue? I need to use 2d arrays for my specific use case.
var tx types.Transaction
err = client.Call(eth.Tx(common.HexToHash("0x35360e885766d3e26207f248da7ce5656a2d526f6669a52e234af6dfde7a6851")).Returns(&tx))
if err != nil {
panic(err)
}
// How to get Transaction from address?
how to pass bytes32 as a parameter? The examples includes only primitive types. would be a nice to see a complex one (involving dynamic size types etc)
var contractAddress common.Address
resolverFunc := w3.MustNewFunc("resolver(bytes32)", "address")
resolverCall := eth.CallFunc(w3.A(registryAddr), resolverFunc, []byte("hello.xyz")).Returns(&contractAddress)
err := w3Client.Call(resolverCall)
if err != nill {
log.Println("error occurred during the resolver call: ", err)
}
fmt.Println(contractAddress)
I get the below error
error occurred during the resolver call: abi: cannot use slice as type array as argument
Hello, i'm trying to decode transfer(address recipient, uint256 amount) function and sometimes i'm get this error:
github.com/lmittmann/w3.(*Func).DecodeArgs(...)
C:/Users/James/go/pkg/mod/github.com/lmittmann/[email protected]/func.go:88
main.main.func1({0x12, 0x26, 0xa8, 0xc7, 0x8d, 0xa0, 0x1, 0xf0, 0x7a, 0x9b, ...})
I dont know which transaction makes this error.
Could you provide an example of debug.CallTrace? When attempting to use it, I receive the following error:
err := e.client.Call(debug.CallTraceTx(txHash, w3types.State{}).Returns(&trace))
ERR = w3: call failed: the method debug_traceTransaction does not exist
hi all~
can anyone give a example code for deploy contract with bytecode in w3vm?
I attempted to set the account state with bytecode, but it didn't run.
I am trying to interact with a smart contract using the package, and it seem to work.
But i can not find it on etherscan after it has been sent. I have tried 2 different RPC's but cant seem to get it working
Here is the code im using to test it. Fill in your own PRIVATE_KEY and RPC to run it.
package main
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/lmittmann/w3"
"github.com/lmittmann/w3/module/eth"
)
const PRIVATE_KEY = "Fill in a private key for a wallet with goerli eth"
const CONTRACT_ADDRESS = "0x42c7d192696481710b99979ef9647382816ac2ab"
const SELECTED_FUNCTION = "mint(uint256)"
const RETURN_VALUE = ""
func main() {
var client = w3.MustDial("https://eth-goerli.g.alchemy.com/v2/yourAlchemyApiKeyHere")
defer client.Close()
// Make a variable named privateKey with the type ecdsa key from the string wallet
privKey, err := crypto.HexToECDSA(PRIVATE_KEY)
if err != nil {
fmt.Println(err)
return
}
selectedFunc, err := w3.NewFunc(SELECTED_FUNCTION, RETURN_VALUE)
// Print the public key from privKey
fmt.Println("Address: ", crypto.PubkeyToAddress(privKey.PublicKey).Hex())
if err != nil {
fmt.Println(err)
return
}
contractAddress := common.HexToAddress(CONTRACT_ADDRESS)
var balance big.Int
var nonce uint64
err2 := client.Call(
eth.Nonce(contractAddress, nil).Returns(&nonce),
eth.Balance(crypto.PubkeyToAddress(privKey.PublicKey), nil).Returns(&balance),
)
if err2 != nil {
fmt.Println(err2)
return
}
fmt.Println("Balance: ", balance.String())
signer := types.LatestSigner(params.GoerliChainConfig)
input, err3 := selectedFunc.EncodeArgs(w3.I("1"))
if err3 != nil {
fmt.Println(err3)
return
}
tx := types.MustSignNewTx(privKey, signer, &types.DynamicFeeTx{
To: &contractAddress,
Nonce: nonce,
Data: input,
Gas: 300000,
GasFeeCap: w3.I("15 gwei"),
GasTipCap: w3.I("1 gwei"),
Value: w3.I("0 gwei"),
})
var txHash common.Hash
err4 := client.Call(
eth.SendTransaction(tx).Returns(&txHash),
)
if err4 != nil {
fmt.Println(err4)
return
}
fmt.Println("Tx Hash: ", txHash.String())
}
Logs out this in my case
Address: 0x598aa6f8D6377629C1B933754019a01Bd89931f8
Balance: 250000000000000000
Tx Hash: 0x5d98e4104c5300711a2243780bb1336e69fd26168a71967b875dc75cc27bf928
Hope some of you know what the issue is!
And thanks for providing this great package.
The token balance example is not working as expected:
After running go run main.go
inside the folder, I receive the following output:
Call failed: w3: response handling failed: invalid argument 0: json: cannot unmarshal non-string into Go struct field CallArgs.nonce of type hexutil.Uint64
I noticed that downgrading back to 0.8.1 fixes this issue.
How about adding proxy requests to the client? It's just that free RPCs have limitations. With a proxy, this problem can be solved.
var gasLimit uint64
err = chain.Client.Call(
eth.EstimateGas(&w3types.Message{
To: &contractAddress,
Func: funcTransfer,
From: address,
Args: []any{&recipient, &token.Balance},
}, nil).Returns(&gasLimit),
)
Returns w3: call failed: too many arguments, want at most 1
I want to simulate how to execute a contract using eth_call, for example
payload = {
"jsonrpc": "2.0",
"method": "eth_call",
"id": 1,
"params": [
{
"to": "0xc2edad668740f1aa35e4d8f227fb8e17dca888cd",
"data": "0x8d88a90e000000000000000000000000c2edad668740f1aa35e4d8f227fb8e17dca888cd"
},
"latest"
]
}
headers = {
"accept": "application/json",
"content-type": "application/json"
}
I want to execute contract function that requires bytes32[]
I have this array in json:
"proof":["0xdac2beda9cd88c89679f4c41539e8196b29fd38407219841f936f0b6b7e8ff1a","0x22eb93710252e79914d1d4ec15716071ed5fe64b0b0c7e7e1badbce95b386442","0x7d463be3ff9f50f990b008c19834d74bf916fa71b4db3855bd54491b8b07bea7","0xb6577628cd0917349f8d6d059a5f33e8a6b2e2e8e9e95cd005ed7e0981a4a713","0x2b7733395a061fcf4c05a866e05142035f370a4a088969bb560c3761620e57e8","0x5a467b8b8aad5b144e01c349a0a3380ca8ce0829863afa03d99cff8a9b613273","0xe024adad50aa103636a4c42c0fb428c82e154bff3501d84dc5695f70cf32639d","0xc8c9fed8ed870eb1e8462d19a6e107d55c8df05528e81fa9e90af548bf985f30","0x9841222888c5a80644cf54b7d877b85efcd5789e2c2ae8388475f7871f6a1bf7","0x9a046dc08506268e16603452a33ea179b4932eeae59338dd3fee75685cc490f1","0xacba6c0ed0c90792bb6f9f696ad1417efe0032bb0e86b6927234ce419628e24c","0x0d577b40b8956166e4d21cba88b58b32dec0a00b2864e8ed4ac5d7be6683f5f2","0x97aaf35d6ca208a954554f4ab14a1ca973daf13e7c1dad49db82611f4dadf2a3","0xc32355753f5e11ba88adc0d27f10ad32ad4904bfd782c15693c6795b047124fc","0xcd0f927a7dda89206be7ad613644d02a622c3f30f5de40d052b4c3e10ef02a18","0x107e7a23a7abca2aacc0bf854e247569f822013a86927b10f772b7b13fbc8732"]
I unmarshal it into []hexutil.Bytes and when i'm passing this slice into function i get this error:
abi: cannot use []hexutil.Bytes as type [0]array as argument
I'm trying to read a smart contract that has a getReserves() function that returns 3 values - reserve0, reserve1 and blockTimestampLast. How should that get coded?
getReserves := w3.MustNewFunc("getReserves()", "uint112, uint112, uint32")
var reserves big.Int
err := client.Call(eth.CallFunc(getReserves, tokenPairAddress).Returns(&reserves))
if err != nil {
log.Fatal(err)
}
The above code is getting the following result:
{false [12569833997705177805 642440]}
client := w3.MustDial("https://rpc.ankr.com/eth")
contractAddress := w3.A("0xdAC17F958D2ee523a2206206994597C13D831ec7")
tokenTransferFunc := w3.MustNewFunc("transfer(address recipient, uint256 amount)", "bool success")
var tokenTransferGas uint64
err := client.Call(
eth.EstimateGas(&w3types.Message{
To: &contractAddress,
Func: tokenTransferFunc,
}, nil).Returns(&tokenTransferGas),
)
if err != nil {
log.Fatal(err)
}
Error:
argument count mismatch: got 0 for 2
If so is there an example somewhere of how to implement?
Thanks
Hi! First of all, love the lib. Thanks for taking the time to work on it!
I can't seem to get log parsing for the ENS NameRegistered event to work. I suspect it's because of the indexed
keyword.
Here's the contract source and here's a snippet referencing the event of my interest:
event NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires);
package main
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/lmittmann/w3"
)
func main() {
// from https://etherscan.io/tx/0xbba96a6bc0c49cfb4607c02670affffad64a58cd7789d6843a774e5fcd851c4a#eventlog
l := &types.Log{
Address: w3.A("0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5"),
Topics: []common.Hash{
w3.H("0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f"),
w3.H("0x4e59ffc7ae105a2b19f7f29b63e9f9c5ac28e27bce744a330804c6a89269cec0"),
w3.H("0x000000000000000000000000bd08f39b2523426cc1d6961e2d6a9744b3b432b5"),
},
Data: w3.B("0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000165a7d3a3e48ad0000000000000000000000000000000000000000000000000000000066e4d0a50000000000000000000000000000000000000000000000000000000000000009656c666172657373690000000000000000000000000000000000000000000000"),
}
e := w3.MustNewEvent("NameRegistered(string name, bytes32 label, address owner, uint cost, uint expires)")
args := []any{new(string), new(common.Hash), new(common.Address), new(big.Int), new(big.Int)}
err := e.DecodeArgs(l, args...)
if err == nil {
fmt.Println(args)
} else {
fmt.Println(err)
}
}
Produces:
panic: w3: invalid ABI: unexpected token ' ', want ')', ',' or EOF
indexed
keywords from MustNewEvent
calle := w3.MustNewEvent("NameRegistered(string name, bytes32 label, address owner, uint cost, uint expires)")
Produces:
abi: cannot marshal in to go slice: offset 35439416906938938518729653100551098276713131344231382706165141882278127455968 would go over slice boundary (len=224)
Any ideas what the issue could be?
Manual declare ERC20 token ABI
// smart contract functions
var (
erc20FuncBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256")
erc20FuncCheckAllowance = w3.MustNewFunc("allowance(address owner, address spender)", "uint256")
erc20FuncApprove = w3.MustNewFunc("approve(address spender, uint256 value)", "bool")
erc20FuncTransfer = w3.MustNewFunc("transfer(address recipient, uint256 amount)", "bool")
)
Many L2s have differences from the standard rpc endpoints available in geth. In most cases, I don't this is an issue, additional fields and the like, are ignored during serialization.
https://docs.arbitrum.io/arbitrum-ethereum-differences#json-rpc-api
For example, Optimism and Arbitrum have some additional transaction types that do not break the rpc spec but do break when serializing into geth types.
For example:
client.CallCtx(ctx, eth.BlockByNumber(head).Returns(block))
will return
panic: w3: call failed: transaction type not supported
w3 uses the default client that geth provides:
Line 47 in 4919290
However, geth also provides finer control over some transports e.g.
It would be nice to have a feature where this can be overridden through a method on the w3 Client
itself e.g.
func (c *Client ) SetCustomRPCClient(client *rpc.Client)`
If this is within scope, I can send a PR.
Add method bindings for
txpool_content
txpool_contentFrom
txpool_status
Hello,
When marshaling the Message struct to JSON i noticed that the GasFeeCap
& GasTipCap
fields are marshaled as gasFeeCap
& gasTipCap
which is incompatible with some of geth's RPC methods which take TransactionArgs
as a parameter:
This causes GasFeeCap
& GasTipCap
fields in the message struct to be ignored by geth.
Wondering if I can use this library on op-geth as it's a fork that's behind by a bit, so sometimes the types it uses are different to GETH.
Hi!
I was thinking if there's any way we could add something similar to abigen
, where you'd take a contract ABI and it would generate w3
bindings for you. I'd personally love to have some type safety when using the Event
/Func
interfaces and thought this would be the way to do it with the least friction.
What I'd love to see is if we could get it to work with the existing interfaces like Func
or Event
and make those type safe. For example:
func main() {
WETH_DEPOSIT := w3.MustNewEvent("Deposit(address indexed destination, uint256 amount)")
// when using this WETH_DEPOSIT, instead of having generic `any` functions, we would have them with types.
// so instead of this:
func (e *w3.Event) DecodeArgs(log *types.Log, args ...any) error
// we would have:
func (e *w3.Event) DecodeArgs(log *types.Log, destination common.Address, amount *big.Int) error
}
Let me know if you think something like this would be possible!
#16 same issue.
Trying to get balance of BUSD on Binance Smart Chain
client := w3.MustDial("https://rpc.ankr.com/bsc")
err = client.Call(
eth.CallFunc(funcBalanceOf, contractAddress, address).Returns(&tokenBalance),
)
if err != nil {
log.Fatal(err)
}
It returns
w3: response handling failed: invalid argument 0: json: cannot unmarshal non-string into Go struct field CallArgs.gas of type hexutil.Uint64
The following code currently panics:
package main
import (
"fmt"
"github.com/lmittmann/w3"
)
// we have the following structs and function in solidity:
/*
struct Recipient {
address to;
}
struct testFnParam {
Recipient[] recipients;
}
function testFn(testFnParam param) {
// .
// .
// .
}
*/
func main() {
// panic: w3: invalid ABI: unexpected token '[', want ')', ',' or EOF
fn := w3.MustNewFunc(
"testFn(((address to)[] recipients) param)",
"", // returns
)
fmt.Println(fn)
}
It looks like the combined usage of tuple arrays are not supported currently.
The ABI parser expects any function to be named. In some cases it would be useful to encode constructor args. (address)
for example doesn't work. One way would be to reserve the constructor
keyword in the lexer.
constructorFunc, err := w3.NewFunc("constructor(address)", "")
if err != nil {
return nil, err
}
constructorArgs := []any{w3.A(0x765DE816845861e75A25fCA122bb6898B8B1282a)}
constructorBytecode, err := constructorFunc.EncodeArgs(constructorArgs...)
if err != nil {
return nil, err
}
// Should return bytearray representing 000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a
Not sure if this is within scope of w3 or should the abi package (abi.Pack) from geth be used instead.
Example code that illustrates the issue:
w3.MustNewFunc("test((address, uint256))", "")
Result:
panic: w3: invalid ABI: syntax error: unexpected ",", want name
I have function signatures without names, e.g. as returned by openchain.xyz, and I would like to be able to decode args from them. I don't care as much about actually extracting the tuple values, and will likely just provide nil
for any tuples in the args
I pass to DecodeArgs
. But, I would still like the function to be successfully created.
That said, I am working on implementing this in such a way that you can decode tuples into []any
slices, which will allow unnamed tuple fields to be supported and actually decodable. I'll open the PR soon!
If one of the calls from a batch request fails, return values from the following calls won't be returned (even if they are executed successfully).
I personally think it would be better if w3 returned an error when the batch request fails (network error, etc.) but NOT if one of the calls inside the batch request fails. Something similar to how go-ethereum handles their batch request calls.
I propose we add a .Errors
method to the CallFuncFactory
, allowing us to specify where the error would get saved the same .Returns
does.
Consider the following snippet:
err := client.Call(
eth.CallFunc(nonExistentFunc, w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")).
Errors(targetErr1).
Returns(res1),
eth.CallFunc(funcBalanceOf, w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), w3.A("0x000000000000000000000000000000000000c0Fe")).
Errors(targetErr2).
Returns(res2),
)
The caller would then be able to check the particular call errors via the targetErr1
and targetErr2
variables in this particular example. If targetErr2 == nil
, I would then expect res2
hold the expected return value.
Thoughts?
I would like to be able to deploy contracts and interact with them, simulating a live network (block and timestamp increasing monotonically). It would be great if this were compatible with forking state from an RPC and maintaining a record of what is overridden locally
Hi,
Great library btw.
I noticed v0.10.0 deprecated some methods. go get -u github.com/lmittmann/w3
will upgrade any 0.x to this version and break any existing code which used the deprecated methods. I propose this library use https://semver.org so that safe dependency upgrades either manually or via @dependabot can be done.
This does not include RevertReason
https://github.com/lmittmann/w3/blob/main/module/debug/call_trace.go#L30-L41 according the spec here https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers . see the calltracer section
As per trufflesuite/ganache#277 and trufflesuite/ganache#578 a Ganache blockchain may report negative gas cost for a REVERT or RETURN EVM command.
The StructLog struct (module/debug/trace.go) for the result of the debug_traceTransaction RPC is using a uint to save the gas resulting in an error.
Hi, I noticed that in refactoring the HeaderByNumber, and dropping the RPCHeader type, I am now not able to get a header with only the transaction hashes.
It would help if either HeaderByNumber could return either a types.Header or types.Block, or for BlockByNumber to return a hydrated or not hydrated list of transactions in the block
The following fails:
w3.MustNewFunc("tokensBalance(address,address[])", "(bool success, bytes data)[]")
with:
panic: w3: invalid ABI: unexpected token '[', want ')', ',' or EOF [recovered]
panic: w3: invalid ABI: unexpected token '[', want ')', ',' or EOF
Actual function signature from contract:
struct Result {
bool success;
bytes data;
}
function tokensBalance(address owner, address[] calldata contracts) external view returns (Result[] memory results) {
//
}
Am I initializing the function incorrectly or does the parser miss this case?
It is common for event signatures definitions in Solidity to end in a semicolon. A test such as:
{
Signature: "Transfer(address,address,uint256);",
WantEvent: &w3.Event{
Signature: "Transfer(address,address,uint256)",
Topic0: w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
},
},
should pass.
However this test will result in a panic. I think a quick fix is to assume a semicolon is an EOF type character in the lexer.
how to decode input data in transaction?I just found it more convenient to take data from input data than from logs, because to get the receipt you need to send another additional request.
Forgive me in advance if this question seems simple. I am a beginner.
How can I get error back with this interface/api? for example say I want to do this
var latestBlockNumber big.Int
eth.BlockNumber().Returns(&latestBlockNumber)
what happens if this network call fails? would the block number be -1 or something? I can eth.BlockNumber().Returns(&latestBlockNumber).createRequest()
but then I am batch BatchElem and ethClient API which is not great. The w3 API looks really good and would be nice if it can also returns errors
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.