> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# How to build with ERC-6551 (Token-Bound Accounts) on Monad

> Give every NFT its own smart-contract wallet on Monad using the canonical Tokenbound ERC-6551 deployment.

export const CopyToClipboard = ({value, children}) => {
  const [copied, setCopied] = useState(false);
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(value);
      setCopied(true);
      setTimeout(() => setCopied(false), 1000);
    } catch {
      const textarea = document.createElement("textarea");
      textarea.value = value;
      textarea.style.position = "fixed";
      textarea.style.opacity = "0";
      document.body.appendChild(textarea);
      textarea.select();
      document.execCommand("copy");
      document.body.removeChild(textarea);
      setCopied(true);
      setTimeout(() => setCopied(false), 1000);
    }
  };
  return <span style={{
    display: "inline",
    whiteSpace: "nowrap"
  }}>
      {children}
      <button onClick={handleCopy} title={copied ? "Copied!" : "Copy to clipboard"} style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    padding: "2px",
    display: "inline-flex",
    alignItems: "center",
    verticalAlign: "middle",
    marginLeft: "4px",
    opacity: copied ? 1 : 0.4,
    transition: "opacity 0.15s"
  }} onMouseEnter={e => {
    if (!copied) e.currentTarget.style.opacity = "0.8";
  }} onMouseLeave={e => {
    if (!copied) e.currentTarget.style.opacity = "0.4";
  }}>
        {copied ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="20 6 9 17 4 12" />
          </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
          </svg>}
      </button>
    </span>;
};

This guide shows how to give any NFT its own account (wallet) on Monad using the canonical [Tokenbound](https://tokenbound.org) ERC-6551 v3 deployment. The full stack is live on both Monad mainnet and testnet at the same canonical addresses used on Ethereum and Base, so the standard `@tokenbound/sdk` works with no custom contract configuration.

## What is ERC-6551?

[ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) gives every ERC-721 NFT its own smart-contract account — a "token-bound account" (TBA). The account is owned by whoever currently holds the NFT, so anything the account owns or can do transfers automatically when the NFT is transferred.

Concretely, a token-bound account can:

* Hold assets — ERC-20s, other NFTs, and native MON.
* Execute arbitrary transactions, authorized by the current NFT holder.
* Act as an identity or inventory for games, agents, memberships, and loyalty programs.

Because accounts are created deterministically through a shared, permissionless registry, the account address for a given NFT is knowable in advance and identical across every chain the standard is deployed on.

### Key benefits

* **Ownership follows the NFT**: transfer the NFT and its entire account — assets and permissions — moves with it, atomically, with no migration step.
* **Deterministic addresses**: an NFT's account address is computed from `(chainId, tokenContract, tokenId, implementation, salt)`, so it can be derived off-chain before the account is even deployed.
* **No new standard to learn on the wallet side**: a TBA is a smart account, compatible with existing tooling and ERC-4337 account abstraction.
* **Works out of the box**: Monad uses the canonical Tokenbound contracts at their standard cross-chain addresses, so existing ERC-6551 apps and the Tokenbound SDK point at Monad with a config change only.

## Canonical deployment on Monad

The Tokenbound ERC-6551 v3 stack is deployed at its canonical, deterministic addresses on **Monad mainnet (chain ID 143)** and **Monad testnet (chain ID 10143)**. The addresses are identical on both networks and match the Ethereum/Base deployments. All contracts are source-verified on [Monadscan](https://monadscan.com) and [MonadVision](https://monadvision.com).

<ul>
  <li>
    <strong>ERC-6551 Registry</strong>:

    <CopyToClipboard value="0x000000006551c19487814612e58FE06813775758">
      `0x000000006551c19487814612e58FE06813775758`
    </CopyToClipboard>

    <span>
      (
      <a href="https://monadscan.com/address/0x000000006551c19487814612e58FE06813775758">mainnet</a>

      {", "}

      <a href="https://testnet.monadscan.com/address/0x000000006551c19487814612e58FE06813775758">testnet</a>
      )
    </span>
  </li>

  <li>
    <strong>V3 Account Implementation</strong>:

    <CopyToClipboard value="0x41C8f39463A868d3A88af00cd0fe7102F30E44eC">
      `0x41C8f39463A868d3A88af00cd0fe7102F30E44eC`
    </CopyToClipboard>

    <span>
      (
      <a href="https://monadscan.com/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC">mainnet</a>

      {", "}

      <a href="https://testnet.monadscan.com/address/0x41C8f39463A868d3A88af00cd0fe7102F30E44eC">testnet</a>
      )
    </span>
  </li>

  <li>
    <strong>V3 Account Proxy</strong>:

    <CopyToClipboard value="0x55266d75D1a14E4572138116aF39863Ed6596E7F">
      `0x55266d75D1a14E4572138116aF39863Ed6596E7F`
    </CopyToClipboard>

    <span>
      (
      <a href="https://monadscan.com/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F">mainnet</a>

      {", "}

      <a href="https://testnet.monadscan.com/address/0x55266d75D1a14E4572138116aF39863Ed6596E7F">testnet</a>
      )
    </span>
  </li>

  <li>
    <strong>V3 Account Guardian</strong>:

    <CopyToClipboard value="0x2fe5CCB0d7Ea195FEB87987D3573f9FccE2b5d57">
      `0x2fe5CCB0d7Ea195FEB87987D3573f9FccE2b5d57`
    </CopyToClipboard>

    <span>
      (
      <a href="https://monadscan.com/address/0x2fe5CCB0d7Ea195FEB87987D3573f9FccE2b5d57">mainnet</a>

      {", "}

      <a href="https://testnet.monadscan.com/address/0x2fe5CCB0d7Ea195FEB87987D3573f9FccE2b5d57">testnet</a>
      )
    </span>
  </li>

  <li>
    <strong>Authenticated Multicall (Forwarder)</strong>:

    <CopyToClipboard value="0xcA1167915584462449EE5b4Ea51c37fE81eCDCCD">
      `0xcA1167915584462449EE5b4Ea51c37fE81eCDCCD`
    </CopyToClipboard>

    <span>
      (
      <a href="https://monadscan.com/address/0xcA1167915584462449EE5b4Ea51c37fE81eCDCCD">mainnet</a>

      {", "}

      <a href="https://testnet.monadscan.com/address/0xcA1167915584462449EE5b4Ea51c37fE81eCDCCD">testnet</a>
      )
    </span>
  </li>
</ul>

The V3 account implementation is wired to the ERC-4337 EntryPoint v0.6 at [`0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789`](https://monadscan.com/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789) ([testnet](https://testnet.monadscan.com/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789)), which is also live on Monad.

## Quickstart with the Tokenbound SDK

Install the SDK and [viem](https://viem.sh):

```bash theme={null}
npm install @tokenbound/sdk viem@^2.40.0
```

Point the client at Monad. Because Monad's deployment uses the canonical v3 addresses that ship as the SDK's defaults, you only need to supply the chain — no custom contract addresses:

```ts theme={null}
import { TokenboundClient } from "@tokenbound/sdk"
import { createWalletClient, custom } from "viem"
import { monad } from "viem/chains" // monadTestnet for chain 10143

const [account] = (await window.ethereum.request({
  method: "eth_requestAccounts",
})) as [`0x${string}`]

const walletClient = createWalletClient({
  account,
  chain: monad,
  transport: custom(window.ethereum),
})

const tokenboundClient = new TokenboundClient({
  walletClient,
  chain: monad,
})
```

<Note>
  Pass the viem `chain` object (`monad` / `monadTestnet`) explicitly. Recognizing Monad by `chainId` alone (e.g. `chainId: 143`) requires Monad to be registered in the SDK's bundled chain list — a change tracked upstream in [tokenbound/sdk](https://github.com/tokenbound/sdk). Requires `viem` ≥ 2.40.0, which is the first release to export the `monad` mainnet chain.
</Note>

Derive an NFT's account address (deterministic — works before the account is deployed), then create it:

```ts theme={null}
// Deterministic account address for tokenId 1 of an NFT contract
const account = tokenboundClient.getAccount({
  tokenContract: "0xYourNftContract",
  tokenId: "1",
})

// Deploy the account on-chain (idempotent — safe to call if it already exists)
const { account: created, txHash } = await tokenboundClient.createAccount({
  tokenContract: "0xYourNftContract",
  tokenId: "1",
})
```

Once created, the account is controlled by the current holder of the NFT. The holder can execute transactions through it:

```ts theme={null}
const executedTxHash = await tokenboundClient.execute({
  account,
  to: "0xRecipient",
  value: 0n,
  data: "0x",
})
```

Transfer the underlying NFT and control of the account — along with everything it holds — moves to the new owner automatically. No further action required.

## Notes and limitations

* **Cross-chain execution is not enabled on Monad.** The core TBA stack is fully deployed, but the optional LayerZero V2 executor that powers Tokenbound's cross-chain calls was not deployed. Same-chain account creation, ownership resolution, and execution work as normal.

## Resources

* [ERC-6551 Specification](https://eips.ethereum.org/EIPS/eip-6551)
* [Tokenbound Documentation](https://docs.tokenbound.org)
* [Tokenbound SDK](https://github.com/tokenbound/sdk)
* [Tokenbound Contracts](https://github.com/tokenbound/contracts)
* [Monad Developer Discord](https://discord.gg/monaddev)

## Need help?

Join the [Monad Developer Discord](https://discord.gg/monaddev).
