# 以太坊(EVM)
Bitget Wallet 在其用户访问的网站中注入一个全局 API,地址是window?.bitkeep?.ethereum
。这个 API 允许网站请求用户的以太坊账户,从用户连接的区块链上读取数据,并建议用户签署信息和交易。提供者对象的存在表明是一个以太坊用户。
# 检测以太坊提供者
function getProvider() {
const provider = window.bitkeep && window.bitkeep.ethereum;
if (!provider) {
window.open('https://web3.bitget.com/zh-CN/wallet-download?type=2');
throw "Please go to our official website to download!!"
}
return provider;
}
2
3
4
5
6
7
8
# 基本用法
对于任何有一定复杂度的以太坊网络应用--又称 dapp、web3 站点等--来说,你必须:
- 检测以太坊提供者(
window?.bitkeep?.ethereum
) - 检测用户连接到哪个以太坊网络
- 获取用户的以太坊账户
你可以参考eth-requestaccounts或address-conflicts-when-switching-network代码片段
提供者 API 是你创建一个全功能的 web3 应用程序所需要的全部内容。
可以参考三方库的 Web3.0 登录以实现快速接入 Bitget 插件钱包。
提示
使用第三方库时,使用 window.bitkeep.ethereum
作为程序的提供者注入。
//npm install bitkeep-web3modal
// fork from https://github.com/WalletConnect/web3modal https://github.com/WalletConnect/web3modal/issues/574
import web3modal from 'bitkeep-web3modal';
const web3Modal = new Web3Modal({
network: 'mainnet', // optional
cacheProvider: true, // optional
providerOptions: {
bitkeep: {
package: true,
},
walletconnect: {
display: {
logo: 'data:image/gif;base64,INSERT_BASE64_STRING',
name: 'Mobile',
description: 'Scan qrcode with your mobile wallet',
},
package: WalletConnectProvider,
options: {
infuraId: 'INFURA_ID', // required
},
},
}, // required
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 链 ID 列表
这些是 Bitget Wallet 默认支持的以太坊链的 chainId。更多信息请参考 chainid.network (opens new window)。
Hex | Decimal | Network | Hex | Decimal | Network |
---|---|---|---|---|---|
0x1 | 1 | Ethereum | 0xa | 10 | Optimism |
0x18 | 24 | KardiaChain | 0x19 | 25 | Cronos |
0x38 | 56 | BNB Chain | 0x39 | 57 | Syscoin |
0x3d | 61 | Ethereum Classic | 0x42 | 66 | OKX Chain |
0x52 | 82 | Meter Mainnet | 0x56 | 86 | GateChain |
0x58 | 88 | TomoChain | 0x64 | 100 | Gnosis Chain |
0x6a | 106 | Velas | 0x73 | 115 | Lucky Chain |
0x7a | 122 | Fuse | 0x80 | 128 | Heco |
0x89 | 137 | Polygon | 0xc7 | 199 | BitTorrent |
0xfa | 250 | Fantom | 0x120 | 288 | Boba Network |
0x141 | 321 | KCC | 0x334 | 820 | Callisto Mainnet |
0x3e6 | 998 | Lucky Network | 0x500 | 1280 | HALO |
0x505 | 1285 | Moonriver | 0x71a | 1818 | CUBE |
0x7e3 | 2019 | ClassZZ | 0x868 | 2152 | Findora |
0x8ae | 2222 | Kava | 0x1251 | 4689 | IoTeX |
0x2019 | 8217 | KLAY | 0x2710 | 10000 | smartBCH |
0x4b82 | 19330 | TRUE | 0x4ef4 | 20212 | ZSC |
0x7f08 | 32520 | Bitgert | 0xa4b1 | 42161 | Arbitrum |
0xa4ec | 42220 | Celo | 0xa516 | 42262 | Oasis Emerald |
0xa86a | 43114 | AVAX-C | 0x116e2 | 71394 | Nervos CKB EVM |
0x335f9 | 210425 | PlatON | 0x3e900 | 256256 | Caduceus |
0xa3488 | 668808 | ASM | 0x4e454152 | 1313161554 | Aurora |
0x63564c40 | 1666600000 | Harmony |
# isConnected()
提示
请注意,这种方法与用户的账户没有任何关系。你可能经常遇到 "connected "这个词,指的是 web3 站点是否可以访问用户的账户。然而,在提供者界面中,"conented "和 "disconnected "指的是提供者是否能向当前链发出RPC
请求。
const Provider = getProvider();
Provider.isConnected();
2
# request(args)
const Provider = getProvider();
interface RequestArguments {
method: string;
params?: unknown[] | object;
}
Provider.request(args: RequestArguments): Promise<unknown>;
2
3
4
5
6
# eth_requestAccounts
提示
EIP-1102 该方法由EIP-1102 (opens new window)指定。它等同于被废弃的bitkeep.ethereum.enable()
提供者 API 方法。
在系统内部,它调用 wallet_requestPermissions 的 eth_accounts 权限。由于 eth_accounts 是目前唯一的权限,这个方法是你目前所需要的全部。
返回值
string[]
- 单个十六进制以太坊地址字符串数组。
描述
请求用户提供一个以太坊地址来识别。返回一个解析为单个以太坊地址字符串数组的 Promise。如果用户拒绝该请求,Promise 将拒绝并返回 4001 错误。
这个请求会弹出 Bitget Wallet 钱包窗口,通常用按钮来触发,在该请求未有响应时,应禁止用户点击按钮。
如果您没有获取到用户的账户信息,您应该提示用户点击按钮等操作来发起请求。
eth_accounts
- 获取 user
eth_chainId
- 获取 chainid(十六进制)
const Provider = getProvider();
function connect() {
Provider.request({ method: 'eth_requestAccounts' })
.then(handleAccountsChainChanged) // address or chainId changed
.catch((error) => {
if (error.code === 4001) {
// EIP-1193 userRejectedRequest error
console.log('Please connect to BitKeep.');
} else {
console.error(error);
}
});
}
//if used injected
const accounts = await Provider.request({ method: 'eth_requestAccounts' });
handleAccountsChainChanged(); // updated address or chainID,refer to accountsChanged/chainChanged(events)
const [address] = await Provider.request({ method: 'eth_accounts' }); // [0x1e805A9aB0FB007B4b9D44d598C6404cE292F20D]
const chainId = await Provider.request({ method: 'eth_chainId' }); // 0x1
//if used web3
import Web3 from 'web3';
const accounts = await Provider.request({ method: 'eth_requestAccounts' });
// [0x1e805A9aB0FB007B4b9D44d598C6404cE292F20D]
const web3 = new Web3(Provider);
handleAccountsChainChanged(); // updated address or chainID, refer to accountsChanged/chainChanged(events)
const accounts = await web3.eth.getAccounts(); // [0x1e805A9aB0FB007B4b9D44d598C6404cE292F20D]
const chainId = await web3.eth.getChainId(); // 0x1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# wallet_watchAsset
EIP-747
这个方法是由EIP-747 (opens new window)规定的。
参数
WatchAssetParams
- 要观察的资产的元数据。
interface WatchAssetParams {
type: 'ERC20'; // In the future, other standards will be supported
options: {
address: string; // The address of the token contract
'symbol': string; // A ticker symbol or shorthand, up to 11 characters
decimals: number; // The number of token decimals
image: string; // A string url of the token logo
};
}
2
3
4
5
6
7
8
9
返回值
boolean
- 如果该代币被添加,则为 true
,否则为 false
。
描述
要求用户在 Bitget Wallet 中跟踪代币。返回一个布尔值,表示该代币是否被成功添加。
很多以太坊钱包都支持一组代币,通常来自集中管理的代币注册表。wallet_watchAsset
使 web3 应用程序开发人员能够在运行时要求他们的用户跟踪他们钱包中的代币。添加后,token 与通过传统方法(例如集中式注册表)添加的 token 无法区分。
const Provider = getProvider();
Provider
.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC20',
options: {
address: '0xb60e8dd61c5d32be8058bb8eb970870f07233155',
symbol: 'FOO',
decimals: 18,
image: 'https://foo.io/token-image.svg',
},
},
})
.then((success) => {
if (success) {
console.log('FOO successfully added to wallet!');
} else {
throw new Error('Something went wrong.');
}
})
.catch(console.error);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# wallet_switchEthereumChain/wallet_addEthereumChain
wallet_addEthereumChain
创建一个确认,要求用户添加指定的链到 Bitget Wallet。用户可以选择在添加后切换到该链。
参数:
对于
rpcUrls
和blockExplorerUrls
数组,至少需要一个元素,并且只使用第一个元素。interface AddEthereumChainParameter { chainId: string; // A 0x-prefixed hexadecimal string chainName: string; nativeCurrency: { name: string, symbol: string, // 2-6 characters long decimals: 18, }; rpcUrls: string[]; blockExplorerUrls?: string[]; iconUrls?: string[]; // Currently ignored. }
1
2
3
4
5
6
7
8
9
10
11
12返回值
null
- 如果请求成功,该方法返回null
,否则返回错误。与 wallet_switchEthereumChain 一起使用
我们建议将此方法与
wallet_addEthereumChain
一起使用:const Provider = getProvider(); try { await Provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0xf00' }], }); } catch (switchError) { // This error code indicates that the chain has not been added to Bitkeep. if (switchError.code === 4902) { try { await ethereum.request({ method: 'wallet_addEthereumChain', params: [ { chainId: '0xf00', chainName: '...', rpcUrls: ['https://...'] /* ... */, }, ], }); } catch (addError) { // handle "add" error } } // handle other "switch" errors }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26wallet_switchEthereumChain
创建一个确认,要求用户切换到指定链ID的链上。
参数:
对于
rpcUrls
和blockExplorerUrls
数组,至少需要一个元素,并且只使用第一个元素。interface SwitchEthereumChainParameter { chainId: string; // A 0x-prefixed hexadecimal string }
1
2
3返回值
null
- 如果请求成功,该方法返回null
,否则返回错误。如果错误代码(
error.code
)是4902
,那么 Bitget Wallet 没有添加所请求的链,你必须通过wallet_addEthereumChain
请求添加它。描述
与任何导致确认出现的方法一样,
wallet_switchEthereumChain
应该只在用户直接操作的情况下被调用,例如点击按钮。在以下情况下,Bitget Wallet 将自动拒绝该请求:
- 如果链 ID 格式错误
- 如果指定的链 ID 未被添加到 Bitget Wallet
# sendTransaction(Transfer)
const Provider = getProvider();
const transactionParameters = {
nonce: '0x00', // ignored by Bitkeep
gasPrice: '0x09184e72a000', // customizable by user during Bitkeep confirmation.
gas: '0x2710', // customizable by user during Bitkeep confirmation.
to: '0x0000000000000000000000000000000000000000', // Required except during contract publications.
from: Provider.selectedAddress, // must match user's active address.
value: '0x00', // Only required to send ether to the recipient from the initiating external account.
data:
'0x7f7465737432000000000000000000000000000000000000000000000000000000600057', // Optional, but used for defining smart contract creation and interaction.
chainId: '0x3', // Used to prevent transaction reuse across blockchains. Auto-filled by Bitkeep.
};
// txHash is a hex string
// As with any RPC call, it may throw an error
const txHash = await Provider.request({
method: 'eth_sendTransaction',
params: [transactionParameters],
});
// if used web3
const accounts = await Provider.request({ method: 'eth_requestAccounts' });
const web3 = new Web3(Provider);
const result = await web3.eth.sendTransaction({
from: Provider.selectedAddress,
to: '0x0000000000000000000000000000000000000000',
value: web3.utils.toWei('1', 'ether'),
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 以太坊 JSON-RPC 方法
关于以太坊 JSON-RPC API,请参见Ethereum wiki (opens new window)。 如何使用参考API Playground (opens new window)。
- eth_accounts (opens new window)
- eth_call (opens new window)
- eth_getBalance (opens new window)
- eth_sendTransaction (opens new window)
- eth_sign (opens new window)
const Provider = getProvider();
await Provider.request({method:"eth_accounts", params:[]})
await Provider.request({method:"eth_getBalance", params:[]})
2
3
4
5
6
# 事件监听器
当地址和网络改变时通知。使用了eventemitter3 (opens new window)
const Provider = getProvider();
// reomove all listeners
Provider.removeAllListeners();
function handleAccountsChainChanged() {
Provider.on('accountsChanged', ([address]) => {
// Handle the new accounts, or lack thereof.
// "accounts" will always be an array, but it can be empty.
alert('address changed');
});
Provider.on('chainChanged', async (chainId) => {
// Handle the new chain.
// Correctly handling chain changes can be complicated.
// We recommend reloading the page unless you have good reason not to.
alert('chainid changed');
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
另外,一旦开启监听器,监听完后不要忘记删除它们(例如在 React 中的组件卸载)。使用 removeAllListeners
防止多次监听。
const Provider = getProvider();
function handleAccountsChanged(accounts) {
// ...
}
Provider.on('accountsChanged', handleAccountsChanged);
//remove
Provider.removeAllListeners(); //remove all
Provider.removeListener('accountsChanged', handleAccountsChanged); // only remove accountsChanged
2
3
4
5
6
7
8
9
accountsChanged
每当 eth_accounts RPC 方法的返回值发生变化时,Bitget Wallet 提供程序都会发出此事件。eth_accounts 返回一个空数组或包含单个帐户地址的数组。返回的地址(如果有)是允许调用者访问的最近使用的帐户的地址。调用者由其 URL 来源标识,这意味着具有相同来源的所有站点共享相同的权限。
这意味着只要用户暴露的账户地址发生变化,就会发出 accountsChanged。
const Provider = getProvider();
Provider.on('accountsChanged', handler: (accounts: Array<string>) => void);
2
chainChanged
当前连接的链发生变化时,BitKeep 提供者会发出这个事件。
所有 RPC 请求都提交给当前连接的链。因此,通过监听这个事件来跟踪当前链的ID是非常重要的。
我们强烈建议在链变化时重新加载页面,除非你有充分的理由不这样做。
const Provider = getProvider();
Provider.on('accountsChanged', handler: (accounts: Array<string>) => void);
2
# 签署数据
eth_sign
personal_sign
eth_signTypedData
eth_signTypedData_v3
eth_signTypedData_v4
你可以参考文档
- signing-data-with-metamask (opens new window)
- eth-sig-util (opens new window).
- demo (opens new window)
# 错误
所有由 Bitget Wallet 提供者抛出或返回的错误都遵循这个接口:
interface ProviderRpcError extends Error {
message: string;
code: number;
data?: unknown;
}
2
3
4
5
ethereum.request(args) 方法会及时的抛出错误。你通常可以使用错误代码属性来确定请求失败的原因。常见的代码及其含义包括:
4001
- 该请求被用户拒绝
-32603
- 内部错误或参数无效
# npm package
# 使用 onboard
# 安装
安装 npm 包
yarn add @web3-onboard/core @web3-onboard/injected-wallets ethers
然后在应用中初始化
import Onboard from '@web3-onboard/core'
import injectedModule, { ProviderLabel } from '@web3-onboard/injected-wallets'
import { ethers } from 'ethers'
const MAINNET_RPC_URL = 'https://mainnet.infura.io/v3/<INFURA_KEY>'
const injected = injectedModule({
// do a manual sort of injected wallets so that BitKeep ordered first
sort: wallets => {
const bitKeep = wallets.find(
({ label }) => label === ProviderLabel.BitKeep
)
return (
[
bitKeep,
...wallets.filter(
({ label }) =>
label !== ProviderLabel.BitKeep
)
]
// remove undefined values
.filter(wallet => wallet)
)
},
})
const appMetadata = {
name: 'BitKeep',
icon: `<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2029_330)">
<rect width="36" height="36" rx="18" fill="#54FFF5"/>
<g filter="url(#filter0_f_2029_330)">
<path d="M1.8957 27.9279C-4.1242 44.8644 28.0774 40.0809 44.9307 35.5721C62.1794 29.8479 50.2574 4.6153 37.8864 4.05686C25.5154 3.49843 39.4203 15.7243 28.9118 19.2162C18.4033 22.7081 9.42056 6.75722 1.8957 27.9279Z" fill="white"/>
</g>
<g filter="url(#filter1_f_2029_330)">
<path d="M12.0251 -6.44486C8.86728 -15.0727 -2.37922 -3.37541 -7.60774 3.55172C-12.5951 11.0869 0.423192 17.5984 5.52949 14.0667C10.6358 10.5349 1.09329 9.84779 4.13027 5.25529C7.16725 0.662788 15.9724 4.33996 12.0251 -6.44486Z" fill="#00FFF0" fill-opacity="0.67"/>
</g>
<g filter="url(#filter2_f_2029_330)">
<path d="M13.5675 31.6991C9.2602 17.2063 -9.29274 24.8386 -18.0308 30.4663C-26.4361 37.1299 -6.47874 56.2979 1.8102 55.3174C10.0991 54.3369 -4.83915 45.9925 0.279432 41.9292C5.39801 37.8658 18.9515 49.8152 13.5675 31.6991Z" fill="#9D81FF"/>
</g>
<g filter="url(#filter3_f_2029_330)">
<path d="M39.6731 -15.0985C30.3816 -26.1625 17.0806 -17.0133 11.5916 -11.0557C6.78848 -4.31133 31.5386 8.04621 38.4077 5.92842C45.2767 3.81064 29.0407 -0.571508 31.9636 -4.68304C34.8865 -8.79457 51.2875 -1.26834 39.6731 -15.0985Z" fill="#4D94FF"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.1047 21.4925H19.2197L12.2637 14.4916L19.3092 7.49057L21.2281 5.625H14.8809L6.79724 13.7499C6.38929 14.1594 6.39139 14.8221 6.80142 15.2295L13.1047 21.4925ZM16.7808 14.508H16.7337L16.7803 14.5074L16.7808 14.508ZM16.7808 14.508L23.7363 21.5084L16.6908 28.5094L14.7719 30.375H21.1191L29.2027 22.2506C29.6107 21.8411 29.6086 21.1784 29.1986 20.771L22.8953 14.508H16.7808Z" fill="black"/>
</g>
<defs>
<filter id="filter0_f_2029_330" x="-12.6901" y="-9.80709" width="80.0941" height="63.4814" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="6.92308" result="effect1_foregroundBlur_2029_330"/>
</filter>
<filter id="filter1_f_2029_330" x="-22.5718" y="-23.3422" width="49.4432" height="52.2431" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="6.92308" result="effect1_foregroundBlur_2029_330"/>
</filter>
<filter id="filter2_f_2029_330" x="-33.9015" y="9.51127" width="62.5572" height="59.6884" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="6.92308" result="effect1_foregroundBlur_2029_330"/>
</filter>
<filter id="filter3_f_2029_330" x="-2.86834" y="-34.1391" width="60.4956" height="54.1552" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="6.92308" result="effect1_foregroundBlur_2029_330"/>
</filter>
<clipPath id="clip0_2029_330">
<rect width="36" height="36" rx="18" fill="white"/>
</clipPath>
</defs>
</svg>
`,
description: 'The multi-chain wallet chosen by 10 million users',
recommendedInjectedWallets: [
{ name: 'BitKeep', url: 'https://web3.bitget.com/zh-CN/wallet-download?type=2' },
]
}
const onboard = Onboard({
wallets: [injected],
chains: [
{
id: '0x1',
token: 'ETH',
label: 'Ethereum Mainnet',
rpcUrl: MAINNET_RPC_URL
}
],
appMetadata
})
const wallets = await onboard.connectWallet()
console.log(wallets)
if (wallets[0]) {
// create an ethers provider with the last connected wallet provider
const ethersProvider = new ethers.providers.Web3Provider(wallets[0].provider, 'any')
// if using ethers v6 this is:
// ethersProvider = new ethers.BrowserProvider(wallet.provider, 'any')
const signer = ethersProvider.getSigner()
// send a transaction with the ethers provider
const txn = await signer.sendTransaction({
to: '0x',
value: 100000000000000
})
const receipt = await txn.wait()
console.log(receipt)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 使用 web3modal v1
提示:
web3modal v1 (opens new window), v1 版本默认支持了 Bitget Wallet, 但是官方不推荐使用V1版本了
查看官方demo (opens new window) 我们提供了一个简单的demo (opens new window)
# 安装
安装 npm 包
yarn add web3modal
然后在应用中初始化
import Web3 from "web3";
import Web3Modal from "web3modal";
const providerOptions = {
/* See Provider Options Section */
};
const web3Modal = new Web3Modal({
network: "mainnet", // optional
cacheProvider: true, // optional
providerOptions // required
});
const provider = await web3Modal.connectTo('bitkeep');
const web3 = new Web3(provider);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
← 快速接入 Bitget 插件钱包 BTC →