0
# Cryptographic Operations
1
2
The cryptographic operations functionality provides comprehensive signing capabilities including message signing, transaction signing, and EIP-712 typed data signing with support for various signature formats.
3
4
## Message Signing
5
6
### sign
7
8
Signs arbitrary messages using an account's private key.
9
10
```typescript { .api }
11
sign(message: Bytes, addressOrIndex: Address | Numbers, returnFormat?: DataFormat): Promise<SignatureObject>;
12
```
13
14
**Parameters:**
15
- `message`: The message to sign (hex string or bytes)
16
- `addressOrIndex`: Account address or wallet index to sign with
17
- `returnFormat`: Output format configuration
18
19
**Usage Example:**
20
```typescript
21
// Sign a simple message
22
const message = "Hello, Ethereum!";
23
const signature = await eth.sign(message, "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E");
24
25
console.log("Message signature:", {
26
messageHash: signature.messageHash,
27
r: signature.r,
28
s: signature.s,
29
v: signature.v,
30
signature: signature.signature
31
});
32
33
// Sign hex-encoded data
34
const hexMessage = "0x48656c6c6f2c20457468657265756d21"; // "Hello, Ethereum!" in hex
35
const hexSignature = await eth.sign(hexMessage, "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E");
36
37
// Verify signature (using web3-utils)
38
import { recover } from "web3-utils";
39
const recoveredAddress = recover(message, signature.signature);
40
console.log("Signature verification:", recoveredAddress === "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E");
41
```
42
43
## Transaction Signing
44
45
### signTransaction
46
47
Signs a transaction without broadcasting it to the network.
48
49
```typescript { .api }
50
signTransaction(transaction: Transaction, returnFormat?: DataFormat): Promise<SignedTransactionInfoAPI>;
51
```
52
53
**Usage Example:**
54
```typescript
55
// Sign a transaction for later broadcast
56
const transaction = {
57
from: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
58
to: "0x8ba1f109551bD432803012645Hac136c1c1b6c5E",
59
value: "1000000000000000000", // 1 ETH
60
gas: "21000",
61
gasPrice: "20000000000", // 20 Gwei
62
nonce: await eth.getTransactionCount("0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E")
63
};
64
65
const signedTx = await eth.signTransaction(transaction);
66
console.log("Signed transaction:", {
67
messageHash: signedTx.messageHash,
68
r: signedTx.r,
69
s: signedTx.s,
70
v: signedTx.v,
71
rawTransaction: signedTx.rawTransaction
72
});
73
74
// Broadcast the signed transaction later
75
const receipt = await eth.sendSignedTransaction(signedTx.rawTransaction);
76
```
77
78
### EIP-1559 Transaction Signing
79
80
```typescript
81
// Sign EIP-1559 transaction
82
const eip1559Transaction = {
83
from: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
84
to: "0x8ba1f109551bD432803012645Hac136c1c1b6c5E",
85
value: "1000000000000000000",
86
gas: "21000",
87
maxFeePerGas: "30000000000", // 30 Gwei
88
maxPriorityFeePerGas: "2000000000", // 2 Gwei
89
nonce: await eth.getTransactionCount("0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E"),
90
type: 2 // EIP-1559
91
};
92
93
const signed1559Tx = await eth.signTransaction(eip1559Transaction);
94
```
95
96
## EIP-712 Typed Data Signing
97
98
### signTypedData
99
100
Signs structured data according to EIP-712 standard for improved user experience and security.
101
102
```typescript { .api }
103
signTypedData(address: Address, typedData: Eip712TypedData, useLegacy?: boolean, returnFormat?: DataFormat): Promise<SignatureObject>;
104
```
105
106
**Parameters:**
107
- `address`: Signer's address
108
- `typedData`: EIP-712 structured data object
109
- `useLegacy`: Use legacy signing format (default: false)
110
- `returnFormat`: Output format configuration
111
112
**Usage Example:**
113
```typescript
114
// Define EIP-712 domain and types
115
const domain = {
116
name: "MyDApp",
117
version: "1",
118
chainId: 1,
119
verifyingContract: "0x1234567890123456789012345678901234567890"
120
};
121
122
const types = {
123
Person: [
124
{ name: "name", type: "string" },
125
{ name: "wallet", type: "address" }
126
],
127
Mail: [
128
{ name: "from", type: "Person" },
129
{ name: "to", type: "Person" },
130
{ name: "contents", type: "string" }
131
]
132
};
133
134
const message = {
135
from: {
136
name: "Alice",
137
wallet: "0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E"
138
},
139
to: {
140
name: "Bob",
141
wallet: "0x8ba1f109551bD432803012645Hac136c1c1b6c5E"
142
},
143
contents: "Hello Bob!"
144
};
145
146
const typedData = {
147
domain,
148
types,
149
primaryType: "Mail",
150
message
151
};
152
153
// Sign the typed data
154
const signature = await eth.signTypedData(
155
"0x742d35Cc6634C0532925a3b8D7389Fc3C1b6c5E",
156
typedData
157
);
158
159
console.log("EIP-712 signature:", signature);
160
```
161
162
### Common EIP-712 Use Cases
163
164
#### ERC-20 Permit Signing
165
166
```typescript
167
// Sign ERC-20 permit for gasless approvals
168
async function signPermit(
169
tokenAddress: Address,
170
owner: Address,
171
spender: Address,
172
value: string,
173
deadline: number,
174
nonce: number
175
) {
176
const domain = {
177
name: "Token Name", // Get from token contract
178
version: "1",
179
chainId: await eth.getChainId(),
180
verifyingContract: tokenAddress
181
};
182
183
const types = {
184
Permit: [
185
{ name: "owner", type: "address" },
186
{ name: "spender", type: "address" },
187
{ name: "value", type: "uint256" },
188
{ name: "nonce", type: "uint256" },
189
{ name: "deadline", type: "uint256" }
190
]
191
};
192
193
const message = {
194
owner,
195
spender,
196
value,
197
nonce,
198
deadline
199
};
200
201
const typedData = {
202
domain,
203
types,
204
primaryType: "Permit",
205
message
206
};
207
208
return await eth.signTypedData(owner, typedData);
209
}
210
```
211
212
#### MetaTransaction Signing
213
214
```typescript
215
// Sign meta-transaction for gasless execution
216
async function signMetaTransaction(
217
from: Address,
218
to: Address,
219
data: string,
220
nonce: number,
221
relayerAddress: Address
222
) {
223
const domain = {
224
name: "MetaTransactionRelay",
225
version: "1",
226
chainId: await eth.getChainId(),
227
verifyingContract: relayerAddress
228
};
229
230
const types = {
231
MetaTransaction: [
232
{ name: "from", type: "address" },
233
{ name: "to", type: "address" },
234
{ name: "data", type: "bytes" },
235
{ name: "nonce", type: "uint256" }
236
]
237
};
238
239
const message = {
240
from,
241
to,
242
data,
243
nonce
244
};
245
246
const typedData = {
247
domain,
248
types,
249
primaryType: "MetaTransaction",
250
message
251
};
252
253
return await eth.signTypedData(from, typedData);
254
}
255
```
256
257
## Signature Utilities
258
259
### Signature Recovery and Verification
260
261
```typescript
262
import { recover, hashMessage } from "web3-utils";
263
264
// Verify message signature
265
function verifyMessageSignature(message: string, signature: string, expectedSigner: Address): boolean {
266
try {
267
const recoveredAddress = recover(message, signature);
268
return recoveredAddress.toLowerCase() === expectedSigner.toLowerCase();
269
} catch (error) {
270
console.error("Signature verification failed:", error);
271
return false;
272
}
273
}
274
275
// Verify EIP-712 signature (requires additional library like @ethersproject/hash)
276
async function verifyTypedDataSignature(
277
typedData: Eip712TypedData,
278
signature: string,
279
expectedSigner: Address
280
): Promise<boolean> {
281
try {
282
// This would require implementing EIP-712 hash calculation
283
// or using a library like ethers.js _TypedDataEncoder
284
const digest = computeTypedDataHash(typedData);
285
const recoveredAddress = recover(digest, signature);
286
return recoveredAddress.toLowerCase() === expectedSigner.toLowerCase();
287
} catch (error) {
288
console.error("Typed data signature verification failed:", error);
289
return false;
290
}
291
}
292
```
293
294
### Batch Signing Operations
295
296
```typescript
297
// Sign multiple messages in batch
298
async function signMultipleMessages(
299
messages: string[],
300
signerAddress: Address
301
): Promise<SignatureObject[]> {
302
const signatures = await Promise.all(
303
messages.map(message => eth.sign(message, signerAddress))
304
);
305
306
return signatures;
307
}
308
309
// Sign multiple transactions in batch
310
async function signMultipleTransactions(
311
transactions: Transaction[],
312
signerAddress: Address
313
): Promise<SignedTransactionInfoAPI[]> {
314
// Add nonces if not present
315
const baseNonce = await eth.getTransactionCount(signerAddress);
316
317
const txsWithNonces = transactions.map((tx, index) => ({
318
...tx,
319
from: signerAddress,
320
nonce: tx.nonce ?? (baseNonce + index)
321
}));
322
323
const signedTxs = await Promise.all(
324
txsWithNonces.map(tx => eth.signTransaction(tx))
325
);
326
327
return signedTxs;
328
}
329
```
330
331
## Signature Format Conversion
332
333
```typescript
334
// Convert between signature formats
335
function parseSignature(signature: string) {
336
if (signature.startsWith('0x')) {
337
signature = signature.slice(2);
338
}
339
340
const r = '0x' + signature.slice(0, 64);
341
const s = '0x' + signature.slice(64, 128);
342
const v = parseInt(signature.slice(128, 130), 16);
343
344
return { r, s, v };
345
}
346
347
function combineSignature(r: string, s: string, v: number): string {
348
const rHex = r.startsWith('0x') ? r.slice(2) : r;
349
const sHex = s.startsWith('0x') ? s.slice(2) : s;
350
const vHex = v.toString(16).padStart(2, '0');
351
352
return '0x' + rHex + sHex + vHex;
353
}
354
```
355
356
## Core Types
357
358
```typescript { .api }
359
interface SignatureObject {
360
messageHash: HexString32Bytes;
361
r: HexString32Bytes;
362
s: HexString32Bytes;
363
v: HexString;
364
signature: HexString;
365
}
366
367
interface SignedTransactionInfoAPI {
368
messageHash: HexString32Bytes;
369
r: HexString32Bytes;
370
s: HexString32Bytes;
371
v: HexString;
372
rawTransaction: HexString;
373
transactionHash: HexString32Bytes;
374
}
375
376
interface Eip712TypedData {
377
domain: {
378
name?: string;
379
version?: string;
380
chainId?: Numbers;
381
verifyingContract?: Address;
382
salt?: HexString32Bytes;
383
};
384
types: {
385
[key: string]: Array<{
386
name: string;
387
type: string;
388
}>;
389
};
390
primaryType: string;
391
message: {
392
[key: string]: any;
393
};
394
}
395
396
interface Transaction {
397
from: Address;
398
to?: Address;
399
value?: Numbers;
400
gas?: Numbers;
401
gasPrice?: Numbers;
402
maxFeePerGas?: Numbers;
403
maxPriorityFeePerGas?: Numbers;
404
data?: Bytes;
405
nonce?: Numbers;
406
type?: Numbers;
407
accessList?: AccessList;
408
chainId?: Numbers;
409
}
410
411
type Address = HexString20Bytes;
412
type Numbers = HexString | number | bigint;
413
type Bytes = HexString;
414
```