# 3. DApp集成指南

### 连接钱包

#### 完整的钱包连接流程

```javascript
class WalletConnector {
  constructor() {
    this.provider = null;
    this.connected = false;
    this.account = null;
    this.chainId = null;
  }

  // 检查钱包是否已安装
  isWalletInstalled() {
    return typeof window.jcWallet !== 'undefined' || 
           (typeof window.ethereum !== 'undefined');
  }

  // 连接钱包
  async connect() {
    if (!this.isWalletInstalled()) {
      throw new Error('请先安装 JuCoin 钱包');
    }

    try {
      // 使用 jucoin 对象或 ethereum 对象
      this.provider = window.jcWallet.ethereum || window.ethereum;
      
      // 请求用户授权
      const accounts = await this.provider.request({
        method: 'eth_requestAccounts'
      });

      // 获取当前链ID
      const chainId = await this.provider.request({
        method: 'eth_chainId'
      });

      // 更新状态
      this.connected = true;
      this.account = accounts[0];
      this.chainId = chainId;

      // 设置事件监听
      this.setupEventListeners();

      return {
        account: this.account,
        chainId: this.chainId
      };
    } catch (error) {
      this.handleError(error);
      throw error;
    }
  }

  // 设置事件监听
  setupEventListeners() {
    if (!this.provider) return;

    // 账户变更事件
    this.provider.on('accountsChanged', (accounts) => {
      if (accounts.length === 0) {
        this.disconnect();
      } else {
        this.account = accounts[0];
        this.onAccountChanged?.(accounts[0]);
      }
    });

    // 链变更事件
    this.provider.on('chainChanged', (chainId) => {
      this.chainId = chainId;
      this.onChainChanged?.(chainId);
    });

    // 断开连接事件
    this.provider.on('disconnect', () => {
      this.disconnect();
    });
  }

  // 断开连接
  disconnect() {
    this.connected = false;
    this.account = null;
    this.chainId = null;
    this.onDisconnect?.();
  }

  // 错误处理
  handleError(error) {
    const errorMessages = {
      4001: '用户拒绝连接请求',
      4100: '未授权的请求',
      4200: '不支持的方法',
      4900: '未连接到任何网络',
      4901: '未连接到请求的网络',
      -32002: '请求已在处理中，请在钱包中确认'
    };

    const message = errorMessages[error.code] || error.message;
    console.error('钱包连接错误:', message);
    return message;
  }

  // 获取当前状态
  getStatus() {
    return {
      installed: this.isWalletInstalled(),
      connected: this.connected,
      account: this.account,
      chainId: this.chainId
    };
  }
}

// 使用示例
const wallet = new WalletConnector();

// 设置事件回调
wallet.onAccountChanged = (account) => {
  console.log('账户已变更:', account);
};

wallet.onChainChanged = (chainId) => {
  console.log('链已变更:', chainId);
  // 通常需要刷新页面
  window.location.reload();
};

wallet.onDisconnect = () => {
  console.log('钱包已断开连接');
};

// 连接钱包
async function connectWallet() {
  try {
    const result = await wallet.connect();
    console.log('连接成功:', result);
  } catch (error) {
    console.error('连接失败:', error);
  }
}
```

### 获取账户信息

#### 账户信息管理类

```javascript
class AccountManager {
  constructor(provider) {
    this.provider = provider;
    this.web3 = null;
    
    // 如果使用 ethers.js
    if (typeof ethers !== 'undefined') {
      this.ethersProvider = new ethers.providers.Web3Provider(provider);
    }
  }

  // 获取当前账户
  async getCurrentAccount() {
    const accounts = await this.provider.request({
      method: 'eth_accounts'
    });
    return accounts[0] || null;
  }

  // 获取账户余额（原生代币）
  async getBalance(address) {
    const balance = await this.provider.request({
      method: 'eth_getBalance',
      params: [address, 'latest']
    });
    
    // 转换为易读格式
    if (this.ethersProvider) {
      return ethers.utils.formatEther(balance);
    }
    
    // 手动转换 (wei to ether)
    return parseInt(balance, 16) / 1e18;
  }

  // 获取账户的交易次数（nonce）
  async getNonce(address) {
    const nonce = await this.provider.request({
      method: 'eth_getTransactionCount',
      params: [address, 'latest']
    });
    return parseInt(nonce, 16);
  }

  // 获取 ERC20 代币余额
  async getTokenBalance(tokenAddress, accountAddress) {
    // ERC20 balanceOf 方法的 ABI
    const balanceOfABI = [{
      constant: true,
      inputs: [{ name: '_owner', type: 'address' }],
      name: 'balanceOf',
      outputs: [{ name: 'balance', type: 'uint256' }],
      type: 'function'
    }];

    // 构建调用数据
    const contract = new ethers.Contract(
      tokenAddress,
      balanceOfABI,
      this.ethersProvider
    );

    try {
      const balance = await contract.balanceOf(accountAddress);
      return balance.toString();
    } catch (error) {
      console.error('获取代币余额失败:', error);
      return '0';
    }
  }

  // 获取账户的交易历史（需要使用区块链浏览器API）
  async getTransactionHistory(address, limit = 10) {
    // 这里以 Etherscan API 为例
    // 实际使用时需要替换为相应的 API
    const chainId = await this.provider.request({
      method: 'eth_chainId'
    });

    // 根据链ID选择对应的API
    let apiUrl;
    switch (chainId) {
      case '0x1': // Ethereum Mainnet
        apiUrl = `https://api.etherscan.io/api?module=account&action=txlist&address=${address}&sort=desc&page=1&offset=${limit}`;
        break;
      case '0x38': // BSC
        apiUrl = `https://api.bscscan.com/api?module=account&action=txlist&address=${address}&sort=desc&page=1&offset=${limit}`;
        break;
      default:
        throw new Error('不支持的网络');
    }

    try {
      const response = await fetch(apiUrl);
      const data = await response.json();
      return data.result;
    } catch (error) {
      console.error('获取交易历史失败:', error);
      return [];
    }
  }

  // 获取账户完整信息
  async getAccountInfo(address) {
    try {
      const [balance, nonce, chainId] = await Promise.all([
        this.getBalance(address),
        this.getNonce(address),
        this.provider.request({ method: 'eth_chainId' })
      ]);

      return {
        address,
        balance,
        nonce,
        chainId,
        network: this.getNetworkName(chainId)
      };
    } catch (error) {
      console.error('获取账户信息失败:', error);
      throw error;
    }
  }

  // 获取网络名称
  getNetworkName(chainId) {
    const networks = {
      '0x1': 'Ethereum Mainnet',
      '0x3': 'Ropsten Testnet',
      '0x4': 'Rinkeby Testnet',
      '0x5': 'Goerli Testnet',
      '0x38': 'BNB Smart Chain',
      '0x89': 'Polygon Mainnet',
      // 添加 JuChain
      '0x...': 'JuChain Mainnet'
    };
    return networks[chainId] || 'Unknown Network';
  }
}

// 使用示例
async function displayAccountInfo() {
  const provider = window.jcWallet.ethereum || window.ethereum;
  const accountManager = new AccountManager(provider);
  
  try {
    const address = await accountManager.getCurrentAccount();
    if (!address) {
      console.log('请先连接钱包');
      return;
    }

    const info = await accountManager.getAccountInfo(address);
    console.log('账户信息:', info);
    
    // 显示在页面上
    document.getElementById('accountInfo').innerHTML = `
      <div class="info">
        <p><strong>地址:</strong> ${info.address}</p>
        <p><strong>余额:</strong> ${info.balance} ETH</p>
        <p><strong>Nonce:</strong> ${info.nonce}</p>
        <p><strong>网络:</strong> ${info.network}</p>
      </div>
    `;
  } catch (error) {
    console.error('获取账户信息失败:', error);
  }
}
```

### 发送交易

#### 交易管理类

```javascript
class TransactionManager {
  constructor(provider) {
    this.provider = provider;
    this.ethersProvider = null;
    
    if (typeof ethers !== 'undefined') {
      this.ethersProvider = new ethers.providers.Web3Provider(provider);
    }
  }

  // 发送ETH转账
  async sendETH(to, amount, from = null) {
    try {
      // 获取发送地址
      if (!from) {
        const accounts = await this.provider.request({
          method: 'eth_accounts'
        });
        from = accounts[0];
      }

      // 转换金额为 wei
      const value = ethers.utils.parseEther(amount.toString()).toHexString();

      // 构建交易参数
      const transactionParameters = {
        from: from,
        to: to,
        value: value,
        gas: '0x5208', // 21000 gas for standard transfer
      };

      // 发送交易
      const txHash = await this.provider.request({
        method: 'eth_sendTransaction',
        params: [transactionParameters]
      });

      console.log('交易已发送:', txHash);
      return txHash;
    } catch (error) {
      console.error('发送交易失败:', error);
      throw error;
    }
  }

  // 发送 ERC20 代币
  async sendToken(tokenAddress, to, amount, decimals = 18) {
    try {
      const signer = this.ethersProvider.getSigner();
      const from = await signer.getAddress();

      // ERC20 Transfer ABI
      const abi = [
        'function transfer(address to, uint256 amount) returns (bool)'
      ];

      // 创建合约实例
      const contract = new ethers.Contract(tokenAddress, abi, signer);

      // 转换金额
      const amountWei = ethers.utils.parseUnits(amount.toString(), decimals);

      // 发送交易
      const tx = await contract.transfer(to, amountWei);
      console.log('代币转账交易已发送:', tx.hash);
      
      // 等待交易确认
      const receipt = await tx.wait();
      console.log('交易已确认:', receipt);
      
      return receipt;
    } catch (error) {
      console.error('代币转账失败:', error);
      throw error;
    }
  }

  // 调用智能合约
  async contractCall(contractAddress, abi, methodName, params = [], value = '0') {
    try {
      const signer = this.ethersProvider.getSigner();
      const contract = new ethers.Contract(contractAddress, abi, signer);

      // 构建交易选项
      const options = {};
      if (value !== '0') {
        options.value = ethers.utils.parseEther(value);
      }

      // 调用合约方法
      const tx = await contract[methodName](...params, options);
      console.log('合约调用交易已发送:', tx.hash);

      // 等待交易确认
      const receipt = await tx.wait();
      return receipt;
    } catch (error) {
      console.error('合约调用失败:', error);
      throw error;
    }
  }

  // 发送 EIP-1559 交易（支持动态手续费）
  async sendEIP1559Transaction(params) {
    try {
      const accounts = await this.provider.request({
        method: 'eth_accounts'
      });

      // 获取建议的 gas 价格
      const { maxFeePerGas, maxPriorityFeePerGas } = await this.getSuggestedGasPrice();

      const transactionParameters = {
        from: params.from || accounts[0],
        to: params.to,
        value: params.value || '0x0',
        data: params.data || '0x',
        gas: params.gas || '0x5208',
        maxFeePerGas: params.maxFeePerGas || maxFeePerGas,
        maxPriorityFeePerGas: params.maxPriorityFeePerGas || maxPriorityFeePerGas,
        type: '0x2' // EIP-1559 transaction type
      };

      const txHash = await this.provider.request({
        method: 'eth_sendTransaction',
        params: [transactionParameters]
      });

      return txHash;
    } catch (error) {
      console.error('EIP-1559 交易失败:', error);
      throw error;
    }
  }

  // 批量发送交易（JuCoin 特有功能）
  async sendBatchTransactions(transactions) {
    try {
      const results = await this.provider.request({
        method: 'jucoin_batchSendTransactions',
        params: transactions
      });
      
      console.log('批量交易结果:', results);
      return results;
    } catch (error) {
      console.error('批量交易失败:', error);
      throw error;
    }
  }

  // 估算 Gas
  async estimateGas(transaction) {
    try {
      const gasEstimate = await this.provider.request({
        method: 'eth_estimateGas',
        params: [transaction]
      });
      
      // 添加 10% 的缓冲
      const gasWithBuffer = Math.ceil(parseInt
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jucoin-wallet.gitbook.io/jucoin-wallet-docs/3.-dapp-ji-cheng-zhi-nan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
