# ERC 6551: Token Bound Accounts (TBA)

### **Basic Understanding**

ERC-6551 allows NFTs to have associated smart contract accounts. These accounts can hold tokens, interact with decentralized applications (dApps), and execute transactions—just like a regular Ethereum account.

Before ERC-6551, NFTs were static assets. With TBAs, an NFT can own ERC-20 tokens, other NFTs, or interact with DeFi protocols.

**How it works:**

1. Each NFT gets an associated **Token Bound Account (TBA)**, which is a smart contract wallet.
2. The TBA is **linked to the NFT** and managed by the NFT's owner.
3. The NFT can **store tokens** or **execute on-chain actions**.

### **Use Cases**

1. **GameFi & Metaverse**
   * A game character NFT can hold in-game assets (weapons, potions, tokens).
   * When the character is sold, the new owner also gets the stored items.
2. **On-Chain Identity**
   * Users can own an NFT-based identity with on-chain history, achievements, and credentials.
3. **DAO & Governance**
   * An NFT membership card can hold voting power and interact with DAO governance contracts.
4. **DeFi & Financial Instruments**
   * NFT-backed loans: An NFT with a TBA can hold staked assets or act as collateral.
5. **Composable NFTs**
   * A fashion NFT (e.g., a digital avatar) can own wearable NFTs (clothing, accessories).

### **Advantages**

* **NFTs Become Wallets** – NFTs can own assets, removing the need for separate wallets.
* **Better Composability** – Enables richer interactions between NFTs and DeFi, DAOs, gaming.
* **Improved Security** – Smart contract-controlled accounts reduce risks of external wallets.
* **Gas Efficiency** – Reduces the need for multiple transactions to move assets.

### **Disadvantages**

* **Smart Contract Complexity** – More complex than standard NFTs, requiring secure contract audits.
* &#x20;**Adoption Curve** – Wallets, marketplaces, and dApps need to support ERC-6551.
* &#x20;**Higher Gas Costs** – Deploying smart contract accounts for NFTs adds gas costs.

### **Architecture & Code Structure**

#### **1. Key Components**

* **ERC-721 NFT**: The main NFT that will have an associated wallet.
* **Token Bound Account (TBA) Smart Contract**: A contract that acts as the NFT’s wallet.
* **Registry Contract**: Deploys and manages TBAs for NFTs.

2. Diagram

```
+----------------------+
| ERC-721 NFT         |  
| (e.g., Game Avatar) |
+----------------------+
        |
        | Links to TBA
        v
+----------------------+
| Token Bound Account  |  
| (Smart Contract)     |
+----------------------+
        |
        | Can store tokens, interact with dApps
        v
+----------------------+
| ERC-20, NFTs, dApps |
| (Assets & Contracts)|
+----------------------+

```

#### **3. Code Structure**

Here’s a basic implementation of an **ERC-6551 Token Bound Account**:

**A.  ERC-6551 Registry (Factory to deploy TBAs)**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC6551Registry {
    function createAccount(
        address implementation,
        uint256 chainId,
        address tokenContract,
        uint256 tokenId
    ) external returns (address);
}

contract ERC6551Registry {
    mapping(bytes32 => address) public accounts;

    function createAccount(
        address implementation,
        uint256 chainId,
        address tokenContract,
        uint256 tokenId
    ) external returns (address) {
        bytes32 salt = keccak256(abi.encodePacked(chainId, tokenContract, tokenId));
        require(accounts[salt] == address(0), "Account already exists");

        ERC6551Account account = new ERC6551Account();
        accounts[salt] = address(account);
        return address(account);
    }
}

```

**B. Token Bound Account (Smart Contract Wallet for NFT)**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

contract ERC6551Account is Ownable {
    event Executed(address target, uint256 value, bytes data);

    constructor() {
        transferOwnership(msg.sender);
    }

    function execute(address target, uint256 value, bytes calldata data) external onlyOwner {
        (bool success, ) = target.call{value: value}(data);
        require(success, "Execution failed");
        emit Executed(target, value, data);
    }

    receive() external payable {} // Accept Ether
}

```

**C. NFT Contract (Uses ERC-6551)**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721URIStorage, Ownable {
    IERC6551Registry public registry;
    address public implementation;

    constructor(address _registry, address _implementation) ERC721("MyNFT", "MNFT") {
        registry = IERC6551Registry(_registry);
        implementation = _implementation;
    }

    function mint(address to, uint256 tokenId, string memory tokenURI) public onlyOwner {
        _mint(to, tokenId);
        _setTokenURI(tokenId, tokenURI);
        
        // Create Token Bound Account for NFT
        registry.createAccount(implementation, block.chainid, address(this), tokenId);
    }
}

```
