Type-safe contract read calls (eth_call).
Build a read call, encode it for the JS port, decode the response. The return type is parameterized so your decoder is checked at compile time.
import Web3.Contract.Call as Call
import Web3.Abi.Decode as Decode
import Web3.Abi.Encode as Encode
-- Read a uint256 return value
totalSupply : T.Address -> Call.ReadCall BigInt
totalSupply token =
Call.readCall
{ contract = token
, method = "totalSupply()"
, args = []
, decoder = Decode.uint256
, id = "total-supply"
}
-- Simulate a write to catch reverts before broadcasting
simulate : T.Address -> BigInt -> T.Address -> Call.ReadCall Bool
simulate router amount caller =
Call.readCall
{ contract = router
, method = "buy(uint256)"
, args = [ Encode.uint256 amount ]
, decoder = Decode.bool
, id = "sim-buy"
}
|> Call.withFrom caller
-- Send via port
web3Cmd (Call.encode (totalSupply tokenAddress))
-- Decode response
result = D.decodeValue (Call.responseDecoder myCall) incomingRelated modules: Web3.Multicall for batching multiple reads into one RPC call;
Web3.Contract.Send for write calls.
Create a read call. The id is echoed back in the response so you can
match responses to requests when multiple calls are in flight.
Create a read call from pre-built hex calldata -- the result of
Web3.Abi.Calldata.calldata. The JS port
bridge sends data directly without re-encoding, so the wire path is
entirely pure-Elm: no method-name string, no arg encoding outside of Elm.
-- balanceOf(address) -- selector baked at codegen time
balanceOf : T.Address -> T.Address -> ReadCall BigInt
balanceOf contract holder =
readCallRaw
{ contract = contract
, data = Calldata.calldata "70a08231" [ Calldata.address holder ]
, decoder = AbiDecode.uint256
, id = "balanceOf"
}The data argument must be a complete "0x..." calldata string including the
4-byte function selector.
Set the block number for the call.
Add a from address -- turns eth_call into a simulation of a write.
Catches reverts without broadcasting.
simulateBuy tokenAddress amount userAddress
|> withFrom userAddress
|> encode
|> web3CmdEncode a read call for the JS port.
encode myReadCall
-- sends { tag: "call", id: ..., contract: ..., block: ..., method: ..., args: ... }
-- raw-calldata reads send { tag: "call", id: ..., contract: ..., data: ... }
-- JS replies with { tag: "callResult", id: ..., data: "0x..." }, whose
-- `data` field is what `responseDecoder` reads.A failure replies on the shared failure channel instead --
{ tag: "failed", error, code, revertData } -- which
Web3.Error.decoder turns into a typed
Web3.Error.Error, so a reverted simulation is
distinguishable from a dead RPC without matching on English.
Get the response decoder for a read call.
A read-only contract call with a typed return value.