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
- Each relay contract is bound to a specific Totem ticker
- When you call
transfer(), it forwards toTotems.transfer() - Balances and supply are queried directly from the Totems contract
- 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:
- Keep it simple - Minimize logic beyond forwarding calls
- Open source it - Allow community review
- Get audited - Professional audits are essential for adoption
- No admin functions - Avoid upgradeability or owner privileges that could be exploited
- 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