@enscribe/hardhat-enscribe 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +211 -0
  2. package/dist/src/index.d.ts +4 -0
  3. package/dist/src/index.js +33 -0
  4. package/dist/src/internal/abi/ENSRegistry.d.ts +36 -0
  5. package/dist/src/internal/abi/ENSRegistry.js +377 -0
  6. package/dist/src/internal/abi/NameWrapper.d.ts +51 -0
  7. package/dist/src/internal/abi/NameWrapper.js +1456 -0
  8. package/dist/src/internal/abi/Ownable.d.ts +36 -0
  9. package/dist/src/internal/abi/Ownable.js +55 -0
  10. package/dist/src/internal/abi/PublicResolver.d.ts +40 -0
  11. package/dist/src/internal/abi/PublicResolver.js +1014 -0
  12. package/dist/src/internal/abi/ReverseRegistrar.d.ts +40 -0
  13. package/dist/src/internal/abi/ReverseRegistrar.js +337 -0
  14. package/dist/src/internal/config/contracts.d.ts +175 -0
  15. package/dist/src/internal/config/contracts.js +168 -0
  16. package/dist/src/internal/constants.d.ts +1 -0
  17. package/dist/src/internal/constants.js +1 -0
  18. package/dist/src/internal/tasks/name.d.ts +9 -0
  19. package/dist/src/internal/tasks/name.integration.test.d.ts +1 -0
  20. package/dist/src/internal/tasks/name.integration.test.js +180 -0
  21. package/dist/src/internal/tasks/name.js +265 -0
  22. package/dist/src/internal/tasks/name.test.d.ts +1 -0
  23. package/dist/src/internal/tasks/name.test.js +55 -0
  24. package/dist/src/internal/type-extensions.d.ts +1 -0
  25. package/dist/src/internal/type-extensions.js +16 -0
  26. package/dist/src/internal/utils.d.ts +8 -0
  27. package/dist/src/internal/utils.js +48 -0
  28. package/dist/test/enscribe.hardhat.test.d.ts +1 -0
  29. package/dist/test/enscribe.hardhat.test.js +290 -0
  30. package/dist/test/enscribe.integration.test.d.ts +1 -0
  31. package/dist/test/enscribe.integration.test.js +229 -0
  32. package/package.json +59 -0
package/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # hardhat-enscribe
2
+
3
+ A Hardhat v3 plugin that enables you to assign ENS (Ethereum Name Service) names to your smart contracts, making them easily discoverable and human-readable.
4
+
5
+ ## What is hardhat-enscribe?
6
+
7
+ hardhat-enscribe allows developers to automatically assign ENS names to their smart contracts during or after deployment. This plugin handles the complete ENS integration process, including:
8
+
9
+ - **Subname Creation**: Creates ENS subnames for your contracts
10
+ - **Forward Resolution**: Maps ENS names to contract addresses
11
+ - **Reverse Resolution**: Maps contract addresses back to ENS names
12
+ - **Multi-chain Support**: Works across multiple networks including Ethereum, Sepolia, Linea, and more
13
+
14
+ ## Features
15
+
16
+ - 🏷️ **Primary ENS Naming**: Assign human-readable names to your contracts
17
+ - 🌐 **Multi-chain Support**: Works on Ethereum, Sepolia
18
+ - 🔧 **Hardhat v3 Compatible**: Built specifically for Hardhat v3 with Viem integration
19
+ - 🛡️ **Contract Type Detection**: Automatically detects Ownable and ReverseClaimer contracts
20
+ - ⚡ **Transaction Optimization**: Waits for confirmations to prevent race conditions
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @enscribe/hardhat-enscribe
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ Add the plugin to your `hardhat.config.ts`:
31
+
32
+ ```typescript
33
+ import type { HardhatUserConfig } from "hardhat/config";
34
+ import hardhatEnscribePlugin from "@enscribe/hardhat-enscribe";
35
+ import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem";
36
+
37
+ const config: HardhatUserConfig = {
38
+ plugins: [hardhatToolboxViemPlugin, hardhatEnscribePlugin],
39
+ // ... rest of your config
40
+ };
41
+
42
+ export default config;
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ### Basic Command
48
+
49
+ ```bash
50
+ npx hardhat enscribe name <ENS_NAME> --contract <CONTRACT_ADDRESS>
51
+ ```
52
+
53
+ ### Examples
54
+
55
+ #### Name a contract on Sepolia
56
+ ```bash
57
+ npx hardhat enscribe name mycontract.mydomain.eth --contract 0x1234...5678
58
+ ```
59
+
60
+ #### Name a contract on Linea
61
+ ```bash
62
+ npx hardhat enscribe name mycontract.mydomain.eth --contract 0x1234...5678 --chain linea
63
+ ```
64
+
65
+ ### Command Options
66
+
67
+ - `name` (required): The ENS name to assign (e.g., `mycontract.mydomain.eth`)
68
+ - `--contract` (required): The contract address to name
69
+ - `--chain` (optional): The network/chain to use (defaults to `sepolia`)
70
+
71
+ ## Supported Networks
72
+
73
+ The plugin supports the following networks:
74
+
75
+ - **Ethereum Mainnet** (`mainnet`)
76
+ - **Sepolia Testnet** (`sepolia`) - Default
77
+ - **Linea Mainnet** (`linea`)
78
+ - **Linea Sepolia** (`linea-sepolia`)
79
+
80
+ ## Contract Requirements
81
+
82
+ Your contract must implement one of the following patterns:
83
+
84
+ ### 1. Ownable Pattern
85
+ Contracts that implement the `owner()` function (like OpenZeppelin's Ownable):
86
+
87
+ ```solidity
88
+ contract MyContract {
89
+ address public owner;
90
+
91
+ function owner() public view returns (address) {
92
+ return owner;
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### 2. ReverseClaimer Pattern
98
+ Contracts that have reverse ENS resolution already set up.
99
+
100
+ ## How It Works
101
+
102
+ 1. **Subname Creation**: Creates an ENS subname record if it doesn't exist
103
+ 2. **Forward Resolution**: Maps the ENS name to your contract address
104
+ 3. **Reverse Resolution**: Maps your contract address back to the ENS name
105
+ 4. **Confirmation**: Waits for all transactions to be confirmed before proceeding
106
+
107
+ ## Example Workflow
108
+
109
+ ```bash
110
+ # 1. Deploy your contract
111
+ npx hardhat run scripts/deploy.ts --network sepolia
112
+
113
+ # 2. Name your contract
114
+ npx hardhat enscribe name myawesomecontract.mydomain.eth --contract 0x1234567890123456789012345678901234567890
115
+
116
+ # 3. Your contract is now discoverable at:
117
+ # https://app.enscribe.xyz/explore/11155111/myawesomecontract.mydomain.eth
118
+ ```
119
+
120
+ ## Environment Setup
121
+
122
+ ### Required Environment Variables
123
+
124
+ For testnets like Sepolia, you'll need:
125
+
126
+ ```bash
127
+ # Set your private key (use hardhat-keystore for security)
128
+ npx hardhat keystore set SEPOLIA_PRIVATE_KEY
129
+
130
+ # Or set as environment variable
131
+ export SEPOLIA_PRIVATE_KEY="your_private_key_here"
132
+ ```
133
+
134
+ ### Network Configuration
135
+
136
+ Ensure your `hardhat.config.ts` includes the networks you want to use:
137
+
138
+ ```typescript
139
+ networks: {
140
+ sepolia: {
141
+ type: "http",
142
+ chainType: "l1",
143
+ url: configVariable("SEPOLIA_RPC_URL"),
144
+ accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
145
+ },
146
+ linea: {
147
+ type: "http",
148
+ chainType: "l2",
149
+ url: configVariable("LINEA_RPC_URL"),
150
+ accounts: [configVariable("LINEA_PRIVATE_KEY")],
151
+ },
152
+ }
153
+ ```
154
+
155
+ ## Troubleshooting
156
+
157
+ ### Common Issues
158
+
159
+ **"Contract does not implement required interface"**
160
+ - Ensure your contract implements either `owner()` function or reverse ENS resolution
161
+ - Check that the contract address is correct and deployed
162
+
163
+ **"Insufficient funds"**
164
+ - Ensure your account has enough ETH to pay for ENS transactions
165
+ - Gas fees vary by network and ENS operation complexity
166
+
167
+ ## Development
168
+
169
+ ### Building
170
+
171
+ ```bash
172
+ npm run build
173
+ ```
174
+
175
+ ### Testing
176
+
177
+ ```bash
178
+ # Run all tests
179
+ npm test
180
+
181
+ # Run specific test suites
182
+ npm run test:unit
183
+ npm run test:integration
184
+ npm run test:hardhat
185
+ ```
186
+
187
+ ### Linting
188
+
189
+ ```bash
190
+ npm run lint
191
+ npm run format
192
+ ```
193
+
194
+ ## Contributing
195
+
196
+ Contributions are welcome! Please feel free to submit a Pull Request.
197
+
198
+ ## License
199
+
200
+ MIT
201
+
202
+ ## Links
203
+
204
+ - [GitHub Repository](https://github.com/enscribexyz/hardhat-enscribe)
205
+ - [Enscribe](https://app.enscribe.xyz)
206
+ - [Hardhat Documentation](https://hardhat.org/docs)
207
+ - [ENS Documentation](https://docs.ens.domains/)
208
+
209
+ ## Support
210
+
211
+ For support, please open an issue on GitHub or visit [app.enscribe.xyz](https://app.enscribe.xyz).
@@ -0,0 +1,4 @@
1
+ import "./internal/type-extensions";
2
+ import type { HardhatPlugin } from "hardhat/types/plugins";
3
+ declare const plugin: HardhatPlugin;
4
+ export default plugin;
@@ -0,0 +1,33 @@
1
+ import "./internal/type-extensions";
2
+ import { PLUGIN_ID } from "./internal/constants.js";
3
+ import { emptyTask, task } from "hardhat/config";
4
+ import { ArgumentType } from "hardhat/types/arguments";
5
+ const plugin = {
6
+ id: PLUGIN_ID,
7
+ dependencies: () => [],
8
+ tasks: [
9
+ emptyTask("enscribe", "Set ENS primary names for smart contracts.").build(),
10
+ task(["enscribe", "name"])
11
+ .addPositionalArgument({
12
+ name: "name",
13
+ type: ArgumentType.STRING,
14
+ })
15
+ .addOption({
16
+ name: "contract",
17
+ type: ArgumentType.STRING_WITHOUT_DEFAULT,
18
+ description: "Contract address for which the primary name is to be set.",
19
+ defaultValue: undefined,
20
+ })
21
+ .addOption({
22
+ name: "chain",
23
+ type: ArgumentType.STRING_WITHOUT_DEFAULT,
24
+ description: "Chain on which the address is to be named.",
25
+ defaultValue: undefined,
26
+ })
27
+ .setAction(() => import("./internal/tasks/name.js"))
28
+ .build(),
29
+ ],
30
+ hookHandlers: {},
31
+ globalOptions: [],
32
+ };
33
+ export default plugin;
@@ -0,0 +1,36 @@
1
+ declare const ensRegistryABI: ({
2
+ inputs: never[];
3
+ stateMutability: string;
4
+ type: string;
5
+ anonymous?: undefined;
6
+ name?: undefined;
7
+ outputs?: undefined;
8
+ } | {
9
+ anonymous: boolean;
10
+ inputs: {
11
+ indexed: boolean;
12
+ internalType: string;
13
+ name: string;
14
+ type: string;
15
+ }[];
16
+ name: string;
17
+ type: string;
18
+ stateMutability?: undefined;
19
+ outputs?: undefined;
20
+ } | {
21
+ inputs: {
22
+ internalType: string;
23
+ name: string;
24
+ type: string;
25
+ }[];
26
+ name: string;
27
+ outputs: {
28
+ internalType: string;
29
+ name: string;
30
+ type: string;
31
+ }[];
32
+ stateMutability: string;
33
+ type: string;
34
+ anonymous?: undefined;
35
+ })[];
36
+ export default ensRegistryABI;
@@ -0,0 +1,377 @@
1
+ const ensRegistryABI = [
2
+ {
3
+ inputs: [],
4
+ stateMutability: "nonpayable",
5
+ type: "constructor",
6
+ },
7
+ {
8
+ anonymous: false,
9
+ inputs: [
10
+ {
11
+ indexed: true,
12
+ internalType: "address",
13
+ name: "owner",
14
+ type: "address",
15
+ },
16
+ {
17
+ indexed: true,
18
+ internalType: "address",
19
+ name: "operator",
20
+ type: "address",
21
+ },
22
+ {
23
+ indexed: false,
24
+ internalType: "bool",
25
+ name: "approved",
26
+ type: "bool",
27
+ },
28
+ ],
29
+ name: "ApprovalForAll",
30
+ type: "event",
31
+ },
32
+ {
33
+ anonymous: false,
34
+ inputs: [
35
+ {
36
+ indexed: true,
37
+ internalType: "bytes32",
38
+ name: "node",
39
+ type: "bytes32",
40
+ },
41
+ {
42
+ indexed: true,
43
+ internalType: "bytes32",
44
+ name: "label",
45
+ type: "bytes32",
46
+ },
47
+ {
48
+ indexed: false,
49
+ internalType: "address",
50
+ name: "owner",
51
+ type: "address",
52
+ },
53
+ ],
54
+ name: "NewOwner",
55
+ type: "event",
56
+ },
57
+ {
58
+ anonymous: false,
59
+ inputs: [
60
+ {
61
+ indexed: true,
62
+ internalType: "bytes32",
63
+ name: "node",
64
+ type: "bytes32",
65
+ },
66
+ {
67
+ indexed: false,
68
+ internalType: "address",
69
+ name: "resolver",
70
+ type: "address",
71
+ },
72
+ ],
73
+ name: "NewResolver",
74
+ type: "event",
75
+ },
76
+ {
77
+ anonymous: false,
78
+ inputs: [
79
+ {
80
+ indexed: true,
81
+ internalType: "bytes32",
82
+ name: "node",
83
+ type: "bytes32",
84
+ },
85
+ {
86
+ indexed: false,
87
+ internalType: "uint64",
88
+ name: "ttl",
89
+ type: "uint64",
90
+ },
91
+ ],
92
+ name: "NewTTL",
93
+ type: "event",
94
+ },
95
+ {
96
+ anonymous: false,
97
+ inputs: [
98
+ {
99
+ indexed: true,
100
+ internalType: "bytes32",
101
+ name: "node",
102
+ type: "bytes32",
103
+ },
104
+ {
105
+ indexed: false,
106
+ internalType: "address",
107
+ name: "owner",
108
+ type: "address",
109
+ },
110
+ ],
111
+ name: "Transfer",
112
+ type: "event",
113
+ },
114
+ {
115
+ inputs: [
116
+ {
117
+ internalType: "address",
118
+ name: "owner",
119
+ type: "address",
120
+ },
121
+ {
122
+ internalType: "address",
123
+ name: "operator",
124
+ type: "address",
125
+ },
126
+ ],
127
+ name: "isApprovedForAll",
128
+ outputs: [
129
+ {
130
+ internalType: "bool",
131
+ name: "",
132
+ type: "bool",
133
+ },
134
+ ],
135
+ stateMutability: "view",
136
+ type: "function",
137
+ },
138
+ {
139
+ inputs: [
140
+ {
141
+ internalType: "bytes32",
142
+ name: "node",
143
+ type: "bytes32",
144
+ },
145
+ ],
146
+ name: "owner",
147
+ outputs: [
148
+ {
149
+ internalType: "address",
150
+ name: "",
151
+ type: "address",
152
+ },
153
+ ],
154
+ stateMutability: "view",
155
+ type: "function",
156
+ },
157
+ {
158
+ inputs: [
159
+ {
160
+ internalType: "bytes32",
161
+ name: "node",
162
+ type: "bytes32",
163
+ },
164
+ ],
165
+ name: "recordExists",
166
+ outputs: [
167
+ {
168
+ internalType: "bool",
169
+ name: "",
170
+ type: "bool",
171
+ },
172
+ ],
173
+ stateMutability: "view",
174
+ type: "function",
175
+ },
176
+ {
177
+ inputs: [
178
+ {
179
+ internalType: "bytes32",
180
+ name: "node",
181
+ type: "bytes32",
182
+ },
183
+ ],
184
+ name: "resolver",
185
+ outputs: [
186
+ {
187
+ internalType: "address",
188
+ name: "",
189
+ type: "address",
190
+ },
191
+ ],
192
+ stateMutability: "view",
193
+ type: "function",
194
+ },
195
+ {
196
+ inputs: [
197
+ {
198
+ internalType: "address",
199
+ name: "operator",
200
+ type: "address",
201
+ },
202
+ {
203
+ internalType: "bool",
204
+ name: "approved",
205
+ type: "bool",
206
+ },
207
+ ],
208
+ name: "setApprovalForAll",
209
+ outputs: [],
210
+ stateMutability: "nonpayable",
211
+ type: "function",
212
+ },
213
+ {
214
+ inputs: [
215
+ {
216
+ internalType: "bytes32",
217
+ name: "node",
218
+ type: "bytes32",
219
+ },
220
+ {
221
+ internalType: "address",
222
+ name: "owner",
223
+ type: "address",
224
+ },
225
+ ],
226
+ name: "setOwner",
227
+ outputs: [],
228
+ stateMutability: "nonpayable",
229
+ type: "function",
230
+ },
231
+ {
232
+ inputs: [
233
+ {
234
+ internalType: "bytes32",
235
+ name: "node",
236
+ type: "bytes32",
237
+ },
238
+ {
239
+ internalType: "address",
240
+ name: "owner",
241
+ type: "address",
242
+ },
243
+ {
244
+ internalType: "address",
245
+ name: "resolver",
246
+ type: "address",
247
+ },
248
+ {
249
+ internalType: "uint64",
250
+ name: "ttl",
251
+ type: "uint64",
252
+ },
253
+ ],
254
+ name: "setRecord",
255
+ outputs: [],
256
+ stateMutability: "nonpayable",
257
+ type: "function",
258
+ },
259
+ {
260
+ inputs: [
261
+ {
262
+ internalType: "bytes32",
263
+ name: "node",
264
+ type: "bytes32",
265
+ },
266
+ {
267
+ internalType: "address",
268
+ name: "resolver",
269
+ type: "address",
270
+ },
271
+ ],
272
+ name: "setResolver",
273
+ outputs: [],
274
+ stateMutability: "nonpayable",
275
+ type: "function",
276
+ },
277
+ {
278
+ inputs: [
279
+ {
280
+ internalType: "bytes32",
281
+ name: "node",
282
+ type: "bytes32",
283
+ },
284
+ {
285
+ internalType: "bytes32",
286
+ name: "label",
287
+ type: "bytes32",
288
+ },
289
+ {
290
+ internalType: "address",
291
+ name: "owner",
292
+ type: "address",
293
+ },
294
+ ],
295
+ name: "setSubnodeOwner",
296
+ outputs: [
297
+ {
298
+ internalType: "bytes32",
299
+ name: "",
300
+ type: "bytes32",
301
+ },
302
+ ],
303
+ stateMutability: "nonpayable",
304
+ type: "function",
305
+ },
306
+ {
307
+ inputs: [
308
+ {
309
+ internalType: "bytes32",
310
+ name: "node",
311
+ type: "bytes32",
312
+ },
313
+ {
314
+ internalType: "bytes32",
315
+ name: "label",
316
+ type: "bytes32",
317
+ },
318
+ {
319
+ internalType: "address",
320
+ name: "owner",
321
+ type: "address",
322
+ },
323
+ {
324
+ internalType: "address",
325
+ name: "resolver",
326
+ type: "address",
327
+ },
328
+ {
329
+ internalType: "uint64",
330
+ name: "ttl",
331
+ type: "uint64",
332
+ },
333
+ ],
334
+ name: "setSubnodeRecord",
335
+ outputs: [],
336
+ stateMutability: "nonpayable",
337
+ type: "function",
338
+ },
339
+ {
340
+ inputs: [
341
+ {
342
+ internalType: "bytes32",
343
+ name: "node",
344
+ type: "bytes32",
345
+ },
346
+ {
347
+ internalType: "uint64",
348
+ name: "ttl",
349
+ type: "uint64",
350
+ },
351
+ ],
352
+ name: "setTTL",
353
+ outputs: [],
354
+ stateMutability: "nonpayable",
355
+ type: "function",
356
+ },
357
+ {
358
+ inputs: [
359
+ {
360
+ internalType: "bytes32",
361
+ name: "node",
362
+ type: "bytes32",
363
+ },
364
+ ],
365
+ name: "ttl",
366
+ outputs: [
367
+ {
368
+ internalType: "uint64",
369
+ name: "",
370
+ type: "uint64",
371
+ },
372
+ ],
373
+ stateMutability: "view",
374
+ type: "function",
375
+ },
376
+ ];
377
+ export default ensRegistryABI;
@@ -0,0 +1,51 @@
1
+ declare const nameWrapperABI: ({
2
+ inputs: {
3
+ internalType: string;
4
+ name: string;
5
+ type: string;
6
+ }[];
7
+ stateMutability: string;
8
+ type: string;
9
+ name?: undefined;
10
+ anonymous?: undefined;
11
+ outputs?: undefined;
12
+ } | {
13
+ inputs: {
14
+ internalType: string;
15
+ name: string;
16
+ type: string;
17
+ }[];
18
+ name: string;
19
+ type: string;
20
+ stateMutability?: undefined;
21
+ anonymous?: undefined;
22
+ outputs?: undefined;
23
+ } | {
24
+ anonymous: boolean;
25
+ inputs: {
26
+ indexed: boolean;
27
+ internalType: string;
28
+ name: string;
29
+ type: string;
30
+ }[];
31
+ name: string;
32
+ type: string;
33
+ stateMutability?: undefined;
34
+ outputs?: undefined;
35
+ } | {
36
+ inputs: {
37
+ internalType: string;
38
+ name: string;
39
+ type: string;
40
+ }[];
41
+ name: string;
42
+ outputs: {
43
+ internalType: string;
44
+ name: string;
45
+ type: string;
46
+ }[];
47
+ stateMutability: string;
48
+ type: string;
49
+ anonymous?: undefined;
50
+ })[];
51
+ export default nameWrapperABI;