Package w3-celo
implements a blazing fast and modular Celo JSON RPC client with
first-class ABI support.
w3-celo
- Batch request support significantly reduces the duration of requests to both remote and local endpoints.
- ABI bindings are specified for individual functions using Solidity syntax.
No need for
abigen
and ABI JSON files. - Modular API allows to create custom RPC method integrations that can be used alongside the methods implemented by the package.
w3-celo
is closely linked to celo-blockchain
and uses a variety of its types, such as common.Address
or types.Transaction
.
Batch requests with w3-celo
are up to 85x faster than sequential requests with
celo-blockchain/ethclient
.
Benchmarks
name ethclient time/op w3 time/op delta Call_BalanceNonce 78.3ms ± 2% 39.0ms ± 1% -50.15% (p=0.000 n=23+22) Call_Balance100 3.90s ± 5% 0.05s ± 2% -98.84% (p=0.000 n=20+24) Call_BalanceOf100 3.99s ± 3% 0.05s ± 2% -98.73% (p=0.000 n=22+23) Call_Block100 6.89s ± 7% 1.94s ±11% -71.77% (p=0.000 n=24+23)
Note Check out the original w3!
w3-celo
is a fork of the original library replacing all incompatible Ethereum types with Celo types.
w3VM changes will not be included in this library as it closely follows Ethereum Geth.
Versioning closely follows the original.
go get github.com/grassrootseconomics/w3-celo
Note Check out the examples!
Connect to an RPC endpoint via HTTP, WebSocket, or IPC using Dial
or MustDial
.
// Connect (or panic on error)
client := w3.MustDial("https://rpc.ankr.com/celo")
defer client.Close()
Batch request support in the Client
allows to send multiple RPC requests in a single HTTP request. The speed gains
to remote endpoints are huge. Fetching 100 blocks in a single batch request
with w3
is ~80x faster compared to sequential requests with ethclient
.
Example: Request the nonce and balance of an address in a single request
var (
addr = w3.A("0x000000000000000000000000000000000000c0Fe")
nonce uint64
balance big.Int
)
err := client.Call(
eth.Nonce(addr, nil).Returns(&nonce),
eth.Balance(addr, nil).Returns(&balance),
)
ABI bindings in w3
are specified for individual functions using Solidity
syntax and are usable for any contract that supports that function.
Example: ABI binding for the ERC20-function balanceOf
funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256")
A Func
can be used to
- encode arguments to the contracts input data (
Func.EncodeArgs
), - decode arguments from the contracts input data (
Func.DecodeArgs
), and - decode returns form the contracts output data (
Func.DecodeReturns
).
Func
's can be used with
eth.CallFunc
in the client to read contract data.
var (
weth9 = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
dai = w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F")
weth9Balance big.Int
daiBalance big.Int
)
err := client.Call(
eth.CallFunc(weth9, funcBalanceOf, addr).Returns(&weth9Balance),
eth.CallFunc(dai, funcBalanceOf, addr).Returns(&daiBalance),
)
Sending a transaction to a contract requires three steps.
- Encode the transaction input data using
Func.EncodeArgs
.
var funcTransfer = w3.MustNewFunc("transfer(address,uint256)", "bool")
input, err := funcTransfer.EncodeArgs(w3.A("0x…"), w3.I("1 ether"))
- Create a signed transaction to the contract using celo-blockchain/types.
signer := types.LatestSigner(params.MainnetChainConfig)
tx := types.MustSignNewTx(privKey, signer, &types.CeloDynamicFeeTx{
To: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
Nonce: 0,
Data: input,
Gas: 75000,
GasFeeCap: w3.I("100 gwei"),
GasTipCap: w3.I("1 gwei"),
})
- Send the signed transaction.
var txHash common.Hash
err := client.Call(
eth.SendTx(tx).Returns(&txHash),
)
Custom RPC methods can be called with the w3
client by creating a
core.Caller
implementation.
The w3/module/eth
package can be used as implementation reference.
Static addresses, hashes, hex byte slices or big.Int
's can be parsed from
strings with the following utility functions.
var (
addr = w3.A("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
hash = w3.H("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
bytes = w3.B("0x27c5342c")
big = w3.I("12.34 ether")
)
Note that these functions panic if the string cannot be parsed. Use celo-blockchain/common to parse strings that may not be valid instead.
List of supported RPC methods.
Method | Go Code |
---|---|
eth_blockNumber |
eth.BlockNumber().Returns(blockNumber *big.Int) |
eth_call |
eth.Call(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(output *[]byte) eth.CallFunc(contract common.Address, f w3types.Func, args ...any).Returns(returns ...any) |
eth_chainId |
eth.ChainID().Returns(chainID *uint64) |
eth_createAccessList |
eth.AccessList(msg *w3types.Message, blockNumber *big.Int).Returns(resp *eth.AccessListResponse) |
eth_estimateGas |
eth.EstimateGas(msg *w3types.Message, blockNumber *big.Int).Returns(gas *uint64) |
eth_gasPrice |
eth.GasPrice().Returns(gasPrice *big.Int) |
eth_maxPriorityFeePerGas |
eth.GasTipCap().Returns(gasTipCap *big.Int) |
eth_getBalance |
eth.Balance(addr common.Address, blockNumber *big.Int).Returns(balance *big.Int) |
eth_getBlockByHash |
eth.BlockByHash(hash common.Hash).Returns(block *types.Block) eth.HeaderByHash(hash common.Hash).Returns(header *types.Header) |
eth_getBlockByNumber |
eth.BlockByNumber(number *big.Int).Returns(block *types.Block) eth.HeaderByNumber(number *big.Int).Returns(header *types.Header) |
eth_getBlockTransactionCountByHash |
eth.BlockTxCountByHash(hash common.Hash).Returns(count *uint) |
eth_getBlockTransactionCountByNumber |
eth.BlockTxCountByNumber(number *big.Int).Returns(count *uint) |
eth_getCode |
eth.Code(addr common.Address, blockNumber *big.Int).Returns(code *[]byte) |
eth_getLogs |
eth.Logs(q celo.FilterQuery).Returns(logs *[]types.Log) |
eth_getStorageAt |
eth.StorageAt(addr common.Address, slot common.Hash, blockNumber *big.Int).Returns(storage *common.Hash) |
eth_getTransactionByHash |
eth.Tx(hash common.Hash).Returns(tx *types.Transaction) |
eth_getTransactionByBlockHashAndIndex |
eth.TxByBlockHashAndIndex(blockHash common.Hash, index uint).Returns(tx *types.Transaction) |
eth_getTransactionByBlockNumberAndIndex |
eth.TxByBlockNumberAndIndex(blockNumber *big.Int, index uint).Returns(tx *types.Transaction) |
eth_getTransactionCount |
eth.Nonce(addr common.Address, blockNumber *big.Int).Returns(nonce *uint) |
eth_getTransactionReceipt |
eth.TxReceipt(txHash common.Hash).Returns(receipt *types.Receipt) |
eth_sendRawTransaction |
eth.SendRawTx(rawTx []byte).Returns(hash *common.Hash) eth.SendTx(tx *types.Transaction).Returns(hash *common.Hash) |
eth_getUncleByBlockHashAndIndex |
eth.UncleByBlockHashAndIndex(hash common.Hash, index uint).Returns(uncle *types.Header) |
eth_getUncleByBlockNumberAndIndex |
eth.UncleByBlockNumberAndIndex(number *big.Int, index uint).Returns(uncle *types.Header) |
eth_getUncleCountByBlockHash |
eth.UncleCountByBlockHash(hash common.Hash).Returns(count *uint) |
eth_getUncleCountByBlockNumber |
eth.UncleCountByBlockNumber(number *big.Int).Returns(count *uint) |
Method | Go Code |
---|---|
debug_traceCall |
debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace *debug.Trace) debug.CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(trace *debug.CallTrace) |
debug_traceTransaction |
debug.TraceTx(txHash common.Hash, config *debug.TraceConfig).Returns(trace *debug.Trace) debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace *debug.CallTrace) |
Method | Go Code |
---|---|
txpool_content |
txpool.Content().Returns(resp *txpool.ContentResponse) |
txpool_contentFrom |
txpool.ContentFrom(addr common.Address).Returns(resp *txpool.ContentFromResponse) |
txpool_status |
txpool.Status().Returns(resp *txpool.StatusResponse) |
Method | Go Code |
---|---|
web3_clientVersion |
web3.ClientVersion().Returns(clientVersion *string) |
Package | Description |
---|---|
github.com/grassrootseconomics/celoutils | High level Celo utilities specific to Grassroots Economics. |