# 4. API参考

#### 概述

Ju.com 钱包的Provider API完全兼容以太坊的Provider标准，同时提供了一些扩展功能。Provider对象通过`window.jcEthereum`或`window.ethereum`（兼容模式）暴露给DApp。

#### Provider 对象

```javascript
// Provider 接口定义
interface JuCoinProvider {
    // 标准属性
    isConnected(): boolean;               // 检查连接状态
    chainId: string | null;               // 当前链ID
    selectedAddress: string | null;       // 当前选中的账户地址

    // 核心方法
    request(args: RequestArguments): Promise<any>;
    
    // 事件方法
    on(event: string, handler: Function): void;
    once(event: string, handler: Function): void;
    off(event: string, handler: Function): void;
    removeListener(event: string, handler: Function): void;
    removeAllListeners(event?: string): void;
    
    // 已弃用但仍支持的方法（向后兼容）
    enable(): Promise<string[]>;
    send(method: string, params?: any[]): Promise<any>;
    sendAsync(payload: any, callback: Function): void;
}
```

#### 基础用法

```javascript
// 获取provider
const provider = window.jucoin || window.ethereum;

// 检查是否为JuCoin钱包
if (provider?.isJuCoin) {
    console.log('JuCoin钱包已检测到');
}

// 检查连接状态
if (provider.isConnected()) {
    console.log('已连接到区块链网络');
}

// 获取当前账户
const account = provider.selectedAddress;

// 获取当前链ID
const chainId = provider.chainId;
```

#### request 方法

这是与Ju.com钱包交互的主要方法：

```javascript
// request 方法签名
provider.request({
    method: string,
    params?: Array<any> | Object
}): Promise<any>

// 使用示例
try {
    const result = await provider.request({
        method: 'method_name',
        params: [param1, param2, ...]
    });
    console.log('结果:', result);
} catch (error) {
    console.error('错误:', error);
}
```

#### 事件监听

```javascript
// 账户变更事件
provider.on('accountsChanged', (accounts) => {
    if (accounts.length === 0) {
        console.log('钱包已断开连接');
    } else {
        console.log('当前账户:', accounts[0]);
    }
});

// 链变更事件
provider.on('chainChanged', (chainId) => {
    console.log('切换到链:', chainId);
    // 建议刷新页面以确保状态一致
    window.location.reload();
});

// 连接事件
provider.on('connect', (connectInfo) => {
    console.log('已连接，链ID:', connectInfo.chainId);
});

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

// 消息事件（用于监听钱包内部消息）
provider.on('message', (message) => {
    console.log('钱包消息:', message);
});
```

#### 错误处理

```javascript
// Provider错误码
const ProviderErrors = {
    // 用户拒绝错误
    4001: 'User Rejected Request',
    
    // 未授权错误
    4100: 'Unauthorized',
    
    // 不支持的方法
    4200: 'Unsupported Method',
    
    // 断开连接
    4900: 'Disconnected',
    
    // 链断开连接
    4901: 'Chain Disconnected',
    
    // 内部错误
    -32603: 'Internal Error',
    
    // 无效参数
    -32602: 'Invalid Params',
    
    // 方法不存在
    -32601: 'Method Not Found',
    
    // 请求限制
    -32005: 'Request Limit Exceeded'
};

// 错误处理示例
try {
    const accounts = await provider.request({
        method: 'eth_requestAccounts'
    });
} catch (error) {
    switch (error.code) {
        case 4001:
            console.log('用户拒绝了连接请求');
            break;
        case -32002:
            console.log('请求已在处理中，请检查钱包');
            break;
        default:
            console.error('未知错误:', error);
    }
}
```

### Ethereum JSON-RPC

Ju.com钱包支持所有标准的Ethereum JSON-RPC方法。以下是常用方法的详细说明：

#### 账户相关方法

**eth\_requestAccounts**

请求用户授权访问账户：

```javascript
// 请求连接钱包
const accounts = await provider.request({
    method: 'eth_requestAccounts'
});

// 返回值: string[] - 用户授权的账户地址数组
// 示例: ['0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0']
```

**eth\_accounts**

获取当前已授权的账户列表：

```javascript
// 获取已连接的账户
const accounts = await provider.request({
    method: 'eth_accounts'
});

// 返回值: string[] - 已授权的账户地址数组
// 如果未连接，返回空数组 []
```

#### 交易相关方法

**eth\_sendTransaction**

发送交易：

```javascript
// 发送ETH
const transactionHash = await provider.request({
    method: 'eth_sendTransaction',
    params: [{
        from: '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        to: '0x5aeda56215b167893e80b4fe645ba6d5bab767de',
        value: '0x29a2241af62c0000',  // 3 ETH in wei
        gas: '0x5208',  // 21000
        gasPrice: '0x4a817c800'  // 20 Gwei
    }]
});

// 调用智能合约
const txHash = await provider.request({
    method: 'eth_sendTransaction',
    params: [{
        from: '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        to: '0xContractAddress',
        data: '0x095ea7b3...', // 合约调用数据
        gas: '0x186a0',  // 100000
        gasPrice: '0x4a817c800'
    }]
});

// EIP-1559 交易
const txHash = await provider.request({
    method: 'eth_sendTransaction',
    params: [{
        from: '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        to: '0x5aeda56215b167893e80b4fe645ba6d5bab767de',
        value: '0x29a2241af62c0000',
        gas: '0x5208',
        maxFeePerGas: '0x9184e72a000',  // 10000 Gwei
        maxPriorityFeePerGas: '0x77359400',  // 2 Gwei
        type: '0x2'  // EIP-1559
    }]
});
```

**eth\_signTransaction**

签名交易但不广播：

```javascript
const signedTx = await provider.request({
    method: 'eth_signTransaction',
    params: [{
        from: '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        to: '0x5aeda56215b167893e80b4fe645ba6d5bab767de',
        value: '0x29a2241af62c0000',
        gas: '0x5208',
        gasPrice: '0x4a817c800',
        nonce: '0x0'
    }]
});

// 返回已签名的交易数据
// 可以使用 eth_sendRawTransaction 广播
```

#### 签名相关方法

**personal\_sign**

签名消息：

```javascript
const message = 'Hello JuCoin!';
const accounts = await provider.request({ method: 'eth_accounts' });
const account = accounts[0];

// 将消息转换为hex
const hexMessage = '0x' + Buffer.from(message, 'utf8').toString('hex');

const signature = await provider.request({
    method: 'personal_sign',
    params: [hexMessage, account]
});

// 验证签名
const recoveredAddress = ethers.utils.verifyMessage(message, signature);
console.log('签名地址:', recoveredAddress);
```

**eth\_signTypedData\_v4**

签名结构化数据（EIP-712）：

```javascript
const typedData = {
    domain: {
        name: 'JuCoin Exchange',
        version: '1',
        chainId: 1,
        verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
    },
    types: {
        EIP712Domain: [
            { name: 'name', type: 'string' },
            { name: 'version', type: 'string' },
            { name: 'chainId', type: 'uint256' },
            { name: 'verifyingContract', type: 'address' }
        ],
        Order: [
            { name: 'maker', type: 'address' },
            { name: 'taker', type: 'address' },
            { name: 'tokenId', type: 'uint256' },
            { name: 'price', type: 'uint256' },
            { name: 'nonce', type: 'uint256' },
            { name: 'deadline', type: 'uint256' }
        ]
    },
    primaryType: 'Order',
    message: {
        maker: account,
        taker: '0x0000000000000000000000000000000000000000',
        tokenId: 1,
        price: '1000000000000000000',
        nonce: 0,
        deadline: Math.floor(Date.now() / 1000) + 3600
    }
};

const signature = await provider.request({
    method: 'eth_signTypedData_v4',
    params: [account, JSON.stringify(typedData)]
});
```

#### 查询方法

**eth\_getBalance**

获取账户余额：

```javascript
const balance = await provider.request({
    method: 'eth_getBalance',
    params: [
        '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        'latest'  // 或指定区块号
    ]
});

// 返回值为16进制的wei
// 转换为ETH
const balanceInEth = parseInt(balance, 16) / 1e18;
```

**eth\_getTransactionCount**

获取账户nonce：

```javascript
const nonce = await provider.request({
    method: 'eth_getTransactionCount',
    params: [
        '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        'pending'  // 包含pending交易
    ]
});

console.log('Nonce:', parseInt(nonce, 16));
```

**eth\_estimateGas**

估算Gas：

```javascript
const gasEstimate = await provider.request({
    method: 'eth_estimateGas',
    params: [{
        from: '0x742d35Cc6634C0532925a3b844Bc9e7095f0e5E0',
        to: '0x5aeda56215b167893e80b4fe645ba6d5bab767de',
        value: '0x29a2241af62c0000',
        data: '0x'
    }]
});

console.log('预估Gas:', parseInt(gasEstimate, 16));
```

#### 网络相关方法

**eth\_chainId**

获取当前链ID：

```javascript
const chainId = await provider.request({
    method: 'eth_chainId'
});

console.log('当前链ID:', chainId);
// 0x1 - Ethereum Mainnet
// 0x38 - BSC
// 0x8956 - JuChain
```

**wallet\_switchEthereumChain**

切换网络：

```javascript
try {
    await provider.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: '0x38' }]  // 切换到BSC
    });
} catch (error) {
    if (error.code === 4902) {
        console.log('用户钱包中未添加该网络');
    }
}
```

**wallet\_addEthereumChain**

添加自定义网络：

```javascript
try {
    await provider.request({
        method: 'wallet_addEthereumChain',
        params: [{
            chainId: '0x8956',
            chainName: 'JuChain Mainnet',
            nativeCurrency: {
                name: 'JU',
                symbol: 'JU',
                decimals: 18
            },
            rpcUrls: ['https://rpc.juchain.com'],
            blockExplorerUrls: ['https://explorer.juchain.com']
        }]
    });
} catch (error) {
    console.error('添加网络失败:', error);
}
```

### Ju.com扩展API (后续支持)


---

# 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/4.-api-can-kao.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.
