or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

argument-utilities.mdbalance-matchers.mdbignumber-support.mdevent-matchers.mdindex.mdpanic-codes.mdrevert-matchers.mdvalidation-matchers.md

panic-codes.mddocs/

0

# Panic Codes

1

2

Constants and utilities for testing Solidity panic conditions and arithmetic errors that occur during smart contract execution.

3

4

## Import

5

6

```typescript

7

import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";

8

```

9

10

## Capabilities

11

12

### Panic Code Constants

13

14

A comprehensive object containing all standard Solidity panic codes for testing different failure scenarios.

15

16

```typescript { .api }

17

const PANIC_CODES: {

18

ASSERTION_ERROR: 0x1;

19

ARITHMETIC_OVERFLOW: 0x11;

20

DIVISION_BY_ZERO: 0x12;

21

ENUM_CONVERSION_OUT_OF_BOUNDS: 0x21;

22

INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY: 0x22;

23

POP_ON_EMPTY_ARRAY: 0x31;

24

ARRAY_ACCESS_OUT_OF_BOUNDS: 0x32;

25

TOO_MUCH_MEMORY_ALLOCATED: 0x41;

26

ZERO_INITIALIZED_VARIABLE: 0x51;

27

};

28

```

29

30

## Panic Code Reference

31

32

### Assertion Error (0x1)

33

34

Triggered by failed `assert()` statements in Solidity code.

35

36

```typescript

37

import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";

38

39

// Test assertion failures

40

await expect(contract.assertPositive(-5))

41

.to.be.revertedWithPanic(PANIC_CODES.ASSERTION_ERROR);

42

43

// Example Solidity code that triggers this:

44

// function assertPositive(int x) public pure {

45

// assert(x >= 0); // Fails for negative x

46

// }

47

```

48

49

### Arithmetic Overflow (0x11)

50

51

Triggered by arithmetic operations that overflow outside of `unchecked` blocks.

52

53

```typescript

54

// Test arithmetic overflow

55

await expect(contract.addUint256(type(uint256).max, 1))

56

.to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_OVERFLOW);

57

58

// Test underflow

59

await expect(contract.subtractUint256(0, 1))

60

.to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_OVERFLOW);

61

62

// Example Solidity code:

63

// function addUint256(uint256 a, uint256 b) public pure returns (uint256) {

64

// return a + b; // Overflows if a + b > type(uint256).max

65

// }

66

```

67

68

### Division by Zero (0x12)

69

70

Triggered by division or modulo operations with zero divisor.

71

72

```typescript

73

// Test division by zero

74

await expect(contract.divide(100, 0))

75

.to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);

76

77

// Test modulo by zero

78

await expect(contract.modulo(100, 0))

79

.to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);

80

81

// Example Solidity code:

82

// function divide(uint256 a, uint256 b) public pure returns (uint256) {

83

// return a / b; // Panics if b == 0

84

// }

85

```

86

87

### Enum Conversion Out of Bounds (0x21)

88

89

Triggered when converting a value to an enum type that doesn't have a corresponding member.

90

91

```typescript

92

// Test invalid enum conversion

93

await expect(contract.setStatus(99)) // Status enum only has values 0-2

94

.to.be.revertedWithPanic(PANIC_CODES.ENUM_CONVERSION_OUT_OF_BOUNDS);

95

96

// Example Solidity code:

97

// enum Status { Pending, Active, Inactive }

98

// function setStatus(uint8 value) public {

99

// status = Status(value); // Panics for value > 2

100

// }

101

```

102

103

### Incorrectly Encoded Storage Byte Array (0x22)

104

105

Triggered when accessing a storage byte array that has been corrupted or incorrectly encoded.

106

107

```typescript

108

// Test corrupted storage access (rare in normal testing)

109

await expect(contract.accessCorruptedStorage())

110

.to.be.revertedWithPanic(PANIC_CODES.INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY);

111

112

// This is typically caused by low-level storage manipulation

113

```

114

115

### Pop on Empty Array (0x31)

116

117

Triggered when calling `.pop()` on an empty dynamic array.

118

119

```typescript

120

// Test popping from empty array

121

await expect(contract.popFromEmptyArray())

122

.to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);

123

124

// Example Solidity code:

125

// uint256[] public items;

126

// function popFromEmptyArray() public {

127

// items.pop(); // Panics if items.length == 0

128

// }

129

```

130

131

### Array Access Out of Bounds (0x32)

132

133

Triggered when accessing an array element at an invalid index.

134

135

```typescript

136

// Test out of bounds array access

137

await expect(contract.getItem(99)) // Array only has 5 elements

138

.to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);

139

140

// Test negative index (converted to very large uint)

141

await expect(contract.getItemSigned(-1))

142

.to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);

143

144

// Example Solidity code:

145

// uint256[] public items = [1, 2, 3, 4, 5];

146

// function getItem(uint256 index) public view returns (uint256) {

147

// return items[index]; // Panics if index >= items.length

148

// }

149

```

150

151

### Too Much Memory Allocated (0x41)

152

153

Triggered when trying to allocate too much memory or create arrays that are too large.

154

155

```typescript

156

// Test excessive memory allocation

157

await expect(contract.createHugeArray())

158

.to.be.revertedWithPanic(PANIC_CODES.TOO_MUCH_MEMORY_ALLOCATED);

159

160

// Example Solidity code:

161

// function createHugeArray() public pure {

162

// uint256[] memory huge = new uint256[](2**200); // Exceeds memory limits

163

// }

164

```

165

166

### Zero Initialized Variable (0x51)

167

168

Triggered when calling a zero-initialized variable of internal function type.

169

170

```typescript

171

// Test calling uninitialized internal function

172

await expect(contract.callUninitializedFunction())

173

.to.be.revertedWithPanic(PANIC_CODES.ZERO_INITIALIZED_VARIABLE);

174

175

// Example Solidity code:

176

// function() internal callback;

177

// function callUninitializedFunction() public {

178

// callback(); // Panics because callback is not initialized

179

// }

180

```

181

182

## Usage Patterns

183

184

### Generic Panic Testing

185

186

```typescript

187

// Test any panic condition without specifying which one

188

await expect(contract.riskyOperation())

189

.to.be.revertedWithPanic(); // Any panic code accepted

190

191

// Test specific panic code

192

await expect(contract.divideNumbers(a, 0))

193

.to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);

194

```

195

196

### Complex Arithmetic Testing

197

198

```typescript

199

import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";

200

201

describe("SafeMath operations", function() {

202

it("should handle overflow correctly", async function() {

203

const maxUint256 = ethers.MaxUint256;

204

205

// Test addition overflow

206

await expect(contract.safeAdd(maxUint256, 1))

207

.to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_OVERFLOW);

208

209

// Test multiplication overflow

210

await expect(contract.safeMultiply(maxUint256, 2))

211

.to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_OVERFLOW);

212

213

// Test subtraction underflow

214

await expect(contract.safeSubtract(0, 1))

215

.to.be.revertedWithPanic(PANIC_CODES.ARITHMETIC_OVERFLOW);

216

});

217

});

218

```

219

220

### Array Bounds Testing

221

222

```typescript

223

describe("Array operations", function() {

224

it("should handle array bounds correctly", async function() {

225

// Setup array with known length

226

await contract.initializeArray([1, 2, 3, 4, 5]);

227

228

// Test valid access

229

expect(await contract.getItem(0)).to.equal(1);

230

expect(await contract.getItem(4)).to.equal(5);

231

232

// Test out of bounds access

233

await expect(contract.getItem(5))

234

.to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);

235

236

await expect(contract.getItem(100))

237

.to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);

238

239

// Test pop on empty after clearing

240

await contract.clearArray();

241

await expect(contract.popItem())

242

.to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);

243

});

244

});

245

```

246

247

### Enum Validation Testing

248

249

```typescript

250

describe("Enum handling", function() {

251

it("should validate enum conversions", async function() {

252

// Test valid enum values

253

await contract.setStatus(0); // Status.Pending

254

await contract.setStatus(1); // Status.Active

255

await contract.setStatus(2); // Status.Inactive

256

257

// Test invalid enum values

258

await expect(contract.setStatus(3))

259

.to.be.revertedWithPanic(PANIC_CODES.ENUM_CONVERSION_OUT_OF_BOUNDS);

260

261

await expect(contract.setStatus(255))

262

.to.be.revertedWithPanic(PANIC_CODES.ENUM_CONVERSION_OUT_OF_BOUNDS);

263

});

264

});

265

```

266

267

## Advanced Testing Patterns

268

269

### Combining with Other Matchers

270

271

```typescript

272

// Test that operation either succeeds or fails with specific panic

273

const result = contract.riskyDivision(a, b);

274

if (b === 0) {

275

await expect(result).to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);

276

} else {

277

await expect(result).to.not.be.reverted;

278

expect(await result).to.equal(a / b);

279

}

280

```

281

282

### Error Recovery Testing

283

284

```typescript

285

describe("Error recovery", function() {

286

it("should handle and recover from panics", async function() {

287

// Verify panic occurs

288

await expect(contract.dangerousOperation())

289

.to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);

290

291

// Verify contract state remains consistent after panic

292

expect(await contract.isHealthy()).to.be.true;

293

294

// Verify normal operations still work

295

await expect(contract.safeOperation()).to.not.be.reverted;

296

});

297

});

298

```

299

300

### Fuzz Testing with Panics

301

302

```typescript

303

describe("Fuzz testing", function() {

304

it("should handle edge cases gracefully", async function() {

305

const testCases = [

306

{ a: 0, b: 0, expectPanic: PANIC_CODES.DIVISION_BY_ZERO },

307

{ a: ethers.MaxUint256, b: 2, expectPanic: PANIC_CODES.ARITHMETIC_OVERFLOW },

308

{ a: 100, b: 5, expectPanic: null }, // Should succeed

309

];

310

311

for (const { a, b, expectPanic } of testCases) {

312

if (expectPanic) {

313

await expect(contract.calculate(a, b))

314

.to.be.revertedWithPanic(expectPanic);

315

} else {

316

await expect(contract.calculate(a, b)).to.not.be.reverted;

317

}

318

}

319

});

320

});

321

```

322

323

## Integration with Revert Testing

324

325

Panic codes work seamlessly with the revert testing matchers:

326

327

```typescript

328

// These are equivalent ways to test the same condition

329

await expect(contract.divide(10, 0))

330

.to.be.revertedWithPanic(PANIC_CODES.DIVISION_BY_ZERO);

331

332

await expect(contract.divide(10, 0))

333

.to.be.revertedWithPanic(0x12);

334

335

// Can also test generic revert

336

await expect(contract.divide(10, 0)).to.be.reverted;

337

```