or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

artifact-management.mdbuidlerevm-provider.mdbuiltin-tasks.mdconfiguration.mdindex.mdplugin-system.mdtask-system.md

plugin-system.mddocs/

0

# Plugin System

1

2

Buidler's plugin system enables extensible functionality through modular packages that can register tasks, extend the runtime environment, modify configuration, and integrate external tools. Plugins follow a standard pattern for loading, configuration, and integration.

3

4

## Capabilities

5

6

### Plugin Loading

7

8

Load and integrate plugins into the Buidler environment.

9

10

```typescript { .api }

11

/**

12

* Load a Buidler plugin by name

13

* @param pluginName - Name of the plugin package to load

14

*/

15

function usePlugin(pluginName: string): void;

16

17

/**

18

* Load a plugin from a specific file path

19

* @param absolutePluginFilePath - Absolute path to plugin file

20

*/

21

function loadPluginFile(absolutePluginFilePath: string): void;

22

23

/**

24

* Ensure a plugin is loaded via usePlugin (for validation)

25

*/

26

function ensurePluginLoadedWithUsePlugin(): void;

27

```

28

29

**Usage Examples:**

30

31

```typescript

32

// buidler.config.ts

33

import { usePlugin } from "@nomiclabs/buidler/config";

34

35

// Load official plugins

36

usePlugin("@nomiclabs/buidler-ethers");

37

usePlugin("@nomiclabs/buidler-waffle");

38

usePlugin("@nomiclabs/buidler-web3");

39

40

// Load community plugins

41

usePlugin("buidler-gas-reporter");

42

usePlugin("buidler-contract-sizer");

43

44

// Load local plugin file

45

import { loadPluginFile } from "@nomiclabs/buidler/plugins-testing";

46

loadPluginFile(path.join(__dirname, "plugins", "custom-plugin.js"));

47

```

48

49

### Plugin Error Handling

50

51

Specialized error class for plugin-related errors with context information.

52

53

```typescript { .api }

54

/**

55

* Error class for plugin-related failures

56

*/

57

class BuidlerPluginError extends Error {

58

/**

59

* Create a plugin error with context

60

* @param pluginName - Name of the plugin that caused the error

61

* @param message - Error message

62

* @param parent - Optional parent error for error chaining

63

*/

64

constructor(

65

pluginName: string,

66

message: string,

67

parent?: Error

68

);

69

70

/** Name of the plugin that caused the error */

71

readonly pluginName: string;

72

/** Optional parent error */

73

readonly parent?: Error;

74

}

75

```

76

77

**Usage Examples:**

78

79

```typescript

80

// In a plugin

81

import { BuidlerPluginError } from "@nomiclabs/buidler/plugins";

82

83

task("my-task", async (taskArgs, hre) => {

84

try {

85

// Plugin operation that might fail

86

await someOperation();

87

} catch (error) {

88

throw new BuidlerPluginError(

89

"my-plugin",

90

"Failed to execute operation",

91

error

92

);

93

}

94

});

95

96

// Error handling in user code

97

try {

98

await hre.run("my-task");

99

} catch (error) {

100

if (error instanceof BuidlerPluginError) {

101

console.error(`Plugin ${error.pluginName} failed: ${error.message}`);

102

if (error.parent) {

103

console.error("Caused by:", error.parent.message);

104

}

105

}

106

}

107

```

108

109

### Environment Extension

110

111

Plugins can extend the runtime environment to add custom functionality.

112

113

```typescript { .api }

114

/**

115

* Extend the Buidler runtime environment

116

* @param extender - Function to modify the environment

117

*/

118

function extendEnvironment(extender: EnvironmentExtender): void;

119

120

/**

121

* Environment extender function signature

122

* @param env - Runtime environment to extend

123

*/

124

type EnvironmentExtender = (env: BuidlerRuntimeEnvironment) => void;

125

```

126

127

**Usage Examples:**

128

129

```typescript

130

// Plugin extending environment with Ethers.js

131

import { extendEnvironment } from "@nomiclabs/buidler/config";

132

import { ethers } from "ethers";

133

134

extendEnvironment((hre) => {

135

// Add ethers to runtime environment

136

hre.ethers = {

137

provider: new ethers.providers.Web3Provider(hre.network.provider),

138

139

getContractFactory: async (name: string) => {

140

const artifact = await hre.artifacts.readArtifact(name);

141

return new ethers.ContractFactory(

142

artifact.abi,

143

artifact.bytecode,

144

hre.ethers.provider.getSigner()

145

);

146

},

147

148

getContract: async (name: string, address: string) => {

149

const artifact = await hre.artifacts.readArtifact(name);

150

return new ethers.Contract(

151

address,

152

artifact.abi,

153

hre.ethers.provider.getSigner()

154

);

155

}

156

};

157

});

158

159

// Usage in tasks

160

task("deploy", async (taskArgs, hre) => {

161

const ContractFactory = await hre.ethers.getContractFactory("MyContract");

162

const contract = await ContractFactory.deploy();

163

await contract.deployed();

164

console.log("Contract deployed to:", contract.address);

165

});

166

```

167

168

### Configuration Extension

169

170

Plugins can modify and extend the Buidler configuration.

171

172

```typescript { .api }

173

/**

174

* Extend the Buidler configuration

175

* @param extender - Function to modify configuration

176

*/

177

function extendConfig(extender: ConfigExtender): void;

178

179

/**

180

* Configuration extender function signature

181

* @param config - Resolved configuration to modify

182

* @param userConfig - User configuration (read-only)

183

*/

184

type ConfigExtender = (

185

config: ResolvedBuidlerConfig,

186

userConfig: DeepReadonly<BuidlerConfig>

187

) => void;

188

```

189

190

**Usage Examples:**

191

192

```typescript

193

// Plugin adding custom configuration

194

import { extendConfig } from "@nomiclabs/buidler/config";

195

196

extendConfig((config, userConfig) => {

197

// Add default network if not specified

198

if (!config.networks.development) {

199

config.networks.development = {

200

url: "http://localhost:8545",

201

gas: "auto",

202

gasPrice: "auto"

203

};

204

}

205

206

// Modify Solidity settings based on user config

207

if (userConfig.customOptimizer) {

208

config.solc.optimizer.enabled = true;

209

config.solc.optimizer.runs = userConfig.customOptimizer.runs || 200;

210

}

211

212

// Add custom paths

213

config.paths.deployments = path.join(config.paths.root, "deployments");

214

});

215

```

216

217

### Task Registration

218

219

Plugins register new tasks and subtasks to extend Buidler functionality.

220

221

**Usage Examples:**

222

223

```typescript

224

// Plugin registering tasks

225

import { task, internalTask, types } from "@nomiclabs/buidler/config";

226

227

// Register a new public task

228

task("verify", "Verify contracts on Etherscan")

229

.addParam("contract", "Contract name to verify", undefined, types.string)

230

.addOptionalParam("address", "Contract address", undefined, types.string)

231

.addFlag("force", "Force verification even if already verified")

232

.setAction(async (taskArgs, hre) => {

233

console.log(`Verifying ${taskArgs.contract}...`);

234

// Verification logic

235

});

236

237

// Register internal subtask

238

internalTask("verify:prepare", "Prepare verification data", async (taskArgs, hre) => {

239

// Preparation logic

240

});

241

242

// Override existing task

243

task("compile", "Extended compile with verification prep", async (taskArgs, hre, runSuper) => {

244

// Run original compile

245

await runSuper(taskArgs);

246

247

// Additional plugin functionality

248

await hre.run("verify:prepare");

249

});

250

```

251

252

### Lazy Loading Utilities

253

254

Utilities for lazy loading heavy dependencies in plugins.

255

256

```typescript { .api }

257

/**

258

* Create a lazy-loaded object proxy

259

* @param objectCreator - Function that creates the object when first accessed

260

* @returns Proxy object that loads on first property access

261

*/

262

function lazyObject<T extends object>(objectCreator: () => T): T;

263

264

/**

265

* Create a lazy-loaded function proxy

266

* @param functionCreator - Function that creates the function when first called

267

* @returns Proxy function that loads on first call

268

*/

269

function lazyFunction<T extends Function>(functionCreator: () => T): T;

270

```

271

272

**Usage Examples:**

273

274

```typescript

275

import { lazyObject, lazyFunction } from "@nomiclabs/buidler/plugins";

276

277

// Lazy load heavy dependency

278

const ethers = lazyObject(() => require("ethers"));

279

280

// Lazy load function

281

const compile = lazyFunction(() => require("solc").compile);

282

283

extendEnvironment((hre) => {

284

// Heavy objects are only loaded when accessed

285

hre.ethers = ethers;

286

hre.compile = compile;

287

});

288

```

289

290

### Common Plugin Patterns

291

292

Standard patterns for plugin development and integration.

293

294

**Plugin Entry Point Pattern:**

295

296

```typescript

297

// plugin-entry.ts

298

import { extendEnvironment, task } from "@nomiclabs/buidler/config";

299

import { BuidlerPluginError } from "@nomiclabs/buidler/plugins";

300

301

// Extend environment

302

extendEnvironment((hre) => {

303

hre.myPlugin = {

304

doSomething: async () => {

305

try {

306

// Plugin functionality

307

} catch (error) {

308

throw new BuidlerPluginError("my-plugin", "Operation failed", error);

309

}

310

}

311

};

312

});

313

314

// Register tasks

315

task("my-plugin:task", "Description")

316

.setAction(async (taskArgs, hre) => {

317

await hre.myPlugin.doSomething();

318

});

319

```

320

321

**Plugin Configuration Pattern:**

322

323

```typescript

324

import { extendConfig } from "@nomiclabs/buidler/config";

325

326

// Extend user config interface

327

declare module "@nomiclabs/buidler/types" {

328

interface BuidlerConfig {

329

myPlugin?: {

330

option1?: string;

331

option2?: boolean;

332

};

333

}

334

}

335

336

// Apply plugin configuration

337

extendConfig((config, userConfig) => {

338

const pluginConfig = userConfig.myPlugin || {};

339

340

// Set defaults

341

config.myPlugin = {

342

option1: pluginConfig.option1 || "default",

343

option2: pluginConfig.option2 !== false

344

};

345

});

346

```

347

348

**Testing Plugin Pattern:**

349

350

```typescript

351

import { resetBuidlerContext } from "@nomiclabs/buidler/plugins-testing";

352

353

describe("My Plugin", () => {

354

beforeEach(() => {

355

// Reset context between tests

356

resetBuidlerContext();

357

});

358

359

it("should extend environment", async () => {

360

// Load plugin

361

require("../src/plugin");

362

363

// Test plugin functionality

364

const hre = await import("@nomiclabs/buidler");

365

expect(hre.myPlugin).to.exist;

366

});

367

});

368

```

369

370

### Plugin Package Structure

371

372

Standard structure for Buidler plugin packages:

373

374

```

375

my-buidler-plugin/

376

├── package.json

377

├── src/

378

│ ├── index.ts # Plugin entry point

379

│ ├── tasks/ # Task definitions

380

│ ├── types.ts # Type extensions

381

│ └── utils/ # Utility functions

382

├── test/

383

│ └── plugin.test.ts # Plugin tests

384

└── README.md

385

```

386

387

**Package.json example:**

388

389

```json

390

{

391

"name": "buidler-my-plugin",

392

"version": "1.0.0",

393

"main": "dist/index.js",

394

"types": "dist/index.d.ts",

395

"keywords": ["buidler", "plugin"],

396

"peerDependencies": {

397

"@nomiclabs/buidler": "^1.0.0"

398

}

399

}

400

```