or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

eip-712.mderror-handling.mdevent-processing.mdfunction-operations.mdindex.mdparameter-processing.md

eip-712.mddocs/

0

# EIP-712 Structured Data

1

2

Complete support for EIP-712 structured data encoding and message preparation for typed data signing. Essential for implementing secure off-chain message signing with structured data.

3

4

## Capabilities

5

6

### Get Encoded EIP-712 Data

7

8

Gets the EIP-191 encoded message to sign from typed data object. Implements the EIP-712 standard for structured data hashing and signing.

9

10

```typescript { .api }

11

/**

12

* Gets EIP-191 encoded message from typed data for signing

13

* @param typedData - The EIP-712 typed data object

14

* @param hash - Whether to hash the message with Keccak256

15

* @returns The encoded message (hashed if hash=true)

16

*/

17

function getEncodedEip712Data(

18

typedData: Eip712TypedData,

19

hash?: boolean

20

): string;

21

```

22

23

**Usage Examples:**

24

25

```typescript

26

import { getEncodedEip712Data } from "web3-eth-abi";

27

28

// Define EIP-712 typed data

29

const typedData = {

30

types: {

31

EIP712Domain: [

32

{ name: "name", type: "string" },

33

{ name: "version", type: "string" },

34

{ name: "chainId", type: "uint256" },

35

{ name: "verifyingContract", type: "address" }

36

],

37

Person: [

38

{ name: "name", type: "string" },

39

{ name: "wallet", type: "address" }

40

],

41

Mail: [

42

{ name: "from", type: "Person" },

43

{ name: "to", type: "Person" },

44

{ name: "contents", type: "string" }

45

]

46

},

47

primaryType: "Mail",

48

domain: {

49

name: "Ether Mail",

50

version: "1",

51

chainId: 1,

52

verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"

53

},

54

message: {

55

from: {

56

name: "Cow",

57

wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"

58

},

59

to: {

60

name: "Bob",

61

wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"

62

},

63

contents: "Hello, Bob!"

64

}

65

};

66

67

// Get encoded message for signing (not hashed)

68

const encodedMessage = getEncodedEip712Data(typedData, false);

69

console.log(encodedMessage);

70

// 0x1901... (EIP-191 prefix + domain separator + message hash)

71

72

// Get hashed message for signing

73

const hashedMessage = getEncodedEip712Data(typedData, true);

74

console.log(hashedMessage);

75

// 0x... (Keccak256 hash of the encoded message)

76

77

// Use with eth_signTypedData_v4

78

// The hashed message can be used directly with wallet signing methods

79

```

80

81

## EIP-712 Structure

82

83

### Domain Separator

84

85

The domain separator ensures that signatures are specific to a particular application and chain:

86

87

```typescript

88

interface EIP712Domain {

89

name?: string; // Human readable name of signing domain

90

version?: string; // Current major version of signing domain

91

chainId?: number; // EIP-155 chain id

92

verifyingContract?: string; // Address of contract that will verify signature

93

salt?: string; // Disambiguating salt for protocol

94

}

95

```

96

97

### Typed Data Structure

98

99

```typescript

100

interface Eip712TypedData {

101

types: Record<string, Array<{ name: string; type: string }>>;

102

primaryType: string;

103

domain: Record<string, unknown>;

104

message: Record<string, unknown>;

105

}

106

```

107

108

### Type Definitions

109

110

Custom types are defined in the `types` object, with each type specifying its fields and their types:

111

112

```typescript

113

const types = {

114

Person: [

115

{ name: "name", type: "string" },

116

{ name: "wallet", type: "address" }

117

],

118

Mail: [

119

{ name: "from", type: "Person" }, // References Person type

120

{ name: "to", type: "Person" },

121

{ name: "contents", type: "string" }

122

]

123

};

124

```

125

126

## Advanced Usage Examples

127

128

### Token Permit (ERC-2612)

129

130

```typescript

131

const permitTypedData = {

132

types: {

133

EIP712Domain: [

134

{ name: "name", type: "string" },

135

{ name: "version", type: "string" },

136

{ name: "chainId", type: "uint256" },

137

{ name: "verifyingContract", type: "address" }

138

],

139

Permit: [

140

{ name: "owner", type: "address" },

141

{ name: "spender", type: "address" },

142

{ name: "value", type: "uint256" },

143

{ name: "nonce", type: "uint256" },

144

{ name: "deadline", type: "uint256" }

145

]

146

},

147

primaryType: "Permit",

148

domain: {

149

name: "MyToken",

150

version: "1",

151

chainId: 1,

152

verifyingContract: "0x1234567890123456789012345678901234567890"

153

},

154

message: {

155

owner: "0xowner...",

156

spender: "0xspender...",

157

value: "1000000000000000000", // 1 token

158

nonce: 0,

159

deadline: 1700000000

160

}

161

};

162

163

const permitHash = getEncodedEip712Data(permitTypedData, true);

164

```

165

166

### Order Signing (DEX/Marketplace)

167

168

```typescript

169

const orderTypedData = {

170

types: {

171

EIP712Domain: [

172

{ name: "name", type: "string" },

173

{ name: "version", type: "string" },

174

{ name: "chainId", type: "uint256" },

175

{ name: "verifyingContract", type: "address" }

176

],

177

Order: [

178

{ name: "maker", type: "address" },

179

{ name: "taker", type: "address" },

180

{ name: "tokenA", type: "address" },

181

{ name: "tokenB", type: "address" },

182

{ name: "amountA", type: "uint256" },

183

{ name: "amountB", type: "uint256" },

184

{ name: "expiry", type: "uint256" },

185

{ name: "nonce", type: "uint256" }

186

]

187

},

188

primaryType: "Order",

189

domain: {

190

name: "MyDEX",

191

version: "1",

192

chainId: 1,

193

verifyingContract: "0xDEX_CONTRACT_ADDRESS"

194

},

195

message: {

196

maker: "0xmaker...",

197

taker: "0x0000000000000000000000000000000000000000", // Any taker

198

tokenA: "0xTokenA...",

199

tokenB: "0xTokenB...",

200

amountA: "1000000000000000000",

201

amountB: "500000000000000000",

202

expiry: 1700000000,

203

nonce: 1

204

}

205

};

206

207

const orderHash = getEncodedEip712Data(orderTypedData, true);

208

```

209

210

## Implementation Details

211

212

### Encoding Process

213

214

1. **Type Hash**: Calculate keccak256 of the encoded type definition

215

2. **Struct Hash**: Calculate keccak256 of type hash + encoded values

216

3. **Domain Separator**: Calculate keccak256 of domain type hash + domain values

217

4. **Final Message**: EIP-191 prefix + domain separator + message hash

218

219

### Array Handling

220

221

Arrays in EIP-712 are encoded by hashing each element recursively and then hashing the concatenated hashes.

222

223

### String and Bytes Handling

224

225

Strings and dynamic bytes are hashed using keccak256 when used in structured data.

226

227

## Types

228

229

```typescript { .api }

230

interface Eip712TypedData {

231

types: Record<string, Array<{ name: string; type: string }>>;

232

primaryType: string;

233

domain: Record<string, unknown>;

234

message: Record<string, unknown>;

235

}

236

237

interface EIP712Domain {

238

name?: string;

239

version?: string;

240

chainId?: number;

241

verifyingContract?: string;

242

salt?: string;

243

}

244

```