EtherWallet
以太坊钱包 web3swift lib、Generate Account、Import Account、ETH Transfer、ERC20 Transfer、Get ETH Balance、ERC20 Balance、Estimate Transaction Fee with Swift.
Install / Use
/learn @smithSophiav/EtherWalletREADME
EtherWallet
EtherWallet is an iOS toolbelt for interaction with the Ethereum network.

For more specific usage, please refer to the demo
Swift Package Manager
dependencies: [
.package(url: "https://github.com/smithSophiav/EtherWallet.git", .upToNextMajor(from: "1.1.6"))
]
Example usage in Swift Package Manager
import EtherWallet
Quick Start
- Create and setup (must be called before any other API; loads the JS bundle).
let etherWeb = EtherWeb()
// Async (recommended)
Task { @MainActor in
let ready = await etherWeb.setup(showLog: false)
if ready {
// Call any EtherWeb API
}
}
// Or with completion
etherWeb.setup(showLog: true) { success in
if success {
// Call any EtherWeb API
}
}
- Call APIs — All methods have both completion-handler and async variants. Use async when you are in an async context (e.g.
Taskorasyncfunction).
API Reference
Wallet
| Method | Description | Returns |
|--------|-------------|--------|
| generateAccount(password: String?) | Create new wallet (mnemonic + derived key). Optional password returns keystore in result. | [String: Any]? → address, privateKey, mnemonic, keystore? |
| importAccountFromPrivateKey(privateKey:) | Import from hex private key. | address, privateKey |
| importAccountFromMnemonic(mnemonic:) | Import from 12/24-word mnemonic (first account). | address, privateKey, mnemonic |
| importAccountFromKeystore(json:password:) | Import from Keystore JSON string. | address, privateKey, keystore |
| privateKeyToKeystore(privateKey:password:) | Encrypt private key to Keystore JSON (light PBKDF2). | Keystore JSON string or nil |
| getAddressFromPrivateKey(privateKey:) | Get Ethereum address from private key. | Address string or nil |
Example
// Generate wallet (optional password for keystore)
let result = await etherWeb.generateAccount(password: "myPassword")
if let r = result {
print(r["address"] as? String ?? "")
print(r["privateKey"] as? String ?? "")
print(r["keystore"] as? String ?? "")
}
// Import from mnemonic
let imported = await etherWeb.importAccountFromMnemonicAsync(mnemonic: "abandon abandon ...")
Sign & Verify Message (EIP-191)
| Method | Description | Returns |
|--------|-------------|--------|
| signMessage(privateKey:message:) | Sign message with private key (personal_sign). | Signature hex or nil |
| verifyMessage(message:signature:) | Recover signer address from message + signature. | Recovered address or nil |
| verifyMessageSignature(message:signature:expectedAddress:) | Check if signature was produced by expected address. | Bool |
Example
let signature = await etherWeb.signMessage(privateKey: pk, message: "Hello")
let recovered = await etherWeb.verifyMessage(message: "Hello", signature: signature ?? "")
let isValid = await etherWeb.verifyMessageSignature(message: "Hello", signature: sig, expectedAddress: "0x...")
Balance & Gas
All of these require rpcUrl and chainId from the caller (e.g. from your NetworkManager).
| Method | Description | Returns |
|--------|-------------|--------|
| getETHBalance(address:rpcUrl:chainId:) | Native ETH balance. | Human-readable ETH string or nil |
| getERC20TokenBalance(tokenAddress:walletAddress:rpcUrl:chainId:) | ERC20 balance. | Dict: balance, decimals |
| getGasPrice(rpcUrl:chainId:) | Current gas price (legacy). | gasPriceWei, gasPriceGwei |
| getSuggestedFees(rpcUrl:chainId:) | EIP-1559 style fees. | gasPrice?, maxFeePerGas?, maxPriorityFeePerGas? |
Example
let rpcUrl = NetworkManager.shared.currentRpcUrl // your source of RPC URL
let chainId = NetworkManager.shared.currentChainId
let ethBalance = await etherWeb.getETHBalance(address: "0x...", rpcUrl: rpcUrl, chainId: chainId)
let tokenBalance = await etherWeb.getERC20TokenBalance(
tokenAddress: "0x...", walletAddress: "0x...", rpcUrl: rpcUrl, chainId: chainId
)
let gasPrice = await etherWeb.getGasPrice(rpcUrl: rpcUrl, chainId: chainId)
let fees = await etherWeb.getSuggestedFees(rpcUrl: rpcUrl, chainId: chainId)
Transfer
| Method | Description | Returns |
|--------|-------------|--------|
| getAddressFromPrivateKey(privateKey:) | Resolve address from private key (e.g. for estimate). | Address string or nil |
| estimateEthTransferGas(fromAddress:to:valueEth:rpcUrl:chainId:) | Estimate gas for ETH transfer. | gasLimit, gasPrice, estimatedFeeWei, estimatedFeeEth |
| ethTransfer(privateKey:to:valueEth:gasLimit:gasPrice:maxFeePerGas:maxPriorityFeePerGas:rpcUrl:chainId:) | Send ETH. Gas params optional (pass nil to let provider decide). | hash, from, to |
| estimateErc20TransferGas(fromAddress:tokenAddress:to:amountHuman:decimals:rpcUrl:chainId:) | Estimate gas for ERC20 transfer. | gasLimit, gasPrice, estimatedFeeWei, estimatedFeeEth |
| erc20Transfer(privateKey:tokenAddress:to:amountHuman:decimals:gasLimit:gasPrice:maxFeePerGas:maxPriorityFeePerGas:rpcUrl:chainId:) | Send ERC20. Gas params optional. | hash, from, to |
Example
let rpcUrl = NetworkManager.shared.currentRpcUrl
let chainId = NetworkManager.shared.currentChainId
// 1) Estimate ETH transfer
let from = await etherWeb.getAddressFromPrivateKey(privateKey: privateKey)
let estimate = await etherWeb.estimateEthTransferGas(
fromAddress: from!, to: "0x...", valueEth: "0.01", rpcUrl: rpcUrl, chainId: chainId
)
let gasLimit = estimate?["gasLimit"] as? String
let gasPrice = estimate?["gasPrice"] as? String
// 2) Send ETH (optionally use estimated gas)
let tx = await etherWeb.ethTransfer(
privateKey: privateKey, to: "0x...", valueEth: "0.01",
gasLimit: gasLimit, gasPrice: gasPrice, maxFeePerGas: nil, maxPriorityFeePerGas: nil,
rpcUrl: rpcUrl, chainId: chainId
)
let txHash = tx?["hash"] as? String
// ERC20 transfer
let erc20Tx = await etherWeb.erc20Transfer(
privateKey: pk, tokenAddress: "0x...", to: "0x...", amountHuman: "10", decimals: 18,
gasLimit: nil, gasPrice: nil, maxFeePerGas: nil, maxPriorityFeePerGas: nil,
rpcUrl: rpcUrl, chainId: chainId
)
Conventions
- MainActor:
EtherWebis@MainActor; call its methods from the main thread or from Swift concurrency (e.g.Task { @MainActor in ... }). - rpcUrl + chainId: For balance, gas, and transfer APIs you must supply the current chain's RPC URL and chain ID. EtherWeb does not store or choose networks; your app does (e.g. via a
NetworkManager). - Async vs completion: Prefer the async overloads when writing async Swift code; use the completion versions from callback-based code.
- Errors: Failed bridge calls typically return
nil(orfalseforverifyMessageSignature). Ensure your JS bundle returns{ state: true, result }on success and{ state: false, error }on failure so the native side can distinguish.
License
EtherWallet is released under the MIT license. See LICENSE for details.
Related Skills
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
