Relay Adapters

Relay adapters allow Totems to be used with standard token interfaces like ERC-20. This enables compatibility with existing DeFi protocols, wallets, and tools that expect standard token contracts.

Why Relay Adapters?

Totems use a multi-token pattern where all Totems share a single contract. While this is efficient, many existing tools expect each token to have its own contract address. Relay adapters bridge this gap by providing a standard interface that forwards calls to the Totems contract.

%%{init: {'theme': 'dark', 'flowchart': { 'subGraphTitleMargin': { 'top': 10 } }, 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#e5e7eb', 'primaryBorderColor': '#38bdf8', 'lineColor': '#38bdf8', 'clusterBkg': 'transparent', 'clusterBorder': '#38bdf8' }}}%%
flowchart LR
    DeFi["DeFi Protocol"] --> ERC20["ERC-20 Relay"]
    ERC20 --> Totems["Totems Contract"]

    classDef default fill:#1e293b,stroke:#38bdf8,stroke-width:2px,color:#e5e7eb;

Wait, can this do what I think it can?

Yes!

Not only can you use Totems in practically any format, but you can also wrap standard tokens (ERC20 for example) into Totems and then use them with other adapters, effectively extending those tokens to new standards.

An example might be adding x402 support for WETH by wrapping WETH into a Totem, then using an x402 relay adapter.

Note

That will create a new address for the wrapped token, so it’s not the same as the original token contract.

ERC-20 Relay Example

The TotemERC20 contract wraps a Totem with a full ERC-20 interface:

contract TotemERC20 {
    // Standard ERC-20 functions
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

How It Works

  1. Each relay contract is bound to a specific Totem ticker
  2. When you call transfer(), it forwards to Totems.transfer()
  3. Balances and supply are queried directly from the Totems contract
  4. Allowances are managed within the relay contract itself

Creating a Relay

Relay contracts are created through the TotemERC20Factory:

interface IRelayFactory {
    function createRelay(string calldata ticker) external returns (address);

    event RelayCreated(string indexed ticker, address relay);
}

Relays actually deploy the adapter contract and register it with the Totems contract. Once created, the relay address can be used anywhere an ERC-20 token address is expected.

Use Cases

DeFi Integration

Use relay adapters to:

  • Add liquidity to Uniswap, SushiSwap, or other DEXs
  • Use totems as collateral in lending protocols
  • Integrate with yield aggregators

Wallet Compatibility

Most wallets display ERC-20 tokens automatically. With a relay adapter, your totem will:

  • Show up in MetaMask and other wallets
  • Display proper name, symbol, and decimals
  • Support standard approval flows or other varying token standard mechanisms

Block Explorers

Relay adapters make totems visible on block explorers like Etherscan, showing:

  • Token transfers
  • Holder counts
  • Total supply

Tip

Caveat: The adapter should not be considered the source of truth for totem data. Always refer back to the Totems contract for authoritative information. Adapter -> Totems is one-way, so there could be transfers/burns happening directly on the Totems contract that the adapter is unaware of.

Relay Info

Each totem tracks its relay adapters in the RelayInfo struct:

struct RelayInfo {
    address relay;    // The relay contract address
    string standard;  // e.g., "ERC20"
}

You can query a totem’s relays through the Totems contract to discover available adapters.

Security Considerations

Caution

Relay adapters are highly privileged contracts. A malicious relay can steal user funds.

Why Relays Are Sensitive

Relay contracts forward the original sender’s address to the Totems contract. The Totems contract trusts that the relay is correctly reporting who initiated the action:

// Inside relay contract
function transfer(address to, uint256 amount) external returns (bool) {
    // Forwards msg.sender as the "from" address
    totems.transfer(ticker, msg.sender, to, amount, "");
    return true;
}

A malicious relay could pass any address as the sender, allowing it to transfer totems from any holder without permission.

Trust Requirements

Totem creators are responsible for adding relays to their totems. Because of the security implications:

  • Internal relays: Relays developed by the Totems team are the most trusted
  • Third-party relays: Must be open source and undergo extensive scrutiny before being displayed in the UI
  • All relays: Must have no admin functions or upgradeability, and be verified on Etherscan

Warning

The Totems UI will only display relays that meet strict trust criteria.

If you’re building a custom relay:

  1. Keep it simple - Minimize logic beyond forwarding calls
  2. Open source it - Allow community review
  3. Get audited - Professional audits are essential for adoption
  4. No admin functions - Avoid upgradeability or owner privileges that could be exploited
  5. Submit for review - Contact the Totems team to have your relay evaluated for inclusion in the official UI

Limitations

  • Gas costs: Relay calls add overhead since they forward to the Totems contract
  • Hook execution: Transfers through relays still trigger all licensed mod hooks
  • Allowances: Managed per-relay, not shared across different relay contracts
<-
Proxy Mod
Totem Details
->