@tetherto/wdk-wallet-evm 1.0.0-beta.10 → 1.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -448
- package/hardhat.config.cjs +1 -0
- package/package.json +9 -3
- package/src/wallet-account-evm.js +17 -2
- package/src/wallet-account-read-only-evm.js +37 -14
- package/src/wallet-manager-evm.js +30 -12
- package/types/src/wallet-account-evm.d.ts +7 -0
- package/types/src/wallet-account-read-only-evm.d.ts +14 -2
package/README.md
CHANGED
|
@@ -1,493 +1,99 @@
|
|
|
1
1
|
# @tetherto/wdk-wallet-evm
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@tetherto/wdk-wallet-evm)
|
|
4
|
+
[](https://www.npmjs.com/package/@tetherto/wdk-wallet-evm)
|
|
5
|
+
[](https://github.com/tetherto/wdk-wallet-evm/blob/main/LICENSE)
|
|
6
|
+
[](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm)
|
|
3
7
|
|
|
4
8
|
**Note**: This package is currently in beta. Please test thoroughly in development environments before using in production.
|
|
5
9
|
|
|
6
10
|
A simple and secure package to manage BIP-44 wallets for EVM-compatible blockchains. This package provides a clean API for creating, managing, and interacting with Ethereum-compatible wallets using BIP-39 seed phrases and EVM-specific derivation paths.
|
|
7
11
|
|
|
8
|
-
##
|
|
12
|
+
## About WDK
|
|
9
13
|
|
|
10
|
-
This module is part of the [**WDK (Wallet Development Kit)**](https://
|
|
14
|
+
This module is part of the [**WDK (Wallet Development Kit)**](https://docs.wdk.tether.io/) project, which empowers developers to build secure, non-custodial wallets with unified blockchain access, stateless architecture, and complete user control.
|
|
11
15
|
|
|
12
|
-
For detailed documentation about the complete WDK ecosystem, visit [docs.
|
|
16
|
+
For detailed documentation about the complete WDK ecosystem, visit [docs.wdk.tether.io](https://docs.wdk.tether.io).
|
|
13
17
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
- **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases
|
|
17
|
-
- **EVM Derivation Paths**: Support for BIP-44 standard derivation paths for Ethereum (m/44'/60')
|
|
18
|
-
- **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
|
|
19
|
-
- **Transaction Management**: Send transactions and get fee estimates with EIP-1559 support
|
|
20
|
-
- **ERC20 Support**: Query native token and ERC20 token balances using smart contract interactions
|
|
21
|
-
- **EIP-7702 Delegation**: Delegate EOAs to smart contracts, sign authorizations, and send type 4 transactions
|
|
22
|
-
|
|
23
|
-
## ⬇️ Installation
|
|
24
|
-
|
|
25
|
-
To install the `@tetherto/wdk-wallet-evm` package, follow these instructions:
|
|
26
|
-
|
|
27
|
-
You can install it using npm:
|
|
18
|
+
## Installation
|
|
28
19
|
|
|
29
20
|
```bash
|
|
30
21
|
npm install @tetherto/wdk-wallet-evm
|
|
31
22
|
```
|
|
32
23
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
### Importing from `@tetherto/wdk-wallet-evm`
|
|
36
|
-
|
|
37
|
-
### Creating a New Wallet
|
|
24
|
+
## Quick Start
|
|
38
25
|
|
|
39
26
|
```javascript
|
|
40
|
-
import WalletManagerEvm
|
|
27
|
+
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
const seedPhrase = 'test only example nut use this real life secret phrase must random'
|
|
29
|
+
const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
|
|
44
30
|
|
|
45
|
-
// Create wallet manager with provider config
|
|
46
31
|
const wallet = new WalletManagerEvm(seedPhrase, {
|
|
47
|
-
|
|
48
|
-
provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key', // or any EVM RPC endpoint
|
|
49
|
-
transferMaxFee: 100000000000000 // Optional: Maximum fee in wei
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// OR
|
|
53
|
-
|
|
54
|
-
// Option 2: Using EIP-1193 provider (e.g., from browser wallet)
|
|
55
|
-
const wallet2 = new WalletManagerEvm(seedPhrase, {
|
|
56
|
-
provider: window.ethereum, // EIP-1193 provider
|
|
57
|
-
transferMaxFee: 100000000000000 // Optional: Maximum fee in wei
|
|
32
|
+
provider: 'https://sepolia.drpc.org',
|
|
58
33
|
})
|
|
59
34
|
|
|
60
|
-
// Get a full access account
|
|
61
|
-
const account = await wallet.getAccount(0)
|
|
62
|
-
|
|
63
|
-
// Convert to a read-only account
|
|
64
|
-
const readOnlyAccount = await account.toReadOnlyAccount()
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Managing Multiple Accounts
|
|
68
|
-
|
|
69
|
-
```javascript
|
|
70
|
-
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
|
|
71
|
-
|
|
72
|
-
// Assume wallet is already created
|
|
73
|
-
// Get the first account (index 0)
|
|
74
35
|
const account = await wallet.getAccount(0)
|
|
75
36
|
const address = await account.getAddress()
|
|
76
|
-
console.log('
|
|
77
|
-
|
|
78
|
-
// Get the second account (index 1)
|
|
79
|
-
const account1 = await wallet.getAccount(1)
|
|
80
|
-
const address1 = await account1.getAddress()
|
|
81
|
-
console.log('Account 1 address:', address1)
|
|
82
|
-
|
|
83
|
-
// Get account by custom derivation path
|
|
84
|
-
// Full path will be m/44'/60'/0'/0/5
|
|
85
|
-
const customAccount = await wallet.getAccountByPath("0'/0/5")
|
|
86
|
-
const customAddress = await customAccount.getAddress()
|
|
87
|
-
console.log('Custom account address:', customAddress)
|
|
88
|
-
|
|
89
|
-
// Note: All addresses are checksummed Ethereum addresses (0x...)
|
|
90
|
-
// All accounts inherit the provider configuration from the wallet manager
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Checking Balances
|
|
94
|
-
|
|
95
|
-
#### Owned Account
|
|
96
|
-
|
|
97
|
-
For accounts where you have the seed phrase and full access:
|
|
98
|
-
|
|
99
|
-
```javascript
|
|
100
|
-
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
|
|
101
|
-
|
|
102
|
-
// Assume wallet and account are already created
|
|
103
|
-
// Get native token balance (in wei)
|
|
104
|
-
const balance = await account.getBalance()
|
|
105
|
-
console.log('Native balance:', balance, 'wei') // 1 ETH = 1000000000000000000 wei
|
|
106
|
-
|
|
107
|
-
// Get ERC20 token balance
|
|
108
|
-
const tokenContract = '0x...'; // ERC20 contract address
|
|
109
|
-
const tokenBalance = await account.getTokenBalance(tokenContract);
|
|
110
|
-
console.log('Token balance:', tokenBalance);
|
|
111
|
-
|
|
112
|
-
// Note: Provider is required for balance checks
|
|
113
|
-
// Make sure wallet was created with a provider configuration
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
#### Read-Only Account
|
|
117
|
-
|
|
118
|
-
For addresses where you don't have the seed phrase:
|
|
119
|
-
|
|
120
|
-
```javascript
|
|
121
|
-
import { WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
|
|
122
|
-
|
|
123
|
-
// Create a read-only account
|
|
124
|
-
const readOnlyAccount = new WalletAccountReadOnlyEvm('0x...', { // Ethereum address
|
|
125
|
-
provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' // Required for balance checks
|
|
126
|
-
})
|
|
37
|
+
console.log('Address:', address)
|
|
127
38
|
|
|
128
|
-
// Check native token balance
|
|
129
|
-
const balance = await readOnlyAccount.getBalance()
|
|
130
|
-
console.log('Native balance:', balance, 'wei')
|
|
131
|
-
|
|
132
|
-
// Check ERC20 token balance using contract
|
|
133
|
-
const tokenBalance = await readOnlyAccount.getTokenBalance('0x...') // ERC20 contract address
|
|
134
|
-
console.log('Token balance:', tokenBalance)
|
|
135
|
-
|
|
136
|
-
// Note: ERC20 balance checks use the standard balanceOf(address) function
|
|
137
|
-
// Make sure the contract address is correct and implements the ERC20 standard
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Sending Transactions
|
|
141
|
-
|
|
142
|
-
Send native tokens and estimate fees using `WalletAccountEvm`. Supports EIP-1559 fee model.
|
|
143
|
-
|
|
144
|
-
```javascript
|
|
145
|
-
// Send native tokens
|
|
146
|
-
// Modern EIP-1559 style transaction (recommended)
|
|
147
|
-
const result = await account.sendTransaction({
|
|
148
|
-
to: '0x...', // Recipient address
|
|
149
|
-
value: 1000000000000000000n, // 1 ETH in wei
|
|
150
|
-
maxFeePerGas: 30000000000, // Optional: max fee per gas (in wei)
|
|
151
|
-
maxPriorityFeePerGas: 2000000000 // Optional: max priority fee per gas (in wei)
|
|
152
|
-
})
|
|
153
|
-
console.log('Transaction hash:', result.hash)
|
|
154
|
-
console.log('Transaction fee:', result.fee, 'wei')
|
|
155
|
-
|
|
156
|
-
// OR Legacy style transaction
|
|
157
|
-
const legacyResult = await account.sendTransaction({
|
|
158
|
-
to: '0x...',
|
|
159
|
-
value: 1000000000000000000n,
|
|
160
|
-
gasPrice: 20000000000n, // Optional: legacy gas price (in wei)
|
|
161
|
-
gasLimit: 21000 // Optional: gas limit
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
// Get transaction fee estimate
|
|
165
|
-
const quote = await account.quoteSendTransaction({
|
|
166
|
-
to: '0x...',
|
|
167
|
-
value: 1000000000000000000n
|
|
168
|
-
});
|
|
169
|
-
console.log('Estimated fee:', quote.fee, 'wei');
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Token Transfers
|
|
173
|
-
|
|
174
|
-
Transfer ERC20 tokens and estimate fees using `WalletAccountEvm`. Uses standard ERC20 `transfer` function.
|
|
175
|
-
|
|
176
|
-
```javascript
|
|
177
|
-
// Transfer ERC20 tokens
|
|
178
|
-
const transferResult = await account.transfer({
|
|
179
|
-
token: '0x...', // ERC20 contract address
|
|
180
|
-
recipient: '0x...', // Recipient's address
|
|
181
|
-
amount: 1000000n // Amount in token's base units (use BigInt for large numbers)
|
|
182
|
-
});
|
|
183
|
-
console.log('Transfer hash:', transferResult.hash);
|
|
184
|
-
console.log('Transfer fee:', transferResult.fee, 'wei');
|
|
185
|
-
|
|
186
|
-
// Quote token transfer fee
|
|
187
|
-
const transferQuote = await account.quoteTransfer({
|
|
188
|
-
token: '0x...', // ERC20 contract address
|
|
189
|
-
recipient: '0x...', // Recipient's address
|
|
190
|
-
amount: 1000000n // Amount in token's base units
|
|
191
|
-
})
|
|
192
|
-
console.log('Transfer fee estimate:', transferQuote.fee, 'wei')
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Message Signing and Verification
|
|
196
|
-
|
|
197
|
-
Sign messages using `WalletAccountEvm` and verify signatures using `WalletAccountReadOnlyEvm`.
|
|
198
|
-
|
|
199
|
-
```javascript
|
|
200
|
-
// Sign a message
|
|
201
|
-
const message = 'Hello, Ethereum!'
|
|
202
|
-
const signature = await account.sign(message)
|
|
203
|
-
console.log('Signature:', signature)
|
|
204
|
-
|
|
205
|
-
// Verify a signature (can use read-only account)
|
|
206
|
-
const isValid = await readOnlyAccount.verify(message, signature)
|
|
207
|
-
console.log('Signature valid:', isValid)
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Fee Management
|
|
211
|
-
|
|
212
|
-
Retrieve current fee rates using `WalletManagerEvm`. Supports EIP-1559 fee model.
|
|
213
|
-
|
|
214
|
-
```javascript
|
|
215
|
-
// Get current fee rates
|
|
216
|
-
const feeRates = await wallet.getFeeRates();
|
|
217
|
-
console.log('Normal fee rate:', feeRates.normal, 'wei'); // 1.1x base fee
|
|
218
|
-
console.log('Fast fee rate:', feeRates.fast, 'wei'); // 2.0x base fee
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Memory Management
|
|
222
|
-
|
|
223
|
-
Clear sensitive data from memory using `dispose` methods in `WalletAccountEvm` and `WalletManagerEvm`.
|
|
224
|
-
|
|
225
|
-
```javascript
|
|
226
|
-
// Dispose wallet accounts to clear private keys from memory
|
|
227
|
-
account.dispose()
|
|
228
|
-
|
|
229
|
-
// Dispose entire wallet manager
|
|
230
39
|
wallet.dispose()
|
|
231
40
|
```
|
|
232
41
|
|
|
233
|
-
|
|
42
|
+
## Key Capabilities
|
|
234
43
|
|
|
235
|
-
|
|
44
|
+
- **BIP-39 Seed Phrase Support**: Generate and validate mnemonic seed phrases
|
|
45
|
+
- **BIP-44 Derivation Paths**: Standard Ethereum derivation (m/44'/60')
|
|
46
|
+
- **Multi-Account Management**: Derive multiple accounts from a single seed phrase
|
|
47
|
+
- **EIP-1559 Transaction Support**: Modern fee estimation and transaction sending
|
|
48
|
+
- **ERC-20 Token Support**: Query balances and transfer tokens
|
|
49
|
+
- **Message Signing**: Sign and verify messages (EIP-191 and EIP-712)
|
|
50
|
+
- **Fee Estimation**: Real-time network fee rates with normal/fast tiers
|
|
51
|
+
- **Secure Memory Disposal**: Clear private keys from memory when done
|
|
236
52
|
|
|
237
|
-
|
|
53
|
+
## Compatibility
|
|
238
54
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
55
|
+
- **Ethereum Mainnet** and testnets (Sepolia)
|
|
56
|
+
- **Layer 2 Networks**: Arbitrum, Optimism, Base
|
|
57
|
+
- **Other EVM Chains**: Polygon, Avalanche C-Chain, and any EVM-compatible chain
|
|
242
58
|
|
|
243
|
-
|
|
244
|
-
const delegation = await account.getDelegation()
|
|
245
|
-
console.log('Is delegated:', delegation.isDelegated)
|
|
246
|
-
console.log('Delegate address:', delegation.delegateAddress)
|
|
59
|
+
## Documentation
|
|
247
60
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
61
|
+
| Topic | Description | Link |
|
|
62
|
+
|-------|-------------|------|
|
|
63
|
+
| Overview | Module overview and feature summary | [Wallet EVM Overview](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm) |
|
|
64
|
+
| Usage | End-to-end integration walkthrough | [Wallet EVM Usage](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage) |
|
|
65
|
+
| Configuration | Provider, fees, and network configuration | [Wallet EVM Configuration](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/configuration) |
|
|
66
|
+
| API Reference | Complete class and type reference | [Wallet EVM API Reference](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference) |
|
|
251
67
|
|
|
252
|
-
|
|
68
|
+
## Examples
|
|
253
69
|
|
|
254
|
-
|
|
70
|
+
| Example | Description |
|
|
71
|
+
|---------|-------------|
|
|
72
|
+
| [Create Wallet](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/create-wallet.ts) | Initialize a wallet manager and derive accounts from a seed phrase |
|
|
73
|
+
| [Manage Accounts](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/manage-accounts.ts) | Work with multiple accounts and custom derivation paths |
|
|
74
|
+
| [Check Balances](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/check-balances.ts) | Query native token and ERC-20 balances for owned accounts |
|
|
75
|
+
| [Read-Only Account](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/read-only-account.ts) | Monitor balances for any address without a private key |
|
|
76
|
+
| [Send Transaction](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/send-transaction.ts) | Estimate fees and send native token transactions (EIP-1559 + legacy) |
|
|
77
|
+
| [Token Transfer](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/token-transfer.ts) | Transfer ERC-20 tokens and estimate transfer fees |
|
|
78
|
+
| [Sign & Verify Message](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/sign-verify-message.ts) | Sign messages and verify signatures |
|
|
79
|
+
| [Fee Management](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/fee-management.ts) | Retrieve current network fee rates |
|
|
80
|
+
| [Memory Management](https://github.com/tetherto/wdk-examples/blob/main/wallet-evm/memory-management.ts) | Securely dispose wallets and clear private keys from memory |
|
|
255
81
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const auth = await account.signAuthorization({
|
|
259
|
-
address: '0x...' // contract address
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
// Send a type 4 transaction with the authorization list
|
|
263
|
-
const result = await account.sendTransaction({
|
|
264
|
-
type: 4,
|
|
265
|
-
to: '0x...',
|
|
266
|
-
value: 0,
|
|
267
|
-
data: '0x...',
|
|
268
|
-
authorizationList: [auth]
|
|
269
|
-
})
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
#### Check Delegation (Read-Only)
|
|
273
|
-
|
|
274
|
-
```javascript
|
|
275
|
-
import { WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
|
|
276
|
-
|
|
277
|
-
const readOnly = new WalletAccountReadOnlyEvm('0x...', {
|
|
278
|
-
provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key'
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
const delegation = await readOnly.getDelegation()
|
|
282
|
-
console.log('Is delegated:', delegation.isDelegated)
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
## 📚 API Reference
|
|
286
|
-
|
|
287
|
-
### Table of Contents
|
|
288
|
-
|
|
289
|
-
### Table of Contents
|
|
290
|
-
|
|
291
|
-
| Class | Description | Methods |
|
|
292
|
-
|-------|-------------|---------|
|
|
293
|
-
| [WalletManagerEvm](#walletmanagerevm) | Main class for managing EVM wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) |
|
|
294
|
-
| [WalletAccountEvm](#walletaccountevm) | Individual EVM wallet account implementation. Extends `WalletAccountReadOnlyEvm` and implements `IWalletAccount` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) |
|
|
295
|
-
| [WalletAccountReadOnlyEvm](#walletaccountreadonlyevm) | Read-only EVM wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-2), [Methods](#methods-2) |
|
|
296
|
-
|
|
297
|
-
### WalletManagerEvm
|
|
298
|
-
|
|
299
|
-
The main class for managing EVM wallets.
|
|
300
|
-
Extends `WalletManager` from `@tetherto/wdk-wallet`.
|
|
301
|
-
|
|
302
|
-
#### Constructor
|
|
303
|
-
|
|
304
|
-
```javascript
|
|
305
|
-
new WalletManagerEvm(seed, config)
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
**Parameters:**
|
|
309
|
-
- `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
|
|
310
|
-
- `config` (object, optional): Configuration object
|
|
311
|
-
- `provider` (string | Eip1193Provider): RPC endpoint URL or EIP-1193 provider instance
|
|
312
|
-
- `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations (in wei)
|
|
313
|
-
|
|
314
|
-
**Example:**
|
|
315
|
-
```javascript
|
|
316
|
-
const wallet = new WalletManagerEvm(seedPhrase, {
|
|
317
|
-
provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key',
|
|
318
|
-
transferMaxFee: '100000000000000' // Maximum fee in wei
|
|
319
|
-
})
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
#### Methods
|
|
323
|
-
|
|
324
|
-
| Method | Description | Returns |
|
|
325
|
-
|--------|-------------|---------|
|
|
326
|
-
| `getAccount(index)` | Returns a wallet account at the specified index | `Promise<WalletAccountEvm>` |
|
|
327
|
-
| `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise<WalletAccountEvm>` |
|
|
328
|
-
| `getFeeRates()` | Returns current fee rates for transactions | `Promise<{normal: bigint, fast: bigint}>` |
|
|
329
|
-
| `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` |
|
|
330
|
-
|
|
331
|
-
### WalletAccountEvm
|
|
332
|
-
|
|
333
|
-
Represents an individual wallet account. Implements `IWalletAccount` from `@tetherto/wdk-wallet`.
|
|
334
|
-
|
|
335
|
-
#### Constructor
|
|
336
|
-
|
|
337
|
-
```javascript
|
|
338
|
-
new WalletAccountEvm(seed, path, config)
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
**Parameters:**
|
|
342
|
-
- `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
|
|
343
|
-
- `path` (string): BIP-44 derivation path (e.g., "0'/0/0")
|
|
344
|
-
- `config` (object, optional): Configuration object
|
|
345
|
-
- `provider` (string | Eip1193Provider): RPC endpoint URL or EIP-1193 provider instance
|
|
346
|
-
- `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations (in wei)
|
|
347
|
-
|
|
348
|
-
#### Methods
|
|
349
|
-
|
|
350
|
-
| Method | Description | Returns |
|
|
351
|
-
|--------|-------------|---------|
|
|
352
|
-
| `getAddress()` | Returns the account's address | `Promise<string>` |
|
|
353
|
-
| `sign(message)` | Signs a message using the account's private key | `Promise<string>` |
|
|
354
|
-
| `signTypedData(typedData)` | Signs typed data according to EIP-712 | `Promise<string>` |
|
|
355
|
-
| `verify(message, signature)` | Verifies a message signature | `Promise<boolean>` |
|
|
356
|
-
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature | `Promise<boolean>` |
|
|
357
|
-
| `sendTransaction(tx)` | Sends an EVM transaction | `Promise<{hash: string, fee: bigint}>` |
|
|
358
|
-
| `quoteSendTransaction(tx)` | Estimates the fee for an EVM transaction | `Promise<{fee: bigint}>` |
|
|
359
|
-
| `transfer(options)` | Transfers ERC20 tokens to another address | `Promise<{hash: string, fee: bigint}>` |
|
|
360
|
-
| `quoteTransfer(options)` | Estimates the fee for an ERC20 transfer | `Promise<{fee: bigint}>` |
|
|
361
|
-
| `getBalance()` | Returns the native token balance (in wei) | `Promise<bigint>` |
|
|
362
|
-
| `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise<bigint>` |
|
|
363
|
-
| `signAuthorization(auth)` | Signs an ERC-7702 authorization tuple | `Promise<Authorization>` |
|
|
364
|
-
| `delegate(delegateAddress)` | Delegates this EOA to a smart contract via a type 4 transaction | `Promise<{hash: string, fee: bigint}>` |
|
|
365
|
-
| `revokeDelegation()` | Revokes any active ERC-7702 delegation | `Promise<{hash: string, fee: bigint}>` |
|
|
366
|
-
| `getDelegation()` | Checks if the account has an active ERC-7702 delegation | `Promise<{isDelegated: boolean, delegateAddress: string \| null}>` |
|
|
367
|
-
| `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` |
|
|
82
|
+
> For detailed walkthroughs, see the [Usage Guide](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage).
|
|
83
|
+
> See all runnable examples in the [wdk-examples](https://github.com/tetherto/wdk-examples) repository.
|
|
368
84
|
|
|
369
|
-
|
|
370
|
-
Sends an EVM transaction.
|
|
85
|
+
## Community
|
|
371
86
|
|
|
372
|
-
|
|
373
|
-
- `tx` (object): The transaction object
|
|
374
|
-
- `to` (string): Recipient address
|
|
375
|
-
- `value` (number | bigint): Amount in wei
|
|
376
|
-
- `data` (string, optional): Transaction data in hex format
|
|
377
|
-
- `gasLimit` (number | bigint, optional): Maximum gas units
|
|
378
|
-
- `gasPrice` (number | bigint, optional): Legacy gas price in wei
|
|
379
|
-
- `maxFeePerGas` (number | bigint, optional): EIP-1559 max fee per gas in wei
|
|
380
|
-
- `maxPriorityFeePerGas` (number | bigint, optional): EIP-1559 max priority fee per gas in wei
|
|
381
|
-
- `type` (number, optional): Transaction type (e.g. 4 for ERC-7702)
|
|
382
|
-
- `nonce` (number, optional): Transaction nonce
|
|
383
|
-
- `authorizationList` (Authorization[], optional): Signed ERC-7702 authorizations for type 4 transactions
|
|
87
|
+
Join the [WDK Discord](https://discord.gg/arYXDhHB2w) to connect with other developers.
|
|
384
88
|
|
|
385
|
-
|
|
89
|
+
## Support
|
|
386
90
|
|
|
387
|
-
|
|
91
|
+
For support, please [open an issue](https://github.com/tetherto/wdk-wallet-evm/issues) on GitHub or reach out via [email](mailto:wallet-info@tether.io).
|
|
388
92
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
| Property | Type | Description |
|
|
392
|
-
|----------|------|-------------|
|
|
393
|
-
| `index` | `number` | The derivation path's index of this account |
|
|
394
|
-
| `path` | `string` | The full derivation path of this account |
|
|
395
|
-
| `keyPair` | `object` | The account's key pair (⚠️ Contains sensitive data) |
|
|
396
|
-
|
|
397
|
-
⚠️ **Security Note**: The `keyPair` property contains sensitive cryptographic material. Never log, display, or expose the private key.
|
|
398
|
-
|
|
399
|
-
### WalletAccountReadOnlyEvm
|
|
400
|
-
|
|
401
|
-
Represents a read-only wallet account.
|
|
402
|
-
|
|
403
|
-
#### Constructor
|
|
404
|
-
|
|
405
|
-
```javascript
|
|
406
|
-
new WalletAccountReadOnlyEvm(address, config)
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**Parameters:**
|
|
410
|
-
- `address` (string): The account's address
|
|
411
|
-
- `config` (object, optional): Configuration object
|
|
412
|
-
- `provider` (string | Eip1193Provider): RPC endpoint URL or EIP-1193 provider instance
|
|
413
|
-
|
|
414
|
-
#### Methods
|
|
415
|
-
|
|
416
|
-
| Method | Description | Returns |
|
|
417
|
-
|--------|-------------|---------|
|
|
418
|
-
| `getBalance()` | Returns the native token balance (in wei) | `Promise<bigint>` |
|
|
419
|
-
| `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise<bigint>` |
|
|
420
|
-
| `quoteSendTransaction(tx)` | Estimates the fee for an EVM transaction | `Promise<{fee: bigint}>` |
|
|
421
|
-
| `quoteTransfer(options)` | Estimates the fee for an ERC20 transfer | `Promise<{fee: bigint}>` |
|
|
422
|
-
| `verify(message, signature)` | Verifies a message signature | `Promise<boolean>` |
|
|
423
|
-
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature | `Promise<boolean>` |
|
|
424
|
-
| `getDelegation()` | Checks if the account has an active ERC-7702 delegation | `Promise<{isDelegated: boolean, delegateAddress: string \| null}>` |
|
|
425
|
-
|
|
426
|
-
#### Properties
|
|
427
|
-
|
|
428
|
-
| Property | Type | Description |
|
|
429
|
-
|----------|------|-------------|
|
|
430
|
-
| `address` | `string` | The account's address |
|
|
431
|
-
|
|
432
|
-
## 🌐 Supported Networks
|
|
433
|
-
|
|
434
|
-
This package works with any EVM-compatible blockchain, including:
|
|
435
|
-
|
|
436
|
-
- **Ethereum Mainnet**
|
|
437
|
-
- **Ethereum Testnets** (Sepolia, etc.)
|
|
438
|
-
- **Layer 2 Networks** (Arbitrum, Optimism, etc.)
|
|
439
|
-
- **Other EVM Chains** (Polygon, Avalanche C-Chain, etc.)
|
|
440
|
-
|
|
441
|
-
## 🔒 Security Considerations
|
|
442
|
-
|
|
443
|
-
- **Seed Phrase Security**: Always store your seed phrase securely and never share it
|
|
444
|
-
- **Private Key Management**: The package handles private keys internally with memory safety features
|
|
445
|
-
- **Provider Security**: Use trusted RPC endpoints and consider running your own node for production
|
|
446
|
-
- **Transaction Validation**: Always validate transaction details before signing
|
|
447
|
-
- **Memory Cleanup**: Use the `dispose()` method to clear private keys from memory when done
|
|
448
|
-
- **Fee Limits**: Set `transferMaxFee` in config to prevent excessive transaction fees
|
|
449
|
-
- **Gas Estimation**: Always estimate gas before sending transactions
|
|
450
|
-
- **EIP-1559**: Consider using EIP-1559 fee model for better gas price estimation
|
|
451
|
-
- **Contract Interactions**: Verify contract addresses and token decimals before transfers
|
|
452
|
-
|
|
453
|
-
## 🛠️ Development
|
|
454
|
-
|
|
455
|
-
### Building
|
|
456
|
-
|
|
457
|
-
```bash
|
|
458
|
-
# Install dependencies
|
|
459
|
-
npm install
|
|
460
|
-
|
|
461
|
-
# Build TypeScript definitions
|
|
462
|
-
npm run build:types
|
|
463
|
-
|
|
464
|
-
# Lint code
|
|
465
|
-
npm run lint
|
|
466
|
-
|
|
467
|
-
# Fix linting issues
|
|
468
|
-
npm run lint:fix
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### Testing
|
|
472
|
-
|
|
473
|
-
```bash
|
|
474
|
-
# Run tests
|
|
475
|
-
npm test
|
|
476
|
-
|
|
477
|
-
# Run tests with coverage
|
|
478
|
-
npm run test:coverage
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
## 📜 License
|
|
482
|
-
|
|
483
|
-
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
|
484
|
-
|
|
485
|
-
## 🤝 Contributing
|
|
93
|
+
## Contributing
|
|
486
94
|
|
|
487
95
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
488
96
|
|
|
489
|
-
##
|
|
97
|
+
## License
|
|
490
98
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
---
|
|
99
|
+
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
package/hardhat.config.cjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tetherto/wdk-wallet-evm",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
4
|
"description": "A simple package to manage BIP-32 wallets for evm blockchains.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wdk",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"@noble/curves": "1.9.2",
|
|
31
31
|
"@noble/hashes": "1.8.0",
|
|
32
32
|
"@noble/secp256k1": "2.2.3",
|
|
33
|
-
"@tetherto/wdk-
|
|
33
|
+
"@tetherto/wdk-failover-provider": "1.0.0-beta.2",
|
|
34
|
+
"@tetherto/wdk-wallet": "1.0.0-beta.8",
|
|
34
35
|
"bare-node-runtime": "^1.1.4",
|
|
35
36
|
"bip39": "3.1.0",
|
|
36
37
|
"ethers": "6.14.4",
|
|
@@ -45,9 +46,14 @@
|
|
|
45
46
|
"typescript": "5.8.3"
|
|
46
47
|
},
|
|
47
48
|
"overrides": {
|
|
49
|
+
"brace-expansion": "1.1.13",
|
|
48
50
|
"cookie": "1.0.2",
|
|
51
|
+
"immutable": "4.3.8",
|
|
52
|
+
"picomatch@2": "2.3.2",
|
|
53
|
+
"serialize-javascript": ">=7.0.5",
|
|
49
54
|
"tmp": "0.2.5",
|
|
50
|
-
"undici": "7.
|
|
55
|
+
"undici": ">=7.24.0",
|
|
56
|
+
"uuid": "14.0.0"
|
|
51
57
|
},
|
|
52
58
|
"exports": {
|
|
53
59
|
".": {
|
|
@@ -147,6 +147,19 @@ export default class WalletAccountEvm extends WalletAccountReadOnlyEvm {
|
|
|
147
147
|
return await this._account.signTypedData(domain, types, message)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Signs a transaction.
|
|
152
|
+
*
|
|
153
|
+
* @param {EvmTransaction} tx - The transaction to sign.
|
|
154
|
+
* @returns {Promise<string>} The signed transaction as a hex string.
|
|
155
|
+
*/
|
|
156
|
+
async signTransaction (tx) {
|
|
157
|
+
return await this._account.signTransaction({
|
|
158
|
+
from: await this.getAddress(),
|
|
159
|
+
...tx
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
|
|
150
163
|
/**
|
|
151
164
|
* Sends a transaction.
|
|
152
165
|
*
|
|
@@ -234,9 +247,11 @@ export default class WalletAccountEvm extends WalletAccountReadOnlyEvm {
|
|
|
234
247
|
* @returns {Promise<WalletAccountReadOnlyEvm>} The read-only account.
|
|
235
248
|
*/
|
|
236
249
|
async toReadOnlyAccount () {
|
|
237
|
-
|
|
250
|
+
if (!this._evmReadOnlyAccount) {
|
|
251
|
+
this._evmReadOnlyAccount = new WalletAccountReadOnlyEvm(this._account.address, this._config)
|
|
252
|
+
}
|
|
238
253
|
|
|
239
|
-
return
|
|
254
|
+
return this._evmReadOnlyAccount
|
|
240
255
|
}
|
|
241
256
|
|
|
242
257
|
/**
|
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
|
|
17
17
|
import { WalletAccountReadOnly } from '@tetherto/wdk-wallet'
|
|
18
18
|
|
|
19
|
-
import { BrowserProvider, Contract, Interface, JsonRpcProvider, Signature, toQuantity, verifyMessage, verifyTypedData } from 'ethers'
|
|
19
|
+
import { BrowserProvider, Contract, Interface, JsonRpcProvider, Network, Signature, toQuantity, verifyMessage, verifyTypedData } from 'ethers'
|
|
20
20
|
|
|
21
21
|
import { multicall } from './multicall.js'
|
|
22
22
|
|
|
23
|
+
import FailoverProvider from '@tetherto/wdk-failover-provider'
|
|
24
|
+
|
|
23
25
|
/** @typedef {import('ethers').Provider} Provider */
|
|
24
26
|
/** @typedef {import('ethers').Eip1193Provider} Eip1193Provider */
|
|
25
27
|
/** @typedef {import('ethers').TypedDataDomain} TypedDataDomain */
|
|
@@ -54,6 +56,7 @@ import { multicall } from './multicall.js'
|
|
|
54
56
|
* @property {number | bigint} [maxPriorityFeePerGas] - The price (in wei) per unit of gas this transaction will allow in addition to the [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) block's base fee to bribe miners into giving this transaction priority. This is included in the maxFeePerGas, so this will not affect the total maximum cost set with maxFeePerGas.
|
|
55
57
|
* @property {number} [type] - The transaction type (e.g. 4 for ERC-7702).
|
|
56
58
|
* @property {number} [nonce] - The transaction nonce.
|
|
59
|
+
* @property {number | bigint} [chainId] - The chain ID of the network.
|
|
57
60
|
* @property {AuthorizationLike[]} [authorizationList] - An optional list of ERC-7702 signed authorizations for type 4 transactions.
|
|
58
61
|
*/
|
|
59
62
|
|
|
@@ -67,7 +70,9 @@ import { multicall } from './multicall.js'
|
|
|
67
70
|
|
|
68
71
|
/**
|
|
69
72
|
* @typedef {Object} EvmWalletConfig
|
|
70
|
-
* @property {string | Eip1193Provider} [provider] - The url of the rpc provider, or an instance of a class that implements eip-1193.
|
|
73
|
+
* @property {string | Eip1193Provider | Array<string | Eip1193Provider>} [provider] - The url of the rpc provider, or an instance of a class that implements eip-1193. It's also possible to provide an array of urls or EIP 1193 providers instead. In such case, connection errors will cause the wallet to automatically fallback on the next provider in the list.
|
|
74
|
+
* @property {number} [retries] - If set and if 'provider' is a list of urls or EIP 1193 providers, the number of additional retry attempts after the initial call fails. Total attempts = `1 + retries`. For example, `retries: 3` with 4 providers will try each provider once before throwing. If `retries` exceeds the number of providers, the failover will loop back and retry already-failed providers in round-robin order. Default: 3.
|
|
75
|
+
* @property {number} [chainId] - The chain ID of the network. When provided, skips automatic chain ID detection from the provider.
|
|
71
76
|
* @property {number | bigint} [transferMaxFee] - The maximum fee amount for transfer operations.
|
|
72
77
|
*/
|
|
73
78
|
|
|
@@ -93,18 +98,36 @@ export default class WalletAccountReadOnlyEvm extends WalletAccountReadOnly {
|
|
|
93
98
|
*/
|
|
94
99
|
this._config = config
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
/**
|
|
102
|
+
* An ethers provider to interact with a node of the blockchain.
|
|
103
|
+
*
|
|
104
|
+
* @protected
|
|
105
|
+
* @type {Provider | undefined}
|
|
106
|
+
*/
|
|
107
|
+
this._provider = undefined
|
|
108
|
+
|
|
109
|
+
const { provider, retries = 3 } = config
|
|
110
|
+
const network = config.chainId ? Network.from(config.chainId) : undefined
|
|
111
|
+
const providerOpts = config.chainId ? { staticNetwork: true } : undefined
|
|
112
|
+
|
|
113
|
+
if (Array.isArray(provider)) {
|
|
114
|
+
if (provider.length > 0) {
|
|
115
|
+
const failoverProvider = new FailoverProvider({ retries })
|
|
116
|
+
|
|
117
|
+
for (const entry of provider) {
|
|
118
|
+
const option = typeof entry === 'string'
|
|
119
|
+
? new JsonRpcProvider(entry, network, providerOpts)
|
|
120
|
+
: new BrowserProvider(entry)
|
|
121
|
+
failoverProvider.addProvider(option)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this._provider = failoverProvider.initialize()
|
|
125
|
+
}
|
|
126
|
+
} else if (provider) {
|
|
127
|
+
this._provider =
|
|
128
|
+
typeof provider === 'string'
|
|
129
|
+
? new JsonRpcProvider(provider, network, providerOpts)
|
|
130
|
+
: new BrowserProvider(provider)
|
|
108
131
|
}
|
|
109
132
|
}
|
|
110
133
|
|
|
@@ -18,6 +18,8 @@ import WalletManager from '@tetherto/wdk-wallet'
|
|
|
18
18
|
|
|
19
19
|
import { BrowserProvider, JsonRpcProvider } from 'ethers'
|
|
20
20
|
|
|
21
|
+
import FailoverProvider from '@tetherto/wdk-failover-provider'
|
|
22
|
+
|
|
21
23
|
import WalletAccountEvm from './wallet-account-evm.js'
|
|
22
24
|
|
|
23
25
|
/** @typedef {import('ethers').Provider} Provider */
|
|
@@ -60,18 +62,34 @@ export default class WalletManagerEvm extends WalletManager {
|
|
|
60
62
|
*/
|
|
61
63
|
this._config = config
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
/**
|
|
66
|
+
* An ethers provider to interact with a node of the blockchain.
|
|
67
|
+
*
|
|
68
|
+
* @protected
|
|
69
|
+
* @type {Provider | undefined}
|
|
70
|
+
*/
|
|
71
|
+
this._provider = undefined
|
|
72
|
+
|
|
73
|
+
const { provider, retries = 3 } = config
|
|
74
|
+
|
|
75
|
+
if (Array.isArray(provider)) {
|
|
76
|
+
if (provider.length > 0) {
|
|
77
|
+
const failoverProvider = new FailoverProvider({ retries })
|
|
78
|
+
|
|
79
|
+
for (const entry of provider) {
|
|
80
|
+
const option = typeof entry === 'string'
|
|
81
|
+
? new JsonRpcProvider(entry)
|
|
82
|
+
: new BrowserProvider(entry)
|
|
83
|
+
failoverProvider.addProvider(option)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this._provider = failoverProvider.initialize()
|
|
87
|
+
}
|
|
88
|
+
} else if (provider) {
|
|
89
|
+
this._provider =
|
|
90
|
+
typeof provider === 'string'
|
|
91
|
+
? new JsonRpcProvider(provider)
|
|
92
|
+
: new BrowserProvider(provider)
|
|
75
93
|
}
|
|
76
94
|
}
|
|
77
95
|
|
|
@@ -54,6 +54,13 @@ export default class WalletAccountEvm extends WalletAccountReadOnlyEvm implement
|
|
|
54
54
|
* @returns {Promise<string>} The typed data signature.
|
|
55
55
|
*/
|
|
56
56
|
signTypedData({ domain, types, message }: TypedData): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Signs a transaction.
|
|
59
|
+
*
|
|
60
|
+
* @param {EvmTransaction} tx - The transaction to sign.
|
|
61
|
+
* @returns {Promise<string>} The signed transaction as a hex string.
|
|
62
|
+
*/
|
|
63
|
+
signTransaction(tx: EvmTransaction): Promise<string>;
|
|
57
64
|
/**
|
|
58
65
|
* Sends a transaction.
|
|
59
66
|
*
|
|
@@ -176,6 +176,10 @@ export type EvmTransaction = {
|
|
|
176
176
|
* - The transaction nonce.
|
|
177
177
|
*/
|
|
178
178
|
nonce?: number;
|
|
179
|
+
/**
|
|
180
|
+
* - The chain ID of the network.
|
|
181
|
+
*/
|
|
182
|
+
chainId?: number | bigint;
|
|
179
183
|
/**
|
|
180
184
|
* - An optional list of ERC-7702 signed authorizations for type 4 transactions.
|
|
181
185
|
*/
|
|
@@ -201,9 +205,17 @@ export type EvmTransferOptions = {
|
|
|
201
205
|
};
|
|
202
206
|
export type EvmWalletConfig = {
|
|
203
207
|
/**
|
|
204
|
-
* - The url of the rpc provider, or an instance of a class that implements eip-1193.
|
|
208
|
+
* - The url of the rpc provider, or an instance of a class that implements eip-1193. It's also possible to provide an array of urls or EIP 1193 providers instead. In such case, connection errors will cause the wallet to automatically fallback on the next provider in the list.
|
|
209
|
+
*/
|
|
210
|
+
provider?: string | Eip1193Provider | Array<string | Eip1193Provider>;
|
|
211
|
+
/**
|
|
212
|
+
* - If set and if 'provider' is a list of urls or EIP 1193 providers, the number of additional retry attempts after the initial call fails. Total attempts = `1 + retries`. For example, `retries: 3` with 4 providers will try each provider once before throwing. If `retries` exceeds the number of providers, the failover will loop back and retry already-failed providers in round-robin order. Default: 3.
|
|
213
|
+
*/
|
|
214
|
+
retries?: number;
|
|
215
|
+
/**
|
|
216
|
+
* - The chain ID of the network. When provided, skips automatic chain ID detection from the provider.
|
|
205
217
|
*/
|
|
206
|
-
|
|
218
|
+
chainId?: number;
|
|
207
219
|
/**
|
|
208
220
|
* - The maximum fee amount for transfer operations.
|
|
209
221
|
*/
|