> ## Documentation Index
> Fetch the complete documentation index at: https://anchoragedigital-docs-swig-highlight.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Chain Metadata

> Provide ABIs and IDLs for enhanced transaction parsing

Chain metadata helps the parser understand smart contract interactions. Without metadata, contract calls may appear as raw hex data. With metadata, they're parsed into meaningful field names and values.

## When to provide metadata

| Scenario                                 | Metadata needed?      |
| ---------------------------------------- | --------------------- |
| Native transfers (ETH, SOL, SUI)         | No                    |
| Known protocols (Uniswap, Jupiter, Aave) | No (built-in support) |
| Standard token transfers (ERC-20, SPL)   | No (built-in support) |
| Custom smart contracts                   | Yes                   |
| Anchor programs without public IDL       | Yes                   |

## Ethereum: Contract ABI

For Ethereum and EVM chains, provide the contract ABI to decode function calls. ABIs are passed as a map keyed by contract address, so wallets can supply one ABI per contract the transaction touches.

For an end-to-end Ethereum integration walkthrough (supported networks, what's auto-decoded, the rendered payload), see [Ethereum for Wallets](../chains/ethereum).

### gRPC example

```go theme={null}
request := &pb.ParseRequest{
    UnsignedPayload: rawTxHex,
    Chain: pb.Chain_CHAIN_ETHEREUM,
    ChainMetadata: &pb.ChainMetadata{
        Metadata: &pb.ChainMetadata_Ethereum{
            Ethereum: &pb.EthereumMetadata{
                NetworkId: proto.String("ETHEREUM_MAINNET"),
                AbiMappings: map[string]*pb.Abi{
                    "0xdac17f958d2ee523a2206206994597c13d831ec7": &pb.Abi{
                        Value: contractABI, // JSON ABI string
                    },
                },
            },
        },
    },
}
```

### Address casing

`abi_mappings` keys are 0x-prefixed contract addresses. The parser parses each key into a numeric address before registration, so lookup is case-insensitive: `0xdAC17...` and `0xdac17...` resolve to the same contract. Use a consistent casing convention (all lowercase or EIP-55 checksummed) across your ABI store to avoid duplicate entries for the same address.

### ABI format

The ABI is standard Solidity ABI JSON:

```json theme={null}
[
  {
    "name": "transfer",
    "type": "function",
    "inputs": [
      { "name": "recipient", "type": "address" },
      { "name": "amount", "type": "uint256" }
    ]
  },
  {
    "name": "approve",
    "type": "function",
    "inputs": [
      { "name": "spender", "type": "address" },
      { "name": "amount", "type": "uint256" }
    ]
  }
]
```

### Specifying network

For EVM chains other than mainnet, set `network_id`. The parser recognizes a broad set of values (Ethereum mainnet and testnets, BSC, Polygon, Avalanche, Gnosis, Celo, Fantom, Optimism, Arbitrum, Base, Blast, Mantle, World Chain, zkSync Era, Linea, Scroll, Zora, Unichain, and their testnet variants where applicable). The authoritative list is defined by `network_id_to_chain_id` in [`src/chain_parsers/visualsign-ethereum/src/networks.rs`](https://github.com/anchorageoss/visualsign-parser/blob/main/src/chain_parsers/visualsign-ethereum/src/networks.rs).

Built-in token metadata is preloaded only for `ETHEREUM_MAINNET`, `POLYGON_MAINNET`, `ARBITRUM_MAINNET`, `OPTIMISM_MAINNET`, and `BASE_MAINNET`. On other recognized chains, token symbol and decimal resolution is limited to the built-in registry; `chain_metadata` currently only accepts `network_id` and `abi_mappings`, so wallet-supplied token metadata is not yet supported. Always pass the **actual** `network_id` for the chain you're parsing; the value overrides the transaction's chain ID and reusing an unrelated one will mislabel the Network field.

```go theme={null}
ChainMetadata: &pb.ChainMetadata{
    Metadata: &pb.ChainMetadata_Ethereum{
        Ethereum: &pb.EthereumMetadata{
            NetworkId: proto.String("POLYGON_MAINNET"),
            AbiMappings: map[string]*pb.Abi{
                "0x...": &pb.Abi{ Value: contractABI },
            },
        },
    },
}
```

## Solana: Program IDL

For Solana programs, provide the Anchor IDL to decode instructions:

### gRPC example

```go theme={null}
request := &pb.ParseRequest{
    UnsignedPayload: rawTxHex,
    Chain: pb.Chain_CHAIN_SOLANA,
    ChainMetadata: &pb.ChainMetadata{
        Metadata: &pb.ChainMetadata_Solana{
            Solana: &pb.SolanaMetadata{
                Idl: &pb.Idl{
                    Value: anchorIDL, // JSON IDL string
                    IdlType: pb.SolanaIdlType_SOLANA_IDL_TYPE_ANCHOR,
                },
            },
        },
    },
}
```

### Multiple programs

If your transaction interacts with multiple programs, use the IDL mappings:

```go theme={null}
ChainMetadata: &pb.ChainMetadata{
    Metadata: &pb.ChainMetadata_Solana{
        Solana: &pb.SolanaMetadata{
            IdlMappings: map[string]*pb.Idl{
                "Program1111111111111111111111111111111111111": {
                    Value: program1IDL,
                    IdlType: pb.SolanaIdlType_SOLANA_IDL_TYPE_ANCHOR,
                },
                "Program2222222222222222222222222222222222222": {
                    Value: program2IDL,
                    IdlType: pb.SolanaIdlType_SOLANA_IDL_TYPE_ANCHOR,
                },
            },
        },
    },
}
```

### Supported IDL types

| Type                     | Description          |
| ------------------------ | -------------------- |
| `SOLANA_IDL_TYPE_ANCHOR` | Anchor framework IDL |
| `SOLANA_IDL_TYPE_SHANK`  | Shank IDL format     |

## Library integration

When using the library directly (not gRPC), pass metadata via `VisualSignOptions`. The Ethereum metadata shape mirrors the proto: a `network_id` and an `abi_mappings` map keyed by contract address.

```rust theme={null}
use std::collections::HashMap;
use generated::parser::{Abi, ChainMetadata, EthereumMetadata, chain_metadata::Metadata};
use visualsign::vsptrait::VisualSignOptions;

let mut abi_mappings = HashMap::new();
abi_mappings.insert(
    "0xdac17f958d2ee523a2206206994597c13d831ec7".to_string(),
    Abi { value: contract_abi_json, signature: None },
);

let options = VisualSignOptions {
    metadata: Some(ChainMetadata {
        metadata: Some(Metadata::Ethereum(EthereumMetadata {
            network_id: Some("ETHEREUM_MAINNET".to_string()),
            abi_mappings,
        })),
    }),
    ..Default::default()
};
```

See [Library Integration](../library/getting-started) for the full end-to-end example.

## Obtaining metadata

### Ethereum ABIs

| Source      | How to get                                       |
| ----------- | ------------------------------------------------ |
| Etherscan   | View verified contract → Contract tab → ABI      |
| Compilation | `solc --abi Contract.sol`                        |
| Hardhat     | `artifacts/contracts/Contract.sol/Contract.json` |
| Foundry     | `out/Contract.sol/Contract.json`                 |

### Solana IDLs

| Source       | How to get                            |
| ------------ | ------------------------------------- |
| Anchor build | `target/idl/program_name.json`        |
| On-chain     | Some programs publish IDL on-chain    |
| Program repo | Check the program's source repository |

## Without metadata

If you don't provide metadata for a contract interaction, the parser will:

1. Decode what it can (addresses, amounts in native token)
2. Show the function selector (first 4 bytes) as hex
3. Display raw calldata for unknown parameters

This is safe but less informative. Users see something like:

```
Contract Interaction
Method: 0xa9059cbb (unknown)
To: 0x1234...
Data: 0x...
```

## Next steps

* [How Parsing Works](./how-parsing-works): Understand the parsing pipeline
* [Error Handling](./error-handling): Handle cases where parsing fails
* [gRPC API Reference](/api-reference): Full request/response formats
