> For the complete documentation index, see [llms.txt](https://docs.seismic.systems/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.seismic.systems/clients/alloy/src20.md).

# SRC20

SRC20 is Seismic's privacy-preserving ERC20 standard. Balances and transfer amounts use shielded types (`suint256`), so they are hidden from external observers. The protocol ensures that only authorized parties — the token holder or those with a viewing key — can read balances and decode transfer events.

## Contract Interface

Define the SRC20 interface using Alloy's `sol!` macro:

```rust
use seismic_prelude::client::*;

sol! {
    #[sol(rpc)]
    interface ISRC20 {
        function name() public view returns (string);
        function symbol() public view returns (string);
        function decimals() public view returns (uint8);
        function totalSupply() public view returns (uint256);

        function balanceOf(address account) public view returns (suint256);
        function transfer(address to, suint256 amount) public returns (bool);
        function approve(address spender, suint256 amount) public returns (bool);
        function allowance(address owner, address spender) public view returns (suint256);
        function transferFrom(address from, address to, suint256 amount) public returns (bool);

        event Transfer(address indexed from, address indexed to, suint256 value);
        event Approval(address indexed owner, address indexed spender, suint256 value);
    }
}
```

## Architecture

```
SRC20 Token Contract (on-chain, Mercury EVM)
  |
  |-- Public metadata: name(), symbol(), decimals(), totalSupply()
  |     -> Transparent reads (no encryption needed)
  |
  |-- Shielded balances: balanceOf(address)
  |     -> Signed reads via .seismic().call() or seismic_call() (identity-proven eth_call)
  |     -> Contract uses msg.sender to gate access
  |
  |-- Shielded writes: transfer(), approve(), transferFrom()
  |     -> Calldata auto-encrypted (shielded params) or via .seismic() builder
  |     -> Amounts invisible to observers
  |
  |-- Encrypted events: Transfer, Approval
  |     -> Event data contains encrypted suint256 values
  |     -> Viewing key required to decrypt
```

## Quick Start

```rust
use seismic_prelude::client::*;
use seismic_alloy_network::reth::SeismicReth;

sol! {
    #[sol(rpc)]
    interface ISRC20 {
        function name() public view returns (string);
        function symbol() public view returns (string);
        function decimals() public view returns (uint8);
        function balanceOf(address account) public view returns (suint256);
        function transfer(address to, suint256 amount) public returns (bool);
        function approve(address spender, suint256 amount) public returns (bool);
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let signer: PrivateKeySigner = "0xYOUR_PRIVATE_KEY".parse()?;
    let wallet = SeismicWallet::<SeismicReth>::from(signer);
    let url = "https://testnet-1.seismictest.net/rpc".parse()?;
    let provider = SeismicProviderBuilder::new()
        .wallet(wallet)
        .connect_http(url)
        .await?;

    let token_address: Address = "0xYOUR_TOKEN_ADDRESS".parse()?;
    let contract = ISRC20::new(token_address, &provider);

    // Read public metadata (transparent read)
    let name = contract.name().call().await?;
    println!("Token name: {}", name._0);

    // Read shielded balance (signed read)
    let balance = contract
        .balanceOf(provider.default_signer_address())
        .seismic()
        .call()
        .await?;
    println!("Balance: {}", balance._0);

    Ok(())
}
```

## Navigation

| Page                                                           | Description                                                       |
| -------------------------------------------------------------- | ----------------------------------------------------------------- |
| [Token Interaction](/clients/alloy/src20/token-interaction.md) | Reading and writing SRC20 balances, signed reads, shielded writes |
| [Transfers](/clients/alloy/src20/transfers.md)                 | Shielded transfer patterns, approvals, and multi-step workflows   |
| [Event Decryption](/clients/alloy/src20/event-decryption.md)   | Decrypting encrypted Transfer and Approval events                 |

## Key Concepts

### Signed Reads for Balances

Unlike ERC20 where `balanceOf()` is a simple public read, SRC20's `balanceOf()` uses `msg.sender` to authenticate the caller. This means you must use `seismic_call()` (a signed read) rather than a plain `eth_call`. A plain `eth_call` zeros out the `from` field, so the contract sees the zero address as the sender and returns its balance — which is almost certainly zero.

### Shielded Writes

Transfers and approvals have shielded parameters (`suint256`), so the `sol!` macro wraps them in a `ShieldedCallBuilder` that auto-encrypts — just call `.send()` directly. The `SeismicProviderBuilder`-created provider's filler pipeline automatically handles the encryption before the transaction reaches the node.

### Encrypted Events

SRC20 Transfer and Approval events contain encrypted `suint256` values. To decode the actual transfer amounts, you need a viewing key registered with the Directory contract.

## See Also

* [Contract Interaction](/clients/alloy/contract-interaction.md) — General shielded and transparent call patterns
* [SeismicSignedProvider](/clients/alloy/provider/seismic-signed-provider.md) — Required for shielded operations
* [Encryption](/clients/alloy/provider/encryption.md) — How calldata encryption works


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.seismic.systems/clients/alloy/src20.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
