Signed Reads
Authenticated read calls that prove caller identity
On standard Ethereum, eth_call can spoof any from address -- there is no signature check. Seismic prevents this: all unsigned eth_call requests have msg.sender set to the zero address. To read shielded data that depends on msg.sender, you need a signed read: a signed transaction submitted to eth_call that proves the caller's identity.
Why Signed Reads Matter
Contracts can use msg.sender in view functions to gate access to shielded data. A common example: a token contract with a balanceOf() that takes no arguments and uses msg.sender internally to look up the caller's balance. Without a signed read, the contract sees the zero address and returns that address's balance -- which is almost certainly zero.
// Smart read -- balanceOf(saddress) has shielded param → signed read automatically
const myBalance = await contract.read.balanceOf(["0x1234..."]);
// Smart read -- totalSupply() has no shielded params → transparent read automatically
const totalSupply = await contract.read.totalSupply();
// Force signed read -- always encrypted, even for non-shielded functions
const supply = await contract.sread.totalSupply();seismic-viem provides several approaches:
contract.read.functionName()-- smart routing via getShieldedContract. Auto-detects shielded parameters and uses signed read only when needed.contract.sread.functionName()-- force signed read via getShieldedContract. Always uses signed read regardless of parameter types.signedReadContract()-- standalone function, same API shape as viem'sreadContract. Always uses signed read.walletClient.readContract()-- smart routing via the wallet client. Same auto-detection ascontract.read.walletClient.sreadContract()-- force signed read via the wallet client. Always uses signed read.
The signed read paths all encrypt the calldata, sign it, and decrypt the response automatically.
Standalone: signedReadContract
Parameters
signedReadContract(client, parameters, securityParams?)
address
Hex
Yes
Contract address
abi
Abi
Yes
Contract ABI
functionName
string
Yes
Name of the view/pure function
args
array
No
Function arguments
nonce
number
No
Override the nonce
The optional third argument securityParams: SeismicSecurityParams accepts advanced Seismic metadata overrides (see Security Parameters). Most callers should omit these; they are mainly useful for deterministic tests/debugging, explicit expiry control, and low-level interop.
Returns
Promise<ReadContractReturnType> -- the decoded return value, typed according to the ABI.
Example
Low-level: signedCall
For cases where you have raw calldata instead of ABI-encoded parameters -- for example, pre-encoded data or non-ABI interactions:
signedCall also accepts SeismicSecurityParams as a third argument for overriding the encryption nonce, block hash, or expiry window. See Shielded Writes for the full parameter table.
How It Works
When you call signedReadContract (or contract.sread.functionName), the SDK performs the following steps:
ABI-encode the function call into plaintext calldata
Build Seismic metadata with
signedRead: trueEncrypt calldata with AES-GCM using the shared key derived via ECDH
Sign the transaction:
For local accounts (private key): sign as a raw Seismic transaction, send to
eth_callFor JSON-RPC accounts (MetaMask): sign EIP-712 typed data via
eth_signTypedData_v4, send the typed data + signature toeth_call
Decrypt the response returned by the node
Decode the ABI output into the expected return type
Both the calldata you send and the result you receive are encrypted. An observer watching the network can see that a call was made to a particular contract address, but not what function was called or what was returned.
Signed Read vs Transparent Read
Aspect
.read (Smart)
.sread (Force Signed)
.tread (Transparent)
Calldata
Auto-detected by ABI
Always encrypted
Always plaintext
msg.sender
Signer if shielded, zero if not
Always signer's address
Always zero address
Use case
Default -- handles most cases
Force encryption for sensitive returns
Public view functions
Performance
Optimal -- encrypts only when needed
Slightly slower (sign + encrypt + decrypt)
Standard eth_call speed
.tread and walletClient.treadContract reject the account option and will throw. On Seismic, transparent eth_call zeroes out from on the node, so any account you pass would silently be ignored. For any sender-aware read, use .sread / sreadContract.
See Also
Contract Instance --
getShieldedContractwith.readand.treadnamespacesShielded Writes -- Encrypted write transactions using the same pipeline
Encryption -- ECDH key exchange and AES-GCM details
Shielded Wallet Client -- Creating the client used for signed reads
Last updated

