# 3. DApp Integration Guide

## Connecting to Wallet

#### Complete Wallet Connection Process

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

  // Check if wallet is installed
  isWalletInstalled() {
    return typeof window.jcWallet !== 'undefined' || 
           (typeof window.ethereum !== 'undefined');
  }

  // Connect wallet
  async connect() {
    if (!this.isWalletInstalled()) {
      throw new Error('Please install JuCoin Wallet first');
    }

    try {
      // Use jucoin object or ethereum object
      this.provider = window.jcWallet.ethereum || window.ethereum;
      
      // Request user authorization
      const accounts = await this.provider.request({
        method: 'eth_requestAccounts'
      });

      // Get current chain ID
      const chainId = await this.provider.request({
        method: 'eth_chainId'
      });

      // Update state
      this.connected = true;
      this.account = accounts[0];
      this.chainId = chainId;

      // Set up event listeners
      this.setupEventListeners();

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

  // Set up event listeners
  setupEventListeners() {
    if (!this.provider) return;

    // Account changed event
    this.provider.on('accountsChanged', (accounts) => {
      if (accounts.length === 0) {
        this.disconnect();
      } else {
        this.account = accounts[0];
        this.onAccountChanged?.(accounts[0]);
      }
    });

    // Chain changed event
    this.provider.on('chainChanged', (chainId) => {
      this.chainId = chainId;
      this.onChainChanged?.(chainId);
    });

    // Disconnect event
    this.provider.on('disconnect', () => {
      this.disconnect();
    });
  }

  // Disconnect
  disconnect() {
    this.connected = false;
    this.account = null;
    this.chainId = null;
    this.onDisconnect?.();
  }

  // Error handling
  handleError(error) {
    const errorMessages = {
      4001: 'User rejected connection request',
      4100: 'Unauthorized request',
      4200: 'Unsupported method',
      4900: 'Not connected to any network',
      4901: 'Not connected to requested network',
      -32002: 'Request already pending, please confirm in wallet'
    };

    const message = errorMessages[error.code] || error.message;
    console.error('Wallet connection error:', message);
    return message;
  }

  // Get current status
  getStatus() {
    return {
      installed: this.isWalletInstalled(),
      connected: this.connected,
      account: this.account,
      chainId: this.chainId
    };
  }
}

// Usage example
const wallet = new WalletConnector();

// Set event callbacks
wallet.onAccountChanged = (account) => {
  console.log('Account changed:', account);
};

wallet.onChainChanged = (chainId) => {
  console.log('Chain changed:', chainId);
  // Usually need to refresh the page
  window.location.reload();
};

wallet.onDisconnect = () => {
  console.log('Wallet disconnected');
};

// Connect wallet
async function connectWallet() {
  try {
    const result = await wallet.connect();
    console.log('Connection successful:', result);
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

### Getting Account Information

#### Account Information Management Class

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

  // Get current account
  async getCurrentAccount() {
    const accounts = await this.provider.request({
      method: 'eth_accounts'
    });
    return accounts[0] || null;
  }

  // Get account balance (native token)
  async getBalance(address) {
    const balance = await this.provider.request({
      method: 'eth_getBalance',
      params: [address, 'latest']
    });
    
    // Convert to readable format
    if (this.ethersProvider) {
      return ethers.utils.formatEther(balance);
    }
    
    // Manual conversion (wei to ether)
    return parseInt(balance, 16) / 1e18;
  }

  // Get account transaction count (nonce)
  async getNonce(address) {
    const nonce = await this.provider.request({
      method: 'eth_getTransactionCount',
      params: [address, 'latest']
    });
    return parseInt(nonce, 16);
  }

  // Get ERC20 token balance
  async getTokenBalance(tokenAddress, accountAddress) {
    // ERC20 balanceOf method ABI
    const balanceOfABI = [{
      constant: true,
      inputs: [{ name: '_owner', type: 'address' }],
      name: 'balanceOf',
      outputs: [{ name: 'balance', type: 'uint256' }],
      type: 'function'
    }];

    // Build call data
    const contract = new ethers.Contract(
      tokenAddress,
      balanceOfABI,
      this.ethersProvider
    );

    try {
      const balance = await contract.balanceOf(accountAddress);
      return balance.toString();
    } catch (error) {
      console.error('Failed to get token balance:', error);
      return '0';
    }
  }

  // Get account transaction history (requires blockchain explorer API)
  async getTransactionHistory(address, limit = 10) {
    // Using Etherscan API as example
    // Replace with appropriate API in actual use
    const chainId = await this.provider.request({
      method: 'eth_chainId'
    });

    // Select corresponding API based on chain ID
    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('Unsupported network');
    }

    try {
      const response = await fetch(apiUrl);
      const data = await response.json();
      return data.result;
    } catch (error) {
      console.error('Failed to get transaction history:', error);
      return [];
    }
  }

  // Get complete account information
  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('Failed to get account info:', error);
      throw error;
    }
  }

  // Get network name
  getNetworkName(chainId) {
    const networks = {
      '0x1': 'Ethereum Mainnet',
      '0x3': 'Ropsten Testnet',
      '0x4': 'Rinkeby Testnet',
      '0x5': 'Goerli Testnet',
      '0x38': 'BNB Smart Chain',
      '0x89': 'Polygon Mainnet',
      // Add JuChain
      '0x8956': 'JuChain Mainnet'
    };
    return networks[chainId] || 'Unknown Network';
  }
}

// Usage example
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('Please connect wallet first');
      return;
    }

    const info = await accountManager.getAccountInfo(address);
    console.log('Account info:', info);
    
    // Display on page
    document.getElementById('accountInfo').innerHTML = `
      <div class="info">
        <p><strong>Address:</strong> ${info.address}</p>
        <p><strong>Balance:</strong> ${info.balance} ETH</p>
        <p><strong>Nonce:</strong> ${info.nonce}</p>
        <p><strong>Network:</strong> ${info.network}</p>
      </div>
    `;
  } catch (error) {
    console.error('Failed to get account info:', error);
  }
}
```

### Sending Transactions

#### Transaction Management Class

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

  // Send ETH transfer
  async sendETH(to, amount, from = null) {
    try {
      // Get sender address
      if (!from) {
        const accounts = await this.provider.request({
          method: 'eth_accounts'
        });
        from = accounts[0];
      }

      // Convert amount to wei
      const value = ethers.utils.parseEther(amount.toString()).toHexString();

      // Build transaction parameters
      const transactionParameters = {
        from: from,
        to: to,
        value: value,
        gas: '0x5208', // 21000 gas for standard transfer
      };

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

      console.log('Transaction sent:', txHash);
      return txHash;
    } catch (error) {
      console.error('Failed to send transaction:', error);
      throw error;
    }
  }

  // Send ERC20 tokens
  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)'
      ];

      // Create contract instance
      const contract = new ethers.Contract(tokenAddress, abi, signer);

      // Convert amount
      const amountWei = ethers.utils.parseUnits(amount.toString(), decimals);

      // Send transaction
      const tx = await contract.transfer(to, amountWei);
      console.log('Token transfer transaction sent:', tx.hash);
      
      // Wait for transaction confirmation
      const receipt = await tx.wait();
      console.log('Transaction confirmed:', receipt);
      
      return receipt;
    } catch (error) {
      console.error('Token transfer failed:', error);
      throw error;
    }
  }

  // Call smart contract
  async contractCall(contractAddress, abi, methodName, params = [], value = '0') {
    try {
      const signer = this.ethersProvider.getSigner();
      const contract = new ethers.Contract(contractAddress, abi, signer);

      // Build transaction options
      const options = {};
      if (value !== '0') {
        options.value = ethers.utils.parseEther(value);
      }

      // Call contract method
      const tx = await contract[methodName](...params, options);
      console.log('Contract call transaction sent:', tx.hash);

      // Wait for transaction confirmation
      const receipt = await tx.wait();
      return receipt;
    } catch (error) {
      console.error('Contract call failed:', error);
      throw error;
    }
  }

  // Send EIP-1559 transaction (supports dynamic gas fees)
  async sendEIP1559Transaction(params) {
    try {
      const accounts = await this.provider.request({
        method: 'eth_accounts'
      });

      // Get suggested gas prices
      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 transaction failed:', error);
      throw error;
    }
  }

  // Batch send transactions (JuCoin specific feature)
  async sendBatchTransactions(transactions) {
    try {
      const results = await this.provider.request({
        method: 'jucoin_batchSendTransactions',
        params: transactions
      });
      
      console.log('Batch transaction results:', results);
      return results;
    } catch (error) {
      console.error('Batch transactions failed:', error);
      throw error;
    }
  }

  // Estimate gas
  async estimateGas(transaction) {
    try {
      const gasEstimate = await this.provider.request({
        method: 'eth_estimateGas',
        params: [transaction]
      });
      
      // Add 10% buffer
      const gasWithBuffer = Math.ceil(parseInt(gasEstimate, 16) * 1.1);
      return '0x' + gasWithBuffer.toString(16);
    } catch (error) {
      console.error('Gas estimation failed:', error);
      throw error;
    }
  }
```


---

# 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/developer-documentation-for-jucoin-wallet/developer-guide/3.-dapp-integration-guide.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.
