# Get Started

[Trust Wallet](https://trustwallet.com) is a self-custody, multi-chain crypto wallet used by millions of people worldwide. It supports 100+ blockchains and millions of assets, giving users full control of their keys while providing a seamless experience for storing, sending, receiving, and swapping crypto — as well as connecting to dApps across web3.

This documentation covers everything for developers: building on top of Trust Wallet, listing your project, and integrating Trust Wallet's open-source libraries.

***

## Trust Wallet Agent SDK

### [Agent SDK](/developer/agent-sdk)

Programmatic access to Trust Wallet's multichain infrastructure — balance queries, token prices, swaps, transaction history, and more — through a CLI and an MCP server for AI agents.

* [Quickstart](/developer/agent-sdk/quickstart)
* [CLI Reference](/developer/agent-sdk/cli-reference)
* [Authentication](/developer/agent-sdk/authentication)
* [Key Management](/developer/agent-sdk/key-management)

***

## Build on Trust Wallet

### [Developing for Trust Wallet](/developer/develop-for-trust)

An introduction to web3 development with Trust Wallet. Covers the Provider API, WalletConnect, deep linking, and the browser extension.

* [Browser Extension](/developer/develop-for-trust/browser-extension)
* [Mobile (WalletConnect)](/developer/develop-for-trust/mobile)
* [Deep Linking](/developer/develop-for-trust/deeplinking)

### [Barz — Smart Wallet](/developer/barz-smart-wallet)

Barz is Trust Wallet's ERC-4337 compatible smart contract wallet. Learn how to integrate it into your project for a modular, upgradeable smart wallet experience.

***

## List Your Project

### [Listing a New dApp](/developer/listing-guide)

Submit your dApp for listing in the Trust Wallet browser. Covers the listing requirements and submission process.

### [Listing a New Asset](/developer/new-asset)

Add your token or coin to the Trust Wallet asset repository. Covers logo requirements, token information, and the pull request process.

### [Staking Validators](/developer/new-asset/staking-validator)

List your validator in the Trust Wallet app so users can discover and delegate to it directly.

***

## Libraries

### [Wallet Core](/developer/wallet-core)

Trust Wallet's open-source, cross-platform cryptographic library. Supports 130+ blockchains with native bindings for iOS (Swift), Android (Kotlin/Java), Go, WebAssembly, and more.

***

## Tooling

### [MCP Servers](/developer/mcp)

Trust Wallet publishes two MCP servers for AI coding assistants: a [Docs MCP](/developer/mcp/docs-mcp) for searching developer documentation, and an [API Gateway MCP](/developer/mcp/api-gateway) for querying live blockchain data (prices, swaps, security checks, and more).

### [Claude Code Skills](/developer/claude-code-skills)

Domain-specific Claude Code skills for Trust Wallet libraries, enabling AI-assisted development with knowledge of Trust Wallet's APIs and conventions.


# Trust Wallet Agent SDK

The Trust Wallet Agent SDK gives developers programmatic access to Trust Wallet's multichain infrastructure — balance queries, token prices, swaps, transaction history, and more — through a CLI and an MCP server for AI agents.

## Install

```bash
npx @trustwallet/cli --version
```

Or install globally: `npm install -g @trustwallet/cli`

## Get started

* [Quickstart](/developer/agent-sdk/quickstart) — install the CLI and make your first request in 5 minutes
* [CLI Reference](/developer/agent-sdk/cli-reference) — all commands, subcommands, and flags
* [Authentication](/developer/agent-sdk/authentication) — API keys and HMAC signing
* [Key Management](/developer/agent-sdk/key-management) — wallet keys, encryption, and signing permissions

## Developer portal

Create and manage your API keys at [portal.trustwallet.com](https://portal.trustwallet.com).


# Quickstart

Get from zero to your first API call in under 5 minutes using the `twak` CLI.

## Step 1 — Install the CLI

Run directly without installing (recommended):

```bash
npx @trustwallet/cli --version
```

Or install globally:

```bash
npm install -g @trustwallet/cli
twak --version
```

> **Permission denied?** If you get `EACCES` on macOS/Linux, either use `npx @trustwallet/cli` (no install needed), install Node via [nvm](https://github.com/nvm-sh/nvm) (avoids `/usr/local` permissions), or run `sudo npm install -g @trustwallet/cli`.

## Step 2 — Configure credentials

Get your API key and HMAC secret from the [developer portal](https://portal.trustwallet.com/dashboard/apps), then run:

```bash
twak init --api-key your_access_id \
          --api-secret your_hmac_secret
```

Credentials are stored in `~/.twak/credentials.json` (file permissions `0600`). This is the recommended approach for local development.

For CI/CD pipelines, use environment variables instead:

```bash
export TWAK_ACCESS_ID=your_access_id
export TWAK_HMAC_SECRET=your_hmac_secret
```

> **Do not add these exports to `~/.zshrc` or `~/.bashrc`.** Use `twak init` for persistent local credentials — it stores them in a dedicated file with restricted permissions. Env vars are intended for ephemeral CI/CD environments.

Confirm the setup:

```bash
twak auth status
```

> **Never commit your HMAC secret to version control.** If using a `.env` file, add it to `.gitignore`.

## Step 3 — Make your first request

Fetch the current ETH price — no wallet required:

```bash
twak price ETH
```

Add `--json` for machine-readable output:

```bash
twak price ETH --json
```

List all supported chains:

```bash
twak chains
```

## Step 4 — Explore more commands

```bash
# ETH balance for any address (coin 60 = Ethereum)
twak balance --address <addr> --coin 60

# All token holdings for an address
twak holdings --address <addr> --coin 60

# Trending tokens (with optional category and sort)
twak trending --limit 5
twak trending --category ai
twak trending --category memes --sort volume

# Browse DApps and protocols
twak dapps
twak dapps --category defi

# Search for tokens by name or symbol
twak search uniswap

# Transaction history for an address
twak history --address <addr> --chain ethereum

# Security / rug-risk check for a token
twak risk c60_t0x1f9840a85d5af5bf1d1762f925bdaddc4201f984

# Create an embedded agent wallet
twak wallet create --password <pw>

# Portfolio with USD values across all chains
twak wallet portfolio

# Get a swap quote first, then execute
twak swap 0.1 ETH USDC --chain ethereum --quote-only
twak swap 0.1 ETH USDC --chain ethereum

# Start an MCP server for AI agent integrations
twak serve
```

Run any command with `--help` to see all options.

## Next steps

* [CLI Reference](/developer/agent-sdk/cli-reference) — full command reference
* [Authentication](/developer/agent-sdk/authentication) — how HMAC signing works


# CLI Reference

The `twak` CLI provides full access to the Trust Wallet Agent SDK from the command line.

**Run:** `npx @trustwallet/cli <command>` or install globally with `npm install -g @trustwallet/cli`

***

## init

Initialize configuration and save credentials.

```bash
twak init --api-key <key> --api-secret <secret>
```

| Flag           | Required | Description        |
| -------------- | -------- | ------------------ |
| `--api-key`    | Yes      | TWAK API access ID |
| `--api-secret` | Yes      | HMAC secret        |

Credentials are saved to `~/.twak/credentials.json`.

***

## auth

### auth setup

```bash
twak auth setup --api-key <key> --api-secret <secret>
```

### auth status

```bash
twak auth status [--json]
```

***

## wallet

### wallet create

```bash
twak wallet create --password <pw> [--no-keychain] [--skip-password-check] [--json]
```

### wallet address

```bash
twak wallet address --chain <chain> [--password <pw>] [--json]
```

Password falls back to the OS keychain or `TWAK_WALLET_PASSWORD` environment variable. See [Key Management](/developer/agent-sdk/key-management) for full details on key storage, password resolution, and signing permissions.

### wallet addresses

```bash
twak wallet addresses [--password <pw>] [--json]
```

### wallet balance

```bash
twak wallet balance [--chain <chain>] [--all] [--no-tokens] [--password <pw>] [--json]
```

Use `--all` to show balances across all chains with funds. Use `--no-tokens` to skip token balance lookup.

### wallet portfolio

Full portfolio across all chains — native balances, token holdings, and USD values.

```bash
twak wallet portfolio [--chains <list>] [--password <pw>] [--json]
```

Default chains include all major EVM chains plus Solana and TRON.

### wallet sign-message

Sign an arbitrary message with the agent wallet key.

```bash
twak wallet sign-message --chain <chain> --message <text> [--password <pw>] [--json]
```

### wallet keychain save

Save the wallet password to the OS keychain for passwordless usage.

```bash
twak wallet keychain save --password <pw>
```

### wallet keychain delete

```bash
twak wallet keychain delete
```

### wallet keychain check

```bash
twak wallet keychain check
```

### wallet status

```bash
twak wallet status [--json]
```

***

## transfer

```bash
twak transfer --to <address> --amount <amount> --token <token> \
              [--confirm-to <address>] [--max-usd <n>] [--skip-safety-check] \
              [--password <pw>] [--json]
```

| Flag                  | Description                                                         |
| --------------------- | ------------------------------------------------------------------- |
| `--to`                | Destination address or ENS name (e.g., `vitalik.eth`)               |
| `--amount`            | Amount in human-readable format                                     |
| `--token`             | Asset ID (e.g., `c60` for ETH, `c60_t0xA0b8...` for ERC-20)         |
| `--max-usd`           | Maximum allowed transfer value in USD (default: 10000)              |
| `--skip-safety-check` | Skip the USD-value safety check                                     |
| `--confirm-to`        | Pin expected resolved address — rejects if ENS resolves differently |

***

## swap

```bash
twak swap <amount> <from> <to> [--chain <chain>] [--to-chain <chain>] \
          [--slippage <pct>] [--quote-only] [--password <pw>] [--json]
```

| Flag           | Description                                |
| -------------- | ------------------------------------------ |
| `--chain`      | Source chain (default: ethereum)           |
| `--to-chain`   | Destination chain for cross-chain swaps    |
| `--slippage`   | Slippage tolerance % (default: 1, max: 50) |
| `--quote-only` | Preview quote without executing            |

Use `--quote-only` to preview without executing.

***

## onramp

Buy crypto with fiat (onramp) or sell crypto for fiat (offramp) through third-party providers. Quotes are aggregated; the user completes KYC and payment in the provider's hosted browser flow. Available providers depend on the user's region.

### onramp quote

Get fiat-to-crypto quotes from multiple providers.

```bash
twak onramp quote --amount <fiat> --asset <id> [--currency <code>] \
                  [--wallet <address>] [--password <pw>] [--json]
```

| Flag         | Description                                                                                      |
| ------------ | ------------------------------------------------------------------------------------------------ |
| `--amount`   | Fiat amount, e.g. `100`                                                                          |
| `--asset`    | Asset ID, e.g. `c60` for ETH                                                                     |
| `--currency` | Fiat currency (default: `USD`)                                                                   |
| `--wallet`   | Override the destination address (defaults to your stored wallet's address on the asset's chain) |

Quotes are sorted lowest-spread-first; the top row is the provider giving the most crypto for the same fiat input.

### onramp buy

Open the provider checkout URL for a chosen quote.

```bash
twak onramp buy --quote-id <id> [--asset <id>] [--wallet <address>] \
                [--password <pw>] [--json]
```

| Flag         | Description                                                                                     |
| ------------ | ----------------------------------------------------------------------------------------------- |
| `--quote-id` | Quote ID from `twak onramp quote`                                                               |
| `--asset`    | Crypto asset ID — required when `--wallet` is omitted (used to derive your destination address) |
| `--wallet`   | Override the destination address                                                                |

### onramp sell-quote

Get crypto-to-fiat quotes.

```bash
twak onramp sell-quote --amount <crypto> --asset <id> [--currency <code>] \
                       [--method <method>] [--wallet <address>] \
                       [--password <pw>] [--json]
```

| Flag         | Description                                                                                 |
| ------------ | ------------------------------------------------------------------------------------------- |
| `--amount`   | Crypto amount to sell, e.g. `0.1`                                                           |
| `--asset`    | Asset ID being sold                                                                         |
| `--currency` | Fiat currency for the payout (default: `USD`)                                               |
| `--method`   | Payout method: `ANY`, `card`, `bank_transfer` (default: `ANY`)                              |
| `--wallet`   | Override the source address (defaults to your stored wallet's address on the asset's chain) |

Sorted lowest-spread-first; the top row is the provider returning the most fiat for the same crypto input.

### onramp sell

Open the provider checkout URL to complete KYC and reveal the deposit address.

```bash
twak onramp sell --quote-id <id> [--asset <id>] [--wallet <address>] \
                 [--password <pw>] [--json]
```

| Flag         | Description                                                                                |
| ------------ | ------------------------------------------------------------------------------------------ |
| `--quote-id` | Quote ID from `twak onramp sell-quote`                                                     |
| `--asset`    | Crypto asset ID — required when `--wallet` is omitted (used to derive your source address) |
| `--wallet`   | Override the source address                                                                |

### onramp sell-confirm

Broadcast the on-chain payout to the provider's deposit address. Run this **after** completing KYC in the browser and copying the deposit address and exact amount the provider displayed.

```bash
twak onramp sell-confirm --asset <id> --to <deposit-address> --amount <n> \
                         [--memo <tag>] [--quote-id <id>] \
                         [--max-usd <n>] [--skip-safety-check] \
                         [--password <pw>] [--json]
```

| Flag                  | Description                                                                                                                   |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `--asset`             | Asset being sold                                                                                                              |
| `--to`                | Provider's deposit address (shown after KYC)                                                                                  |
| `--amount`            | Exact amount the provider displays — must match                                                                               |
| `--memo`              | Memo / destination tag (Cosmos, XRP, Stellar, BNB Beacon) — funds can be unrecoverable without it when the chain requires one |
| `--quote-id`          | Optional. Recorded in the output for traceability; the on-chain tx is built from `--to` / `--amount`, not from this ID        |
| `--max-usd`           | USD safety cap (default: 10000)                                                                                               |
| `--skip-safety-check` | Bypass the USD cap                                                                                                            |

The deposit address is **not under your control** — verify it byte-for-byte against what the provider displayed before broadcasting. Signing always happens locally; the browser flow has no access to your keys.

***

## price

```bash
twak price <token> [--chain <chain>] [--json]
```

Chain is auto-detected from native token symbols (ETH, BNB, SOL, etc.).

***

## balance

Get the native balance for any address using a SLIP44 coin ID.

```bash
twak balance --address <address> --coin <coinId> [--json]
```

Common coin IDs: `60` (Ethereum), `0` (Bitcoin), `501` (Solana).

***

## search

```bash
twak search <query> [--networks <ids>] [--limit <n>] [--json]
```

***

## trending

```bash
twak trending [--category <cat>] [--sort <field>] [--limit <n>] [--json]
```

Categories: `ai`, `rwa`, `memes`, `defi`, `dex`, `bnb`, `eth`, `sol`, `pumpfun`, `bonk`, `launchpad`, `launchpool`, `layer1`.

Sort fields: `price_change` (default), `market_cap`, `volume`.

***

## dapps

Browse featured DApps and protocols.

```bash
twak dapps [--category <cat>] [--search <query>] [--categories] [--limit <n>] [--json]
```

Categories: `defi`, `dex`, `lending`, `nft`, `gaming`, `social`. Use `--categories` to list all available.

***

## history

```bash
twak history --address <address> [--chain <chain>] [--from <date>] \
             [--to <date>] [--limit <n>] [--json]
```

***

## tx

```bash
twak tx <hash> --chain <chain> [--json]
```

***

## chains

```bash
twak chains [--json]
```

***

## asset

```bash
twak asset <assetId> [--json]
```

***

## validate

```bash
twak validate --address <address> [--asset-id <id>] [--json]
```

***

## risk

Check token security and rug-risk info.

```bash
twak risk <assetId> [--json]
```

***

## erc20

### erc20 approve

```bash
twak erc20 approve --token <assetId> --spender <address> --amount <amount> \
                   [--confirm-unlimited] --password <pw> [--json]
```

Token uses the Trust Wallet asset ID format (e.g., `c60_t0xA0b8...`).

### erc20 revoke

```bash
twak erc20 revoke --token <assetId> --spender <address> --password <pw> [--json]
```

### erc20 allowance

```bash
twak erc20 allowance --token <assetId> --owner <address> --spender <address> [--json]
```

***

## alert

### alert create

```bash
twak alert create --token <token> --chain <chain> (--above <price> | --below <price>) [--json]
```

### alert list

```bash
twak alert list [--active] [--json]
```

### alert check

```bash
twak alert check [--json]
```

### alert delete

```bash
twak alert delete <id> [--json]
```

***

## serve

Start an MCP server (stdio) or REST API server for AI agent integrations.

```bash
twak serve [--rest] [--port <port>] [--host <host>] \
           [--auto-lock <minutes>] [--password <pw>] \
           [--x402] [--payment-amount <amount>] [--payment-asset <asset>] \
           [--payment-chain <chain>] [--payment-recipient <address>]
```

| Flag          | Description                                    |
| ------------- | ---------------------------------------------- |
| `--rest`      | Start REST HTTP server instead of MCP stdio    |
| `--port`      | Port for REST server (default: 3000)           |
| `--auto-lock` | Auto-lock wallet after N minutes of inactivity |
| `--x402`      | Require x402 micropayment for REST endpoints   |

The REST server authenticates requests via `Authorization: Bearer <HMAC_SECRET>`. This is separate from the HMAC signing used by `tws.trustwallet.com` — the REST server runs locally and uses the raw secret as a shared token for simplicity.


# Authentication

All requests to the Trust Wallet API are authenticated with an **API access ID** and an **HMAC-SHA256 signature** derived from your HMAC secret.

## Getting credentials

1. Sign in at [portal.trustwallet.com](https://portal.trustwallet.com)
2. Create an app, then create an API key inside it
3. Copy your **Access ID** and **HMAC Secret** — the secret is shown only once

## Configuring the CLI

The recommended approach is `twak init`, which stores credentials in `~/.twak/credentials.json` with `0600` permissions:

```bash
twak init --api-key your_access_id \
          --api-secret your_hmac_secret
```

For CI/CD pipelines, use environment variables:

```bash
export TWAK_ACCESS_ID=your_access_id
export TWAK_HMAC_SECRET=your_hmac_secret
```

> **Do not add these exports to shell config files** (`~/.zshrc`, `~/.bashrc`). Use `twak init` for persistent local credentials. Env vars are intended for ephemeral CI/CD environments where secrets are injected at runtime.

## How HMAC signing works

Every API request is signed with HMAC-SHA256 over six fields concatenated together:

```
METHOD + PATH + QUERY + ACCESS_ID + NONCE + DATE
```

| Field       | Description                                           |
| ----------- | ----------------------------------------------------- |
| `METHOD`    | HTTP method in uppercase — `GET`, `POST`, `DELETE`    |
| `PATH`      | URL path without query string — `/v1/wallet/balance`  |
| `QUERY`     | Query string (without leading `?`), or empty string   |
| `ACCESS_ID` | Your API access ID                                    |
| `NONCE`     | Unique random string — prevents replay attacks        |
| `DATE`      | ISO 8601 timestamp — validated within a ±5 min window |

The resulting base64 signature is sent in the `Authorization` header. Four headers are required on every request:

| Header            | Value                                |
| ----------------- | ------------------------------------ |
| `X-TW-Credential` | Your API access ID                   |
| `X-TW-Nonce`      | The nonce used in signing            |
| `X-TW-Date`       | The timestamp used in signing        |
| `Authorization`   | Base64-encoded HMAC-SHA256 signature |

The CLI and TypeScript SDK handle signing automatically — you only need to understand this if you are making raw HTTP calls.

## Raw HTTP example

```bash
ACCESS_ID="$TWAK_ACCESS_ID"
NONCE=$(uuidgen | tr -d '-')
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
METHOD="GET"
REQ_PATH="/v1/search/assets"
QUERY="query=ethereum&limit=5"
SIGNATURE=$(printf '%s' "${METHOD}${REQ_PATH}${QUERY}${ACCESS_ID}${NONCE}${DATE}" \
  | openssl dgst -sha256 -hmac "$TWAK_HMAC_SECRET" -binary \
  | base64)

curl -X GET "https://tws.trustwallet.com${REQ_PATH}?${QUERY}" \
  -H "X-TW-Credential: $ACCESS_ID" \
  -H "X-TW-Nonce: $NONCE" \
  -H "X-TW-Date: $DATE" \
  -H "Authorization: $SIGNATURE"
```

## Security best practices

* Use `twak init` for local credentials — stores in `~/.twak/credentials.json` with restricted permissions
* Use `twak wallet keychain save` to store the wallet password in the OS keychain (macOS Keychain / Linux Secret Service)
* Never commit your HMAC secret to version control — add `.env` to `.gitignore`
* Never add credentials to shell config files (`~/.zshrc`, `~/.bashrc`) — use `twak init` instead
* Rotate keys regularly from the developer portal
* Use separate keys for development and production


# Key Management

## How Keys Are Stored

TWAK generates and stores private keys locally on the host machine. Keys never leave the device — not to Trust Wallet servers, not to the AI model provider, not anywhere.

When the agent wallet is initialized, a BIP39 HD wallet is generated via Trust Wallet Core. The mnemonic is encrypted immediately with AES-256-GCM, using a key derived from the user's password via PBKDF2, and written to `~/.twak/wallet.json`. The mnemonic is never stored in plaintext.

**What's stored on disk (`~/.twak/wallet.json`):**

| Field               | Type       | Description                                |
| ------------------- | ---------- | ------------------------------------------ |
| `encryptedMnemonic` | hex string | AES-256-GCM ciphertext of the mnemonic     |
| `iv`                | hex string | Random initialization vector               |
| `authTag`           | hex string | GCM authentication tag (detects tampering) |
| `salt`              | hex string | Random PBKDF2 salt                         |
| `createdAt`         | ISO 8601   | Wallet creation timestamp                  |
| `chains`            | string\[]  | List of supported chain keys               |

No plaintext keys, no plaintext mnemonic, no password on disk.

## What the Agent Can and Cannot Do

TWAK enforces a strict boundary between read-only queries and signing operations.

**Without the wallet password, the agent can:**

* Query any address balance
* Search tokens and fetch prices
* Get swap quotes
* Validate addresses and check token risk
* View transaction history

**The following operations require the wallet password:**

* Derive or reveal wallet addresses
* Sign or send transactions
* Execute swaps
* Approve token spending (ERC-20)
* Sign messages

The AI model never has direct access to the mnemonic or private keys. It interacts through TWAK's action layer, which gates all signing operations behind password authentication.

## Password Resolution

When a signing operation is requested, TWAK tries each source in order and uses the first one available:

| Source                         | Notes                                                          |
| ------------------------------ | -------------------------------------------------------------- |
| `--password` flag              | Checked first. Visible in shell history — avoid in production. |
| `TWAK_WALLET_PASSWORD` env var | Suitable for CI/CD and containerized environments.             |
| OS keychain                    | macOS Keychain, Linux Secret Service. Most secure option.      |

If none are available, the operation fails with an authentication error.

## Multi-Chain Key Derivation

A single wallet derives keys for 25+ supported chains using standard BIP-44 derivation paths. All key derivation and transaction signing is handled by Trust Wallet Core:

* **Ethereum and other EVM-compatible chains**: shared address across all EVM networks
* **Bitcoin**: Legacy, SegWit, and Taproot derivation paths
* **Solana**: Ed25519 key derivation
* **Cosmos, TON, SUI, NEAR, Aptos, Tron**: chain-specific derivation

## Password Requirements

Wallet creation enforces password strength:

* Minimum 8 characters
* At least one uppercase letter, one lowercase letter, and one number

These can be bypassed with `--skip-password-check` for test environments. See [CLI Reference](/developer/agent-sdk/cli-reference) for the full `wallet create` command.


# MCP Servers

Trust Wallet publishes two [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers for AI coding assistants:

* [**Docs MCP**](/developer/mcp/docs-mcp) — search and retrieve content from the full Trust Wallet developer documentation. Powered by GitBook; no API key required.
* [**API Gateway MCP**](/developer/mcp/api-gateway) — query live blockchain data: token prices, swap quotes, trending tokens, address security checks, and more. Requires API credentials from [portal.trustwallet.com](https://portal.trustwallet.com).

## Which one should I use?

Use the **Docs MCP** when you want your AI assistant to answer questions about Trust Wallet's developer documentation — integration guides, Wallet Core, asset listing, and so on.

Use the **API Gateway MCP** when you want your AI agent to interact with live blockchain data and crypto services programmatically.

Both servers can be active at the same time.


# Docs MCP

Trust Wallet publishes a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server powered by GitBook, giving AI coding assistants direct access to the Trust Wallet developer documentation.

**MCP endpoint:**

```
https://developer.trustwallet.com/developer/~gitbook/mcp
```

## What is MCP?

MCP is an open standard that lets AI tools (Claude, Cursor, VS Code Copilot, etc.) connect to external knowledge sources and services. When an MCP server is configured, the AI can query it in real time rather than relying solely on its training data.

## Configuration

### Claude Desktop

Add the following to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "trust-wallet-docs": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://developer.trustwallet.com/developer/~gitbook/mcp"
      ]
    }
  }
}
```

### Claude Code

```
claude mcp add --transport http trust-wallet-docs https://developer.trustwallet.com/developer/~gitbook/mcp
```

### Cursor

Add to `.cursor/mcp.json` in your project (or the global `~/.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "trust-wallet-docs": {
      "url": "https://developer.trustwallet.com/developer/~gitbook/mcp"
    }
  }
}
```

## What the server exposes

Once connected, your AI assistant can search and retrieve content from the full Trust Wallet developer documentation, including:

* Browser Extension and WalletConnect integration guides
* Deep linking reference
* Asset listing requirements and PR process
* Wallet Core API usage, building, and blockchain support
* Barz smart wallet documentation
* Claude Code Skills for Trust Wallet

## Usage example

After configuring the MCP server, you can ask your AI assistant questions like:

> "How do I detect the Trust Wallet browser extension?"

> "What are the asset listing requirements for a new token?"

> "Show me how to sign a transaction with Wallet Core in Swift."

The assistant will query the Trust Wallet docs in real time and return accurate, up-to-date answers.


# API Gateway MCP

The Trust Wallet API Gateway MCP server gives AI agents programmatic access to live blockchain data — token prices, swap quotes, trending tokens, address security, and more — through the [Model Context Protocol](https://modelcontextprotocol.io).

**MCP endpoint:**

```
https://mcp.trustwallet.com/tws
```

## Get API credentials

Register at [portal.trustwallet.com](https://portal.trustwallet.com) to obtain your **Access ID** and **HMAC Secret Key**.

## Authentication

Every request to the gateway must include two headers:

| Header            | Value                |
| ----------------- | -------------------- |
| `X-TW-CREDENTIAL` | Your Access ID       |
| `X-TW-SECRET-KEY` | Your HMAC Secret Key |

The gateway handles HMAC-SHA256 signing of all upstream requests automatically — you only need to pass your credentials as headers. The connection must use HTTPS; credentials travel as plaintext headers and depend on TLS for protection in transit.

## Configuration

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "trust-wallet": {
      "url": "https://mcp.trustwallet.com/tws",
      "headers": {
        "X-TW-CREDENTIAL": "your-access-id",
        "X-TW-SECRET-KEY": "your-hmac-secret"
      }
    }
  }
}
```

### Claude Code

```bash
claude mcp add --transport http trust-wallet https://mcp.trustwallet.com/tws \
  --header "X-TW-CREDENTIAL: <your-access-id>" \
  --header "X-TW-SECRET-KEY: <your-hmac-secret>"
```

### Cursor

Add to `.cursor/mcp.json` in your project (or the global `~/.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "trust-wallet": {
      "url": "https://mcp.trustwallet.com/tws",
      "headers": {
        "X-TW-CREDENTIAL": "your-access-id",
        "X-TW-SECRET-KEY": "your-hmac-secret"
      }
    }
  }
}
```

### VS Code

Add to `.vscode/mcp.json` in your project:

```json
{
  "servers": {
    "trust-wallet": {
      "url": "https://mcp.trustwallet.com/tws",
      "headers": {
        "X-TW-CREDENTIAL": "your-access-id",
        "X-TW-SECRET-KEY": "your-hmac-secret"
      }
    }
  }
}
```

## Available tools

### Token Information

| Tool                | Description                                                                |
| ------------------- | -------------------------------------------------------------------------- |
| `search_assets`     | Search tokens by name, symbol, or contract address across 100+ blockchains |
| `get_asset_details` | Get detailed info about a specific asset by ID or SLIP-44 coin number      |
| `get_coin_status`   | Get coin status, feature flags, staking info, and optional security data   |

### Swap and Bridge

| Tool                   | Description                                                    |
| ---------------------- | -------------------------------------------------------------- |
| `get_swap_domains`     | List supported blockchain domains with available DEX providers |
| `get_swap_providers`   | List all available swap and bridge providers                   |
| `get_provider_details` | Get details about a specific swap/bridge provider              |
| `get_swap_quote`       | Get optimal swap/bridge routes for token swaps across chains   |
| `get_swap_route_step`  | Get executable transaction data for a swap route step          |

### Market Data

| Tool                     | Description                                                             |
| ------------------------ | ----------------------------------------------------------------------- |
| `get_token_prices`       | Get current market prices for up to 50 tokens at once                   |
| `get_trending_tokens`    | Get trending/categorized token listings with multi-timeframe price data |
| `get_listing_categories` | Get available categories (DeFi, NFT, Layer 2, AI, Memes, etc.)          |

### Security

| Tool                   | Description                                                                       |
| ---------------------- | --------------------------------------------------------------------------------- |
| `validate_address`     | Validate a wallet address for a given chain; returns `{"status":"ok"}` on success |
| `check_token_security` | Analyze token risks: honeypot detection, audit status, freeze authority           |

## Usage examples

| Prompt                                           | Tools used                                 |
| ------------------------------------------------ | ------------------------------------------ |
| "What's the current price of ETH, SOL, and BNB?" | `get_token_prices`                         |
| "Find me trending meme tokens right now"         | `get_trending_tokens` with category filter |
| "Is this token safe? `c60_t0xdAC17F...`"         | `check_token_security`                     |
| "Is this a valid Ethereum address? `0x...`"      | `validate_address`                         |
| "Get a swap quote for 1 ETH to USDC on Base"     | `get_swap_quote`                           |
| "Search for Arbitrum DeFi tokens"                | `search_assets` with network filter        |

## Asset ID format

Trust Wallet uses SLIP-44 based asset identifiers:

* **Native coins**: `c{coinId}` — e.g., `c0` (Bitcoin), `c60` (Ethereum), `c714` (BNB)
* **Tokens**: `c{coinId}_t{contractAddress}` — e.g., `c60_t0xdAC17F958D2ee523a2206206994597C13D831ec7` (USDT on Ethereum)

Common coin IDs:

| Coin ID | Blockchain      |
| ------- | --------------- |
| 0       | Bitcoin         |
| 60      | Ethereum        |
| 714     | BNB Smart Chain |
| 501     | Solana          |
| 137     | Polygon         |
| 43114   | Avalanche       |
| 42161   | Arbitrum        |
| 10      | Optimism        |
| 8453    | Base            |


# Agent Skills

**Agent Skills** give AI coding agents domain-specific knowledge about Trust Wallet libraries and APIs. When a skill is active, the agent understands architecture, endpoints, and conventions without you having to paste documentation into every conversation.

Skills are published in an open-source marketplace on GitHub: [`trustwallet/tw-agent-skills`](https://github.com/trustwallet/tw-agent-skills).

## Installation

Install all skills with a single command:

```
npx skills add trustwallet/tw-agent-skills
```

The installer auto-detects your agent. To target a specific agent:

```
npx skills add trustwallet/tw-agent-skills -a claude-code
npx skills add trustwallet/tw-agent-skills -a cursor
npx skills add trustwallet/tw-agent-skills -a windsurf
npx skills add trustwallet/tw-agent-skills -a codex
npx skills add trustwallet/tw-agent-skills -a github-copilot
npx skills add trustwallet/tw-agent-skills -a cline
npx skills add trustwallet/tw-agent-skills -a opencode
npx skills add trustwallet/tw-agent-skills -a roo
```

To install a single skill:

```
npx skills add trustwallet/tw-agent-skills -s swap-quote
```

## Prerequisites

API skills require credentials from [portal.trustwallet.com](https://portal.trustwallet.com). Set the following environment variables:

```
TWAK_ACCESS_ID=<your-access-id>
TWAK_HMAC_SECRET=<your-hmac-secret>
```

* **Base URL**: `https://tws.trustwallet.com`
* **Authentication**: HMAC-SHA256
* **Rate limit**: 1 request/second (free tier)

## API Skills

5 skills, 14 actions.

| Skill         | Actions | Description                                                    |
| ------------- | ------- | -------------------------------------------------------------- |
| `setup`       | —       | Authentication (HMAC-SHA256), base URLs, 100+ supported chains |
| `token-info`  | 3       | Token search, asset details, and coin status                   |
| `swap-quote`  | 6       | Swap quotes, step transactions, providers, domains via Amber   |
| `market-data` | 3       | Token prices, trending tokens across 16+ categories            |
| `security`    | 2       | Address validation and token risk analysis                     |

## CLI Skills

The `trust-wallet-cli` skill gives agents access to `twak`, the Trust Wallet CLI for multichain wallet operations.

| Skill              | Actions | Description                                                                                        |
| ------------------ | ------- | -------------------------------------------------------------------------------------------------- |
| `trust-wallet-cli` | 12      | Wallet management, balances, transfers, swaps, alerts, DCA, limit orders, ERC-20, token risk, x402 |

Key capabilities:

* **Wallet**: Create HD wallets, derive addresses for 110+ chains, export keys, keychain integration
* **Transfers**: Send native tokens and ERC-20s with ENS support and safety limits
* **Swaps**: Same-chain and cross-chain swaps via Amber/Rango with inline approval
* **Alerts**: Price alerts with continuous monitoring via `twak watch`
* **Automations**: DCA (recurring swaps) and limit orders (conditional swaps) executed by `twak watch`
* **ERC-20**: Token approvals, allowance checks, revocations
* **MCP Server**: `twak serve` exposes all operations as MCP tools for AI agents

| Skill                 | Description                                                                |
| --------------------- | -------------------------------------------------------------------------- |
| `wallet-core`         | HD wallet creation, address derivation, tx signing across 140+ blockchains |
| `trust-web3-provider` | Web3 provider for Ethereum, Solana, Cosmos, Bitcoin, Aptos, TON, Tron      |
| `trust-developer`     | Deep links, browser extension detection, WalletConnect                     |
| `assets`              | Token logos and metadata across 180+ blockchains                           |
| `barz`                | Modular ERC-4337 smart contract wallet                                     |

## Usage

After installing, mention the skill by name in your request:

```
Use the swap-quote skill to get a quote for swapping 1 ETH to USDC
```

```
Use the wallet-core skill to implement transaction signing in Swift
```

```
Use the market-data skill to find trending tokens on Ethereum
```

## Contributing

Skills are markdown files. To add or improve a skill, open a PR on [`trustwallet/tw-agent-skills`](https://github.com/trustwallet/tw-agent-skills).


# Developing for Trust Wallet platform

Trust Wallet supports web3 integrations across mobile and desktop. Whether you're building a dApp that connects to the mobile app, integrating with the browser extension, or using deep links to route users into specific in-app flows, this section covers what you need.

## Guides

### [Browser Extension](/developer/develop-for-trust/browser-extension)

Integrate with the Trust Wallet browser extension to let users connect their wallets, sign transactions, and interact with your dApp from their desktop browser. Supports Ethereum, EVM-compatible chains, Bitcoin, Solana, Tron, TON, and other major networks.

### [Mobile (WalletConnect)](/developer/develop-for-trust/mobile)

Connect your dApp to the Trust Wallet mobile app using WalletConnect v2. Covers session setup, supported networks, and integration using the Sign API or higher-level libraries like Wagmi.

### [Deep Linking](/developer/develop-for-trust/deeplinking)

Use deep links to route users directly into specific pages within the Trust Wallet app — open a dApp browser, initiate a swap, send a payment, stake, buy crypto, and more. Works with both `https://link.trustwallet.com` and the `trust://` URI scheme.

***

**Prerequisites:** The examples in these guides assume familiarity with the JavaScript ecosystem. No prior web3 experience is required — you won't have to relearn anything, just understand a few new building blocks.


# Browser Extension

Trust Wallet Browser Extension enables web3 interactions across multiple networks. Integrate with Trust Wallet to allow users to connect their wallets, sign transactions, and interact with your dApp directly from their browser.

> Trust Wallet Browser Extension supports Ethereum, EVM-compatible chains, Bitcoin, Solana, Tron, TON and other major networks.


# Ethereum & EVM chains

### Provider discovery with EIP-6963

Modern browsers often have multiple wallet extensions installed. [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963) standardizes provider discovery through a well-defined event mechanism, allowing each wallet to announce itself without conflicts. This replaces the legacy `window.ethereum` pattern where wallets would overwrite each other.

Trust Wallet supports EIP-6963 to announce itself. You should always use this discovery mechanism to locate the Trust Wallet EIP-1193 provider.

```ts
/**
 * Represents the assets needed to display a wallet
 */
interface EIP6963ProviderInfo {
  uuid: string;
  name: string;
  icon: string;
  rdns: string;
}

// EIP-6963 Provider Detail containing wallet info and provider instance
interface EIP6963ProviderDetail {
  info: EIP6963ProviderInfo;
  provider: EIP1193Provider;
}

// Announce Event dispatched by a Wallet
interface EIP6963AnnounceProviderEvent extends CustomEvent {
  type: "eip6963:announceProvider";
  detail: EIP6963ProviderDetail;
}

// Request Event dispatched by a DApp
interface EIP6963RequestProviderEvent extends Event {
  type: "eip6963:requestProvider";
}

// Store all announced providers by their UUID identifier
const announcedProviders = new Map<string, EIP6963ProviderDetail>();

function initializeEIP6963() {
  const onAnnounce = (event: EIP6963AnnounceProviderEvent) => {
    const { info, provider } = event.detail;
    const key = info.uuid
    // Avoid duplicates
    if(announcedProviders.has(key)) return

    announcedProviders.set(key, { info, provider });
  };

  // Listen for wallet announcements
  window.addEventListener("eip6963:announceProvider", onAnnounce);

  // Request all wallets to announce themselves
  window.dispatchEvent(new Event("eip6963:requestProvider"));

  // Return cleanup function
  return () => {
    window.removeEventListener("eip6963:announceProvider", onAnnounce);
  };
}

// Start listening for wallet announcements
initializeEIP6963()
```

Initialize discovery by calling `initializeEIP6963()` early in your application lifecycle. This allows you to detect which wallet extensions are installed in the user's browser.

### Detecting Trust Wallet

Use the `getTrustWalletProvider()` function to check if Trust Wallet is installed by matching its reverse DNS identifier (`com.trustwallet.app`):

```ts
function getTrustWalletProvider(): EIP1193Provider | null {
  for (const entry of announcedProviders.values()) {
    if (entry.info?.rdns === 'com.trustwallet.app') {
      return entry.provider;
    }
  }
  return null;
}
```

If Trust Wallet is not installed, prompt users to download it:

```ts
const provider = getTrustWalletProvider();

if (!provider) {
  // Trust Wallet is not installed
  console.log("Please install Trust Wallet to connect");
  // Redirect users to download page
  window.open("https://trustwallet.com/download", "_blank");
} else {
  // Trust Wallet is installed, proceed with connection
  const accounts = await provider.request({ method: "eth_requestAccounts" });
}
```

### Connecting to Trust Wallet

Once you have the Trust Wallet provider, use its `provider.request()` method ([EIP-1193](https://eips.ethereum.org/EIPS/eip-1193)) to make wallet RPC calls.

#### Request user accounts (connect)

The `eth_requestAccounts` method ([EIP-1102](https://eips.ethereum.org/EIPS/eip-1102)) prompts the user to authorize your dApp and share their account addresses.

```jsx
try {
  const accounts = await provider.request({ method: "eth_requestAccounts" });
  console.log(accounts[0]); // => '0x...'
} catch (e) {
  if (e.code === 4001) console.error("User denied connection.");
}
```

#### Check connected accounts

The `eth_accounts` method ([EIP-1474](https://eips.ethereum.org/EIPS/eip-1474)) returns currently connected accounts without triggering a user prompt.

```jsx
const accounts = await provider.request({ method: "eth_accounts" });
```

### Listening for account changes

The `accountsChanged` event ([EIP-1193](https://eips.ethereum.org/EIPS/eip-1193)) fires when the user switches accounts or disconnects from your dApp.

```jsx
provider.on("accountsChanged", (accounts) => {
  if (accounts.length === 0) {
    console.log("User disconnected.");
  } else {
    console.log("Active account:", accounts[0]);
  }
});
```

### Working with networks

#### Listen for network changes

The `chainChanged` event ([EIP-1193](https://eips.ethereum.org/EIPS/eip-1193)) notifies your dApp when the user switches to a different network.

```jsx
provider.on("chainChanged", (chainId) => {
  console.log("New chain:", chainId); // hex string
});
```

#### Get current network

The `eth_chainId` method ([EIP-695](https://eips.ethereum.org/EIPS/eip-695)) returns the currently active network's chain ID as a hexadecimal string.

```jsx
const chainId = await provider.request({ method: "eth_chainId" });
```

#### Request network switch

The `wallet_switchEthereumChain` method ([EIP-3326](https://eips.ethereum.org/EIPS/eip-3326)) prompts the user to switch to a different network.

```jsx
try {
  await provider.request({
    method: "wallet_switchEthereumChain",
    params: [{ chainId: "0x1" }], // Ethereum mainnet
  });
} catch (e) {
  if (e.code === 4001) console.error("User rejected switching chains.");
}
```

#### Add a new network

The `wallet_addEthereumChain` method ([EIP-3085](https://eips.ethereum.org/EIPS/eip-3085)) requests that the user add a custom network to Trust Wallet.

```jsx
try {
  await provider.request({
    method: "wallet_addEthereumChain",
    params: [{
      chainId: "0x89", // Polygon Mainnet
      chainName: "Polygon Mainnet",
      nativeCurrency: {
        name: "MATIC",
        symbol: "MATIC",
        decimals: 18
      },
      rpcUrls: ["https://polygon-rpc.com"],
      blockExplorerUrls: ["https://polygonscan.com"]
    }]
  });
} catch (e) {
  if (e.code === 4001) console.error("User rejected adding the network.");
}
```

### Signing messages

#### Sign arbitrary messages

The `personal_sign` method ([EIP-1474](https://eips.ethereum.org/EIPS/eip-1474)) requests a signature for an arbitrary message. This is commonly used for authentication and proof of ownership.

```jsx
try {
  const signature = await provider.request({
    method: "personal_sign",
    params: [hexMessage, accountAddress]
  });
  console.log("Signature:", signature);
} catch (e) {
  if (e.code === 4001) console.error("User rejected signature.");
  else console.error("Signature error:", e);
}
```

#### Sign typed data (EIP-712)

The `eth_signTypedData_v4` method ([EIP-712](https://eips.ethereum.org/EIPS/eip-712)) signs structured data, providing better UX and security than raw message signing.

```jsx
const typedData = {
  domain: {
    name: "My DApp",
    version: "1",
    chainId: 1,
    verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  },
  types: {
    Person: [
      { name: "name", type: "string" },
      { name: "wallet", type: "address" }
    ],
    Mail: [
      { name: "from", type: "Person" },
      { name: "to", type: "Person" },
      { name: "contents", type: "string" }
    ]
  },
  primaryType: "Mail",
  message: {
    from: {
      name: "Alice",
      wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
    },
    to: {
      name: "Bob",
      wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
    },
    contents: "Hello, Bob!"
  }
};

try {
  const signature = await provider.request({
    method: "eth_signTypedData_v4",
    params: [accountAddress, JSON.stringify(typedData)]
  });
  console.log("Typed signature:", signature);
} catch (e) {
  if (e.code === 4001) console.error("User rejected signature.");
  else console.error("Signature error:", e);
}
```

### Managing assets

#### Add token to wallet

The `wallet_watchAsset` method ([EIP-747](https://eips.ethereum.org/EIPS/eip-747)) requests that the user track a token in Trust Wallet.

```jsx
try {
  const wasAdded = await provider.request({
    method: "wallet_watchAsset",
    params: {
      type: "ERC20",
      options: {
        address: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI token
        symbol: "DAI",
        decimals: 18,
        image: "https://cryptologos.cc/logos/multi-collateral-dai-dai-logo.png"
      }
    }
  });

  if (wasAdded) {
    console.log("Token added to wallet");
  }
} catch (e) {
  console.error("Error adding token:", e);
}
```

### Interacting with smart contracts

#### Send transactions to contracts

The `eth_sendTransaction` method ([EIP-1474](https://eips.ethereum.org/EIPS/eip-1474)) creates a transaction that modifies blockchain state. This requires user approval and gas fees.

```jsx
// Example: Transfer ERC20 tokens
try {
  const txHash = await provider.request({
    method: "eth_sendTransaction",
    params: [{
      from: accountAddress,
      to: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // Contract address
      data: "0xa9059cbb...", // ABI-encoded function call
      value: "0x0" // Amount of ETH to send (0 for token transfers)
    }]
  });
  console.log("Transaction hash:", txHash);
} catch (e) {
  if (e.code === 4001) console.error("User rejected transaction.");
  else console.error("Transaction error:", e);
}
```

When interacting with smart contracts, you need to encode function calls into the `data` field of transactions. This encoding follows the [Contract ABI Specification](https://docs.soliditylang.org/en/latest/abi-spec.html).

#### Understanding the `data` field

The `data` field contains:

1. **Function selector**: First 4 bytes (8 hex characters) - the keccak256 hash of the function signature
2. **Encoded parameters**: The function arguments encoded according to ABI rules

For example, calling `transfer(address recipient, uint256 amount)`:

* Function signature: `transfer(address,uint256)`
* Function selector: `0xa9059cbb` (first 4 bytes of keccak256 hash)
* Encoded parameters: recipient address (32 bytes) + amount (32 bytes)

To simplify this process you can use libraries like [Viem](https://viem.sh/), [Voltaire](https://voltaire.tevm.sh/) or [Ethers.js](https://docs.ethers.org/) to handle ABI encoding automatically. These libraries take care of the complex encoding process for you.

### High level abstractions

While the manual provider approach shown in this guide is useful for understanding the underlying protocol, production applications can use higher-level abstractions that handle the complexity for you.

#### Wagmi (React/Vue) and Wagmi Core (framework-agnostic)

We recommend [Wagmi](https://wagmi.sh/), which provide a higher-level, TypeScript-first API on top of EIP-1193 providers:

* **Automatic EIP-6963 discovery**: Detects injected wallets (including Trust Wallet) without manual event wiring
* **Type-safe APIs**:
  * Wagmi (React/Vue): hooks like `useAccount`, `useConnect`, `useWriteContract`, `useReadContract`, and more
  * Wagmi Core (any framework / vanilla JS): action-based functions like `getAccount`, `connect`, `writeContract`, `readContract`
* **Built-in state management** (Wagmi): handles connection state, caching, and automatic reconnection

### Need help?

If you have questions or need assistance integrating Trust Wallet into your application, feel free to open a discussion on our [GitHub Discussions](https://github.com/trustwallet/developer/discussions).


# Mobile (WalletConnect)

Trust Wallet supports WalletConnect v2.0 with multi-chain capabilities. You can connect to multiple blockchains simultaneously and sign transactions.

[WalletConnect](https://walletconnect.org/) is an open source protocol for connecting dApps to mobile wallets with QR code scanning or deep linking.

**Supported Networks**

* Ethereum and all EVM chains
* Solana

> **Note:** We are currently working on adding more network support.

## Dapp Integration

There are two common ways to integrate WalletConnect: you can use the low-level library [Sign API](https://specs.walletconnect.com/2.0/specs/clients/sign/) directly for more control, or use a higher-level library like [Wagmi](https://wagmi.sh/) that simplifies the integration.

## Wagmi

[Wagmi](https://wagmi.sh/) provides React Hooks for WalletConnect with built-in Trust Wallet support, it also supports Vue and vanilla JavaScript. See their [documentation](https://wagmi.sh/) for integration guides.

## Sign API

### Installation

```bash
npm install --save-exact @walletconnect/sign-client
```

### Initiate Connection

WalletConnect v2 uses the Sign API. You'll need to initialize the client with your project ID from [WalletConnect Cloud](https://cloud.walletconnect.com):

```typescript
import { SignClient } from "@walletconnect/sign-client";

// Initialize Sign Client
const signClient = await SignClient.init({
  projectId: "YOUR_PROJECT_ID", // Get from https://cloud.walletconnect.com
  metadata: {
    name: "Your dApp Name",
    description: "Your dApp Description",
    url: "https://yourdapp.com",
    icons: ["https://yourdapp.com/icon.png"],
  },
});

// Subscribe to session events
signClient.on("session_event", ({ event }) => {
  // Handle session events
  console.log("Session event:", event);
});

signClient.on("session_update", ({ topic, params }) => {
  const { namespaces } = params;
  const session = signClient.session.get(topic);
  // Update session state
  console.log("Session updated:", session);
});

signClient.on("session_delete", () => {
  // Session was deleted, reset dApp state
  console.log("Session disconnected");
});
```

WalletConnect v2 follows the [CAIP-25](https://chainagnostic.org/CAIPs/caip-25) protocol for establishing sessions. To connect with different networks, refer to the [WalletConnect namespaces specification](https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces#example-of-a-proposal-namespace).

```typescript
// Request session
try {
  const { uri, approval } = await signClient.connect({
    optionalNamespaces: {
      eip155: {
        methods: [
          "eth_sendTransaction",
          "personal_sign",
          "eth_signTypedData",
        ],
        chains: ["eip155:1"],
        events: ["chainChanged", "accountsChanged"],
      },
    },
  });
// ...
}
```

The connect function will return two variables:

* `uri`: A string used to establish the session. You can use it to generate a QR Code that wallets can scan, or pass it via deep link to connect from a mobile browser or mobile dApp to the Trust Wallet mobile app.
* `approval`: A function that returns a promise which resolves once the session proposal has been either accepted or rejected by the wallet.

> **Important:** On iOS Safari, `window.open()` must be called synchronously in response to a user action (like a button click). Calling it inside an async function or after an `await` will be blocked by the popup blocker.

```typescript
function openMobileWallet(){
	const deepLink = `https://link.trustwallet.com/wc?uri=${encodeURIComponent(uri)}`
	window.open(deepLink, '_blank', 'noreferrer noopener')
}
```

or

```tsx
import { Cuer } from 'cuer'

export function QRCodeComponent() {
  return uri && <Cuer arena={uri} />
}
```

Finally, we wait for the user's approval

```typescript
try {
  // ...
  // Await session approval from the wallet
  const session = await approval();

  console.log("Session established:", session);
} catch (error) {
  console.error("Connection error:", error);
}
```

For more details, check the [WalletConnect v2 Sign API specs](https://specs.walletconnect.com/2.0/specs/clients/sign).


# Deep Linking

All deeplink routes can be used with either `https://link.trustwallet.com` or `trust://`.

The `https://link.trustwallet.com` domain will route the user to a download landing page where the user can download the app for iOS, Android, or web extension. If the user already has the app installed, they will get a pop-up deeplinking them to the actual route page in the app.

The `trust://` URI will directly deeplink route the user to the corresponding in-app page and should be used in campaigns where it is known that all users clicking on the link already have the Trust Wallet app installed.

## DApp Browser

Open dapp browser with a specific url and network

* `coin` slip44 index
* `url` website url

```
https://link.trustwallet.com/open_url?coin_id=60&url=https://compound.finance
```

## Assets

### Open coin

* `asset` asset in [UAI format](/developer/new-asset/universal_asset_id)

```
https://link.trustwallet.com/open_coin?asset=c60
```

### Add asset

Asset will be added to local storage and will show up on the wallet screen.

* `asset` asset in [UAI format](/developer/new-asset/universal_asset_id)

```
https://link.trustwallet.com/add_asset?asset=c60_t0x514910771af9ca656af840dff83e8264ecf986ca
```

## Payment

### Send Payment

* `asset` asset in [UAI format](/developer/new-asset/universal_asset_id)
* `address` Recipient address
* `amount` Optional. Payment amount
* `memo` Optional. Memo
* `data` Optional. Data

```
https://link.trustwallet.com/send?asset=c60_t0x6B175474E89094C44Da98b954EedeAC495271d0F&address=0x650b5e446edabad7eba7fa7bb2f6119b2630bfbb&amount=1&memo=test
```

## Staking

### Stake details

* `coin` slip44 index

```
https://link.trustwallet.com/stake?coin=118
```

### Stake / Delegate

* `coin` slip44 index
* `id` validator / delegator to be selected. Optional

```
https://link.trustwallet.com/stake_delegate?coin=118&id=cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf
```

### Unstake / Undelegate

* `coin` slip44 index

```
https://link.trustwallet.com/stake_undelegate?coin=118
```

### Claim Rewards

* `coin` slip44 index

```
https://link.trustwallet.com/stake_claim_rewards?coin=118
```

## Exchange

### Open Swap

* `from` asset in [UAI format](/developer/new-asset/universal_asset_id)
* `to` asset in [UAI format](/developer/new-asset/universal_asset_id)

```
https://link.trustwallet.com/swap?from=c60_t0x6B175474E89094C44Da98b954EedeAC495271d0F&to=c60
```

### Open Buy Crypto

* `asset` asset in [UAI format](/developer/new-asset/universal_asset_id)
* `provider` Specifies the fiat ramp provider (e.g., moonpay, mercuryo, ramp). Optional.
* `payment_method` Specifies the payment method (e.g., credit\_card, bank\_transfer, apple\_pay, google\_pay, digital\_wallet). Optional.
* `sub_payment_method` Specifies the sub payment method (e.g., paypal, skrill, blik). Optional.
* `fiat_currency` Specifies the currency for the amount (e.g., USD, GBP). Optional.
* `fiat_quantity` Specifies the default quantity of the asset to buy (e.g., 3, 0.25). Optional.

```
https://link.trustwallet.com/buy?asset=c60&provider=moonpay&payment_method=digital_wallet&sub_payment_method=paypal&fiat_currency=USD&fiat_quantity=300
```

### Open Sell Crypto

* `asset` asset in [UAI format](/developer/new-asset/universal_asset_id)

```
https://link.trustwallet.com/sell?asset=c60_t0x6B175474E89094C44Da98b954EedeAC495271d0F
```

### Open Market Info

* `asset` asset in [UAI format](/developer/new-asset/universal_asset_id)

```
https://link.trustwallet.com/market?asset=c60_t0x6B175474E89094C44Da98b954EedeAC495271d0F
```

## Hot Tokens

Open the Hot Tokens tab on the Swap page.

```
https://link.trustwallet.com/hot_tokens
```

### Open Hot category and all networks

* `category_id` category identifier

```
https://link.trustwallet.com/hot_tokens?category_id=hot
```

### Open Hot category and specific network

* `category_id` category identifier
* `network` network identifier (slip44 index)

```
https://link.trustwallet.com/hot_tokens?category_id=hot&network=c0
```

## WalletConnect

### Connect to a WalletConnect session

Pass a URL-encoded WalletConnect v2 URI as the `uri` parameter:

```
https://link.trustwallet.com/wc?uri=wc%3A1234abcd...%402%3FrelaySrotocol%3Dirn%26symKey%3D...
```

See the [Mobile (WalletConnect)](/developer/develop-for-trust/mobile) guide for how to generate the `uri` from the Sign API.

## NFTs

Open NFTs tab.

```
https://link.trustwallet.com/nfts
```

## Quest

Open the quest page.

```
https://link.trustwallet.com/quest
```

## Launchpool

Open the Launchpool page.

```
https://link.trustwallet.com/launchpool
```

## Settings

### Open notification settings

```
https://link.trustwallet.com/notification_settings
```

### Open notifications

```
https://link.trustwallet.com/notifications
```

### Open price alerts

```
https://link.trustwallet.com/alerts
```


# Listing new dApps

Joining the Trust Wallet ecosystem with an already established base of users, projects, and communities is a great opportunity for your dApp project to leapfrog its growth. Before you can be listed alongside the other top dApps partnered with Trust Wallet, there is a documented process that needs to be carefully followed and completed.

Trust Wallet is proud of the high standards of quality required for listed dApps, where the user and their experience are the key areas of focus. The app is one of the most popular wallets available for easy access to digital assets and dApps in one place.

By improving the functionality of your project and its overall optimization, you allow users already familiar with the Trust Wallet space the best chance of using your dApp. Taking advantage of the vibrant [community](https://twitter.com/TrustWallet) is a logical step to take.

Missing out on just any one part of the optimization and application process will ultimately lead to an unsuccessful application. The journey involves rounds of:

1. [Optimization](/developer/listing-guide/mobile-optimize)
2. [Application Form](https://forms.gle/bdZPHseXypr72S8E7)

The whole process can be divided into these key stages, along with some recommended marketing activities to help give your project a better chance of success.

* [ ] Optimization of your dApp for the Trust Wallet browser
* [ ] Optimization of your dApp for desktop users
* [ ] Application to join the Trust Wallet dApp listing

Only by following closely the clearly defined instructions and recommendations will your dApp be able to join the list after careful scrutiny from the Trust Wallet team.

> **Important:** Do not submit any assets (logos, metadata) to the Trust Wallet Assets repository until your application has been reviewed by the Business Development team and an agreement has been reached. Premature asset submissions will be rejected.

### Applying for the Trust Wallet dApp Listing

Adding your dApp to the official Trust Wallet listing provides users with a guarantee of the quality and service provided by your dApp. Not every project that is submitted to the listing is approved. *Upon review, a member of the Trust Wallet team will reach out with additional information or follow up questions if necessary*.

Trust Wallet is proud of the standards set in place to ensure that only the best projects are presented. Once you’ve applied, a member of the Trust Wallet team will reach out should we feel your app is a good candidate based on UX, mobile optimization, responsiveness, value proposition relative to other apps, etc.

The aim of the Trust Wallet dApp Directory is twofold:

1. It empowers users to discover high-quality dApps within Trust Wallet.
2. It allows developers to showcase their work to millions of users as part of a developed and supported ecosystem.

#### Curation Guidelines

dApp listing submissions are considered on a case-by-case basis. While there isn’t a strict formula that dictates which apps we decide to list, the safety and experience of our users are of the utmost importance to us. For that reason, the dApp Directory is curated with the following set of guidelines:

* We believe the dApp ecosystem should be open and allow for the expression of diverse ideas and opinions. dApp submissions with content or behavior that fails to meet a “common sense” bar for respecting different ideas or users will be rejected.
* Attempts to misrepresent or otherwise deceive the listing and review process will result in your dApp being rejected or delisted from the directory.
* Stronger consideration will be given to dApps that demonstrate a unique value proposition relative to other existing/popular apps
* Good design is a critical component to increasing the accessibility of crypto and Defi. We look for dApps that scale gracefully across screen sizes and devices, and appropriate management of complex user flows through thoughtful UI

Before submitting your dApp and filling out the submission form, you should ensure that your dApp is fully compliant with our submission criteria.

You are responsible for the use of ad networks, analytics services, and third-party SDKs used within your dApp, so review and choose them carefully.

#### Safety and Security

Trust Wallet users require confidence that using dApps won’t jeopardize their funds, personal information, or device security.

Additionally, dApps that contain malware are strictly prohibited. This includes any functionality that seeks to gain or provide unauthorized access or control to a user’s device.

#### Objectionable and misleading content

Trust Wallet will reject any dApp submitted for listing that contains or promotes spam, violence, pornography, fake news, or other inappropriate content not suitable for a decentralized application.

#### Legal & Business

Ensure that your dApp is compliant with all relevant laws and regulations where you plan on making it available. dApps that encourage or solicit criminal or reckless behavior will not be tolerated and may result in notifying law enforcement.

### Support and Questions

Should you at any point find yourself with questions about any of the processes laid out in this guide, then don’t hesitate to get in touch with us via <partnerships@trustwallet.com>

It should be noted that this guide contains the minimum needed to begin the submission process and is not exhaustive. There may be other qualities that are considered for listing, but completing the process of optimization and following our guidelines will get you the best chance of success.


# Optimizing your dApp for Trust Wallet

Users of the Trust Wallet app enjoy the ease and experience of accessing their wallets, assets, and DApps all at the same time. This is made possible through the Trust Wallet DApp browser and WalletConnect. Without needing to swap between apps, users can trade and browse in a fluid, uninterrupted experience.

Optimizing your DApp for the Trust Wallet is an integral part of making sure your project is up to scratch for listing. We recommend that you take a considerable amount of time to ensure fully that your app has at least the basic levels of optimization laid out below.

## Preparing your DApp for Trust Wallet

The Trust Wallet App currently offers the following functionality:

* A Web3 browser for interacting with decentralized applications
* A range of tools to provide a seamless connection between the DApps and the user on the Ethereum, Solana, Cosmos, BNB Smart Chain, Polygon, Osmosis, EVMOS, Aptos and many more EVM and Cosmos compatible networks.
* A fully optimized, integrated interface experience for mobile users

There are simple steps for blockchain developers to implement to take full advantage of these key features. Most are basic tips but none can be missed out.

## Metamask/Phantom/Keplr/Petra is a good place to start

Familiarity with MetaMask interaction for Ethereum DApps, Phantom for Solana, Keplr for Cosmos or Petra for Aptos puts you off to a good start in terms of optimizing or developing a DApps for Trust Wallet. The web3 development process is the same when using MetaMask/Phantom/Keplr/Petra as a dev tool. It's our recommended choice for DApp development and gives you a quick, golden rule to use: if it works well with MetaMask, Phantom, Keplr or Petra it works well with Trust Wallet.

## Create a UI that Is mobile-friendly

It can't be forgotten that Trust Wallet is accessed by two groups of people: those using the app on [Android](https://trustwallet.com/download) and those using an iOS device. Your project must be developed to have a mobile-friendly UI as the Trust Wallet inbuilt browser is the primary point of access for the majority of our users.

iOS users require the latest build from Apple App Store. UI/UX design needs to also be considered in your mobile design to provide the best in-wallet experience.

## Master Web3

All Ethereum DApps should be [EIP1193](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md) (Ethereum Improvement Protocol 1193) compatible. This allows for a high degree of wallet interoperability when exposing an API through JavaScript objects in the Ethereum DApp.

For Solana integration the best way would be to use the official [Wallet Adapter](https://github.com/solana-labs/wallet-adapter) which supports Trust Wallet and include it as the connection point to your DApp.

For Cosmos you can refer to the official [Keplr guide](https://docs.keplr.app/api/), just make sure to use `window.trustwallet.cosmos` instead of `window.keplr`.

For Aptos please follow the official [Petra guide](https://petra.app/docs/sending-a-transaction). `window.trustwallet.aptos` is also preferred over `window.aptos`, although both will work.

Consider including an explicit Trust Wallet icon or button in your DApp. This will help Trust Wallet users connect to your DApp for the first time.

Recommended steps to improve the user experience when a user clicks or taps the Trust Wallet icon:

1. Check the [trust-web3-provider](https://github.com/trustwallet/trust-web3-provider) README for provider identification guidance.
2. Verify that the DApp is open in desktop browsers or no `window.trustwallet.(ethereum/solana/cosmos/aptos)` -> Display the WalletConnect pairing popup
3. Verify that the DApp is open in the Trust Wallet DApp browser -> Access the `window.trustwallet.(ethereum/solana/cosmos/aptos)` directly.

## Test your DApp on both iOS and Android

Trust Wallet users access their wallets on both Android and iOS devices, so your app must be thoroughly tested for both operating systems. Issues may occur on one operating system but not on the other.

This is one of the most important areas to optimize for but is often brushed over. Just open up your DApp with the Trust Wallet browser on both an iOS and Android device, then test the DApps functionalities such as sending or depositing tokens.

## Implement deep links

There is no native support for Web3 in iOS or Android mobile browsers. Your DApp's links must be [deep links](/developer/develop-for-trust/deeplinking) that combine numerous steps into one simple, easy click. Without them, users will need to follow tedious and long chains of links that greatly impact the user experience.

## References

Web3 is incredibly powerful for developing DApps and outlining their interactions with Ethereum or Solana nodes. The most up-to-date Web3 open-source [Ethereum JavaScript library](https://github.com/ethers-io/ethers.js/) or [Solana JavaScript library](https://github.com/solana-labs/solana-web3.js) needs to be implemented for your DApp to be well optimized for the Trust Wallet browser.


# Debugging

Make sure you have the [latest app version](https://trustwallet.com/download), check if there is any new update on Google Play or App Store

## 1. Install a mobile web console

We use [vConsole](https://github.com/Tencent/vConsole) on our test dapp: <https://js-eth-sign.surge.sh/>, click the bottom green `vConsole` button to see logs.

<div><img src="/files/-MZSTl7T2HJ6ers4VK46" alt="" width="45%"> <img src="/files/-MZSTl7UMQBY22esNvTg" alt="" width="45%"></div>

## 2. \[Android] Chrome Remote debugging

Download Trust Wallet apk from [trustwallet.com](https://trustwallet.com/download) and drag it to your emulator. (app installed from Google Play won't work)

Open the dapp in Trust Wallet (1inch.io as example)

<div><img src="/files/-MZSTl7VZr2hF4428v4m" alt="" width="45%"> <img src="/files/-MZSTl7WGBKiRu8XprNL" alt="" width="45%"></div>

Visit `chrome://inspect/#devices` or `edge://inspect/#devices` to inspect the web console

![Edge inspect](/files/-MZSTl7XH6_7R0PPyIlk) ![Edge inspect](/files/-MZSTl7Ycv4sm2Vu1qPN)

## 3. \[iOS] Safari WebView debugging

iOS doesn't support debugging app built for distribution, you can try to build this iOS demo in [trust-web3-provider](https://github.com/trustwallet/trust-web3-provider/tree/main/packages/ios-web3-provider) and check if it can connect to your DApp or not, please follow this [guide](https://webkit.org/web-inspector/enabling-web-inspector/) to inspect.


# Listing new assets

![](https://trustwallet.com/assets/images/media/assets/horizontal_blue.png)

## Overview

The [Trust Wallet Token Repository](https://github.com/trustwallet/assets) is a comprehensive, up-to-date collection of information about several thousand crypto tokens. [Trust Wallet](https://trustwallet.com) uses token logos from this source, alongside a number of third-party projects.

The repository contains token info from several blockchains, info on dApps, staking validators, etc. For every token, a logo and optional additional information is available (such data is not available on-chain).

Such a large collection can be maintained only through a community effort, so *additions are welcome*, primarily from token projects.

> **⚠️ NOTE**
>
> * All assets are [subject to review before](#disclaimer) being approved; so-called "meme tokens", spammy, or assets identified as fraudulent in nature will not be merged into the repository
> * Payment of the [Pull Request Fee](/developer/new-asset/pr-fee) does not guarantee your asset will be approved. **Fee is non-refundable**.

***

## Contribution Checklist

This guide is for adding a logo for the following Trust Wallet supported blockchains:

* [Ethereum ERC20 token](https://github.com/trustwallet/assets/tree/master/blockchains/ethereum/assets)
* [BNB Chain (BSC) BEP20 token](https://github.com/trustwallet/assets/tree/master/blockchains/smartchain/assets)
* [Solana SPL token](https://github.com/trustwallet/assets/tree/master/blockchains/solana/assets)
* [TRON TRC10, TRC20 token](https://github.com/trustwallet/assets/tree/master/blockchains/tron/assets)

For **adding a token**:

* [ ] Ensure your asset meets our [requirements](/developer/new-asset/requirements)
* [ ] Create a pull request to <https://github.com/trustwallet/assets>
* [ ] Pay the [processing fee](/developer/new-asset/pr-fee)

Adding a DApp logo or other type of asset? Check the [DApps](/developer/listing-guide) section or [contribution guidelines](/developer/new-asset/repository_details#contribution-guidelines).

Adding new chain? Please contact our Business Development team at **<partnerships@trustwallet.com>** to discuss this further.

***

### Pull Request Fee

Due to the increasing number of pull requests and the proportional checking and merging effort, a modest fee is required for processing each pull request, payable in cryptocurrency. Follow the instructions in the pull request to complete the fee payment.

A fee of 500 TWT or 2.5 BNB is required per Pull Request. Payment details will be provided by the merge-fee-bot. Before submitting, please review the [listing requirements](https://developer.trustwallet.com/assets/requirements).

**Important**: The fee is non-refundable and does not guarantee approval. All submissions are subject to due diligence by the maintainers.

For more details, see the [PR fee page](https://developer.trustwallet.com/assets/pr-fee) and the [fee FAQ](/developer/new-asset/pr-fee)

***

## Disclaimer

The Trust Wallet team allows anyone to submit new assets to this repository. However, this does not mean that we are in direct partnership with any of the projects listed.

The Trust Wallet team will reject projects that are deemed to be scams, high risk, stablecoin-mimicking, or fraudulent after careful review. The Trust Wallet team reserves the right to change the terms of asset submissions at any time due to changing market conditions, risk of fraud, or any other factors deemed relevant.

Additionally, spam-like behavior, including but not limited to the mass distribution of tokens to random addresses, will result in the asset being flagged as spam and possible removal from the repository.


# Requirements

Before submitting an asset to this repository, we recommend you have the following information ready:

* Asset details
  * Token Name
  * Symbol
  * Contract Address
  * Decimals
* BNB or TWT to cover the **non-refundable** [processing fee](/developer/new-asset/pr-fee)
* Logo
  * File Extension: `png` (Uppercase PNG is considered invalid)
  * File Name: `logo.png`
  * Size: 256px by 256px
  * Background: Preferably transparent
* Token information file
  * File Extension: `json` (Uppercase JSON is considered invalid)
  * File Name: `info.json`
  * Required fields:
    * `name`: name of the token
    * `type`: such as ERC20, BEP20, TRC20, TRC10, ...
    * `symbol`: the token symbol
    * `decimals`: number of decimal digits used in the amounts (e.g. 18 for ETH)
    * `description`: a few sentence summary of the token/project
    * `website`: project website
    * `explorer`: URL of the token explorer page
    * `id`: the id/contract/address of the token, same as the subfolder name
    * `links`: array with name/url pairs, for social media links, documentation, etc.
    * `tags`: assigning these tags to tokens helps place them on appropriate token menus and ensures your token is evaluated correctly in conditions.
* Checksum address (for ERC20 and BEP20 tokens)
  * Checksum addresses can be found on [Etherscan](https://etherscan.io).

***

## Listing Acceptance Guidelines

The following criteria will be considered before an asset is accepted into the repository.

> **Note:** Meeting all these criteria does not guarantee a submission will be accepted. The team reserves the right to reject projects deemed **spammy**, **high-risk**, **fraudulent**, or otherwise **low value**.

* **Website & Documentation** — A live website with a detailed white paper, including a clear roadmap, tokenomics, and use case.
* **Social Media & Support** — An active social media presence and a responsive support team. Accounts with fake followers or bots will be rejected.
* **Security Audit** — A completed full audit by a reputable security firm.
* **Originality** — No plagiarized content, names, or logos from other projects or companies. Tokens that mimic the name, symbol, or branding of established projects and stablecoins (e.g. USDT, USDC, DAI) will be rejected.
* **Price Tracking** — Token must be listed on CoinMarketCap for price tracking with detailed token information.
* **On-Chain Activity** — Minimum of 10,000 holders and 15,000 transactions. **Airdropped tokens are excluded from these counts.** This threshold may be adjusted on a case-by-case basis.


# Pull Request Fee

Trust Wallet supports a vast number of asset and token requests. We are committed to supporting the tokens used by our users, but maintaining millions of assets comes at a significant cost — from running infrastructure and ensuring continuous integration, to handling the massive volume of asset info requests and filtering out spam and scam tokens.

To help manage this, we introduced a crypto contribution to filter out low-quality submissions and free up more time to review genuine requests. This approach was partly inspired by the concept of a Token Curated Registry.

> A fee of **500 TWT or 2.5 BNB** is required for each Pull Request. The merge-fee-bot will provide payment details once your PR is submitted. Before submitting, please review the [listing requirements](/developer/new-asset/requirements)

***

## Why the payment?

> Due to the high volume of pull requests, maintaining the infrastructure that powers millions of assets and tokens comes at a significant cost. A modest fee is required to process each pull request, payable in cryptocurrency. This fee helps to:
>
> * Cover the cost of running and maintaining backend infrastructure
> * Reduce the number of spam and scam token submissions
> * Ensure smooth integration and handling of the large volume of asset requests

### How does this Fee fit with Open Source?

> * We believe in the power of open-source software, and essential parts of Trust Wallet are open source to contribute to the community (e.g., Wallet-Core). However, Trust Wallet is a branded product, and running its backend infrastructure, support, marketing, and other operations has real costs, handled by a dedicated team.
> * The assets repository is open source — you are free to use it or fork it and create your own version. But if you want your asset included in the Trust Wallet app, you must follow our guidelines, which include a contribution fee to support the maintenance of the Trust Wallet product.

### What do I have to pay attention to?

> * Always double-check the [contribution guidelines](/developer/new-asset/requirements) before submitting your pull request.
> * Make sure to set the correct `memo` on your transfer.

***

## See FAQs question:

### Is crypto payment for processing my Pull Request a scam?

> No, it's not a scam!

> This is a legitimate request from the Trust Wallet team. However, always be cautious when someone asks you for payment. Verify that the fee is documented under the Trust Wallet Developer documentation (this page), that the repository is under the official Trust Wallet GitHub account.

### When is my payment evaluated?

> Payment is handled automatically by our bot and is typically detected within a minute.

### What happens after I pay? Is merging automatically?

> Once the bot detects your payment, it automatically places an "Accept Review" on the PR. This is a precondition for merging, but merging itself is not automatic — it is done by the maintainers.

### I forgot to set a memo in my transfer, do I have to send another payment?

> Yes. Crypto transactions are final and irreversible. Payments with missing memos or mistyped addresses cannot be recovered. Please verify all transaction details carefully before sending payment.

### If you decide not to merge my PR, do I get my payment back?

> No. The pull request fee is non-refundable and covers processing only. Payment does not guarantee that your pull request will be merged. Please review the [contribution guidelines](/developer/new-asset/requirements) before paying the fee.

### Do I need to pay the PR fee again to make updates to my submission?

> Yes. If your asset is already in the repository, subsequent updates (such as name changes, logo changes, or rebranding) will require payment of the fee to cover processing.

### Can the fee be waived?

> Generally, no. Inclusions initiated and performed by our team are done without a fee, but externally submitted changes require the fee.

### What is Trust Wallet Token TWT?

> [TWT](https://coinmarketcap.com/currencies/trust-wallet-token/) is the native token of Trust Wallet, used for features such as our Referral Program. [TWT](https://coinmarketcap.com/currencies/trust-wallet-token/) is available on BEP20 and can be obtained on several exchanges.


# FAQ

## Why is the build on my pull request red?

> Contributions in a pull request are verified by an automated build. The checks fail if something is wrong, like the logo is too large or an Ethereum contract is not in [checksum format](/developer/new-asset/repository_details#checksum-format). Check the exact error message in the build to find out the problem.

## Why is there a merge conflict in my pull request?

> A merge conflict happens if the same file has been modified in the pull request, and also in the master branch since the fork was created. With the assets repo, this is typically caused by using a fork that was created long ago. The simplest way to resolve this is to:
>
> 1. Open your branch locally, fetch the latest changes from the origin, then push your updates.
> 2. If that doesn't resolve the conflict, close your current pull request, fork the latest version of our repository, and submit a new one.

## Why I don't see my token in search after PR was merged?

> After PR was merged, it may take some time, but not longer than one hour, until the search shows the new logo.

## Why do I still see old logo in Trust Wallet after uploading a new one?

> All clients (Android, iOS, and Browser Extension) cache images for a few hours. To see your changes immediately, clear your cache or reinstall Trust Wallet.
>
> **Important**: Back up all your wallets before reinstalling.

## What is smart contract deprecation?

> Smart contract deprecation is the process of removing a token's logo and information from this repository. The deprecated contract address is added to the denylist and will no longer appear in token search results within the Trust Wallet app.
>
> #### When should a contract be deprecated?
>
> A deprecation request is appropriate when a contract is:
>
> * No longer active or has been abandoned by its organization
> * Upgraded and replaced by a new contract
> * Involved in a scam
> * Mimicking the name or symbol of a legitimate token
>
> **Note**: All deprecation requests must include supporting evidence with links to verifiable sources.

## Why isn't my token's price displaying in the app?

> Trust Wallet sources pricing data from CoinMarketCap (CMC). For your token's price to appear, the following must be in place:
>
> 1. Your token's correct contract address is linked to its CMC listing.
> 2. The token has sufficient transaction volume on CMC.
>
> If your contract address is missing or incorrect on CMC, you can submit an update through their [online form](https://support.coinmarketcap.com/hc/en-us/requests/new).
>
> Once both conditions are met, pricing data will appear in Trust Wallet automatically.
>
> **Note**: Listing a token in the Trust Wallet repository does not guarantee that CMC will associate pricing data with it. Please review CMC's [listing criteria](https://support.coinmarketcap.com/hc/en-us/articles/360043659351-Listings-Criteria) for more details.


# Repository Details

### Repository Details

#### Collections

The token repository contains the following collections:

1. [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) tokens on Ethereum-compatible networks, including:
   * [Ethereum (ETH)](https://ethereum.org/)
   * [BNB Chain (BSC)](https://www.bnbchain.org)
   * [Base](https://www.base.org/)
   * [Arbitrum](https://arbitrum.io/)
   * [Avalanche C-Chain](https://www.avax.network/)
   * [Optimism](https://www.optimism.io/)
   * [Polygon](https://polygon.technology/)
   * [Celo](https://celo.org/)
   * [Gnosis](https://www.gnosis.io/)
   * [Monad](https://www.monad.xyz/)
   * [Plasma](https://www.plasma.to/)
   * [Sonic](https://www.soniclabs.com/)
   * [Linea](https://linea.build)
   * [MegaETH](https://www.megaeth.com/)
   * [Moonbeam](https://moonbeam.network/)
   * [Ronin](https://roninchain.com/)
   * [Mantle](https://mantle.xyz/)
   * [Manta Pacific](https://manta.network/)
   * [Acala EVM](https://acala.network/)
   * [Blast](https://blast.io/)
   * [Ethereum Classic (ETC)](https://ethereumclassic.org/)
   * [POA Network (POA)](https://poa.network/)
   * [TomoChain (TOMO)](https://tomochain.com/)
   * [GoChain (GO)](https://gochain.io/)
   * [Wanchain (WAN)](https://wanchain.org/)
   * [Callisto Network (CLO)](https://callisto.network/)
   * [Thunder Token (TT)](https://thundercore.com/)
   * and other EVM-compatible networks
2. Tokens on TRON blockchain [(TRC10, TRC20)](https://developers.tron.network/docs/trc10-token)
3. Tokens on Solana blockchain [(SPL)](https://solana.com/)
4. Tokens on TON blockchain [(JETTONS)](https://ton.org/)
5. Other information for coins/tokens
6. DApp logos displayed in `Browser` section of the Trust Wallet app, and bookmarks icons
   * [Image naming requirements](#dapp-image-naming-requirements)
   * [Request listing in Trust Wallet DApp Browser](#dapp-submission-and-listing-requirements)
7. Staking validators information, such as name: `image`, `validator_id`, `website_url`
   * [Supported staking coins](https://trustwallet.com/staking/)
   * [Read requirements](#staking-validators-requirements).
8. Smart contract deprecation/upgrade. [Read more](#update-and-remove-an-existing-asset)

#### Repository structure

The `blockchains` folder contains several subfolders corresponding to blockchain networks, such as `ethereum`, `smartchain`, etc.

The `assets` subfolder contains token folders named by smart contract address, in [checksum format](#checksum-format) for Ethereum-like networks.\
This folder should contain the `logo.png` image file, and the `info.json` file.

For other networks the address must be specified as it was originated on the chain, e.g. TRON TRC10: `1002000`, TRON TRC20: `TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t` etc.

The `info` folder contains a `logo.png` that represents the coin image.

The `validators` folder contains folders: `assets` same structure as above and `list.json` information about validators.

**Checksum format**

For Ethereum-like networks, contract folders must be named according to the **Checksum Format**, with mixed lowercase and uppercase letters, such as `0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359`. Non-checksum addresses (e.g. all lowercase) are considered invalid.

You can find the checksum address by searching on [etherscan.io](https://etherscan.io), for example stablecoin [DAI](https://etherscan.io/address/0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359) the checksum address is located at the top left corner of the page and has both uppercase and lowercase characters.

**Layout**

```
.
├── blockchains
│   └──ethereum
│   │   └──assets
│   │   │  └──0x0a2D9370cF74Da3FD3dF5d764e394Ca8205C50B6 // address folder
│   │   │     └──logo.png  // token logo
|   |   |     └──info.json  // token info
│   │   └──info
│   │      └──logo.png   // chain coin logo
|   |      └──info.json  // chain coin info
|   |
|   └──tron
│   |  └──assets
│   |  │  └──1002000
│   |  │  |   └──logo.png
|   |  |  |   └──info.json
|   |  |  └──TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
|   |  |      └──logo.png
|   |  |      └──info.json
|   |  |
│   |  └──info
│   |     └──logo.png
|   |     └──info.json
|   |
|   └──cosmos
│   │   └──info
|   |   |  └──logo.png
|   |   |  └──info.json
|   |   |
│   │   └──validators
│   │   |  └──assets
|   |   |     └──cosmosvaloper1clpqr4nrk4khgkxj78fcwwh6dl3uw4epsluffn
|   |   |        └──logo.png
|   |   |
|   |   └──list.json
├── ...
```

### Contribution Guidelines

#### Contribution Use Cases

**Add new asset**

1. Prepare asset, look at [image requirements](#image-requirements), [dapp requirements](#dapp-image-naming-requirements), [staking validator requirements](/developer/new-asset/staking-validator).
2. Get familiar with our [folder structure](#repository-structure), it will give you an understanding where assets should be placed
3. [Add asset guide](#how-to-add-files)
4. Pay the merge [fee](#fee)

**Update and remove an existing asset**

When updating or deprecating an asset — whether on behalf of the asset owner or because you found outdated information — please provide a link to a source confirming the changes. This helps speed up the review process.

This instruction applies if you want to [deprecate](#what-is-smart-contract-deprecation) an asset:

1. Create a new branch, navigate to the old contract's folder, and update the `status` field in `info.json` to `abandoned`:

```
{
    "name": "Sample Token",
    "website": "https://sample.website",
    "description": "This is an example",
    "explorer": "https://etherscan.io/token/<OLD_CONTRACT_ADDRESS>",
    "type": "ERC20",
    "symbol": "SAMPLE",
    "decimals": 18,
    "status": "abandoned",
    "id": "<OLD_CONTRACT_ADDRESS>"
}
```

2. Remove the logo file from the old contract's folder:

```
rm ./blockchains/<COIN>/assets/<OLD_CONTRACT_ADDRESS>/logo.png
```

3. Create a new directory for the new contract address with its `info.json` and `logo`:

```
./blockchains/<COIN>/assets/<NEW_CONTRACT_ADDRESS>/info.json
./blockchains/<COIN>/assets/<NEW_CONTRACT_ADDRESS>/logo.png
```

4. Commit your changes and submit a Pull Request

Here are some examples:

* [Ethereum](https://github.com/trustwallet/assets/blob/67d328b3d1ba646f402baf46c4cd254a048fb7f0/blockchains/ethereum/assets/0x57e299eE8F1C5A92A9Ed54F934ACC7FF5F159699/info.json#L8)
* [BNB Chain (BSC)](https://github.com/trustwallet/assets/blob/67d328b3d1ba646f402baf46c4cd254a048fb7f0/blockchains/smartchain/assets/0x611DFe661C82B858087AB5b16e3Cb082552df4F3/info.json#L8)
* [Solana](https://github.com/trustwallet/assets/blob/67d328b3d1ba646f402baf46c4cd254a048fb7f0/blockchains/solana/assets/zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF/info.json#L9)
* [Tron](https://github.com/trustwallet/assets/blob/67d328b3d1ba646f402baf46c4cd254a048fb7f0/blockchains/tron/assets/1001411/info.json#L8)

#### Image Requirements

* **File location**: must be placed in the correct folder and subfolder within the [folder structure](#repository-structure).
* **File name**: `logo.png`, all lowercase. Extension: `png` (uppercase `PNG` is considered invalid).
* **Dimension**: recommended `256 x 256 pixels`, maximum `512 x 512 pixels`, aspect ratio should be 1:1.
* **File size**: maximum 100kB.
* **Edges and background**:
  * Logos are displayed cropped to a circular mask, a circle fitting in the square shape. Thus the corners of the logo image will not be visible. The logo should fit in the circle, but also fill it as much as possible, i.e. there should not be unused spaces on the sides/top/bottom.
  * Logos should look OK with white/lightgray background as well as on black/darkgray background (night mode). For dark themed logos use white contour lines to make sure they stand out on dark background as well.
  * Avoid using transparency inside the logo, as the color beneath the transparent layer is changing (light or dark). Use transparency only outside of the logo.

#### Info.json Contents

The `info.json` file contains basic information about the token/project.

It has the following required fields:

* `name`: name of the token
* `type`: such as ERC20, BEP2, BEP20, TRC20, TRC10, ...
* `symbol`: the token symbol
* `decimals`: number of decimal digits used in the amounts (e.g. 18 for ETH)
* `description`: a few sentence summary of the token/project
* `website`: project web site
* `explorer`: URL of the token explorer page
* `status`: `"active"`
* `id`: the id/contract/address of the token, same as the subfolder name
* `links`: Array with `name`/`url` pairs, for social media links, documentation, etc. List of currently supported types: `github`, `whitepaper`, `x`, `telegram`, `telegram_news`, `medium`, `discord`, `reddit`, `facebook`, `youtube`, `coinmarketcap`, `coingecko`, `blog`, `forum`, `docs`, `source_code`.
* `tags`: Assigning these tags to tokens helps place them on appropriate token menus and ensures your token is evaluated correctly in conditions. List of currently supported tags: `stablecoin`, `wrapped`, `synthetics`, `nft`, `governance`, `defi`, `staking`, `staking-native`, `privacy`, `nsfw`, `binance-peg`, `deflationary`, `memes`, `gamefi`.

If in doubt about fields, look around / search in existing info.json files.

Sample `info.json`:

```json
{
    "name": "Trust Wallet",
    "website": "https://trustwallet.com",
    "description": "Utility token to increase adoption of cryptocurrency.",
    "explorer": "https://bscscan.com/token/0x4B0F1812e5Df2A09796481Ff14017e6005508003",
    "research": "https://research.binance.com/en/projects/trustwallet",
    "type": "BEP20",
    "symbol": "TWT",
    "decimals": 18,
    "status": "active",
    "id": "0x4B0F1812e5Df2A09796481Ff14017e6005508003",
    "links": [
        {
            "name": "github",
            "url": "https://github.com/trustwallet/"
        },
        {
            "name": "x",
            "url": "https://x.com/TrustWalletApp"
        },
        {
            "name": "reddit",
            "url": "https://reddit.com/r/trustapp"
        }
    ],
    "tags": [
        "governance"
    ]
}
```

#### dApp image naming requirements

* [Folder for upload](https://github.com/trustwallet/assets/tree/master/dapps)
* `<subdomain>.<domain_name>.png` e.g: <https://app.compound.finance/> => `app.compound.finance.png` <https://kyberswap.com/> => `kyberswap.com.png`

#### dApp submission and listing requirements

* Please refer to and follow our [dApp listing guide](/developer/listing-guide).

#### Common Uploads

1. Ethereum ERC20 [token folder](https://github.com/trustwallet/assets/tree/master/blockchains/ethereum/assets)
2. TRON TRC10, TRC20 token [token folder](https://github.com/trustwallet/assets/tree/master/blockchains/tron/assets)
3. [Add Cosmos validator image](https://github.com/trustwallet/assets/tree/master/blockchains/cosmos/validators)
4. [Add Tezos validator info](https://github.com/trustwallet/assets/tree/master/blockchains/tezos/validators/list.json)

#### How To Add Files

If you are not familiar with GitHub or Git, the process of adding new tokens may look complicated at first glance, but it consists of only a few steps, and is not very complicated.

**Basics, Prerequisites**

The assets repository is maintained in [GitHub](https://github.com), the largest hosting for open source projects. You need a GitHub account to interact with it.

To do changes in the assets repository, you need to create a personal copy called a *fork*.

Once the changes are prepared inside the fork, you need to create a *pull request* to the main repository. Upon review the maintainers will accept your pull request, and the changes will be incorporated.

### Token Status

| Status      | Description                                                                                                                                |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `active`    | Token meets the standard requirements in circulation (number of holders and transactions).                                                 |
| `spam`      | Token that is distributed to a large number of recipients that have no inherent value or has been verified as a dishonest scheme or fraud. |
| `abandoned` | Token with very low activity (below 100 token transfers a year), migrated to mainnet or to a new contract.                                 |


# Staking Validators

Trust Wallet displays staking validator information sourced directly from the [Trust Wallet Assets repository](https://github.com/trustwallet/assets). Validators are listed per supported blockchain, allowing users to discover and delegate to them directly within the Trust Wallet app.

> **Note:** Submitting a Pull Request and making a payment do not guarantee it will be merged or displayed in Trust Wallet. All entries are subject to review, and the team reserves the right to reject entries that do not meet quality standards.

***

## Supported Chains

Validator listings are currently supported for **52 blockchains**, including:

Agoric, Akash, Aptos, Axelar, Band, Binance, Cardano, Comdex, Coreum, Cosmos, Crescent, Crypto.org, Elrond, Ethereum, Fetch.ai, Harmony, IoTeX, IRISnet, Juno, Kava, Kujira, Kusama, Loom, Mars, Canto, Evmos, Injective, NEAR, Ontology, Osmosis, Persistence, Polkadot, Quasar, Secret Network, Sei, BNB Smart Chain, Solana, Sommelier, Stargaze, Stride, Sui, Teritori, Terra Classic, Terra v2, Tezos, Celestia, TRON, Umee, VeChain, Wanchain, Waves, ZetaChain

See all [supported staking coins](https://trustwallet.com/staking/) on the Trust Wallet website.

***

## Repository Structure

Validator data follows a consistent structure across all chains:

```
blockchains/<chain>/validators/
├── list.json                    (metadata for all validators on this chain)
└── assets/
    └── <validator_id>/
        └── logo.png             (validator logo image)
```

**Examples by chain:**

```
blockchains/cosmos/validators/assets/cosmosvaloper1k6e7l0lz497l8njqjxpd3g4wlkdfwe93uqf03k/logo.png
blockchains/solana/validators/assets/FiijvR2ibXEHaFqB127CxrL3vSj19K2Kx1jf2RbK4BWS/logo.png
blockchains/tezos/validators/assets/tz1hAYfexyzPGG6RhZZMpDvAHifubsbb6kgn/logo.png
blockchains/ethereum/validators/assets/0x2401c39d7ba9E283668a53fcC7B8F5FD9e716fdf/logo.png
```

***

## How to Add a Validator

1. **Add validator metadata** — append your entry to the bottom of `blockchains/<chain>/validators/list.json`
2. **Add a logo** — place `logo.png` at `blockchains/<chain>/validators/assets/<validator_id>/logo.png`
3. **Open a pull request** — submit your changes and [pay the processing fee](/developer/new-asset/pr-fee)

> **Tip:** Review the existing entries in the chain's `list.json` before adding yours to understand the expected ID format and any chain-specific fields.

***

## list.json Schema

Each entry in `list.json` is a JSON object within a top-level array.

### Required Fields

| Field         | Type     | Description                                                                                                    |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `id`          | `string` | The validator's unique identifier on-chain (address, operator address, or public key — format varies by chain) |
| `name`        | `string` | Display name shown in the Trust Wallet app                                                                     |
| `description` | `string` | A brief description of the validator or service                                                                |
| `website`     | `string` | The validator's official website URL                                                                           |

### Optional Fields

#### `payout` object

| Field          | Type      | Description                                                    |
| -------------- | --------- | -------------------------------------------------------------- |
| `commission`   | `integer` | Fee charged by the validator as a percentage (e.g. `10` = 10%) |
| `payoutDelay`  | `integer` | Number of cycles/periods before rewards are distributed        |
| `payoutPeriod` | `integer` | Frequency of reward payouts (in cycles/periods)                |

#### `staking` object

| Field           | Type     | Description                                           |
| --------------- | -------- | ----------------------------------------------------- |
| `minDelegation` | `number` | Minimum amount required to delegate to this validator |

#### `status` object

| Field      | Type      | Description                                                     |
| ---------- | --------- | --------------------------------------------------------------- |
| `disabled` | `boolean` | Set to `true` to mark the validator as inactive                 |
| `note`     | `string`  | Optional note explaining the status (e.g. reason for disabling) |

***

## Examples

### Basic entry (Cosmos)

```json
{
    "id": "cosmosvaloper1k6e7l0lz497l8njqjxpd3g4wlkdfwe93uqf03k",
    "name": "Trust Nodes",
    "description": "The most trusted & secure crypto wallet",
    "website": "https://trustwallet.com"
}
```

### Entry with payout and staking details (Tezos)

```json
{
    "id": "tz1hAYfexyzPGG6RhZZMpDvAHifubsbb6kgn",
    "name": "Swiss Staking",
    "description": "Experienced validator based in Switzerland. We offer a highly secure and stable staking infrastructure.",
    "website": "https://swiss-staking.ch",
    "payout": {
        "commission": 10,
        "payoutDelay": 6,
        "payoutPeriod": 1
    },
    "staking": {
        "minDelegation": 100
    }
}
```

### Disabled validator

```json
{
    "id": "tz1...",
    "name": "Example Validator",
    "description": "...",
    "website": "https://example.com",
    "status": {
        "disabled": true,
        "note": "This validator has ceased operations."
    }
}
```

***

## Logo Requirements

Place the logo at: `blockchains/<chain>/validators/assets/<validator_id>/logo.png`

| Property     | Requirement                                        |
| ------------ | -------------------------------------------------- |
| File name    | `logo.png` (all lowercase — `PNG` is invalid)      |
| Format       | `png`                                              |
| Dimensions   | `256 x 256 px` recommended, `512 x 512 px` maximum |
| File size    | Maximum `100 kB`                                   |
| Aspect ratio | `1:1`                                              |

For full logo design guidelines — including circular cropping, background handling, and dark mode compatibility — see [Image Requirements](/developer/new-asset/repository_details#image-requirements).

***

## Chain-Specific Requirements

The `id` format and available metadata fields vary by chain. Before submitting, review the existing `list.json` for your target chain to confirm the correct ID format.

Reference validator lists for commonly supported chains:

* [Cosmos](https://github.com/trustwallet/assets/tree/master/blockchains/cosmos/validators/list.json)
* [Kava](https://github.com/trustwallet/assets/tree/master/blockchains/kava/validators/list.json)
* [Solana](https://github.com/trustwallet/assets/tree/master/blockchains/solana/validators/list.json)
* [Polkadot](https://github.com/trustwallet/assets/tree/master/blockchains/polkadot/validators/list.json)
* [Tezos](https://github.com/trustwallet/assets/tree/master/blockchains/tezos/validators/list.json)
* [TRON](https://github.com/trustwallet/assets/tree/master/blockchains/tron/validators/list.json)
* [Harmony](https://github.com/trustwallet/assets/tree/master/blockchains/harmony/validators/list.json)


# Universal Asset ID

A `UAI` is a unique identifier for assets. It is blockchain-agnostic and provides the ability to easily distinguish assets across blockchains.

## Params:

* `c` - coin (required), for most coins it uses [slip 44 index](https://github.com/trustwallet/wallet-core/blob/master/docs/registry.md) conventions. There are some exceptions that use [coinId](https://github.com/trustwallet/wallet-core/blob/master/registry.json#L1472) based on Wallet Core config
* `t` - token (optional), following standard of unique identifier on the blockchain as smart contract address or asset ID

## Examples:

### Coins:

* Bitcoin: `c0`
* Ethereum: `c60`
* BNB Chain (BSC): `c20000714`

### Tokens:

* DAI (Ethereum): `c60_t0x6B175474E89094C44Da98b954EedeAC495271d0F`
* USDT (Tron): `c195_tTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t`
* DAI (BSC): `c20000714_t0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3`

Template: `c{coin}_t{token_id}`


# Wallet Core

![](/files/-LeN195G8On2Q1y5l3pm)

## Introduction

Trust Wallet Core is an open-source, cross-platform, mobile-focused library implementing low-level cryptographic wallet functionality for a high number of blockchains. It is a core part of [Trust Wallet](https://trustwallet.com) and several other projects.

Most of the code is C++ with a set of strict C interfaces, and idiomatic interfaces for supported languages: Swift for iOS and Java/Kotlin for Android. Additional bindings are available for Rust, Kotlin Multiplatform, WebAssembly, Go, and NPM (beta).

Wallet Core supports more than **130 blockchains**: Bitcoin, Ethereum, BNB, Cosmos, Solana, and most major blockchain platforms. The full list is in the [registry](https://github.com/trustwallet/wallet-core/blob/master/docs/registry.md).

## Usage

If you want to use Wallet Core in your project, follow these instructions:

* For building locally, or using a Docker image, see the [Build Instructions](/developer/wallet-core/developing-the-library/building).
* For trying out key management and address derivation, see the [WalletConsole utility](/developer/wallet-core/developing-the-library/walletconsole).
* If you want to include Wallet Core in your project, see the [Integration Guides](/developer/wallet-core/integration-guide). Start with the overview of the most common wallet operations ([Usage Guide](/developer/wallet-core/integration-guide/wallet-core-usage)), and see the platform-specific guides for [iOS](/developer/wallet-core/integration-guide/ios-guide) and [Android](/developer/wallet-core/integration-guide/android-guide).
* We have a [FAQ](/developer/wallet-core/faq) that may already answer some of your questions.

## Projects using Wallet Core

Add yours too!

* [Trust Wallet](https://trustwallet.com)
* [Crypto.com](https://crypto.com)
* [Frontier](https://frontier.xyz/)
* [Tokenary](https://tokenary.io/)
* [MemesWallet](https://planetmemes.com/)
* [xPortal](https://xportal.com/)
* [Slingshot](https://slingshot.finance/)
* [ECOIN Wallet](https://play.google.com/store/apps/details?id=org.ecoinwallet)

## Contributing

The best way to submit feedback and report bugs related to Wallet Core is to [open a GitHub issue](https://github.com/trustwallet/wallet-core/issues/new). If the bug is not related to Wallet Core but to the Trust Wallet app, please [create a Customer Support ticket](https://support.trustwallet.com/). If you want to contribute code, see [Contributing](/developer/wallet-core/developing-the-library/contributing). If you want to add support for a new blockchain, see [Adding Support for a New Blockchain](/developer/wallet-core/newblockchain).

Thanks to all the people who contribute. [![](https://opencollective.com/wallet-core/contributors.svg?width=890\&button=false)](https://github.com/trustwallet/wallet-core/graphs/contributors)

## Disclaimer

The Wallet Core project is led and managed by Trust Wallet with a large contributor community and is actively used in several projects. Our goal is to give other wallets an easy way to add chain support.

Trust Wallet products leverage Wallet Core, however they may not leverage all of its capabilities, features, and assets due to their own product requirements.

## License

Trust Wallet Core is available under the Apache 2.0 license. See the [LICENSE](https://github.com/trustwallet/wallet-core/blob/master/LICENSE) file for more info.


# New Blockchain Support

> **Important:** At this time, new blockchains are not merged into Wallet Core without a positive decision from our Business Development team. Before investing time in an implementation, please reach out to <partnerships@trustwallet.com> to start that conversation.

If you haven't, first read the [guide to contributing](/developer/wallet-core/developing-the-library/contributing). It contains important information about the library and how to contribute.

## Blockchains, Coins and Tokens

* If you are interested in adding a new Token, e.g. ERC20, in this case no code changes are needed, see the [Assets](/developer/new-asset) section for more details.
* If you are adding an EVM-compatible chain, that is much simpler, see [EVM Chain docs](/developer/wallet-core/newblockchain/newevmchain).
* For new coins you need to implement address handling and signing functionality in wallet-core (described in this section). For new coins on already supported blockchains, or variations of already supported blockchains, please consider proper reuse of existing implementation.

## Integration Criteria

The Trust Wallet development team is always striving to add more blockchains that will be essential for developers and wallet users. We choose blockchains carefully based on the impact they will have for our community.

Please keep in mind that Wallet Core is open source and used in many other projects besides Trust Wallet, so adding it to Wallet Core is a prerequisite but not a sufficient condition for adding it to Trust Wallet.

The general integration criteria is as follows:

* The blockchain has launched mainnet and has stably run for at least 3 \~ 6 months without major security incidents.
* The blockchain has extensive public documentation and tools available for developers to use.
* The native coin is listed in the top 100 coins on CoinMarketCap.
* The project needs to provide API/JSON-RPC access to the node with a load balancing setup for private use, see detail requirements [here](https://developer.trustwallet.com/wallet-core/rpc-requirements).
* The native coin is tradable on major exchanges.

After integrating into Trust Wallet projects are expected to provide timely support for any urgent matters.

## Overview

Adding support for a new coin consists of these steps:

* Add **coin definition** -- contains basic parameters of the new coin, several definition source files are generated from the definitions
* Extend a few **central files**. There are a few central source files that need to be extended (some definitions, dispatching logic to coin implementations).
* **Rust implementation** of **address** handling and **signing** functionality. Optionally protobuf definitions might be needed for more complex parameters.
* **Unit tests** for coin definitions, address and signing functionality
* **C interface** (basis for mobile integration)
* **Kotlin** and **Swift** bindings -- these are generated
* **Integration tests** for testing through C interface, and through JN and Swift interfaces.

It helps to pick an existing coin, and refer to its implementation. Try to pick an existing coin that is similar to the new one, and check how/where is it implemented, tested, etc.

Note that unit **tests** are crucial in ensuring quality needed for multi-coin support. Functionality here can be well unit-tested, so don't ignore them. Coverage must not decrease! This is enforced automatically in the validation of the pull requests.

## Blockchain definition

The first step to add a blockchain is to define its coin configuration. Add the definition to the `registry.json` file. Consult a similar blockchain (or simply copy & modify).

The fields are documented here: <https://github.com/trustwallet/wallet-core/blob/master/docs/registry-fields.md>.

## Skeleton generation

Run the `tools/new-blockchain <coinid>` script, where `<coinid>` is the ID of the new coin from `registry.json`. This script runs `codegen-v2` and `codegen/bin/newcoin-mobile-tests` and generates the following files, crates and structures:

* `src/proto/<CoinId>.proto` - Blockchain Protobuf interface.
* `rust/chains/tw_<coinid>` - Rust crate that will contain all necessary code related to the new blockchain.
* `rust/chains/tw_<coinid>/tests` - Rust unit and integration tests.
* `src/<CoinId>/Entry.h` - Intermediate layer between an end-user app and the Rust codebase.
* `BlockchainType::<CoinId>` - Rust enum variant and its dispatching within the `rust/tw_coin_registry` crate.
* `TWBlockchain<CoinId>` and `TWCoinType<CoinId>` - C++ enum variants.
* `tests/chains/<CoinId>` - C++ integration tests.

Run `tools/generate-files` to generate message proto files.

Run `cmake` to include the new files in the build (`cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug`), and build the project.

## Definition tests, first commit

Review tests in `tests/chains/<CoinId>/TWCoinTypeTests.cpp` (where `X` is the name of the blockchain), exactly as in other blockchains. Run `cd rust && cargo check --tests` and `make -Cbuild -j12 tests TrezorCryptoTests` to check if Rust and C++ compile successfully.

You should create a commit with this change, (but don't create a pull request yet).

*Note:* don't forget to add new files to git. *Note:* don't forget to re-run `cmake` before building, to include new files in the build.

## Rust implementation

Implement the required functionality in Rust. The code should be placed in the `rust/chains/tw_<coinid>` folder.

Don't just dump an existing codebase in the repo. The code needs to follow the code style and use existing hashing and cryptographic functionality if possible. Adding new dependencies is something we want to avoid as much as possible. We want to keep the codebase and the binary library as small as we can.

If you do need to add a new cryptographic function or other building block please do so as a separate PR from the blockchain implementation.

### Entry point for coin functionality

The Rust's `Entry` structure implements the [CoinEntry](https://github.com/trustwallet/wallet-core/blob/master/rust/tw_coin_entry/src/coin_entry.rs) trait that is responsible for address management and the transaction signing. It should be kept minimal, have no logic, just call into relevant Address, Signer, etc. classes. Ensure that it fits well with the existing infrastructure and conventions.

*Note:* Do not forget to implement trait methods and declare associated types similar to [tw\_ethereum/entry.rs](https://github.com/trustwallet/wallet-core/blob/master/rust/tw_ethereum/src/entry.rs).

### Address encoding/decoding

The first step is to support the address format specific to the blockchain. Start with the generated source files `rust/chains/X/src/address.rs` (where `X` is the blockchain name).

At minimum the address needs a string validation static method, a string constructor, a constructor from a public key, and a method to convert back to a string. Make sure you can parse a string representation of an address and detect invalid addresses. Write unit tests for this. Also make sure that you can derive an address string from a private key. Write unit tests for this as well.

For an example of this have a look at Ethereum [address.rs](https://github.com/trustwallet/wallet-core/blob/master/rust/tw_evm/src/address.rs).

Make sure the dispatcher of address validation and derivation in `rust/chains/tw_<coinid>/src/entry.rs` is also extended.

### Transaction signing

The second step is supporting signing of transactions. Work on the `rust/chains/tw_<coinid>/src/signer.rs` source file. Make sure you can generate a valid signature and a valid signed and encoded transaction. Write a unit tests for this.

For an example of this have a look at Aptos's [signer.rs](https://github.com/trustwallet/wallet-core/blob/master/rust/tw_aptos/src/signer.rs).

### Unit Tests

Unit tests are used to test public and non-public, usually, a single structure, method or function. Rust allows to test non-public identities straightforward. Unit tests can be placed in any Rust source file (under the `#[cfg(test)]` attribute) or in a test file under the `rust/chains/tw_<coinid>/tests` directory. *Note:* All Rust code needs to be unit tested.

For an example of this have a look at Ethereum's Unit tests: [tw\_evm/tests/signer.rs](https://github.com/trustwallet/wallet-core/blob/master/rust/tw_evm/tests/signer.rs) and [tw\_evm/src/address.rs](https://github.com/trustwallet/wallet-core/blob/master/rust/tw_evm/src/address.rs).

The Rust implementation with tests should be a separate commit.

### Rust Integration Tests

Integration tests are used to test if the blockchain implementation can be accessed through the `TWAnySigner`, `TWAnyAddress`, ... public interfaces. They should be placed in the `rust/chains/tw_<coinid>/tests` directory.

Usually you don't need to change the generated FFI interfaces, those interfaces are made as small as possible so that clients don't need to worry about implementation details.

## C++ routing

At this moment, every blockchain implemented in Rust must be routed through an intermediate C++ layer. The `src/X/Entry.h` is generated the way, so it passes requests to sign transactions, generate or validate addresses to Rust through FFI. So it can be considered as a bridge between an end-user app and the Rust codebase. *Note:* FFI forwarding is derived from the `src/rust/RustCoinEntry` base class. *Note:* Currently, blockchains in Rust do not support JSON signing as it is deprecated and will be removed in the future. Instead, if the blockchain should support JSON signing, consider overriding `RustCoinEntry::signJSON` method as in Ethereum: [src/Ethereum/Entry.h](https://github.com/trustwallet/wallet-core/blob/master/src/Ethereum/Entry.cpp).

### C++ Integration Tests

Once you are satisfied with your Rust implementation, time to write some tests for C interface. C++ integration tests can help us to ensure if the Rust functionality is routed correctly, and available to be used by end-user apps.

## Mobile Integration Tests

It is also required to test the interface on Android, iOS. Mobile integration tests are generated automatically by `tools/new-blockchain`. The generated files are:

* `android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/foobar/Test<CoinId>Address.kt` - Address integration tests.
* `android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/foobar/Test<CoinId>Signer.kt` - Signing integration tests.
* `swift/Tests/Blockchains/<CoinId>Tests.swift` - Address, signing and compiling integration tests.

## Blockchain checklist

The above steps are summarized below as a checklist:

* [ ] Coin Definition:
  * [ ] Add the coin definition to `registry.json`.
  * [ ] Execute `tools/new-blockchain <coinid>` to generate blockchain skeleton, integration tests, and mobile test scaffolding.
  * [ ] Execute `tools/generate-files`.
  * [ ] Execute `pushd rust && cargo check --tests && popd` to check if Rust codebase compiles successfully.
  * [ ] Execute `make -Cbuild -j12 tests TrezorCryptoTests` to check if C++ codebase compiles successfully.
* [ ] Add relevant constants in `Curve`, `Hasher` etc., in C++ and Rust, as necessary.
* [ ] Implement functionality in Rust.
  * [ ] Entry at `rust/chains/tw_<coinid>/src/entry.rs`.
  * [ ] Address at `rust/chains/tw_<coinid>/src/address.rs`.
  * [ ] Transaction (if necessary) at `rust/chains/tw_<coinid>/src/transaction.rs`.
  * [ ] Signer at `rust/chains/tw_<coinid>/src/signer.rs`.
  * [ ] Compiler at `rust/chains/tw_<coinid>/src/compiler.rs`.
  * [ ] Write unit tests. Put them in the `rust/chains/tw_<coinid>/tests` directory.
  * [ ] Write Rust integration tests. Put them in `rust/chains/tw_<coinid>/tests`
    * [ ] Transaction signing tests, at least one mainnet transaction test.
    * [ ] Add stake, unstake, get rewards tests if the blockchain is PoS like.
* [ ] Write C++ integration tests. Put them in a subfolder of `tests/chains/<CoinId>`.
* [ ] Validate generated code in Android an iOS projects. Write integration tests for each.
* [ ] Extend central derivation and validation tests: make sure the following tests are extended with the new coin: `CoinAddressDerivationTests.cpp` and `coin_address_derivation_test.rs`, `CoinAddressValidationTests.cpp`, `TWHRPTests.cpp`, `CoinAddressDerivationTests.kt`, `CoinAddressDerivationTests.swift`.
* [ ] Upload coin icon to [trustwallet/assets](https://github.com/trustwallet/assets/#how-to-add-asset) if necessary.

### Bitcoin forks checklist

If you're adding a Bitcoin fork, you might not need to implement new Address or Signer class, please complete this checklist before you submit a pull request:

* [ ] Derive address according to definition in `registry.json`, `p2pkh` address for `bip44` or native `bech32` segwit address for `bip84`.
* [ ] Check [SLIP-0132 :Registered HD version bytes](https://github.com/satoshilabs/slips/blob/master/slip-0132.md).
* [ ] Check fee preference, use static fee or not, Trust will use fee that can be confirmed with in 2 blocks.
* [ ] Add tests to validate all possible addresses, `p2pkh`, `p2sh` and `bech32`.
* [ ] Add tests to derive `xpub` / `xprv` and cross check the values with other wallets, like ledger or trezor.
* [ ] Add tests to derive address from `xpub` at random index.
* [ ] Add tests to cover lock scripts for all addresses.
* [ ] Add tests to make sure transaction detail url in block explorer is correct.
* [ ] Add a mainnet transaction test, you can construct it by using wallet core and validate it by broadcasting it.


# RPC / API Requirements

Trust Wallet is a light client wallet, which means it needs to get data / information from remote nodes (either light nodes or full nodes). In order to integrate your blockchain into Trust Wallet smoothly, you must also fulfill RPC / API requirements. We list all needed APIs or RPCs plus an example below for your reference.

## for Trust Wallet:

We need API or RPC to:

* [ ] query account / address balance
* [ ] query transaction details
* [ ] query fee / nonce for sending transaction
* [ ] query blockchain status (block height etc)
* [ ] send raw transaction

## for Backend:

Used to create transaction list index and notify users about incoming/outgoing transactions.

* [ ] query transactions in a block

## Example

We will take XRP as an example here, it supports WebSocket, JSON-RPC (including over HTTP)

### Query account / address balance:

* [x] JSON RPC method: `account_info` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account\\_info>)

### Query transaction details:

* [x] JSON RPC method: `tx` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/transaction-methods/tx>)

### Query fee / nonce for sending transaction:

* [x] fee: JSON RPC method: `fee` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/fee>)
* [x] nonce: same as `account_info`, you can find `Sequence` in response.

### Query blockchain status (block height etc):

* [x] JSON RPC method: `server_state` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/server\\_state>)

### Send raw transaction:

* [x] JSON RPC method: `submit` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/transaction-methods/submit>)

### Query sent / received transactions for an account / address:

* [x] JSON RPC method: `account_tx` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account\\_tx>)

### Query transactions in a block:

* [x] JSON RPC method: `ledger` (<https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/ledger-methods/ledger>)


# New EVM-compatible chain

> **Important:** At this time, new blockchains are not merged into Wallet Core without a positive decision from our Business Development team. Before investing time in an implementation, please reach out to <partnerships@trustwallet.com> to start that conversation.

Adding support for a new fully EVM-compatible chain to Wallet Core requires only a few changes, follow the steps here. For more complex chain integrations, see [general new blockchain docs](/developer/wallet-core/newblockchain).

## Prerequisites / Needed information

* `ChainID`. EVM chains have a unique ChainID, such as `8217`.
* `Derivation path` used. Most EVM chains use Ethereum derivation path, `"m/44'/60'/0'/0/0"` (but not all).
* `CoinID`. Most EVM chains do not have a SLIP 44 CoinID, but some do. We'll see below what to use if one is not available.

## Steps

* Start with an up-to-date workspace ([more info](/developer/wallet-core/developing-the-library/contributing)).
* Add chain information to `registry.json`. Some notable fields:
  * blockchain: "Ethereum",
  * coinId: If own coinID is available, use that. Otherwise, use: `10000000 + chainID`, such as `10008217`.
* Run `tools/new-evmchain <chain>` to generate template source files, where `<chain>` is the chain `id` from registry.
* The result will be a new line in `TWCoinType.h` and a new test file `tests/<Chain>/TWCoinTypeTests.cpp`.
* There are some test cases that test derivation for all coins. Extend these with the new chain. If the new chain reuses Ethereum address, it can reuse the Ethereum case in the switch statements.

```
rust/tw_tests/tests/coin_address_derivation_test.rs
tests/common/CoinAddressDerivationTests.cpp
android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt
kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt
swift/Tests/CoinAddressDerivationTests.swift
```

* Update generated sources, build the project, execute unit tests (see [building](/developer/wallet-core/developing-the-library/building)):

```
./tools/build-and-test
```

* If all is fine, create a PR with the changes.

## Some Sample PRs:

* [github.com/trustwallet/wallet-core/pull/2307](https://github.com/trustwallet/wallet-core/pull/2307)
* [github.com/trustwallet/wallet-core/pull/2157](https://github.com/trustwallet/wallet-core/pull/2157)


# Developing the Library


# Contributing

We want to make Trust Wallet Core as good as it can be. If you want to contribute your help is greatly appreciated. Contributing is also a great way to learn more about blockchain technology and improve Trust Wallet. To make the process as smooth as possible please read this document and follow our guidelines. We are happy to review your code but please ensure that you have a [clean pull request](#pull-requests).

Wallet Core implements the cryptographic functionality of blockchains. This includes elliptic curve cryptography, hashing, address derivation and transaction signing. However it *does not* implement other aspects like networking and UI. Wallet core behaves like a black box for higher level users like Trust Wallet; it takes inputs from the blockchain and the user (for instance UTXOs, private keys, etc.) and produces an output (like a signed and encoded transaction). Keep this in mind when adding functionality.

This is a diagram representing how Trust Wallet interacts with Trust Wallet Core.

![](/files/-LeN0MO2-zQV4MP-Owfr)

## Library Design Guidelines

This library is designed so that it can be used from any other programming languages, and that every language has an idiomatic interface. Design goals also include minimizing the binary size and maximizing performance.

With these goals in mind we chose C/C++ for the implementation and a strict subset of C for the interface. This C interface is used to generate the idiomatic interfaces for every supported language. To augment the expressivity of the interface we also use Protocol Buffer objects that get serialized across the interface.

Keep this in mind when adding to the library:

* Only expose C headers. Clients should not have access to the C++ interfaces.
* C headers need to have annotations for the code generation tool, see below.
* Use Protocol Buffers to represent models. C doesn't have good abstractions for variable-sized types.
* Every time you modify the interface run the code generation tool and make sure the interface also makes sense in target languages.

There is a [Sourcetrail](https://github.com/CoatiSoftware/Sourcetrail) [project file](https://github.com/trustwallet/wallet-core/blob/master/wallet_core.srctrlprj) that may help you explore the code after running `bootstrap.sh` and building.

![](/files/-Lv9SlTQPsSD0HwUAuTV)

## Pull Requests

Please follow these instructions when submitting a pull request (PR):

* Create a personal fork of the project on GitHub.
* Clone the fork on your local machine. Your remote repo on Github is called `origin`.
* Add the official repository as a remote called `upstream`.
* If you created your fork a while ago be sure to pull upstream changes into your local repository.
* Create a new branch to work on! Branch from the latest `upstream/master`.
* Implement/fix your feature, comment your code.
* Write or adapt tests as needed.
* Follow the code style of the project, including indentation. Use `clang-format` if you are unsure.
* Run the tests.
* Modify your commit history so that it tells a story using git's [interactive rebase](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History). Create a new branch if necessary.
* Write your commit messages in the present tense. Your commit message should describe what the commit, when applied, does to the code, not what you did to the code.
* Push your branch to your fork on Github, the remote `origin`.
* From your fork open a pull request in the correct branch. Target the project's `master` branch.
* If we request further changes push them to your branch. The PR will be updated automatically.
* Once the pull request is approved and merged you can pull the changes from `upstream` to your local repo and delete

  your extra branch(es).

Is it not uncommon for a PR to accumulate commits and merges with time. The library is in constant change. If your PR falls out of sync with the upstream master you need to rebase. We can't reliably review code that is spread over too many other changes to the codebase. Please use git's [interactive rebase](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) and if necessary create a new PR.

## Project organization

This project has a number of different pieces. Each piece lives in its own subfolder.

* The `docs` folder contains documentation.
* The `src` folder contains the C++ implementation of the core functionality.
* The `include` folder contains the public C header files used to expose a cross-platform interface.
* The `rust` folder contains the Rust implementation of blockchain functionality.
* The `codegen` folder contains the code and templates used to generate code for different platforms and languages.
* The `codegen-v2` folder contains the newer Rust-based code generator.
* The `jni` folder contains the generated JNI interface and Java classes.
* The `android` folder contains the Android Studio project and integration tests.
* The `swift` folder contains the generated Swift code and Xcode project.
* The `trezor-crypto` folder contains a fork of <https://github.com/trezor/trezor-crypto/> with modifications.
* The `tests` folder contains C++ unit and integration tests.
* The `tools` folder contains scripts to automate common tasks.
* The `samples` folder contains sample applications.

## Prerequisites and Building

Please refer to [build instructions](/developer/wallet-core/developing-the-library/building) for building the library locally.

## Testing

After running `bootstrap.sh`, use `tools/build-and-test` to build and run all C++ unit tests. To run integration tests on each platform run the respective script in the tools folder:

* Android: run `tools/android-test` or import the `android` folder into Android Studio
* iOS: run `tools/ios-test` or open `TrustWalletCore.xcworkspace` in the `swift` folder (generated after running `tools/generate-files`)

To run all tests across all platforms in one go, use the `tools/tests` script.

## C Headers

The wallet core code generator parses C headers for class and struct definitions. Headers need to be in the `include/TrustWalletCore` folder and start with the `TW` prefix followed by the class or struct name. Inside each header file there needs to be exactly one class or struct definition.

A class definition starts with the `TW_EXPORT_CLASS` macro followed by a forward-declared struct. For example:

```c
TW_EXPORT_CLASS
struct TWPrivateKey;
```

Similarly, a struct definition start with the `TW_EXPORT_STRUCT` macro followed by an inline-declared struct. For example:

```c
TW_EXPORT_STRUCT
struct TWPublicKey {
    uint8_t bytes[TWPublicKeyUncompressedSize];
};
```

You can also define enumerations using the `TW_EXPORT_ENUM()` macro:

```
TW_EXPORT_ENUM(uint32_t)
enum TWCoinType {
    TWCoinTypeBitcoin = 0,
};
```

After the class or struct definition you can declare as many methods and properties as necessary. There are four types of declarations: static method, static property, method, and property. Each is declared by `TW_EXPORT_STATIC_METHOD`, `TW_EXPORT_STATIC_PROPERTY`, `TW_EXPORT_METHOD`, and `TW_EXPORT_PROPERTY` respectively. Each method or property name needs to start with the type name. For instance `TWPublicKeyIsValid` gets translated to the `isValid` property in the `PublicKey` type.

The types that methods can take and return are restricted to: `bool`, `int`, `size_t`, `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `TWData`, `TWString`, and any defined classses, structs or enums.

Methods always take the type as their first argument. The type needs to be a pointer if the type is a class and a struct if the type is a struct. Properties need to take the type as its only argument.

Static property declarations can take no arguments. Static methods can take any arguments.

Since C interface doesn't know how to handle C++ exception, we should catch all possible exceptions in the C implementation.

## Coin definition

The wallet core code generator also parses coin configuration defined in `registry.json`, the generated code will be located at `src/Generated/Coins.cpp`. See the documentation of the fields here: <https://github.com/trustwallet/wallet-core/blob/master/docs/registry-fields.md>.

Example:

```json
{
  "id": "bitcoin",
  "name": "Bitcoin",
  "coinId": 0,
  "symbol": "BTC",
  "decimals": 8,
  "blockchain": "Bitcoin",
  "derivation": [
    {
      "name": "segwit",
      "path": "m/84'/0'/0'/0/0",
      "xpub": "zpub",
      "xprv": "zprv"
    },
    {
      "name": "legacy",
      "path": "m/44'/0'/0'/0/0",
      "xpub": "xpub",
      "xprv": "xprv"
    }
  ],
  "curve": "secp256k1",
  "publicKeyType": "secp256k1",
  "p2pkhPrefix": 0,
  "p2shPrefix": 5,
  "hrp": "bc",
  "publicKeyHasher": "sha256ripemd",
  "base58Hasher": "sha256d",
  "explorer": {
    "url": "https://blockchair.com",
    "txPath": "/bitcoin/transaction/",
    "accountPath": "/bitcoin/address/",
    "sampleTx": "0607f62530b68cfcc91c57a1702841dd399a899d0eecda8e31ecca3f52f01df2",
    "sampleAccount": "17A16QmavnUfCW11DAApiJxp7ARnxN5pGX"
  },
  "info": {
    "url": "https://bitcoin.org",
    "source": "https://github.com/trezor/blockbook",
    "rpc": "",
    "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md"
  }
}
```

## Protocol Buffers

Since the C language doesn't provide good abstractions for variable-sized arrays and strings, the C interface uses [Protocol Buffers](https://developers.google.com/protocol-buffers/). All models are defined in the `src/proto` folder. These models can then be used in the C interface by using the proto model name with underscores. For instance `TW_Binance_Proto_SigningInput`.

The proto file will be used to generate C++ classes and also classes in each supported client language (Swift, Java, etc.). The code generator will also generate the protobuf serialization code so that library clients don't have to worry about serialization. To generate the Protocol Buffers code run the `tools/generate-files` script when you modify the `src/TrustWalletCore.proto` file.

## Code Style

Wallet core follows the [LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html) for C++. We use `clang-format` to ensure a consistent code style. **Do not** reformat files that you didn't modify, or the header files in the `include` folder. You can install a clang-format extension for your IDE.

## More

* [Build instructions](/developer/wallet-core/developing-the-library/building)
* [Adding Support for a New Blockchain](/developer/wallet-core/newblockchain)
* [Releasing](/developer/wallet-core/developing-the-library/releasing)


# Building

Find here instructions for building the Wallet Core library locally.

## Platforms

The following *target platforms* are supported:

* **iOS** (Swift language is used)
* **Android**
* **Wasm** (Emscripten)

The following *development platforms* are supported:

* **macOS**: is the *primary* development platform, as it supports compiling for both target platforms.
* **Linux**: is supported as a development platform if you only need to build C++ and Wasm targets.

## Build Methods

Wallet Core can be build inside a Docker image, or natively.

* Inside **Docker** image: This way is easier to get the prerequisites, as they are all inside a Docker image. However, all building has to be done inside the Docker image.
* Natively, in your dev OS (macOS, Linux).

## Prerequisites

Use one top-level script to install all required dependencies and prepare WalletCore for building:

```shell
./bootstrap.sh all
```

Please note that the script configures the environment for all target platforms: Native, Android, iOS (on MacOS), and WASM. If you intend to use WalletCore on specific platforms only, you can specify those platforms in the arguments:

```shell
./bootstrap.sh android ios
```

Otherwise, consider installing the required prerequisites manually below.

### Prerequisites on macOS

* CMake `brew install cmake`
* Boost `brew install boost`
* Xcode
* Xcode command line tools: `xcode-select --install`
* Ruby `brew install ruby`
* Other tools: `brew install git ninja autoconf automake libtool xcodegen clang-format ccache cocoapods`
* [Android Studio](https://developer.android.com/studio/index.html)
* [Android NDK](https://developer.android.com/ndk/guides/)
* Rust: `brew install rustup && rustup-init`
* [emscripten (for WASM)](https://emscripten.org/docs/introducing_emscripten/about_emscripten.html)

### Prerequisites on Linux

Ubuntu as an example:

* Various essential packages `sudo apt-get install build-essential libtool autoconf pkg-config ninja-build ccache`
* Clang `sudo apt-get install clang-14 llvm-14 libc++-dev libc++abi-dev`
* Ruby `sudo apt-get install ruby-full`
* Boost `sudo apt-get install libboost-all-dev`
* CMake `sudo apt-get install cmake` or (from <https://github.com/Kitware/CMake/releases>)
* [Android Studio](https://developer.android.com/studio/index.html)
* Rust: `sudo apt-get install rustc`
* [emscripten (for WASM)](https://emscripten.org/docs/introducing_emscripten/about_emscripten.html)

### Managed Prerequisites

Additionally, the following prerequisites are also needed, but they are managed by Wallet Core. The script `tools/install-dependencies` downloads and compiles them (see below).

* Google test (gtest)
* libcheck
* nlohmann json
* Protobuf

## Full Build

WalletCore is ready to be built after installing all prerequisites. Building for each platform is different.

### Native building and testing

To build and run tests on the native platform (Linux, MacOS), run the following command:

```shell
./tools/build-and-test
```

Or, broken up in smaller steps:

1. This script generates source files, coin- and protobuf files. Needs to be re-run whenever `registry.json`, or protobuf files, or `./include` interface, or Rust codebase are changed.

```shell
./tools/generate-files
```

2. Standard CMake and make commands for building the library. The `cmake` command needs to be re-run whenever a new C++ source file is added.

```shell
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug
```

3. Build TrezorCrypto and WalletCore C++ tests.

```shell
make -Cbuild -j12 tests TrezorCryptoTests
```

4. Run TrezorCrypto and WalletCore C++ tests.

```shell
./build/tests/tests tests --gtest_filter=*
```

If you'd rather use and IDE for building and debugging you can specify the `-G` option to cmake. For instance to use Xcode call `cmake -Bxcode -GXcode -DCMAKE_BUILD_TYPE=Debug` and use the generated project in the xcode folder.

### Wasm building

Configure WASM environment with either running a bootstrap:

```shell
./bootstrap.sh wasm
```

Or installing [Emscripten SDK](https://emscripten.org/docs/introducing_emscripten/about_emscripten.html) (emsdk) manually:

```shell
`tools/install-wasm-dependencies`
```

Activate `emsdk`:

```shell
`source emsdk/emsdk_env.sh`
```

After WASM environment is configured, build WalletCore for WASM:

```shell
tools/wasm-build
```

Run Wasm tests:

```shell
cd wasm
npm install && npm run copy:wasm && npm run build
npm run test
```

## Testing Rust library

Rust library can be tested separately from the C++ part.

```shell
cd rust
cargo test
```

## Checking Rust lints

We use [rustfmt](https://github.com/rust-lang/rustfmt), [clippy](https://github.com/rust-lang/rust-clippy) to check if the Rust code is formatted and does not contain common warnings/errors.

Run Rust lints:

```shell
./tools/rust-lints
```

## Building inside Docker image

Here are the instructions to build Wallet Core with the provided `Dockerfile`.

Prerequisite is a working Docker installation.

The command for building the Docker image:

```shell
docker build . --tag wallet-core-dev
```

Then launch the container:

```shell
docker run -i -t wallet-core-dev /bin/bash
```

Inside the container the build commands can be executed (as described above; note that install-dependencies is not necessary):

```shell
cd wallet-core
./tools/build-and-test
```

## Executing inside Docker image

The Docker image also contains a pre-built, runnable version of the library, so it is possible to run it, 'toy around' with it without any building. *Note:* this may not be the most recent version!

Unit tests and [wallet console utility](/developer/wallet-core/developing-the-library/walletconsole) can be executed straight from this Docker image:

```shell
docker run -i -t trustwallet/wallet-core
cd wallet-core
./build/tests/tests tests
./build/walletconsole/walletconsole
exit
```

## Linux

Building on Linux is possible, it requires some extra work. If you have access to macOS we highly recommend developing on that platform. Using the Docker image is also recommended. Otherwise, the prerequisites have to be installed manually. We recommend using Ubuntu 22.04 LTS, same as [Wallet Core CI](https://github.com/trustwallet/wallet-core/blob/master/.github/workflows/linux-ci.yml).

## Unit tests with Coverage

For executing tests locally with coverage measurement, some extra `cmake` settings are needed; see [section on coverage instructions](/developer/wallet-core/developing-the-library/coverage).

## All CMake options

We enable these options on CI: `-DCMAKE_BUILD_TYPE=Debug -DTW_UNITY_BUILD=ON -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON`

| Name                     | Description                                                                               | How to enable it              | Notes                                                                                                                                                                                                |
| ------------------------ | ----------------------------------------------------------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TW\_IDE\_CLION           | Specify that your IDE is CLion, way to enable coverage is different on CLion              | -DTW\_IDE\_CLION=ON           | <p>Do not enable multiple IDE options at the same time<br>Off by default</p>                                                                                                                         |
| TW\_IDE\_VSCODE          | Specify that your IDE is vscode, way to use PVS-studio is different on VSCode             | -DTW\_IDE\_VSCODE=ON          | <p>Do not enable multiple IDE options at the same time<br>Off by default</p>                                                                                                                         |
| TW\_UNITY\_BUILD         | Specify that you want to use UNITY BUILD in the project, use it in order to build faster. | -DTW\_UNITY\_BUILD=ON         | <p>To be used for CI environment.<br>Off by default</p>                                                                                                                                              |
| TW\_ENABLE\_CLANG\_TIDY  | Specify that you want to build with clang-tidy static analyzer.                           | -DTW\_ENABLE\_CLANG\_TIDY=ON  | <p>Do not use it at the same time as <code>TW\_ENABLE\_PVS\_STUDIO</code><br>Clang-tidy must be installed<br>Off by default</p>                                                                      |
| TW\_ENABLE\_PVS\_STUDIO  | Specify that you want to build with pvs-studio static analyzer                            | -DTW\_ENABLE\_PVS\_STUDIO=ON  | <p>Do not use it at the same time as <code>TW\_ENABLE\_CLANG\_TIDY</code><br>PVS-Studio must be installed and configured.<br>Can be combined with <code>TW\_IDE\_VSCODE</code><br>Off by default</p> |
| TW\_CLANG\_ASAN          | Specify that you want to build with ASAN dynamic analyzer.                                | -DTW\_CLANG\_ASAN=ON          | <p>use it in Debug for optimal result.<br>Do not mix with other runtime analyzer.<br>Off by default</p>                                                                                              |
| TW\_COMPILE\_WASM        | Specify that you are targeting WASM.                                                      | -DTW\_COMPILE\_WASM=ON        | Off by default                                                                                                                                                                                       |
| TW\_CODE\_COVERAGE       | Specify that you want to build with coverage support                                      | -DTW\_CODE\_COVERAGE=ON       | <p>Can be combined with <code>TW\_IDE\_CLION</code><br>Off by default</p>                                                                                                                            |
| TW\_WARNINGS\_AS\_ERRORS | Specify that you want to treat all the warnings as error                                  | -DTW\_WARNINGS\_AS\_ERRORS=ON | <p>Adviced to be used locally, during development.<br>Off by default</p>                                                                                                                             |
| TW\_ENABLE\_CCACHE       | Specify that you want to use CCACHE                                                       | -DTW\_ENABLE\_CCACHE=ON       | On by default                                                                                                                                                                                        |
| TW\_UNIT\_TESTS          | Specify that you want to enable unit tests in the project                                 | -DTW\_UNIT\_TESTS=ON          | On by default on native platforms                                                                                                                                                                    |
| TW\_BUILD\_EXAMPLES      | Specify that you want to enable examples in the project                                   | -DTW\_BUILD\_EXAMPLES=ON      | On by default on native platforms                                                                                                                                                                    |


# WalletConsole utility

The *Wallet Core* library comes with an interactive command-line utility, for accessing key- and address management functionality of the library.

## Quick Start

```shell
$ ./build/walletconsole/walletconsole
Wallet-Core Console                          (c) TrustWallet
Type 'help' for list of commands.
> help
Commands:
    . . .
    newKey                  Create new pseudo-random 32-byte key (secret!)
    . . .
> coin btc
Set active coin to: bitcoin
> addrDefault
Result:  bc1q2kecrqfvzj7l6phet956whxkvathsvsgn7twav
```

## Starting

The utility builds together with the library and can be started from: `build/walletconsole/walletconsole` . See [build instructions](/developer/wallet-core/developing-the-library/building).

Walletconsole can be also executed 'off the shelf' using the Docker image:

```shell
docker run -i -t trustwallet/wallet-core /wallet-core/build/walletconsole/walletconsole
```

## Commands

Here is a snapshot of the commands:

```shell
Commands:
exit                    Exit
quit                    Exit
help                    This help
Inputs, buffer:
#                       Take last result
#<n>                    Take nth previous result
buffer                  Take buffer values
Coins:
coins                   List known coins
coin <coin>             Set active coin, selected by its ID or symbol or name
Keys:
newKey                  Create new pseudo-random 32-byte key (secret!)
pubPri <priKey>         Derive public key from a secret private key (type is coin-dependent)
priPub <pubKey>         Derive private key from public key :)
setMnemonic <word1> ... Set current mnemonic, several words (secret!)
newMnemonic <strength>  Create and store a new mnemonic, of strength (128 -- 256) (secret!)
dumpSeed                Dump the seed of the current mnemonic (secret!)
dumpMnemonic            Dump the current mnemonic (secret!)
dumpDP                  Dump the default derivation path of the current coin (ex.: m/84'/0'/0'/0/0)
dumpXpub                Dump the XPUB of the current mnemonic
priDP [<derivPath>]     Derive a new private key for the coin, from the current mnemonic and given derivation path.
                        If derivation path is missing, the default one is used (see dumpDP).
Addresses:
addrPub <pubKey>        Create <coin> address from public key
addrPri <priKey>        Create <coin> address from private key
addr <addr>             Check string <coin> address
addrDefault             Derive default address, for current coin, fom current mnemonic; see dumpDP
addrDP <derivPath>      Derive a new address with the given derivation path (using current coin and mnemonic)
addrXpub <xpub> <index> Derive a new address from the given XPUB and address index (using current coin)
Coin-specific methods:
Transformations:
hex <inp>               Encode given string to hex
base64Encode <inp>      Encode given hex data to Base64
base64Decode <inp>      Decode given Base64 string to hex data
File methods:
fileW <fileName> <data> Write data to a (new) binary file.
fileR <fileName>        Read data from a binary file.
```

## Examples

Here are various sample usages.

Create a new private key, derive a BTC address from it, write it to a file:

```shell
> coin bitcoin
Set active coin to: bitcoin    Use 'coin' to change.  (name: 'bitcoin'  symbol: btc  numericalid: 0)
> newKey
Result:  4e8c1773ce1ca447594fa23a445d9952236c7a15e96802b880aab4d918bdcfd9
> addrPri #
Result:  bc1qvjf93nc80f3fu7j2ehqv6xw6zqa5cny32hl90y
> fileW btcaddr.txt #
Written to file 'btcaddr.txt', 21 bytes.
```

Create a new private key, derive the public key from it, derive a BTC address from it:

```shell
> newKey
Result:  ef8f76035c4d4dd29ed4bbe3fc7c0db45d81cd616f2ac8b038cb982bec2a63ad
> pubPri #
Result:  0381277ec943a6cd4033171da547bbe93585a8905fb3dad108e8e51e88a4e136ea
> addrPub #
Result:  bc1qvf6gzfhcelpugw84ks677x5zuke46jm946dtpx
```

Check an ALGO address for validity:

```shell
> coin algo
Set active coin to: algorand    Use 'coin' to change.  (name: 'algorand'  symbol: algo  numericalid: 283)
> addr LCSUSBOLNVT6BND6DWWGM4DLVUYJN3PGBT4T7LTCMDMKS7TR7FZAOHOVPE
Address is a valid algorand address:  LCSUSBOLNVT6BND6DWWGM4DLVUYJN3PGBT4T7LTCMDMKS7TR7FZAOHOVPE
```

Derive private keys using different BIP39 derivation paths, and create address from it:

```shell
> coin btc
Set active coin to: bitcoin    Use 'coin' to change.  (name: 'bitcoin'  symbol: btc  numericalid: 0)
> dumpDP
Result:  m/84'/0'/0'/0/0
> priDP
Using derivation path "m/84'/0'/0'/0/0" for coin bitcoin
Result:  df6a78d65fe3c82f020c25be12debd46e58f5f4366381102485ce26c52416a96
> priDP m/84'/0'/0'/0/1
Using derivation path "m/84'/0'/0'/0/1" for coin bitcoin
Result:  19c44359b4953bb3084dd73ba2854f6822de3b6f8f358055a16a1b19e533e37c
> pubPri #
Result:  02222d3889870d36e0c9e788c69a6509eddfb2105309e7733cfa669bb52ba996d1
> addrPub #
Result:  bc1q7ghe6xyx38vdkzs9ryv3gz47mgvpa747z2mcvy
> addr #
Address is a valid bitcoin address:  bc1q7ghe6xyx38vdkzs9ryv3gz47mgvpa747z2mcvy
```

Derive several NANO addresses (BIP39):

```shell
> coin nano
Set active coin to: nano    Use 'coin' to change.  (name: 'nano'  symbol: nano  numericalid: 165)
> dumpDP
Result:  m/44'/165'/0'
> setMnemonic edge defense waste choose enrich upon flee junk siren film clown finish luggage leader kid quick brick print evidence swap drill paddle truly occur
Mnemonic set (24 words).
> addrDefault
Result:  nano_3yyipbgtnd7183k61nkh5mxnt9wpsfhto95mksdqj6s7p45mwj9osai7asad
> addrDP m/44'/165'/0'
Result:  nano_3yyipbgtnd7183k61nkh5mxnt9wpsfhto95mksdqj6s7p45mwj9osai7asad
> addrDP m/44'/165'/1'
Result:  nano_3zni7o8m4dq1aphffnaq5pwseh7rrzhkrz5mpr8bcm68n6u775pbk7csedam
```

Hex and Base64 encoding example:

```shell
> hex Hello
Result:  48656c6c6f
> base64Encode #
Result:  SGVsbG8=
> base64Decode #
Result:  48656c6c6f
> buffer
Last value:  48656c6c6f
3 previous values:
    #1  48656c6c6f
    #2  SGVsbG8=
    #3  48656c6c6f
```


# Coverage

## Coverage Measurement

Wallet-core is a stable project, we value stability and safety over new features.

Test coverage is one important facet of assuring code quality, and we are strict about high test coverage.

### Checking Coverage Summary in CI build

The `Linux CI` and `Linux CI Rust` CI builds (executed on PRs and commits) contain coverage measurement, and summary is available in the build output:

```
Summary coverage rate:
  lines......: 94.5% (14576 of 15426 lines)
  functions..: 95.0% (2688 of 2830 functions)
```

### Detailed Coverage Report

Detailed coverage report can be generated locally. It includes file and line-level info on coverage.

Steps:

* Run `tools/generate-files` to make sure new added files are generated
* Run `cmake` with `-DTW_CODE_COVERAGE=ON` to enable coverage measurement

```shell
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DTW_CODE_COVERAGE=ON
```

* Build tests

```shell
make -Cbuild -j12 tests TrezorCryptoTests
```

* Cleanup any old coverage files, and run unit tests

```shell
find . -name "*.gcda" -exec rm {} \;
./build/trezor-crypto/crypto/tests/TrezorCryptoTests
./build/tests/tests tests --gtest_output=xml
```

* Generate coverage info (slow). With the `html` argument the script will generate HTML report as well:

```shell
./tools/coverage html
```

if you see genhtml (from lcov) error on macOS like below:

```shell
c++filt: Unknown command line argument '--no-strip-underscores'.  Try: '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++filt --help'
c++filt: Did you mean '--no-strip-underscore'?
genhtml: ERROR: c++filt output not as expected (0 vs 11) lines
```

please upgrade `lcov` to min. `1.16`, or patch `genhtml` (for example /usr/local/Cellar/lcov/1.15/libexec/bin/), change `--no-strip-underscores` to `--no-strip-underscore`

Open the generated `coverage/index.html` to view the report.

See also [tools/coverage](https://github.com/trustwallet/wallet-core/blob/master/tools/coverage) and [linux-ci.yml](https://github.com/trustwallet/wallet-core/blob/master/.github/workflows/linux-ci.yml)

## Detailed Rust Coverage Report

Detailed Rust coverage report can be generated locally. It includes file and line-level info on coverage.

Steps:

* Switch to the nightly toolchain and install dev dependencies

```shell
tools/install-rust-dependencies dev
```

* Run Rust tests and generate coverage info (slow). With the `html` argument the script will generate HTML report as well:

```shell
./tools/rust-coverage html
```


# Releasing

Before releasing, update the version numbers in `android/gradle.properties` and `WalletCore.podspec`, then commit the change. Create a new git tag for that version and push (replace 0.0.0 with the actual version number):

```
git tag 0.0.0
git push
git push origin 0.0.0
```

## iOS

Run `bootstrap.sh` then `tools/ios-xcframework-release`. This will build the xcframework binaries, upload them to GitHub Releases, and auto-generate `Package.swift` with the correct checksums for Swift Package Manager.

You need to be authenticated with the GitHub CLI (`gh auth login`) and registered as a repository collaborator to upload release assets.

## Android

Run `bootstrap.sh` then `tools/android-release`. This will build and publish the Android artifacts to [GitHub Packages](https://github.com/trustwallet/wallet-core/packages).

You need the following credentials as environment variables in order to publish:

```
GITHUB_USER=user
GITHUB_TOKEN=token
```

## Docker Hub

We need to release a new prebuilt Docker image every time our dependencies or sources change. To build the docker image(s), see `tools/docker-build`. Use `docker push` to upload to Docker Hub.


# Integration Guide

This Integration Guide is intended for developers building on top of Wallet Core. Typical projects using Wallet Core are *mobile wallets* -- iOS and/or Android apps, and potentially desktop wallets. Wallet Core functionality can prove to be helpful in some backend-side projects as well.

The guide has the following outline:

* [Wallet Core Usage Guide](/developer/wallet-core/integration-guide/wallet-core-usage). In this general guide we describe the basic wallet operations (*wallet creation*, *address derivation*, *transaction signing*) in detail, with some code examples. This is recommended first.
* [iOS Integration Guide](/developer/wallet-core/integration-guide/ios-guide). This is a walkthrough of a sample iOS wallet application.
* [Android Integration Guide](/developer/wallet-core/integration-guide/android-guide). This is a walkthrough of a sample Android wallet application.
* [Server-Side Go Guide](/developer/wallet-core/integration-guide/server-side). Here we provide instructions on how to integrate Wallet Core into a *Go* language backend-side project.


# Usage Guide

We present here an overview of the basic wallet operations. Language-specific samples are provided in step-by-step [guides](/developer/wallet-core/integration-guide).

The covered basic operations are:

* Wallet management
  * Creating a new multi-coin wallet
  * Importing a multi-coin wallet
* Address derivation (receiving)
  * Generating the default address for a coin
  * Generating an address using a custom derivation path (expert)
* Transaction signing (e.g. for sending)

For the examples we use *Bitcoin* and *Ethereum* as sample coins/blockchains.

Note: Wallet Core does not cover communication with blockchain networks (nodes): address derivation is covered, but address balance retrieval not; transaction signing is covered, but broadcasting transactions to the network not.

In this guide we use small code examples from a Swift sample application, but the focus is on the explanations.

## Wallet Management

### Multi-Coin Wallet

The Multi-Coin Wallet is a structure allowing accounts for many coins, all controlled by a single recovery phrase. It is a standard HD Wallet (Hierarchically Derived), employing the standard derivation schemes, interoperable with many other wallets: **BIP39** for recovery phrase, **BIP44**/**BIP84** for account derivation.

### Creating a New Multi-Coin Wallet

When a new wallet is created, a new seed (and thus recovery phrase) is chosen at random.\
\&#xNAN;*After creation, the user has to be informed and guided to backup the recovery phrase.*

The random generation employs secure random generation, as available on the device.

```swift
let wallet = HDWallet(strength: 128, passphrase: "")
```

| Input parameter | Description                                                                                                                                                             |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| *strength*      | The strength of the secret seed. Higher seed means more information content, longer recovery phrase. Default value is **128**, but 256 is also possible.                |
| *passphrase*    | Optional passphrase, used to scramble the seed. If specified, the wallet can be imported and opened only with the passphrase (Not to be confused with recovery phrase). |

### Importing a Multi-Coin Wallet

A previously created wallet can be imported using the recovery phrase. Typical usecases for import are:

* re-importing a wallet later, into a later installation, or
* importing into another device, or
* importing into another wallet app.

If the wallet was created with a passphrase, it is also required.

```swift
let wallet = HDWallet(mnemonic: "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal", passphrase: "")
```

| Input parameter | Description                                                                               |
| --------------- | ----------------------------------------------------------------------------------------- |
| *mnemonic*      | a.k.a. *recovery phrase*. The string of several words that was used to create the wallet. |
| *passphrase*    | Optional passphrase, used to encrypt the seed.                                            |

## Account Address Derivation

Each coin needs a different account, with matching address. Addresses are derived from the multi-coin wallet. Derivation is based on a *derivation path*, which is unique for each coin, but can have other parameters as well. Each coin has a default derivation path, such as `"m/84'/0'/0'/0/0"` for Bitcoin and `"m/44'/60'/0'/0/0"` for Ethereum.

### Generating the Default Address for a Coin

The simplest is to get the default address for a coin -- this requires no further inputs. The address is generated using the default derivation path of the coin.

For example, the default BTC address, derived for the wallet with the mnemonic shown above, with the default BTC derivation path (`m/84'/0'/0'/0/0`) is: `bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd`. For Ethereum, this is `0xA3Dcd899C0f3832DFDFed9479a9d828c6A4EB2A7`.

Here is the sample code fort obtaining the default address for different coins:

```swift
let addressBTC = wallet.getAddressForCoin(coin: .bitcoin)
let addressETH = wallet.getAddressForCoin(coin: .ethereum)
```

### Generating an Address Using a Custom Derivation Path (Expert)

It is also possible to derive addresses using custom derivation paths. This can be done in two steps: first a derived private key is obtained, then an address from it.

> **Warning**: use this only if you are well aware of the semantics of the derivation path used!

> **Security Warning**: if secrets such as private keys are handled by the wallet, even if for a short time, handle with care! Avoid any risk of leakage of secrets!

```swift
let key = wallet.getKey(derivationPath: "m/44\'/60\'/1\'/0/0")   // m/44'/60'/1'/0/0
let address = CoinType.ethereum.deriveAddress(privateKey: key)
```

For example, a second Ethereum address can be derived using the custom derivation path `”m/44'/60’/1’/0/0”` (note the 1 in the third position), yielding address `0x68eF4e5660620976a5968c7d7925753D3Cc40809`.

## Transaction Signing

In general, when creating a new blockchain transaction, a wallet has to:

1. Put together a transaction with relevant fields (source, target, amount, etc.)
2. Sign the transaction, using the account private key. This is done by Wallet Core.
3. Send to a node for broadcasting to the blockchain network.

The exact fields needed for a transaction are different for each blockchain. In Wallet Core, signing input and output parameters are typically represented in a protobuf message (internally needed for serialization for passing through different language runtimes).

A generic, coin-independent signer also exists (*AnySigner*), usable across all supported platforms and languages.

### Bitcoin Transaction Signing

Bitcoin is the first `UTXO` (Unspent Transaction Output) based cryptocurrency / blockchain, if you haven't read the documentation about Bitcoin, we highly recommend you to read [developer glossary](https://bitcoin.org/en/developer-glossary) and [raw transaction format](https://bitcoin.org/en/developer-reference#raw-transaction-format), these will help you understand how to sign a Bitcoin transaction. Wallet Core supports *Bitcoin*, *Bitcoin Cash*, *Zcash*, *Decred* and a few forks.

The most important models in Swift are `BitcoinSigningInput` and `BitcoinUnspentTransaction`

*BitcoinSigningInput*

| Field         | Sample value                               | Description                                                                                                                                  |
| ------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| hash\_type    | BitcoinSigHashType.all                     | *Bitcoin Cash* needs to `or` with `BitcoinSigHashType.fork` (see [Sighash](https://bitcoin.org/en/glossary/signature-hash) for more details) |
| amount        | 10000                                      | Amount (in satoshi) to send (value of new UTXO will be created)                                                                              |
| byteFee       | 1                                          | Transaction fee is `byte_fee x transaction_size`, Wallet Core will calculate the fee for you by default                                      |
| toAddress     | bc1q03h6k5lt6pzfjaanz5mlnmuc7aha2t3nkz7gh0 | Recipient address (Wallet Core will build lock script for you)                                                                               |
| changeAddress | 1AC4gh14wwZPULVPCdxUkgqbtPvC92PQPN         | Address to receive changes, can be empty if you sweep a wallet                                                                               |
| privateKey    | \[Data(...), Data(...)]                    | Private keys for all the input UTXOs in this transaction                                                                                     |
| scripts       | \[`script_hash`: Data(...)]                | Redeem scripts indexed by script hash, usually for `P2SH`, `P2WPKH` or `P2WSH`                                                               |
| utxo          | \[*BitcoinUnspentTransaction*]             | All the input UTXOs, see below table for more details                                                                                        |
| useMaxAmount  | false                                      | Consume all the input UTXOs, it will affect fee estimation and number of output                                                              |
| coinType      | 145                                        | [SLIP44 Index](https://github.com/trustwallet/wallet-core/blob/master/docs/registry.md) coin type, default is 0 / Bitcoin                    |

*BitcoinUnspentTransaction*

| Field    | Sample value                                         | Description                                                                                                                 |
| -------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| outPoint | *BitcoinOutPoint(hash:index:)*                       | Refer to a particular transaction output, consisting of a 32-byte TXID and a 4-byte output index number (vout)              |
| amount   | 10000                                                | A value field for transferring zero or more satoshis                                                                        |
| script   | 0x76a9146cfa0e96c34fce09c0e4e671fcd43338c14812e588ac | A script (ScriptPubKey) included in outputs which sets the conditions that must be fulfilled for those satoshis to be spent |

Here is the Swift sample code for signing a real world Bitcoin Cash [transaction](https://blockchair.com/bitcoin-cash/transaction/96ee20002b34e468f9d3c5ee54f6a8ddaa61c118889c4f35395c2cd93ba5bbb4)

```swift
let utxoTxId = Data(hexString: "050d00e2e18ef13969606f1ceee290d3f49bd940684ce39898159352952b8ce2")! // latest utxo for sender, "txid" field from blockbook utxo api: https://github.com/trezor/blockbook/blob/master/docs/api.md#get-utxo
let privateKey = PrivateKey(data: Data(hexString: "7fdafb9db5bc501f2096e7d13d331dc7a75d9594af3d251313ba8b6200f4e384")!)!
let address = CoinType.bitcoinCash.deriveAddress(privateKey: privateKey)

let utxo = BitcoinUnspentTransaction.with {
    $0.outPoint.hash = Data(utxoTxId.reversed()) // reverse of UTXO tx id, Bitcoin internal expects network byte order
    $0.outPoint.index = 2                        // outpoint index of this this UTXO, "vout" field from blockbook utxo api
    $0.outPoint.sequence = UINT32_MAX
    $0.amount = 5151                             // value of this UTXO, "value" field from blockbook utxo api
    $0.script = BitcoinScript.lockScriptForAddress(address: address, coin: .bitcoinCash).data // Build lock script from address or public key hash
}

let input = BitcoinSigningInput.with {
    $0.hashType = BitcoinScript.hashTypeForCoin(coinType: .bitcoinCash)
    $0.amount = 600
    $0.byteFee = 1
    $0.toAddress = "1Bp9U1ogV3A14FMvKbRJms7ctyso4Z4Tcx"
    $0.changeAddress = "1FQc5LdgGHMHEN9nwkjmz6tWkxhPpxBvBU" // can be same sender address
    $0.utxo = [utxo]
    $0.privateKey = [privateKey.data]
}

let output: BitcoinSigningOutput = AnySigner.sign(input: input, coin: .bitcoinCash)
guard output.error.isEmpty else { return }
// encoded transaction to broadcast
print(output.encoded)
```

It's worth to note that you can also calcuate fee and change manually (by using a `BitcoinTransactionPlan` struct)\
Below is another real world Zcash [transparent transaction](https://explorer.zcha.in/transactions/ec9033381c1cc53ada837ef9981c03ead1c7c41700ff3a954389cfaddc949256) demonstrate this

```swift
let utxos = [
    BitcoinUnspentTransaction.with {
        $0.outPoint.hash = Data(hexString: "53685b8809efc50dd7d5cb0906b307a1b8aa5157baa5fc1bd6fe2d0344dd193a")!
        $0.outPoint.index = 0
        $0.outPoint.sequence = UINT32_MAX
        $0.amount = 494000
        $0.script = Data(hexString: "76a914f84c7f4dd3c3dc311676444fdead6e6d290d50e388ac")!
    }
]

let input = BitcoinSigningInput.with {
    $0.hashType = BitcoinSigHashType.all.rawValue
    $0.amount = 488000
    $0.toAddress = "t1QahNjDdibyE4EdYkawUSKBBcVTSqv64CS"
    $0.coinType = CoinType.zcash.rawValue
    $0.privateKey = [Data(hexString: "a9684f5bebd0e1208aae2e02bc9e9163bd1965ad23d8538644e1df8b99b99559")!]
    $0.plan = BitcoinTransactionPlan.with {
        $0.amount = 488000
        $0.fee = 6000
        $0.change = 0
        // Sapling branch id
        $0.branchID = Data(hexString: "0xbb09b876")!
        $0.utxos = utxos
    }
}

let output: BitcoinSigningOutput = AnySigner.sign(input: input, coin: .zcash)

// encoded transaction to broadcast
print(output.encoded)
```

Besides [orignal Bitcoin RPC](https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list), there are many other APIs / block explorer can get UTXO and broadcast raw transaction, like: insight api, trezor blockbook, blockchain com, blockchair api.

### Ethereum Transaction Signing

A simple Ethereum send transaction needs the following fields:

| Field    | Sample value | Description                                                                               |
| -------- | ------------ | ----------------------------------------------------------------------------------------- |
| chainID  | 1            | Network selector, use 1 for mainnet (see <https://chainid.network> for more)              |
| nonce    | 1            | The count of the number of outgoing transactions, starting with 0                         |
| gasPrice | 3600000000   | The price to determine the amount of ether the transaction will cost                      |
| gasLimit | 21000        | The maximum gas that is allowed to be spent to process the transaction                    |
| to       | \<address>   | The account the transaction is sent to, if empty, the transaction will create a contract  |
| value    | 100000000    | The amount of ether to send                                                               |
| data     |              | Could be an arbitrary message or function call to a contract or code to create a contract |

Several parameters, like the current nonce and gasPrice values can be obtained from Ethereum node RPC calls (see [Ethereum JSON-RPC Specification](https://ethereum.org/en/developers/docs/apis/json-rpc/), e.g., *eth\_gasPrice*).

Code example to fill in the signer input parameters:

```swift
let input = EthereumSigningInput.with {
    $0.chainID = Data(hexString: "01")!
    $0.gasPrice = Data(hexString: "d693a400")! // decimal 3600000000
    $0.gasLimit = Data(hexString: "5208")! // decimal 21000
    $0.toAddress = "0xC37054b3b48C3317082E7ba872d7753D13da4986"
    $0.transaction = EthereumTransaction.with {
       $0.transfer = EthereumTransaction.Transfer.with {
           $0.amount = Data(hexString: "0348bca5a16000")!
       }
    }
    $0.privateKey = wallet.getKeyForCoin(coin: .ethereum).data
}
```

Then Signer is invoked, and the signed and encoded output retrieved:

```swift
let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum)
print(" data:   ", output.encoded.hexString)
```

For more details on Ethereum transactions, check the Ethereum documentation. A few resources are here:

* <https://medium.com/@codetractio/inside-an-ethereum-transaction-fa94ffca912f>
* <https://kauri.io/article/7e79b6932f8a41a4bcbbd194fd2fcc3a/v2/ethereum-101-part-4-accounts-transactions-and-messages>
* <https://github.com/ethereumbook/ethereumbook/blob/develop/06transactions.asciidoc>

Consult the complete sample applications for more details.


# iOS Integration Guide

Wallet Core is available on the iOS platform, it comes with *Swift* bindings. In this guide we show how to use it.

A sample application is available at: <https://github.com/trustwallet/wallet-core/tree/master/samples/osx> .

## Prerequisites

* [*CocoaPods*](https://cocoapods.org/). If you don't have it, install it by `gem install cocoapods`.
* *Xcode* toolchain
* Wallet Core library

## Adding Library Dependency

An easy way to add Wallet Core dependency to an iOS project is through *CocoaPods*, like this (the exact version may change in the future):

```
  pod 'TrustWalletCore'
```

The dependency can be installed simply by `pod install`:

```shell
pod install
```

SPM is also supported. In Xcode, go to **File → Add Package Dependencies** and enter the repository URL:

```
https://github.com/trustwallet/wallet-core
```

Select the desired version tag. Then add the libraries to your target's dependencies:

```swift
.product(name: "WalletCore", package: "WalletCore"),
.product(name: "WalletCoreSwiftProtobuf", package: "WalletCore"),
```

## Code Examples

In the following sections we show code examples for some common funcions. Please refer to the [Wallet Usage Guide](/developer/wallet-core/integration-guide/wallet-core-usage) for detailed explanations.

Accessing Wallet Core functionality requires one import statement:

```swift
import WalletCore
```

### Wallet Management

Creating or Importing a Multi-Coin HD Wallet

```swift
let wallet = HDWallet(strength: 128, passphrase: "")!
```

```swift
let wallet = HDWallet(mnemonic: "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal", passphrase: "")!
```

### Account Address Derivation

Generating the Default Address for a Coin

```swift
let addressBTC = wallet.getAddressForCoin(coin: .bitcoin)
let addressETH = wallet.getAddressForCoin(coin: .ethereum)
```

Generating an Address Using a Custom Derivation Path (Expert)

```swift
let key = wallet.getKey(derivationPath: "m/44\'/60\'/1\'/0/0")   // m/44'/60'/1'/0/0
let address = CoinType.ethereum.deriveAddress(privateKey: key)
```

### Transaction Signing

In general, when creating a new blockchain transaction, a wallet has to:

1. Put together a transaction with relevant fields (source, target, amount, etc.)
2. Sign the transaction, using the account private key. This is done by Wallet Core.
3. Send to a node for broadcasting to the blockchain network.

Ethereum Transaction Signing

Code example to fill in signer input parameters, perform signing, and retrieve encoded result:

```swift
let signerInput = EthereumSigningInput.with {
    $0.chainID = Data(hexString: "01")!
    $0.gasPrice = Data(hexString: "d693a400")! // decimal 3600000000
    $0.gasLimit = Data(hexString: "5208")! // decimal 21000
    $0.toAddress = "0xC37054b3b48C3317082E7ba872d7753D13da4986"
    $0.transaction = EthereumTransaction.with {
       $0.transfer = EthereumTransaction.Transfer.with {
           $0.amount = Data(hexString: "0348bca5a16000")!
       }
    }
    $0.privateKey = wallet.getKeyForCoin(coin: .ethereum).data
}
let output: EthereumSigningOutput = AnySigner.sign(input: signerInput, coin: .ethereum)
print(" data:   ", output.encoded.hexString)
```


# Android Integration Guide

Wallet Core is available on the Android platform, through Java/JNI bindings. In this guide we show how to use it.

A sample application is available at: <https://github.com/trustwallet/wallet-core/tree/master/samples/android> .

## Prerequisites

* *Android Studio*
* *Android NDK Support plugin*

## Adding Library Dependency

Android releases are hosted on [GitHub packages](https://github.com/trustwallet/wallet-core/packages/700258), It needs authentication to download packages, please checkout [this guide from GitHub](https://docs.github.com/en/packages/guides/configuring-gradle-for-use-with-github-packages#installing-a-package) for more details.

We recommend to create a non-expiring and readonly token for accessing GitHub packages, and add it to `local.properties` of your Android Studio project locally.

Generate a token [here](https://github.com/settings/tokens):

![](/files/q2vOrmZM6ESfyfm2Z1dE)

Add this dependency to build.gradle:

```groovy
dependencies {
    implementation "com.trustwallet:wallet-core:<latest_tag>"
}
```

Add `maven` and `credentials` (`local.properties` for local or system environment variables CI)

```groovy

Properties properties = new Properties()
File localProps = new File(rootDir.absolutePath, "local.properties")
if (localProps.exists()) {
    properties.load(localProps.newDataInputStream())
} else {
    println "local.properties not found"
}

allprojects {
    repositories {
        maven {
            url = uri("https://maven.pkg.github.com/trustwallet/wallet-core")
            credentials {
                username = properties.getProperty("gpr.user") as String?: System.getenv("GITHUB_USER")
                password = properties.getProperty("gpr.key") as String?: System.getenv("GITHUB_TOKEN")
            }
        }
    }
}
```

## Code Examples

In the following sections we show code examples for some common funcions. Please refer to the [Wallet Usage Guide](/developer/wallet-core/integration-guide/wallet-core-usage) for detailed explanations.

### Wallet Management

First thing we need is to load JNI library

```kotlin
init {
    System.loadLibrary("TrustWalletCore")
}
```

Creating or Importing a Multi-Coin HD Wallet

```kotlin
val wallet = HDWallet(128, "")
```

```kotlin
val wallet = HDWallet("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal", "")
```

### Account Address Derivation

Generating the Default Address for a Coin

```kotlin
val addressBTC = wallet.getAddressForCoin(CoinType.BITCOIN)
val addressETH = wallet.getAddressForCoin(CoinType.ETHEREUM)
```

Generating an Address Using a Custom Derivation Path (Expert)

```kotlin
val key = wallet.getKey(CoinType.ETHEREUM, "m/44\'/60\'/1\'/0/0")   // m/44'/60'/1'/0/0
val address = CoinType.ETHEREUM.deriveAddress(key)
```

### Transaction Signing

In general, when creating a new blockchain transaction, a wallet has to:

1. Put together a transaction with relevant fields (source, target, amount, etc.)
2. Sign the transaction, using the account private key. This is done by Wallet Core.
3. Send to a node for broadcasting to the blockchain network.

Ethereum Transaction Signing

Code example to fill in signer input parameters, perform signing, and retrieve encoded result:

```kotlin
val signerInput = Ethereum.SigningInput.newBuilder().apply {
    chainId = ByteString.copyFrom(BigInteger("01").toByteArray())
    gasPrice = BigInteger("d693a400", 16).toByteString() // decimal 3600000000
    gasLimit = BigInteger("5208", 16).toByteString()     // decimal 21000
    toAddress = dummyReceiverAddress
    transaction = Ethereum.Transaction.newBuilder().apply {
       transfer = Ethereum.Transaction.Transfer.newBuilder().apply {
           amount = BigInteger("0348bca5a16000", 16).toByteString()
       }.build()
    }.build()
    privateKey = ByteString.copyFrom(secretPrivateKey.data())
}.build()
val output = AnySigner.sign(signerInput, CoinType.ETHEREUM, Ethereum.SigningOutput.parser())
println("Signed transaction: \n${output.encoded.toByteArray().toHexString()}")
```


# Server-Side

If your server application (most likely on Linux) language supports [FFI](https://en.wikipedia.org/wiki/Foreign_function_interface) to C, it is possible to call wallet core.

## Go

Here is a step by step example using [cgo](https://golang.org/cmd/cgo/), with the Wallet Core docker image.

1. Run `docker run -it trustwallet/wallet-core` The library is already built in this image (Build instructions [here](/developer/wallet-core/developing-the-library/building)). Note: may not be the most recent version.
2. Install Go: `apt-get update && apt-get install golang-go`
3. A complete Go sample application is available at [`samples/go`](https://github.com/trustwallet/wallet-core/tree/master/samples/go) in the repository. It uses a `tw/core` wrapper package over the CGo bindings. Build and run it:

```shell
cd samples/go && go build -o main && ./main
```

4. You might want to copy and run `main` outside of the docker container; make sure you have `libstdc++6` and `libc++abi1` installed on your host Ubuntu.

## Node.js

1. Install the package from NPM:

```shell
npm install @trustwallet/wallet-core
```

2. A TypeScript sample application is available at [`samples/node`](https://github.com/trustwallet/wallet-core/tree/master/samples/node) in the repository. Check [wasm/tests](https://github.com/trustwallet/wallet-core/tree/master/wasm/tests) for further API usage examples.


# References


# FAQ

## General

### Does Wallet Core support Windows?

A: We don't support Windows officially, the community has a fork for Windows, you can find it [here](https://github.com/kaetemi/wallet-core-windows).

### Does Wallet Core support Dart / Flutter?

A: We don't support it officially, the community has a fork for Dart / Flutter, you can find it [here](https://github.com/weishirongzhen/flutter_trust_wallet_core)

### Does Wallet Core support React Native?

A: Not now, but you can try to wrap it using [Native Module](https://reactnative.dev/docs/native-modules-intro) or [JavaScript Interfaces (JSI)](https://reactnative.dev/architecture/glossary#javascript-interfaces-jsi), one example is [here](https://github.com/Liamandrew/react-native-wallet-core).

### I can't install Wallet Core for my Android project!

A: Take a look at `Adding Library Dependency` section in [Android Integration Guide](/developer/wallet-core/integration-guide/android-guide), we have detailed instructions for installing the package.

### Is there any HTTP API to use Trust Wallet service?

A: Nope.

## API

### Does Wallet Core support WIF?

A: No, Here are some reasons:

* WIF (Wallet Import Format) is just a private key encoded in Base58-check format, you can decode it using `Base58` class.
* It's cumbersome to support different prefix byte for all networks (mainly Bitcoin and forks)
* Hex string encoding is a more widely used format.

### Does Wallet Core have a method to verify an address format?

A: Yes, There is a generic `AnyAddress` class to represent an address for any blockchain you can use `AnyAddress.isValid()` to validate if an address is valid.

### How to create `HDWallet` from private key?

A: `HDWallet` class is short for `Hierarchical Deterministic Wallet`, which is a way to deterministically generate a tree of keys from a single seed (aka bip39 recovery phrase). If you only have a private key, you can use `PrivateKey` class directly, no way to create `HDWallet`.

You can read [bip32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), [bip39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki), [bip44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) for more information.

### Where do I find transaction signing examples?

A: You can find some on [Usage Guide](/developer/wallet-core/integration-guide/wallet-core-usage), the comprehensive and up-to-date examples are in tests folder:

* C++ tests: <https://github.com/trustwallet/wallet-core/tree/master/tests>
* Swift tests: <https://github.com/trustwallet/wallet-core/tree/master/swift/Tests>
* Kotlin tests: <https://github.com/trustwallet/wallet-core/tree/master/android/app/src/androidTest/java/com/trustwallet/core/app>
* TypeScript tests: <https://github.com/trustwallet/wallet-core/tree/master/wasm/tests>

## Blockchain

### How to query the balance / tokens of an address?

A: Wallet Core doesn't provide this feature yet, it also differs from chain to chain, you should check out the blockchain's official RPC or API to see how to query the balance.

For instance, you can use [`eth_getbalance`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance) and [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) to query the balance (and token balance) of an Ethereum or EVM compatible address.

### How to send signed transaction?

A: Wallet Core doesn't provide this feature yet, it also differs from chain to chain, you should check out the blockchain's official RPC or API to see how to send a signed transaction.

For instance, you can use [`eth_sendRawTransaction`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction) to send a signed raw transaction to Ethereum or EVM compatible chain.

### Bitcoin signing error :Invalid transaction. Error: bad-txns-inputs-missingorspent

A: Usually this error means the node can't find the unspent transaction (UTXO) you are trying to spend, you can check if the transaction hash is correct, Bitcoin implementation in Wallet Core expects the transaction id is network byte order (big endian), you can try to reverse the bytes of the transaction hash.

### Does it support Bitcoin / Ethereum testnet?

A: Wallet Core doesn't support any testnet in general:

* no testnet network entry in `registry.json`
* no method to generate testnet address for Bitcoin etc.
* extra maintenance effort and we always require mainnet transaction signing test.

But for some networks like Ethereum, the testnet just has a different chain id, you can specify chain id when you signing a transaction.

### How to generate legacy Bitcoin address?

A: `AnyAddress` generates SegWit address by default for Bitcoin, Wallet Core offers another class `BitcoinAddress` for legacy address, you can see all the methods [here](https://github.com/trustwallet/wallet-core/blob/master/include/TrustWalletCore/TWBitcoinAddress.h).

### Does it support ERC20 / BEP20?

A: Yes

### Different Polkadot address derived from same secret phrase.

A: Polkadot supports multiple elliptic curve and signature schemes:

* The vanilla `ed25519` implementation using Schnorr signatures.
* The Schnorrkel/Ristretto `sr25519` variant using Schnorr signatures.
* ECDSA signatures on `secp256k1`

It's might be incompatible with other wallets because Wallet Core currently only supports `ed25519`.

For more information, please refer to [Polkadot Wiki](https://wiki.polkadot.network/docs/learn-keys#account-keys).


# Barz - Smart Wallet

## Introduction

[Barz](https://github.com/trustwallet/barz) is an [ERC 4337](https://eips.ethereum.org/EIPS/eip-4337) compatible Smart Contract Wallet focused on a secure and smarter experience for users through modular, upgradeable, and secure designs.

![Barz](/files/kDIZ0ZfnbL0N9WTCK8fe)

Check out our blog series for details!

[1. Introducing Barz. Trust Wallet's Smart Wallet Solution](/developer/barz-smart-wallet/introducing-barz-trustwallet-smart-wallet-solution)

[2. Cutting Diamonds: How to Make Accounts Awesome](/developer/barz-smart-wallet/cutting-diamonds-how-to-make-accounts-awesome)

[3. Build with Trust Wallet and Barz, A Comprehensive Guide to Integrating Barz with AA SDK](https://github.com/trustwallet/developer/blob/master/barz-smart-wallet/build-with-trust-wallet-and-barz-aa-sdk.md)

[Github Codebase](https://github.com/trustwallet/barz)

## License

Barz is available under the Apache-2.0 license. See the [LICENSE](https://github.com/trustwallet/barz/blob/main/LICENSE) file for more information.


# Introducing Barz. TrustWallet's Smart Wallet Solution

By [David Kim](https://twitter.com/0xDavidKim)

Special thanks to [Luis Ocegueda](https://twitter.com/luis_oce) and [Artem Goryunov](https://twitter.com/ArtemGoryunov) for their feedback and contributions.

This is the first of an article series on Barz.

1. [Introducing Barz: Trust Wallet’s Smart Wallet Solution](https://github.com/trustwallet/developer/blob/master/introducing-barz-trustwallet-smart-wallet-solution/README.md)
2. [Cutting Diamonds: How to make Accounts Awesome](https://github.com/trustwallet/developer/blob/master/cutting-diamonds-how-to-make-accounts-awesome/README.md)
3. For Builders By Builders: Introducing the Barz SDK
4. Multi-tier Module system. A secure foundation for open innovation

In February 2024, we successfully launched [Swift Wallet](https://trustwallet.com/swift), an Account Abstraction Wallet to offer our users a more secure, smarter wallet. Swift Wallet introduced innovative features including Passkeys, gas payment with 200+ tokens, 1 step swap & bridging.

Today, we are open sourcing our robust Smart Wallet solution “Barz”.

Let’s dive into the details of how we got here!

## Why we built Barz

Trust Wallet, empowers more than 122 million Web3 users worldwide, understands the common issues and inconveniences users face when using wallets.

Many users struggle with:

* Improper management of their Mnemonic Phrases
* Granting excessive privileges to a dApp for a single transaction.
* Ability to create multiple automated tasks, e.g. schedule payments.

While the issues and challenges with mnemonic seed phrases are well known, there are larger security and UX issues as more users are onboarded to Web3.

To provide a solution to these challenges and limitations and ultimately drive more adoption of Web3, we decided to develop a Smart Wallet through Account Abstraction, which offers a fundamental solution overcoming these limitations - **Barz**.

## Barz

[Barz](https://github.com/trustwallet/barz) is an [ERC 4337](https://eips.ethereum.org/EIPS/eip-4337) compatible Smart Contract Wallet focused on a secure and smarter experience for users through modular, upgradeable, and secure designs.

We aggregated the benefits from each wallet and pioneered new approaches to provide best-in-class service to users. Barz is also one of the first Passkeys based 4337 account that launched in production.

Barz, at its core is a proxy contract that utilizes the [Diamond Proxy Pattern(EIP 2535)](https://eips.ethereum.org/EIPS/eip-2535) for a scalable and secure addition of use cases with high security threshold.

Barz system currently has 12 fully built Facet implementations that can provide features of:

* Account Recovery
* Lock
* Signature Migration
* Guardian
* Restrictions (Custom Rules for Transactions)
* Diverse Validation Mechanisms
  * Secp256k1 - Default EVM Scheme (e.g., Mnemonic phrase)
  * Secp256r1 - Passkeys, Okta
  * Multi-sig

![Barz Architecture Diagram](/files/kDIZ0ZfnbL0N9WTCK8fe)

Let’s dive into Diamond Proxy pattern and how it works with ERC 4337. We’ll dive into the optimization points we made to Diamond for Barz in our next article.

### Diamond

Diamond is a modular smart contract system enabled by a multi-faceted proxy stated in EIP-2535.

A multi-faceted proxy is different from the conventional proxy pattern like [UUPS(Universal Upgradeable Proxy Standard)](https://eips.ethereum.org/EIPS/eip-1822) and TransparentUpgradeable where they have a single implementation to route the call to.

![Conventional Proxy Pattern e.g., UUPS](/files/UxsXQWeTGTmn0VjGm1UU)

For example, a UUPS based proxy smart contract stores the single implementation contract address in the EIP-1967 based storage slot and performs upgrade by modifying the storage slot.

```solidity
 /**
  * @dev Storage slot with the address of the current implementation.
  * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
  */
  // solhint-disable-next-line private-vars-leading-underscore
  bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
```

```solidity
/**
 * @dev Stores a new address in the ERC-1967 implementation slot.
 */
function _setImplementation(address newImplementation) private {
    if (newImplementation.code.length == 0) {
        revert ERC1967InvalidImplementation(newImplementation);
    }
    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
```

The proxy would then delegate all calls to the implementation contract through a fallback function that makes a `delegatecall` for all calls that comes with `msg.data`.

```solidity
fallback() external payable virtual {
      assembly {
      // Copy msg.data. We take full control of memory in this inline assembly
      // block because it will not return to Solidity code. We overwrite the
      // Solidity scratch pad at memory position 0.
      calldatacopy(0, 0, calldatasize())

      // Call the implementation.
      // out and outsize are 0 because we don't know the size yet.
      let result := delegatecall(gas(), _implementation(), 0, calldatasize(), 0, 0)

      // Copy the returned data.
      returndatacopy(0, 0, returndatasize())

      switch result
      // delegatecall returns 0 on error.
      case 0 {
          revert(0, returndatasize())
      }
      default {
          return(0, returndatasize())
      }
   }
}
```

Unlike the UUPS pattern we saw above, Diamond Proxy has multiple “implementation” smart contracts, which are called Facets.

But Diamond not only includes how Proxy and Facets interact but proposes a comprehensive approach to manage the following components of a proxy contract:

* upgrade
* view
* storage

Let’s dive into the details of how Diamond works under the hood.

![Diamond Proxy Pattern](/files/xJ9yjUiTr9um8dPqXgPd)

Considering Diamond has multiple implementation contracts called Facets, Diamond requires a routing logic to route the function call to the correct corresponding facet.

The core routing logic is implemented through a mapping of `bytes4` type which holds the function selector as the key and an `address` which holds the Facet contract address as value.

```solidity
mapping (bytes4 => address) public selectorTofacet;
```

When a function call is made to the contract and gets routed to the `fallback` function, the `fallback` function will fetch the function selector from the `calldata` through `msg.sig` and make a `delegatecall` to the facet if the corresponding facet exists and reverts otherwise.

```solidity
// Find facet for function that is called and execute the
// function if a facet is found and return any value.
fallback() external payable {
  // get facet from function selector
  address facet = selectorTofacet[msg.sig];
  require(facet != address(0));
  // Execute external function from facet using delegatecall and return any value.
  assembly {
    // copy function selector and any arguments
    calldatacopy(0, 0, calldatasize())
    // execute function call using the facet
    let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
    // get any return value
    returndatacopy(0, 0, returndatasize())
    // return any return value or error back to the caller
    switch result
      case 0 {revert(0, returndatasize())}
      default {return (0, returndatasize())}
  }
}
```

This multi-faceted proxy pattern provides a benefit of modular implementation designs by enabling each facet to be grouped into a specific domain of functionality.

For example, Account Facet could hold account related logic like `execute()`, `executeBatch()` while Token Receiver Facet could hold logic like `onERC721Received()`, `tokensReceived()`.

For a better separation of Facet logic and storage, the Diamond standard also provides an approach of `DiamondStorage` mainly for a specific Facet’s storage and `AppStorage` which is more suitable for shared storage between Facets.

`DiamondStorage` relies on a Solidity struct that contains set variables for the Facet and stores it in the designated namespace storage slot. It is particularly good for isolating or compartmenting state variables to specific facets or functionality.

```solidity
/* Example of Diamond Storage */
struct Secp256k1VerificationStorage {
    address signer;
}

bytes32 constant K1_STORAGE_POSITION =
    keccak256(
        "v0.trustwallet.diamond.storage.Secp256k1VerificationStorage"
    );

function k1Storage()
    internal
    pure
    returns (Secp256k1VerificationStorage storage ds)
{
    bytes32 storagePosition = K1_STORAGE_POSITION;
    assembly {
        ds.slot := storagePosition
    }
}
```

As the storage slot will be intentionally different to prevent storage collision, this provides a scalable approach of utilizing storage with Multiple Facets compared to the approach of using the default EVM Storage Slot.

This concept is also utilized in the Barz implementation to detach the storage between facets.

![Illustrated example of Barz storage per Facet](/files/jCRnPagV1NJ7a4g8a4OB)

In contrast, `App Storage` is another type of storage pattern that is more suitable for storage variables that are shared among facets.

App Storage also uses the Struct to define the storage, however, uses the storage slot `0` unlike the Diamond Storage which used a custom storage slot.

For example, Barz stores the address of the `EntryPoint` contract and `signerMigration` flag which is shared across multiple facets.

```solidity
struct AppStorage {
    mapping(uint256 => InitializersStorage) initStorage;
    uint8 signerMigration;
    bytes4 validateOwnerSignatureSelector;
    IEntryPoint entryPoint;
    IFacetRegistry facetRegistry;
    mapping(uint256 => Lock) locks;
}

function appStorage() internal pure returns (AppStorage storage ds) {
    assembly {
        ds.slot := 0
    }
}
```

Let’s have a look on how Diamonds perform upgrades.

To register a new facet or remove/replace them from Diamond, the contract should comply with the standard interface of `diamondCut()`.

```solidity
interface IDiamondCut {

    enum FacetCutAction {Add, Replace, Remove}
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }
    
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;
    
}
```

`diamondCut()` normally performs 4 main steps

1. Ownership Check
   1. This is crucial considering that a malicious Diamond can overwrite storage or perform malicious activities
2. Facet Check
   1. Check if the Facet is indeed a contract, check if the selector is okay to be added. Diamond does not allow multiple facets from registering an identical function selector.
3. Add/Remove/Replace Facet’s function selector and its corresponding actions
4. Perform Diamond Init
   1. Diamond Init is an approach for one-time initialization for Diamonds similar to constructor.

Once the `diamondCut()` is called to the Diamond, the Diamond should store the mapping of `functionSelectors` and the `Facet address` to route the call from the `fallback` function.

Within the `diamondCut()` execution, Diamond also performs a process called `Diamond Init` for initializing/uninitializing state variables. This is useful during the installation and uninstallation of Facets to clean up storage.

This is enabled by making a `delegatecall` to the `_init` address with the provided `calldata` from `diamondCut()`.

For example, below is an implementation of Diamond Init contract to add ERC-165 based `supportedInterfaces()` check.

```solidity
// You can add parameters to this function in order to pass in 
// data to set your own state variables
function init() external {
    // adding ERC165 data
    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
    ds.supportedInterfaces[type(IERC165).interfaceId] = true;
    ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
    ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
    ds.supportedInterfaces[type(IERC173).interfaceId] = true;
}
```

Now as we’ve checked how storage and upgrade work for Diamonds, let’s check the approaches to view the status of the Diamond - `DiamondLoupe`.

`DiamondLoupe` is a standardized interface to look into Diamond. This allows external components and entities to check which Facet and Function Selectors are registered to the `Diamond`.

```solidity
// A loupe is a small magnifying glass used to look at diamonds.
// These functions look at diamonds
interface IDiamondLoupe {
    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses() external view returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
}
```

The method `facets()` returns the whole information about its Facet mappings.

`facetFunctionSelectors()` returns the list of function selectors corresponding to the given facet.

`facetAddresses()` returns the list of all facets registered to the Diamond.

`facetAddress()` returns the facet address of the corresponding function selector.

By complying with this standard interface, Diamond can transparently show its state to external entities while being compatible with tools like [louper.dev](http://louper.dev).

For example, this is an overview of Barz seen from [louper.dev](http://louper.dev) tool:

[Overview of Barz from Louper - The Ethereum Diamond Inspector](https://louper.dev/diamond/0xbD741C9A6c3C197F863F0657A15D2E9070534BE3?network=polygon)

![Overview of Barz account from louper.dev](/files/MT36qviSspVzWMXneibf)

### ERC 4337 Account with Diamond

From an ERC 4337 account contract perspective, there are 2 main aspects to handle:

* Validation
* Execution

For Validation, the account should implement the `IAccount` interface specified in the ERC 4337 standard.

```solidity
interface IAccount {
  function validateUserOp
      (UserOperation calldata userOp, bytes32 userOpHash, address aggregator, uint256 missingAccountFunds)
      external returns (uint256 sigTimeRange);
}
```

For execution, it can implement its own execution methods like `execute()` and `executeBatch()` .

An example of Barz handling the 4337 logic in a modular approach through Diamond can be seen from the separation of Account Facet and Verification Facet during initialization and execution.

In the `BarzFactory` code below, users can create an account with any verification facet with their preferred signature scheme by providing the address in the `_verificationFacet` and the corresponding `_owner` for initialization.

```solidity
    /**
     * @notice Creates the Barz with a single call. It creates the Barz contract with the given verification facet
     * @param _verificationFacet Address of verification facet used for creating the barz account
     * @param _owner Public Key of the owner to initialize barz account
     * @param _salt Salt used for deploying barz with create2
     * @return barz Instance of Barz contract deployed with the given parameters
     */
    function createAccount(
        address _verificationFacet,
        bytes calldata _owner,
        uint256 _salt
    ) external override returns (Barz barz) {
        address addr = getAddress(_verificationFacet, _owner, _salt);
        uint codeSize = addr.code.length;
        if (codeSize > 0) {
            return Barz(payable(addr));
        }
        barz = new Barz{salt: bytes32(_salt)}(
            accountFacet,
            _verificationFacet,
            entryPoint,
            facetRegistry,
            defaultFallback,
            _owner
        );
        emit BarzDeployed(address(barz));
    }
```

Signer will be initialized using the `verificationFacet` provided in the `createAccount()` function.

This allows `BarzFactory` and `AccountFacet`, together with all the remaining Facets to be ***agnostic*** to the signature validation mechanism and focus on its core logic.

![Barz deploment and initalization flow](/files/XWK4IWe51Bg68ARaMrAm)

This can also be applied during the validation of UserOperation e.g., `validateUserOp()`.

With the separation of Account and Verification logic through modular designs, it enables the account to dynamically switch the signer and signature scheme depending on user’s needs and wants.

It also helps the codebase to be clean and focus on its domain logic which helps reduce potential code bugs and unwanted complexity coming from interdependencies between logic.

```solidity
    function _validateSignature(
        UserOperation calldata _userOp,
        bytes32 _userOpHash
    ) internal override returns (uint256 validationData) {
        // Get Facet with Function Selector
        address facet = LibLoupe.facetAddress(s.validateOwnerSignatureSelector);
        if (facet == address(0))
            revert AccountFacet__NonExistentVerificationFacet();

        // Make function call to VerificationFacet
        bytes memory validateCall = abi.encodeWithSelector(
            s.validateOwnerSignatureSelector,
            _userOp,
            _userOpHash
        );
        (bool success, bytes memory result) = facet.delegatecall(validateCall);
        if (!success) revert AccountFacet__CallNotSuccessful();
        validationData = uint256(bytes32(result));
        if (validationData == 0) emit VerificationSuccess(_userOpHash);
        else emit VerificationFailure(_userOpHash);
    }
```

`Account Facet` delegates the validation of UserOperation signature to the `Verification Facet` and only propagates the result from the `Verification Facet`.

![Barz UserOp Validation Flow](/files/xsKnXBchpRsUx1O8HXO4)

## Conclusion

The Barz Smart Wallet Architecture utilizing Diamond allows modular and flexible development of a wide array of use cases. It allows each Facets to focus on its specific business logic while providing the flexibility to easily switch each component and maintain interoperability.

In our next article, we’ll share the optimizations we did to make Diamonds much better for building smart wallets.

Stay tuned for our next article series and releases of powerful use cases of smart wallet built on [Barz](https://github.com/trustwallet/barz).


# Cutting Diamonds: How to make Accounts Awesome

By [David Kim](https://twitter.com/0xDavidKim)

Special thanks to [Luis Ocegueda](https://twitter.com/luis_oce), [Artem Goryunov](https://twitter.com/ArtemGoryunov) and Dami Odufuwa for their feedback and contributions.

This is the second of an article series on Barz.

1. [Introducing Barz: Trust Wallet’s Smart Wallet Solution](https://github.com/trustwallet/developer/blob/master/introducing-barz-trustwallet-smart-wallet-solution/README.md)
2. [Cutting Diamonds: How to make Accounts Awesome](https://github.com/trustwallet/developer/blob/master/cutting-diamonds-how-to-make-accounts-awesome/README.md)
3. For Builders By Builders: Introducing the Barz SDK
4. Multi-tier Module system. A secure foundation for open innovation

TL;DR:

In this article, we’ll share the optimizations we did to Diamond to make Barz a more efficient and secure Smart Wallet system. We’ll also dive into the components we added outside of Diamond to enhance its security.

In our [first article](https://github.com/trustwallet/developer/blob/master/introducing-barz-trustwallet-smart-wallet-solution/README.md), we introduced the [Barz Smart Wallet System](https://github.com/trustwallet/barz/tree/main), and we’ve also shared about the overall structure of [Barz](https://github.com/trustwallet/barz/tree/main) and how [Diamond Proxy Pattern(EIP-2535)](https://eips.ethereum.org/EIPS/eip-2535) works under the hood.

In this article, we’ll dive into the details of how we optimized Diamond and added smart contract-level infrastructural components to provide better security to our users.

But before we discuss the key points of the optimizations, let me explain how `diamondCut()` works in detail to help provide context to get us to the main point.

### How `diamondCut()` works

[EIP 2535](https://eips.ethereum.org/EIPS/eip-2535) which proposes the Diamond pattern defines the `diamondCut()` function as a standard interface to be compatible with the Diamond standard.

`diamondCut()` is an important component in a Diamond that is used to cut them, which is referred to as *upgrading* the Diamond by adding/removing/replacing `Facets`.

```solidity
interface IDiamondCut {

    enum FacetCutAction {Add, Replace, Remove}
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }
    
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;
    
}
```

For example, let’s assume that a Barz Smart Wallet wants to install a new Facet called `AccountRecoveryFacet` to add a recovery feature.

This could be performed by adding `AccountRecoveryFacet` with `diamondCut()`.

![Adding AccountRecoveryFacet with diamondCut()](/files/W5kLLUtZB6g273aoC12n)

* Explanation about the existing Facets
  * ***AccountFacet***: For general account logic. e.g., `execute()`, `executeBatch()`
  * ***VerificationFacet***: For verifying the signature for the ownership check e.g., `validateOwnerSignature()`, `isValidSignature()`
  * ***TokenReceiverFacet***: For fallbacks for receiving tokens. e.g., `onERC721Received()`
  * ***DiamondCutFacet***: For upgrading Diamond. e.g., `diamondCut()`
  * ***DiamondLoupeFacet***: For checking facet state of Diamond. e.g., `facets()`, `facetFromSelectors()`

Here’s an [example of performing DiamondCut](https://github.com/trustwallet/barz/blob/d509e53196512f6730a3f9bafbf40445beaf68bb/test/foundry/AccountRecoveryFacet.t.sol#L60):

```solidity
/** ### Prepare diamondCut() with AccountRecovery Facet ### */
IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);

cut[0] = IDiamondCut.FacetCut({
   facetAddress: accountRecoveryFacet,
   action: IDiamondCut.FacetCutAction.Add,
   functionSelectors: Constants.accountRecoveryFacetSelectors()
});

address diamondInitAddress = address(0);
bytes memory initCalldata = new bytes(0x00);

bytes memory cutData = abi.encodeWithSignature(
    "diamondCut((address,uint8,bytes4[])[],address,bytes)", cut, diamondInitAddress, initCalldata
);

/** ### Perform the actual call through UserOperation ### */
bytes memory callData = encodeExecuteCall(_barz, 0, cutData);
UserOperation[] memory userOp = new UserOperation[](1);
uint256[] memory signingKey = new uint256[](1);

userOp[0] = this.prepareUserOp(address(_barz), nonce[address(_barz)]++, callData);
signingKey[0] = _ownerKey;

userOp = signUserOperation(userOp, signingKey);

entryPoint.handleOps(userOp, payable(_barz));
```

Let’s walkthrough the above code one by one.

First, we declare a `FacetCut` typed variable cut.

`FacetCut` is a custom struct declared in the [EIP 2535 standard](https://eips.ethereum.org/EIPS/eip-2535)

```solidity
enum FacetCutAction {Add, Replace, Remove}
// Add=0, Replace=1, Remove=2

struct FacetCut {
    address facetAddress;
    FacetCutAction action;
    bytes4[] functionSelectors;
}
```

The struct specifies the following:

1. Address of Facet
2. Add/Replace/Remove action
3. List of function selectors to be added

To add the `AccountRecoveryFacet`, it would be the following data that we should provide as the parameter for the `diamondCut()` function call.

```solidity
1. FacetCut that specifies the action for cutting Diamond

FacetCut {
		facetAddress: AccountRecoveryFacetAddress,
		action: FacetCutAction.Add,
		functionSelectors: [approveRecovery.selector, executeRecovery.selector, hardstopRecovery.selector...]
}

2. Address of contract that performs DiamondInit

3. Calldata to initialize/uninitialize in DiamondInit
```

Second, we’ll encode the function call into the `execute()` function format so that the account can execute and sign the `UserOperation`.

```jsx
/** ### Perform the actual call through UserOperation ### */
bytes memory callData = encodeExecuteCall(_barz, 0, cutData);
UserOperation[] memory userOp = new UserOperation[](1);
uint256[] memory signingKey = new uint256[](1);

userOp[0] = this.prepareUserOp(address(_barz), nonce[address(_barz)]++, callData);
signingKey[0] = _ownerKey;

userOp = signUserOperation(userOp, signingKey);
```

Finally, we send this to the `EntryPoint` contract to coordinate the validation and execution of `UserOperation`.

This is the step when `diamondCut()` actually gets executed.

```jsx
entryPoint.handleOps(userOp, payable(_barz));
```

We’ve just added a new Recovery feature into your Barz Smart Wallet :)

## Conditional Diamond Cut

Considering that our Diamond is an Account, a Smart Wallet, that can support diverse access control mechanisms and state, it is important to note that there are circumstances where we should not permit `diamondCut()`. When these sensitive operations occur, the account should not be able to conduct upgrades as it could potentially result in a bypass of security checks or authorization.

For instance, it is unexpected or abnormal to perform `diamondCut()` during the Account Recovery phase where the owner’s key is suspected to be lost or during the phase when the Account is migrating its signature scheme.

For the conditional flow of `diamondCut()`, we imposed a structured pattern to the `diamondCut()` function through the `onlyWhenUnlocked` modifier.

```solidity
function diamondCut(
    FacetCut[] calldata _diamondCut,
    address _init,
    bytes calldata
) external override onlyWhenUnlocked {
    LibDiamond.enforceIsSelf();
    /** *** Code continues *** */
}
```

Below is an example of `AccountRecoveryFacet` locking the account.

```jsx
function _executeRecovery(bytes memory _recoveryPublicKey) internal {
		/** ### Simplified code showing the lock-related logic ### */
    uint64 executeAfter = uint64(block.timestamp + _getRecoveryPeriod());
    LibAppStorage.setLock(
        block.timestamp + _getLockPeriod(),
        AccountRecoveryFacet.executeRecovery.selector
    );
    emit RecoveryExecuted(_recoveryPublicKey, executeAfter);
}
```

Through this modifier, we only allow the `diamondCut()` to happen in normal state, when sensitive operations (e.g., requiring approvals of guardians) are not taking place.

***

As we’ve read through the first half of this article, we now know how to add `Facets` to Barz and how to seamlessly increase the functionality of the account while preventing these upgrades in sensitive phases through conditional `diamondCut()`.

However, if we take a moment and think from a security perspective, we may wonder:

* What if we add a malicious `Facet` into my Account?
* If Facet is an important component, can we have a registry of Facets that we can trust and use?

Let’s tackle the exact question in the **Facet Registry** section.

## Facet Registry

Diamond is a multi-faceted proxy contract where a single proxy contract has multiple implementations called `Facet` and during the execution, the Diamond makes `delegatecall` to the Facet contract.

Through the `delegatecall` triggered from the fallback function within the Diamond, it executes the logic of `Facet` contract in the context of the Diamond which will update the state of the Diamond itself.

This architecture, utilizing `Facets`, provides an extensible and modular approach for expanding the functionality of the Diamond. Each `Facet` can focus on its logic and functional domain while interacting with other Facets by calling other `Facet’s` functions within the context of the Diamond.

But similar to any other module systems, the security of the Diamond relies on the least secure `Facet` implementation, which means that adding a Facet should be performed after rigorous security checks.

It could cause a critical security risk if a malicious Facet is added to the Diamond.

*(This does not imply Diamond possess more risk compared to Monolithic pattern, it actually helps reduce bug by separating each domain logic. It’s just a trait of Diamond because each facet comprises the Diamond, Facets merging into a single full Diamond.)*

![Diamond Proxy Pattern](/files/xJ9yjUiTr9um8dPqXgPd)

It is evident that users need to be careful when adding a new `Facet` to their wallet, but it is also very demanding and nearly infeasible to expect normal users to assess the security and correctness of a `Facet` implementation by reading the code.

To help reduce the burden on users during Facet addition and reduce the chance of users adding a malicious or vulnerable Facet, we have developed a **Facet Registry** system.

**Facet Registry** is a registry of Facets that users can trust and add to their Smart Wallet.

All the `Facets` registered to the **Facet Registry** will go through extensive security audit and validation process at Trust Wallet to ensure it only includes Facets with very high security thresholds.

Also, further checks are conducted to confirm that each Facet’s storage or logic does not collide with one other before being registered to the registry.

![FacetRegistry forbidding malicious Facets from being added](/files/JfmtZw2ElJxY623PRXhR)

Through **Facet Registry**, users will be able to add `Facets` and frictionlessly make upgrades with much less security burdens to them.

Let’s see an example of how **Facet Registry** works with `Barz` .

```solidity
function diamondCut(
    FacetCut[] calldata _diamondCut,
    address _init,
    bytes calldata
) external override onlyWhenUnlocked {
    LibDiamond.enforceIsSelf();

		/** ### Check if Facets getting added is registered to FacetRegistry ### */
    _checkFacetCutValidity(_diamondCut);
    // require approval from guardian if guardian exists
    if (0 != LibGuardian.guardianCount())
        revert DiamondCutFacet__InvalidRouteWithGuardian();
    if (address(0) != _init) revert DiamondCutFacet__InvalidInitAddress();

    unchecked {
        ++LibFacetStorage.diamondCutStorage().nonce;
    }
    LibDiamond.diamondCut(_diamondCut, address(0), "");
}
```

In Barz’s `DiamondCutFacet`, there is the `diamondCut()` which handles the logic related to Diamond upgrades.

Within the `diamondCut()`, there is a `_checkFacetCutValidity()` which checks the validity of the Facet being added.

`_checkFacetCutValidity()` will make calls to the **Facet Registry** to confirm if it is safe to add this `Facet`.

```solidity
function _checkFacetCutValidity(
    IDiamondCut.FacetCut[] memory _diamondCut
) internal view {
    uint256 diamondCutLength = _diamondCut.length;
    for (uint256 i; i < diamondCutLength; ) {
        if (
            _diamondCut[i].action == IDiamondCut.FacetCutAction.Add ||
            _diamondCut[i].action == IDiamondCut.FacetCutAction.Replace
        ) {
        /** ### Query the FacetRegistry if it is okay to add this Facet ### */
            if (
                !s.facetRegistry.areFacetFunctionSelectorsRegistered(
                   _diamondCut[i].facetAddress,
                   _diamondCut[i].functionSelectors
                )
            ) revert UnregisteredFacetAndSelectors();
        }
        unchecked {
           ++i;
        }
    }
}
```

**Facet Registry** will go through its internal logic to check if the facet is registered when it’s queried through `areFacetFunctionSelectorsRegistered()` . The rest of the flow within `diamondCut()` will continue if the `Facets` are registered to the **Facet Registry** and revert otherwise.

*IMPORTANT NOTE: Facet Registry is only an additional layer of security provided by Trust Wallet. It does not have any right against user’s assets. Also, if the Facet is already added to user’s Smart Wallet, it does not have any right to perform removal or upgrades for user’s account. Facet Registry cannot trigger any type of state changes that changes the state of user’s account or balance. The code is fully open sourced.*

## Diamond Init

One important part to note during the `diamondCut()` execution is the send and third parameter (`_init`, `_calldata`) that enables an initialization mechanism called `DiamondInit` which makes a one-time call to the initializer for the new facet.

It is enabled by making a `delegatecall` to the given contract with the provided `calldata`.

Let’s see the internal implementation of `DiamondInit` to check how it is enabled:

```solidity
function diamondCut(
    IDiamondCut.FacetCut[] memory _diamondCut,
    address _init,
    bytes memory _calldata
) internal {
    DiamondStorage storage ds = diamondStorage();
    // ************ Diamond Cut Logic ************ //
    // NOTE: This is assuming the `Add` operation of DiamondCut
	  // 1-1. Check if Facet address has contract code(to check it's a smart contract)
		// 1-2. Loop through each functionSelectors variable in the _diamondCut array
		// 1-3. Checks if there is no existing facet registered to the function selector
		// 1-4. Register the Function Selector and it's corresponding facet data into it's corresponding storage
		// 1-5. Emit DiamondCut event as below
    emit DiamondCut(_diamondCut, _init, _calldata);
        
    // ************ Diamond Init Logic ************ //
    // 2-1. Check if the Contract to perform Diamond Init is a zero address. Return if it is zero.
    if (_init == address(0)) {
        return;
    }
    // 2-2. Check if the Contrct to perform Diamond Init has contract code. 
    //    This is to check if the given contract is a smart contract(CA not EOA).
    enforceHasContractCode(
        _init,
        "LibDiamondCut: _init address has no code"
    );
    // 2-3. Makes the delegatecall and revert if it fails.
    (bool success, bytes memory error) = _init.delegatecall(_calldata);
    if (!success) {
        if (error.length > 0) {
            // bubble up error
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(error)
                revert(add(32, error), returndata_size)
            }
        } else {
            revert InitializationFunctionReverted(_init, _calldata);
        }
    }
}
```

This approach also synchronizes the upgradeability and state initialization into the same transaction, which helps ensure the Diamond to maintain a consistent state.

As shared in the above code, Diamond Init provides a good way to initialize the storage right after the Diamond Cut operation.

An example of using Diamond Init could be during the setup of ERC165 settings for a newly added `Facet`.

```solidity
// You can add parameters to this function in order to pass in 
// data to set your own state variables
function init() external {
    // adding ERC165 data
    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
    ds.supportedInterfaces[type(IERC165).interfaceId] = true;
    ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
    ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
    ds.supportedInterfaces[type(IERC173).interfaceId] = true;
}
```

The above code will allow Diamond to set it’s ERC165 storage to reflect the newly added `Facet`.

## Remove Diamond Init From `diamondCut()` for Security

Even though Diamond Init is very useful and is a novel approach to initialize state, it may not be the best for every scenario, especially for Accounts.

For instance, an attacker may request a malicious payload to add Valid `Facet` but with a malicious Diamond Init address and calldata to the user for approval - frauding the user as if it was a valid, secure operation.

Upon user’s approval, regardless of the `Facet` being added is valid or not valid, as the Diamond Init address and calldata is malicious, it will be able to override ownership or perform unintended asset transfer.

Let’s see the below example for a better understanding of the scenario:

1. Assume an account is using `Secp256k1VerificationFacet` for ownership validation and signature validation.

   Storage of `Secp256K1VerificationFacet`:

   ```solidity
   struct Secp256k1VerificationStorage {
       address signer;
   }
   bytes32 constant K1_STORAGE_POSITION =
       keccak256(
           "v0.trustwallet.diamond.storage.Secp256k1VerificationStorage"
   		);
   		
   function k1Storage()
       internal
       pure
       returns (Secp256k1VerificationStorage storage ds)
   {
       bytes32 storagePosition = K1_STORAGE_POSITION;
       assembly {
           ds.slot := storagePosition
       }
   }
   ```
2. Malicious entity may request for an addition of valid/secure `AccountRecoveryFacet`, but with the malicious Diamond Init code.

   Below is the malicious implementation of Diamond Init contract targetting the users using `Secp256K1VerificationFacet`

   ```solidity
   function init() external {
   		/** ### Perform valid action ### */
   		LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
       ds.supportedInterfaces[type(IAccountRecoveryFacet).interfaceId] = true;
       
       /** ### Perform overwrite of ownership ### */
       k1Storage().signer = maliciousAddress;
   }
   ```

We considered the following aspects

1. Performing a `delegatecall` to an unknown address is risky, even if the owner may approve it.
2. Adding/Replacing/Removing Facets could be a relatively frequently process as more features and functionalities are added for the users.
3. Initialization/Uninitialization during the setup of Diamond is a common and useful pattern.

*We have decided to disallow DiamondInit logic in Barz and use the approach of imposing an initializer within the Facet that allows a one-time call to setup storage.*

This provides the benefit of:

1. Higher security by disallowing `delegatecall` to arbitrary contract.
2. More structured approach for initializing storage within the `Facet` itself.

Let’s see how an example of how this `initialize()` is implemented in the `AccountFacet` contract:

```solidity
function initialize(
    address _verificationFacet,
    address _anEntryPoint,
    address _facetRegistry,
    address _defaultFallBackHandler,
    bytes calldata _ownerPublicKey
) public override returns (uint256 initSuccess) {
    LibAppStorage.enforceAccountInitialize();
    s.entryPoint = IEntryPoint(_anEntryPoint);
    s.facetRegistry = IFacetRegistry(_facetRegistry);
    LibDiamond.diamondStorage().defaultFallbackHandler = IDiamondLoupe(
        _defaultFallBackHandler
    );

    _cutDiamondAccountFacet(_verificationFacet);

    bytes memory initCall = abi.encodeWithSignature(
        "initializeSigner(bytes)",
        _ownerPublicKey
    );
    // Every Verification Facet should comply with initializeSigner(bytes)
    // to be compatible with the Barz contract(for initialization)
    (bool success, bytes memory result) = _verificationFacet.delegatecall(
        initCall
    );
    if (!success || uint256(bytes32(result)) != 1) {
        revert AccountFacet__InitializationFailure();
    }

    initSuccess = 1;
    emit AccountInitialized(s.entryPoint, _ownerPublicKey);
}

```

Barz approach of forbidding a delegatecall to an arbitrary address and substituting it with an initializer with the Facet eliminates the risk or an attacker of overwriting storage or making unintended asset transfers.

This change increases the security threshold by removing this attack vector coming from DiamondInit and by only enabling initialization through initializers within Facets that are registered to Facet Registry.

***

Congratulations, you have reached the final section on learning to build a cutting-edge account with Diamond.

You may have understood the flexibility and modularity Bars is able to provide with tailored security architecture for Accounts.

But one important aspect remains to incorporate all these pieces into a powerful product for users, GAS.

Let’s dive into the details in the next section to see how Trust Wallet managed to decrease more than `50%` of gas during account creation.

## Default Fallback Handler

In smart contract engineering, other existing software engineering principles like modularity, abstraction, encapsulation, simpleness, and more also exists but the one other important principle that requires much attention is it’s efficiency during execution, in simpler terms, gas efficiency.

Diamond pattern excels in providing modular upgradeability, but compared to other monolithic proxy patterns, it does include more advanced computations and checks to perform upgrades.

In this section, we’ll dive into the `DefaultFallbackHandler` component that Trust Wallet developed to reduce about 55% of deployment gas fee.

The default `diamondCut()` for adding the below facets during account deployment cost about `1 million gas units` (23 functions in total).

[Barz in louper.dev](https://louper.dev/diamond/0xbD741C9A6c3C197F863F0657A15D2E9070534BE3?network=polygon)

![Barz account in louper.dev](/files/g6eQYODHe73BQNUyJhmI)

The part where it cost the most gas is the execution of updating storage for each function selector’s corresponding facet address.

```solidity
if (_action == IDiamondCut.FacetCutAction.Add) {
    enforceHasContractCode(
        _newFacetAddress,
        "LibDiamondCut: Add facet has no code"
    );
    for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
        bytes4 selector = _selectors[selectorIndex];
        bytes32 oldFacet = ds.facets[selector];
        require(
            address(bytes20(oldFacet)) == address(0),
            "LibDiamondCut: Can't add function that already exists"
        );
        // add facet for selector
        ds.facets[selector] =
            bytes20(_newFacetAddress) |
            bytes32(_selectorCount);
        // "_selectorCount & 7" is a gas efficient modulo by eight "_selectorCount % 8"
        // " << 5 is the same as multiplying by 32 ( * 32)
        uint256 selectorInSlotPosition = (_selectorCount & 7) << 5;
        // clear selector position in slot and add selector
        _selectorSlot =
            (_selectorSlot &
                ~(CLEAR_SELECTOR_MASK >> selectorInSlotPosition)) |
            (bytes32(selector) >> selectorInSlotPosition);
        // if slot is full then write it to storage
        if (selectorInSlotPosition == 224) {
            // "_selectorSlot >> 3" is a gas efficient division by 8 "_selectorSlot / 8"
            ds.selectorSlots[_selectorCount >> 3] = _selectorSlot;
            _selectorSlot = 0;
        }
        _selectorCount++;

        unchecked {
            selectorIndex++;
        }
    }
}
```

Although we understood that this was the default behavior of Diamonds which is updating each function selector’s mapping to facet address value, we tried to look for ways tailored to the Account to reduce the gas consumption as much as possible.

During this time, [Nick(Author of EIP-2535 Diamonds)](https://x.com/mudgen) and I had a discussion on how we could further optimize the gas consumption during the `diamondCut()` for default facets, and we came up with an interesting idea of having a pre-existing entity that holds the values for the Diamond’s functionSelector <> Facet mapping.

After having this interesting idea, our team started the implementation of a standalone contract that provides the default mapping value of the diamond, and named it `DefaultFallbackHandler`.

We designed the `DefaultFallbackHandler` to include the default Facets for the accounts like `AccountFacet`, `DiamondCutFacet`, `DiamondLoupeFacet` and `TokenReceiverFacet`.

While we saw the significant decrease in gas during the `diamondCut()` at this stage, it was very important that `DefaultFallbackHandler` does not introduce any security vulnerability or get us handcuffed to the initial value set by the `DefaultFallbackHandler`.

Considering the above aspects and the importance of this contract globally impacting the whole Barz system on chain, we had `2 key principles` when we designed this system:

1. No one should be able to upgrade or modify it → permissionless & non-upgradeable (Upgrading it means, it is allowing the upgrader to add a functionality to the user’s account without user’s consent)
2. Even if the default function-set is added by `DefaultFallbackHandler` in the initial state, the owner of the account should always be able to override it.

With these key principles in mind, we have designed the `DefaultFallbackHandler`.

Let’s see the actual codebase to see how these principles are reflected at the code level.

1. No one should be able to upgrade or modify it → Permissionless & non-upgradeable

   [Link to the actual code - DefaultFallbackHandler](https://github.com/trustwallet/barz/blob/main/contracts/infrastructure/DefaultFallbackHandler.sol)

   ```solidity
   contract DefaultFallbackHandler is IDiamondLoupe {
       /**
        * @notice Sets the middleware diamond for Barz wallet as a fallback handler
        * @dev This contract is also a diamond that holds the default facets to reduce gas cost for wallet activation.
        *      Within the constructor this conducts diamond cut to initially setup the diamond. This is a non-upgradeable contract
        * @param _diamondCutFacet Address if diamond cut facet
        * @param _accountFacet Address account facet
        * @param _tokenReceiverFacet Address of token receiver facet
        * @param _diamondLoupeFacet Address of diamond loupe facet
        */
       constructor(
           address _diamondCutFacet,
           address _accountFacet,
           address _tokenReceiverFacet,
           address _diamondLoupeFacet
       ) payable {
           IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](4);
           bytes4[] memory functionSelectors = new bytes4[](1);
           functionSelectors[0] = IDiamondCut.diamondCut.selector;

           bytes4[] memory accountFunctionSelectors = new bytes4[](5);
           accountFunctionSelectors[0] = IAccountFacet.execute.selector;
           accountFunctionSelectors[1] = IAccountFacet.executeBatch.selector;
           /** *** the code follows *** */
       }
   }
   ```

   As shared in the above codebase, the `DefaultFallbackHandler` is a `non-Ownable` and `non-Upgradeable` smart contract. Once the value is set to the smart contract during the deployment process through the constructor, the `DefaultFallbackHandler` will be a non-modifiable smart contract that only provides view-only functions to allow `Barz` accounts to read the contract storage for routing the coming calls to the corresponding Facets.
2. Even if the default function-set is added by `DefaultFallbackHandler` in the initial state, the owner of the account should always be able to override it.

   [Link to the actual code - Barz](https://github.com/trustwallet/barz/blob/main/contracts/Barz.sol#L63)

   ```solidity
   /**
    * @notice Fallback function for Barz complying with Diamond Standard with customization of adding Default Fallback Handler
    * @dev Find facet for function that is called and execute the function if a facet is found and return any value.
    */
   fallback() external payable {
       LibDiamond.DiamondStorage storage ds;
       bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
       // get diamond storage
       assembly {
           ds.slot := position
       }
       // get facet from function selector
       address facet = address(bytes20(ds.facets[msg.sig]));
       if (facet == address(0))
           facet = ds.defaultFallbackHandler.facetAddress(msg.sig);
       require(facet != address(0), "Barz: Function does not exist");
       // Execute external function from facet using delegatecall and return any value.
       assembly {
           // copy function selector and any arguments
           calldatacopy(0, 0, calldatasize())
           // execute function call using the facet
           let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
           // get any return value
           returndatacopy(0, 0, returndatasize())
           // return any return value or error back to the caller
           switch result
           case 0 {
               revert(0, returndatasize())
           }
           default {
               return(0, returndatasize())
           }
       }
   }
   ```

   In the above code, we query the value from the `DefaultFallbackHandler` only when Barz does not have the corresponding facet registered.

   This fallback architecture allows the user to override its value by adding the Facet directly to the account, which helps the account to adhere to the 2nd principle.

Through the `DefaultFallbackHandler`, we were able to reduce the deployment fee by around `55%` (approximately from `1,000,000` → `431,000` gas units) while adhering to strong security guarantees and self-sovereignty/control of the account.

## Conclusion

Barz Smart Wallet utilizes the Diamond proxy pattern that provides a very flexible management of functionality through Facets but also made optimizations and enhancements to the Diamond, tailored for it’s use case while retaining high security and self-sovereignty of the account.

In our next article, we’ll dive into the details of Trust Wallet’s Barz SDK.

Stay tuned for our next article in this series and releases on the powerful use cases of smart wallets built on Barz.


