# Integration with Existing Code

## 发现：holders 包已有类似实现

在 `holders/db_config.go` 中已经实现了从数据库加载合约地址的完整逻辑：

### holders/db_config.go 的实现
```go
// LoadConfigFromDB 从数据库加载配置（已存在）
func LoadConfigFromDB(chainID int64) (Config, error) {
    // 1. 从 assets 表加载 YT-A, YT-B, YT-C
    var assets []Asset
    db.Table("assets").
        Where("asset_code IN (?, ?, ?)", "YT-A", "YT-B", "YT-C").
        Find(&assets)

    // 2. 根据 chainID 选择合约地址
    for _, asset := range assets {
        address := asset.ContractAddressArb
        if isBSC {
            address = asset.ContractAddressBsc
        }
        ytVaults = append(ytVaults, VaultConfig{
            Name:    asset.AssetCode,
            Address: address,
        })
    }

    // 3. 从 lending_markets 表加载 Lending 合约
    var lendingMarkets []LendingMarket
    db.Table("lending_markets").
        Where("is_active = ?", 1).
        Find(&lendingMarkets)

    lendingAddress := market.ContractAddressArb
    if isBSC {
        lendingAddress = market.ContractAddressBsc
    }

    return Config{
        YTVaults:       ytVaults,
        LendingAddress: lendingAddress,
    }
}
```

### lending/helpers.go 的实现（新建）
```go
// GetYTTokenInfo 从 assets 表获取 YT token 信息（新实现）
func GetYTTokenInfo(assetCode string) (*TokenInfo, error) {
    var asset models.Asset
    db.Where("asset_code = ? AND is_active = ?", assetCode, true).
        First(&asset)

    return &TokenInfo{
        Symbol:             asset.Name,
        ContractAddressArb: asset.ContractAddressArb,
        ContractAddressBsc: asset.ContractAddressBsc,
    }
}
```

## 代码复用建议

### 选项 1：统一使用 holders 包的结构体（推荐）
```go
// lending/helpers.go
import "github.com/gothinkster/golang-gin-realworld-example-app/holders"

func GetYTTokensFromHolders(chainID int64) ([]TokenInfo, error) {
    // 复用 holders.LoadConfigFromDB
    config, err := holders.LoadConfigFromDB(chainID)
    if err != nil {
        return nil, err
    }

    tokens := make([]TokenInfo, len(config.YTVaults))
    for i, vault := range config.YTVaults {
        tokens[i] = TokenInfo{
            Symbol:             vault.Name,
            ContractAddressArb: vault.Address,  // 已根据 chainID 选择
            AssetCode:          vault.Name,
        }
    }
    return tokens, nil
}
```

### 选项 2：共享数据模型
```go
// common/models.go - 创建共享的 Asset 模型
type Asset struct {
    ID                 int64
    AssetCode          string
    Name               string
    ContractAddressArb string
    ContractAddressBsc string
}

// holders 和 lending 都使用这个共享模型
```

### 选项 3：保持当前实现（已完成）
- ✅ lending 包独立实现
- ✅ 功能完整，逻辑清晰
- ⚠️ 与 holders 包有重复代码

## 数据库表结构（一致）

两个包都使用相同的表：

### assets 表
```sql
CREATE TABLE assets (
  id BIGINT PRIMARY KEY,
  asset_code VARCHAR(20),         -- YT-A, YT-B, YT-C
  name VARCHAR(255),
  contract_address_arb VARCHAR(42),
  contract_address_bsc VARCHAR(42),
  is_active BOOLEAN
)
```

### lending_markets 表
```sql
CREATE TABLE lending_markets (
  id BIGINT PRIMARY KEY,
  market_name VARCHAR(100),
  contract_address_arb VARCHAR(42),
  contract_address_bsc VARCHAR(42),
  is_active BOOLEAN
)
```

## Chain ID 处理

### holders 包
- 421614 = Arbitrum Sepolia
- 97 = BSC Testnet

### lending 包（需要添加）
```go
// helpers.go 添加 chain ID 支持
func GetContractAddress(tokenInfo TokenInfo, chainID int) string {
    switch chainID {
    case 421614: // Arbitrum Sepolia
        return tokenInfo.ContractAddressArb
    case 97: // BSC Testnet
        return tokenInfo.ContractAddressBsc
    case 42161: // Arbitrum One (mainnet)
        return tokenInfo.ContractAddressArb
    case 56: // BSC Mainnet
        return tokenInfo.ContractAddressBsc
    default:
        return tokenInfo.ContractAddressArb
    }
}
```

## 总结

### 已实现功能
- ✅ lending 包可以独立从 assets 表读取 YT tokens
- ✅ lending 包可以从 lending_markets 表读取市场配置
- ✅ USDC 地址已硬编码
- ✅ 与 holders 包的实现逻辑一致

### 建议优化（可选）
1. 考虑复用 holders.Asset 结构体
2. 添加对 holders.LoadConfigFromDB 的引用
3. 统一 chain ID 处理逻辑

### 当前状态
**可以直接使用**，无需修改。与 holders 包的实现独立但兼容。
