# ERC6551 Token Bound Accounts (TBA)

This project implements the [ERC6551 standard](https://eips.ethereum.org/EIPS/eip-6551) for token bound accounts, allowing NFTs to own and control their own smart contract accounts.

*[中文版文档](README_CN.md)*

## Features

- **ERC6551Registry**: Contract for creating and tracking token bound accounts
- **ERC6551Account**: Implementation of a token bound account that can be controlled by the NFT owner
- **IPNFT**: Sample NFT contract for intellectual property tokens

## Package Versions

The project provides a framework-agnostic npm package for integration:

- **gotake-contracts**: Pure TypeScript types and ABIs - works with any framework

### Installing the Package

```bash
# Framework-agnostic package (recommended)
npm install gotake-contracts
```

### Using the Package

The package provides pure TypeScript types and ABIs without any runtime dependencies:

```typescript
// Import ABIs
import { ERC6551REGISTRY_ABI, IPNFT_ABI, abis } from 'gotake-contracts';

// Import TypeScript types
import { NetworkConfig, ContractABI } from 'gotake-contracts';

// Import contract addresses and helper functions
import { CONTRACT_ADDRESSES, getContractAddress } from 'gotake-contracts';

// Example usage
const registryAddress = getContractAddress('base_sepolia', 'registry');
const networkConfig = CONTRACT_ADDRESSES.base_sepolia;
```

### Building the Package

```bash
# Build the framework-agnostic package
yarn build
```

### Key Features

- **Zero Dependencies**: No runtime dependencies, works with any ethers version
- **Framework Agnostic**: Compatible with browser, Node.js, React, Vue, etc.
- **TypeScript Support**: Full type safety with generated interfaces
- **Static Assets**: Contract addresses compiled as TypeScript constants

## Setup

1. Clone this repository
2. Install dependencies:
   ```bash
   yarn install
   ```
3. Copy `.env.example` to `.env` and fill in your values:
   ```bash
   cp .env.example .env
   ```
4. Edit the `.env` file to add your private key and RPC URLs

## Deployment

### Deploying to Base Sepolia Testnet

Run the following command to deploy all contracts to Base Sepolia Testnet:

```bash
npx hardhat run scripts/deploy.ts --network base_sepolia
```

This will deploy:

- ERC6551Registry
- ERC6551Account implementation
- IPNFT contract
- Creates a sample Token Bound Account for demonstration

### Verifying Contracts

After deployment, you can verify the contracts on BaseScan using our verification script:

```bash
# Verify all contracts on current network
npx hardhat run scripts/verify-contracts.ts --network base_sepolia

# Verify a specific contract on a specific network
npx hardhat run scripts/verify-contracts.ts --network base_sepolia --contract registry
npx hardhat run scripts/verify-contracts.ts --network base_sepolia --contract accountImplementation
npx hardhat run scripts/verify-contracts.ts --network base_sepolia --contract ipnft
```

Or manually:

```bash
npx hardhat verify --network base_sepolia <CONTRACT_ADDRESS> [CONSTRUCTOR_ARGUMENTS]
```

Example for IPNFT:

```bash
npx hardhat verify --network base_sepolia <IPNFT_ADDRESS> <OWNER_ADDRESS>
```

## Testing

### Local Testing

Run the tests locally:

```bash
npx hardhat test
```

### Testing with Deployed Contracts

Use the `test-tba.ts` script to interact with your deployed contracts:

```bash
# Test on hardhat network (will deploy fresh contracts)
npx hardhat run scripts/test-tba.ts

# Test on Base Sepolia with deployed contracts
npx hardhat run scripts/test-tba.ts --network base_sepolia
```

This script will:

1. Connect to the contracts using the compiled address constants
2. Auto-mint an NFT if none exist on the contract
3. Check NFT ownership and metadata
4. Calculate and create a Token Bound Account if needed
5. Verify token association
6. Send ETH to the TBA if balance is low
7. Execute a transaction from the TBA (requires the signer to be the NFT owner)

Before running on Base Sepolia, make sure:

- Your wallet has Base Sepolia ETH
- Your private key in `.env` has the necessary permissions
- The script will automatically mint an NFT if none exist

## Usage

### Creating a Token Bound Account

1. Mint an NFT using the IPNFT contract
2. Call the `createAccount` function on the registry contract:

```javascript
// Example parameters
const implementation = "<ACCOUNT_IMPLEMENTATION_ADDRESS>";
const salt = ethers.utils.formatBytes32String("SALT");
const chainId = 84532; // Base Sepolia
const tokenContract = "<IPNFT_ADDRESS>";
const tokenId = 0; // The NFT ID

// Create the account
await registry.createAccount(
    implementation,
    salt,
    chainId,
    tokenContract,
    tokenId
);
```

### Interacting with a Token Bound Account

1. Get the account address using the registry's `account` function
2. Connect to the account using the ERC6551Account ABI
3. Call functions on the account using the NFT owner's address

```javascript
// Get the account address
const accountAddress = await registry.account(
    implementation,
    salt,
    chainId,
    tokenContract,
    tokenId
);

// Connect to the account
const account = await ethers.getContractAt("ERC6551Account", accountAddress);

// Execute a transaction from the account (must be called by the NFT owner)
await account.execute(
    targetAddress,  // The address to interact with
    value,          // Amount of ETH to send
    data,           // The calldata for the transaction
    operation       // 0 for call, 1 for delegatecall
);
```

## Running SDK Example Scripts

The SDK provides several example scripts to demonstrate how to work with IPNFT and TBA functionality. These scripts are located in the `gotake-sdk/scripts` directory.

### Prerequisites

1. Install dependencies in the SDK directory:
   ```bash
   cd gotake-sdk
   yarn install
   ```

2. Create an environment file:
   ```bash
   # In the gotake-sdk directory
   cp .env.example .env
   ```

3. Edit the `.env` file to add your Ethereum private key:
   ```
   PRIVATE_KEY=your_private_key_here
   ```

### Example Scripts

#### 1. Creating a TBA

The `create-tba.ts` script demonstrates:
- Creating an SDK instance
- Minting an IPNFT
- Creating a TBA linked to the IPNFT

Run with:
```bash
# In the gotake-sdk directory
npx ts-node --transpile-only scripts/create-tba.ts
```

After successful execution, copy the TBA address to the `.env` file's `TBA_ADDRESS` field for use in subsequent scripts.

#### 2. Sending ETH to a TBA

The `send-eth-to-tba.ts` script demonstrates:
- Sending ETH to a TBA
- Executing transactions from the TBA (sending ETH back to the original account)

Run with:
```bash
# In the gotake-sdk directory
npx ts-node --transpile-only scripts/send-eth-to-tba.ts
```

#### 3. Checking TBA Information

The `check-tba.ts` script demonstrates:
- Querying a TBA's balance
- Getting the Token information associated with a TBA
- Getting the TBA owner
- Getting detailed information about the associated IPNFT

Run with:
```bash
# In the gotake-sdk directory
npx ts-node --transpile-only scripts/check-tba.ts
```

### Recommended Execution Order

1. First run `create-tba.ts` to create a TBA
2. Then run `check-tba.ts` to confirm the TBA was created successfully and check its information
3. Finally run `send-eth-to-tba.ts` to demonstrate interaction with the TBA

### Troubleshooting

If scripts fail, check:
1. Your private key is correct
2. Your account has sufficient test ETH
3. Network connection is stable
4. TBA address is correct (for second and third scripts)

## Package Architecture

This project generates a framework-agnostic npm package with zero runtime dependencies.

### Package Features

- **Pure Static Exports**: Only TypeScript types, ABIs, and contract addresses
- **Environment Universal**: Works in browser, Node.js, React Native, etc.
- **Framework Agnostic**: Compatible with any ethers version (v5, v6) or Web3 library
- **Frontend Safe**: No Node.js dependencies, can be bundled for browsers
- **TypeScript First**: Full type safety with generated interfaces

### Development Workflow

The development environment uses ethers v5 for consistency, while the published package remains framework-agnostic:

```bash
# Development commands
yarn compile                 # Compile contracts
yarn typechain              # Generate TypeChain types
yarn build                  # Build the framework-agnostic package
```

### Package Structure

```
gotake-contracts/
├── abi/                    # Pure JSON ABI files
├── types/                  # Framework-agnostic TypeScript interfaces
├── constants/              # Contract addresses as TypeScript constants
└── index.js               # Main export with all types and ABIs
```

### Integration Examples

```typescript
// React + ethers v6
import { ERC6551REGISTRY_ABI, CONTRACT_ADDRESSES } from 'gotake-contracts';
import { ethers } from 'ethers';

const contract = new ethers.Contract(
  CONTRACT_ADDRESSES.base_sepolia.contracts.registry,
  ERC6551REGISTRY_ABI,
  provider
);

// Node.js + ethers v5
import { IPNFT_ABI, getContractAddress } from 'gotake-contracts';
const address = getContractAddress('base_sepolia', 'ipnft');

// Vue + Web3.js
import { abis } from 'gotake-contracts';
const web3Contract = new web3.eth.Contract(abis.ERC6551Registry, address);
```

## License

This project is licensed under the MIT License.
