0
# Signer Management
1
2
Enhanced signer functionality with SignerWithAddress class and helper functions for managing test accounts and impersonation. Provides streamlined access to signers in the Hardhat environment.
3
4
## Capabilities
5
6
### Get All Signers
7
8
Retrieves all available signers as SignerWithAddress instances, typically configured accounts in your Hardhat network.
9
10
```typescript { .api }
11
/**
12
* Gets all available signers as SignerWithAddress instances
13
* @returns Promise resolving to array of SignerWithAddress instances
14
*/
15
function getSigners(): Promise<SignerWithAddress[]>;
16
```
17
18
**Usage Examples:**
19
20
```typescript
21
import { ethers } from "hardhat";
22
23
// Get all signers
24
const signers = await ethers.getSigners();
25
const [deployer, user1, user2, ...others] = signers;
26
27
console.log("Available signers:", signers.length);
28
console.log("Deployer address:", deployer.address);
29
console.log("User1 address:", user1.address);
30
31
// Use signers for different roles
32
const contract = await ethers.deployContract("MyContract", [], deployer);
33
const contractAsUser1 = contract.connect(user1);
34
```
35
36
### Get Specific Signer
37
38
Retrieves a specific signer by address as a SignerWithAddress instance.
39
40
```typescript { .api }
41
/**
42
* Gets a specific signer by address as SignerWithAddress instance
43
* @param address - Ethereum address of the signer
44
* @returns Promise resolving to SignerWithAddress instance
45
*/
46
function getSigner(address: string): Promise<SignerWithAddress>;
47
```
48
49
**Usage Examples:**
50
51
```typescript
52
import { ethers } from "hardhat";
53
54
// Get signer by known address
55
const signerAddress = "0x1234567890123456789012345678901234567890";
56
const signer = await ethers.getSigner(signerAddress);
57
58
console.log("Signer address:", signer.address);
59
60
// Use specific signer
61
const contract = await ethers.getContractAt("MyContract", contractAddress, signer);
62
const tx = await contract.someFunction();
63
await tx.wait();
64
```
65
66
### Get Impersonated Signer
67
68
Creates an impersonated signer for testing purposes, allowing you to send transactions as any address.
69
70
```typescript { .api }
71
/**
72
* Creates an impersonated signer for testing (enables hardhat_impersonateAccount)
73
* @param address - Ethereum address to impersonate
74
* @returns Promise resolving to SignerWithAddress instance for the impersonated account
75
*/
76
function getImpersonatedSigner(address: string): Promise<SignerWithAddress>;
77
```
78
79
**Usage Examples:**
80
81
```typescript
82
import { ethers } from "hardhat";
83
84
// Impersonate a specific address (useful for testing)
85
const whaleAddress = "0x8ba1f109551bD432803012645Hac136c6348B618";
86
const whaleSigner = await ethers.getImpersonatedSigner(whaleAddress);
87
88
// Now you can send transactions as the whale
89
const token = await ethers.getContractAt("IERC20", tokenAddress, whaleSigner);
90
const balance = await token.balanceOf(whaleAddress);
91
console.log("Whale balance:", ethers.utils.formatEther(balance));
92
93
// Transfer tokens as the whale
94
const tx = await token.transfer(recipientAddress, ethers.utils.parseEther("100"));
95
await tx.wait();
96
```
97
98
## SignerWithAddress Class
99
100
Enhanced signer class that extends ethers.Signer with additional functionality and properties.
101
102
```typescript { .api }
103
/**
104
* Enhanced signer class that includes the address property
105
*/
106
class SignerWithAddress extends ethers.Signer {
107
/** The address of this signer (readonly) */
108
readonly address: string;
109
110
/**
111
* Creates a SignerWithAddress instance from a JsonRpcSigner
112
* @param signer - JsonRpcSigner to wrap
113
* @returns Promise resolving to SignerWithAddress instance
114
*/
115
static create(signer: ethers.providers.JsonRpcSigner): Promise<SignerWithAddress>;
116
117
/**
118
* Gets the address of this signer
119
* @returns Promise resolving to the signer's address
120
*/
121
getAddress(): Promise<string>;
122
123
/**
124
* Signs a message
125
* @param message - Message to sign
126
* @returns Promise resolving to signature string
127
*/
128
signMessage(message: string | ethers.utils.Bytes): Promise<string>;
129
130
/**
131
* Signs a transaction
132
* @param transaction - Transaction to sign
133
* @returns Promise resolving to signed transaction string
134
*/
135
signTransaction(
136
transaction: ethers.utils.Deferrable<ethers.providers.TransactionRequest>
137
): Promise<string>;
138
139
/**
140
* Sends a transaction
141
* @param transaction - Transaction to send
142
* @returns Promise resolving to transaction response
143
*/
144
sendTransaction(
145
transaction: ethers.utils.Deferrable<ethers.providers.TransactionRequest>
146
): Promise<ethers.providers.TransactionResponse>;
147
148
/**
149
* Connects this signer to a different provider
150
* @param provider - Provider to connect to
151
* @returns New SignerWithAddress instance connected to the provider
152
*/
153
connect(provider: ethers.providers.Provider): SignerWithAddress;
154
155
/**
156
* Signs typed data (EIP-712)
157
* @param params - Typed data parameters
158
* @returns Promise resolving to signature string
159
*/
160
_signTypedData(
161
...params: Parameters<ethers.providers.JsonRpcSigner["_signTypedData"]>
162
): Promise<string>;
163
164
/**
165
* Returns JSON representation of the signer
166
* @returns String representation including address
167
*/
168
toJSON(): string;
169
}
170
```
171
172
### SignerWithAddress Usage Examples
173
174
```typescript
175
import { ethers } from "hardhat";
176
177
// Get signers
178
const [deployer, user] = await ethers.getSigners();
179
180
// Access address directly (main advantage over regular ethers.Signer)
181
console.log("Deployer address:", deployer.address);
182
console.log("User address:", user.address);
183
184
// Sign messages
185
const message = "Hello, Ethereum!";
186
const signature = await user.signMessage(message);
187
console.log("Signature:", signature);
188
189
// Send transactions
190
const tx = await user.sendTransaction({
191
to: "0x1234567890123456789012345678901234567890",
192
value: ethers.utils.parseEther("1.0")
193
});
194
await tx.wait();
195
196
// Connect to different provider
197
const mainnetProvider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/...");
198
const userOnMainnet = user.connect(mainnetProvider);
199
```
200
201
## Common Signer Patterns
202
203
### Multi-Signer Contract Interactions
204
205
```typescript
206
import { ethers } from "hardhat";
207
208
async function multiSignerExample() {
209
const [owner, admin, user1, user2] = await ethers.getSigners();
210
211
// Deploy with owner
212
const contract = await ethers.deployContract("MultiSigWallet", [
213
[owner.address, admin.address],
214
2 // require 2 signatures
215
], owner);
216
217
// Different roles interact with contract
218
const contractAsAdmin = contract.connect(admin);
219
const contractAsUser1 = contract.connect(user1);
220
221
// Owner submits transaction
222
await contract.submitTransaction(user1.address, ethers.utils.parseEther("1"), "0x");
223
224
// Admin confirms transaction
225
await contractAsAdmin.confirmTransaction(0);
226
}
227
```
228
229
### Impersonation for Testing
230
231
```typescript
232
import { ethers, network } from "hardhat";
233
234
async function testWithImpersonation() {
235
// Impersonate a whale account
236
const whaleAddress = "0x8ba1f109551bD432803012645Hac136c6348B618";
237
238
// Fund the whale with some ETH for gas
239
await network.provider.send("hardhat_setBalance", [
240
whaleAddress,
241
"0x1000000000000000000", // 1 ETH
242
]);
243
244
const whale = await ethers.getImpersonatedSigner(whaleAddress);
245
246
// Use whale to interact with contracts
247
const token = await ethers.getContractAt("IERC20", tokenAddress, whale);
248
const balance = await token.balanceOf(whale.address);
249
250
if (balance.gt(0)) {
251
await token.transfer(testUserAddress, ethers.utils.parseEther("1000"));
252
}
253
}
254
```
255
256
### Signer Validation
257
258
```typescript
259
import { ethers } from "hardhat";
260
261
async function validateSigners() {
262
const signers = await ethers.getSigners();
263
264
if (signers.length === 0) {
265
throw new Error("No signers available");
266
}
267
268
// Check signer balances
269
for (let i = 0; i < signers.length; i++) {
270
const balance = await signers[i].getBalance();
271
console.log(`Signer ${i} (${signers[i].address}): ${ethers.utils.formatEther(balance)} ETH`);
272
273
if (balance.eq(0)) {
274
console.warn(`Signer ${i} has zero balance`);
275
}
276
}
277
278
return signers;
279
}
280
```
281
282
## Network Compatibility
283
284
### Local Development Networks
285
286
On Hardhat Network and other local networks, `getSigners()` returns the configured accounts:
287
288
```typescript
289
// hardhat.config.js
290
module.exports = {
291
networks: {
292
hardhat: {
293
accounts: {
294
count: 20,
295
accountsBalance: "10000000000000000000000" // 10000 ETH
296
}
297
}
298
}
299
};
300
```
301
302
### Live Networks
303
304
On live networks, signers are typically loaded from:
305
- Private keys in environment variables
306
- Hardware wallets
307
- Mnemonic phrases
308
309
```typescript
310
// Example configuration for live networks
311
const signers = await ethers.getSigners();
312
console.log("Available signers on mainnet:", signers.length);
313
314
// Always check you have the expected signer
315
if (signers.length === 0) {
316
throw new Error("No signers configured for this network");
317
}
318
```
319
320
## Error Handling
321
322
Signer functions can throw errors in the following cases:
323
324
- **No signers available**: When `getSigners()` returns an empty array
325
- **Invalid address**: When `getSigner()` or `getImpersonatedSigner()` receives an invalid address
326
- **Account not found**: When `getSigner()` is called with an address not in the available accounts
327
- **Impersonation failure**: When `getImpersonatedSigner()` fails to enable impersonation (network doesn't support it)
328
- **Insufficient balance**: When signers don't have enough ETH for gas
329
- **Network connection issues**: When unable to connect to the blockchain network