@appliedblockchain/silentdatarollup-hardhat-plugin 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Silent Data [Rollup] Providers - Hardhat Plugin Package
2
+
3
+ ## Table of Contents
4
+
5
+ - [Introduction](#introduction)
6
+ - [Prerequisites](#prerequisites)
7
+ - [Integration](#integration)
8
+ - [Hardhat Integration](#hardhat-integration)
9
+ - [Installing Hardhat Integration Dependencies](#installing-hardhat-integration-dependencies)
10
+ - [Hardhat Integration Example](#hardhat-integration-example)
11
+ - [Troubleshooting](#troubleshooting)
12
+ - [License](#license)
13
+ - [Additional Resources](#additional-resources)
14
+
15
+ ## Introduction
16
+
17
+ Custom providers for integrating Silent Data [Rollup] with Hardhat.
18
+
19
+ ## Prerequisites
20
+
21
+ - Node.js (version 18 or higher)
22
+ - Hardhat v2
23
+ - npm
24
+ - Basic knowledge of Ethereum and smart contracts
25
+
26
+ ## Integration
27
+
28
+ ### Hardhat Integration
29
+
30
+ #### Installing Hardhat Integration Dependencies
31
+
32
+ ```bash
33
+ npm install @appliedblockchain/silentdatarollup-hardhat-plugin @nomicfoundation/hardhat-ignition-ethers@0.15.7
34
+ ```
35
+
36
+ #### Hardhat Integration Example
37
+
38
+ To integrate the Silent Data [Rollup] Provider with Hardhat, you need to configure your Silent Data network in the `hardhat.config.ts` file. Below is an example of how to set it up, and note that a `silentdata` property is needed on the network config to enable it. This property can be an empty object to apply defaults, or you can specify the configurations.
39
+
40
+ ```typescript
41
+ import '@nomicfoundation/hardhat-ignition-ethers'
42
+ import '@appliedblockchain/silentdatarollup-hardhat-plugin'
43
+
44
+ const RPC_URL = 'SILENT_DATA_ROLLUP_RPC_URL'
45
+ const PRIVATE_KEY = process.env.PRIVATE_KEY
46
+
47
+ export default {
48
+ solidity: '0.8.21',
49
+ defaultNetwork: 'sdr',
50
+ networks: {
51
+ sdr: {
52
+ url: RPC_URL,
53
+ accounts: [PRIVATE_KEY], // Note: Currently, only one private key can be passed to the network accounts configuration.
54
+ silentdata: {
55
+ authSignatureType: SignatureType.EIP712, // Optional, defaults to RAW
56
+ },
57
+ },
58
+ },
59
+ }
60
+ ```
61
+
62
+ Note: With the above configuration, you can deploy a contract using Hardhat Ignition. For a detailed example, including a sample contract and an Ignition module, please refer to the [Hardhat Ignition Getting Started Guide](https://hardhat.org/ignition/docs/getting-started).
63
+
64
+ To deploy your contract using Hardhat Ignition, run the following command:
65
+
66
+ ```bash
67
+ npx hardhat ignition deploy ignition/modules/Apollo.ts --network sdr
68
+ ```
69
+
70
+ ## Troubleshooting
71
+
72
+ If you encounter any issues, please check the following:
73
+
74
+ 1. Ensure you're using the correct RPC URL for your desired network.
75
+ 2. Verify that your private key is correctly set.
76
+ 3. Ensure that your token is still active on the SilentData AppChains dashboard.
77
+
78
+ ## License
79
+
80
+ This project is licensed under the [MIT License](LICENSE).
81
+
82
+ ## Additional Resources
83
+
84
+ - [Silent Data [Rollup] Documentation](https://docs.silentdata.com)
85
+ - [Ethers.js Documentation](https://docs.ethers.org/v6/)
86
+ - [Hardhat Documentation](https://hardhat.org/docs)
87
+ - [Hardhat Ignition](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ignition)
@@ -0,0 +1,18 @@
1
+ import { SignatureType } from '@appliedblockchain/silentdatarollup-core';
2
+
3
+ interface SilentdataNetworkConfig {
4
+ /**
5
+ * Signature type to use for authentication headers.
6
+ * If not provided, defaults to SignatureType.Raw.
7
+ */
8
+ authSignatureType: SignatureType;
9
+ }
10
+
11
+ declare module 'hardhat/types/config' {
12
+ interface HttpNetworkUserConfig {
13
+ silentdata?: SilentdataNetworkConfig;
14
+ }
15
+ interface HttpNetworkConfig {
16
+ silentdata?: SilentdataNetworkConfig;
17
+ }
18
+ }
@@ -0,0 +1,18 @@
1
+ import { SignatureType } from '@appliedblockchain/silentdatarollup-core';
2
+
3
+ interface SilentdataNetworkConfig {
4
+ /**
5
+ * Signature type to use for authentication headers.
6
+ * If not provided, defaults to SignatureType.Raw.
7
+ */
8
+ authSignatureType: SignatureType;
9
+ }
10
+
11
+ declare module 'hardhat/types/config' {
12
+ interface HttpNetworkUserConfig {
13
+ silentdata?: SilentdataNetworkConfig;
14
+ }
15
+ interface HttpNetworkConfig {
16
+ silentdata?: SilentdataNetworkConfig;
17
+ }
18
+ }
package/dist/index.js ADDED
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/type-extensions.ts
26
+ var import_config = require("hardhat/types/config");
27
+
28
+ // src/index.ts
29
+ var import_silentdatarollup_core3 = require("@appliedblockchain/silentdatarollup-core");
30
+ var import_debug2 = __toESM(require("debug"));
31
+ var import_ethers = require("ethers");
32
+ var import_config2 = require("hardhat/config");
33
+
34
+ // src/provider.ts
35
+ var import_silentdatarollup_core2 = require("@appliedblockchain/silentdatarollup-core");
36
+ var import_debug = __toESM(require("debug"));
37
+ var import_plugins = require("hardhat/plugins");
38
+
39
+ // src/constants.ts
40
+ var import_silentdatarollup_core = require("@appliedblockchain/silentdatarollup-core");
41
+ var SIGN_RPC_METHODS = [...import_silentdatarollup_core.SIGN_RPC_METHODS, "eth_call"];
42
+
43
+ // src/provider.ts
44
+ var log = (0, import_debug.default)(import_silentdatarollup_core2.DEBUG_NAMESPACE);
45
+ var HardhatSilentDataRollupProvider = class extends import_plugins.ProviderWrapper {
46
+ constructor(signer, _wrappedProvider, config) {
47
+ super(_wrappedProvider);
48
+ this._wrappedProvider = _wrappedProvider;
49
+ this.signer = signer;
50
+ this.config = {
51
+ ...config,
52
+ authSignatureType: config?.authSignatureType ?? import_silentdatarollup_core2.SignatureType.Raw
53
+ };
54
+ log("HardhatSilentDataRollupProvider initialized");
55
+ }
56
+ async request(args) {
57
+ log("Request: %s", args);
58
+ const requiresAuthHeaders = SIGN_RPC_METHODS.includes(args.method);
59
+ if (requiresAuthHeaders) {
60
+ log("Requesting auth headers for method: %s", args.method);
61
+ const clonedProvider = this.cloneWrappedProvider();
62
+ const rpcRequest = clonedProvider._getJsonRpcRequest(
63
+ args.method,
64
+ args.params
65
+ );
66
+ clonedProvider._extraHeaders = await this.getAuthHeaders(rpcRequest);
67
+ return clonedProvider.request(args);
68
+ }
69
+ log("Forwarding request to wrapped provider");
70
+ return this._wrappedProvider.request(args);
71
+ }
72
+ /**
73
+ * Creates a clone of the wrapped provider with a modified _getJsonRpcRequest method.
74
+ *
75
+ * This method is necessary due to the way the wrapped provider handles headers.
76
+ * The original provider uses a shared _extraHeaders property, which can lead to race conditions
77
+ * in concurrent calls, potentially resulting in requests with incorrect headers.
78
+ *
79
+ * By cloning the provider and assigning a unique ID to each request, we ensure that:
80
+ * 1. Each request uses its own set of headers
81
+ * 2. Concurrent calls don't interfere with each other's header information
82
+ *
83
+ * This approach effectively prevents race conditions and ensures the integrity of each request's headers.
84
+ */
85
+ cloneWrappedProvider() {
86
+ const clonedProvider = Object.create(
87
+ Object.getPrototypeOf(this._wrappedProvider),
88
+ Object.getOwnPropertyDescriptors(this._wrappedProvider)
89
+ );
90
+ const payloadId = Math.floor(Math.random() * 1e10);
91
+ clonedProvider._getJsonRpcRequest = (method, params = []) => {
92
+ return {
93
+ jsonrpc: "2.0",
94
+ method,
95
+ params,
96
+ id: payloadId
97
+ };
98
+ };
99
+ return clonedProvider;
100
+ }
101
+ async getAuthHeaders(request) {
102
+ log("Getting auth headers for request", JSON.stringify(request, null, 2));
103
+ const headers = await (0, import_silentdatarollup_core2.getAuthHeaders)(
104
+ this.signer,
105
+ request,
106
+ this.config.authSignatureType
107
+ );
108
+ log("Auth headers generated successfully", headers);
109
+ return headers;
110
+ }
111
+ };
112
+
113
+ // src/index.ts
114
+ var log2 = (0, import_debug2.default)(import_silentdatarollup_core3.DEBUG_NAMESPACE);
115
+ (0, import_config2.extendProvider)(
116
+ async (provider, config, network) => {
117
+ const networkConfig = config.networks[network];
118
+ const httpNetworkConfig = networkConfig;
119
+ if (!httpNetworkConfig.silentdata) {
120
+ log2(
121
+ "SilentData configuration not found. Returning the original provider."
122
+ );
123
+ return provider;
124
+ }
125
+ if (!("url" in networkConfig)) {
126
+ throw new Error("Network config is not an HTTP network");
127
+ }
128
+ const accounts = httpNetworkConfig.accounts;
129
+ if (!Array.isArray(accounts) || accounts.length === 0) {
130
+ throw new Error("No accounts found in network config");
131
+ }
132
+ if (accounts.length > 1) {
133
+ throw new Error("Multiple accounts not supported");
134
+ }
135
+ const account = accounts[0];
136
+ if (typeof account !== "string") {
137
+ throw new Error("Account is not a private key string");
138
+ }
139
+ const signer = new import_ethers.Wallet(account);
140
+ const newProvider = new HardhatSilentDataRollupProvider(
141
+ signer,
142
+ provider,
143
+ httpNetworkConfig.silentdata
144
+ );
145
+ return newProvider;
146
+ }
147
+ );
package/dist/index.mjs ADDED
@@ -0,0 +1,127 @@
1
+ // src/type-extensions.ts
2
+ import "hardhat/types/config";
3
+
4
+ // src/index.ts
5
+ import { DEBUG_NAMESPACE as DEBUG_NAMESPACE2 } from "@appliedblockchain/silentdatarollup-core";
6
+ import debug2 from "debug";
7
+ import { Wallet } from "ethers";
8
+ import { extendProvider } from "hardhat/config";
9
+
10
+ // src/provider.ts
11
+ import {
12
+ DEBUG_NAMESPACE,
13
+ getAuthHeaders,
14
+ SignatureType
15
+ } from "@appliedblockchain/silentdatarollup-core";
16
+ import debug from "debug";
17
+ import { ProviderWrapper } from "hardhat/plugins";
18
+
19
+ // src/constants.ts
20
+ import { SIGN_RPC_METHODS as CORE_SIGN_RPC_METHODS } from "@appliedblockchain/silentdatarollup-core";
21
+ var SIGN_RPC_METHODS = [...CORE_SIGN_RPC_METHODS, "eth_call"];
22
+
23
+ // src/provider.ts
24
+ var log = debug(DEBUG_NAMESPACE);
25
+ var HardhatSilentDataRollupProvider = class extends ProviderWrapper {
26
+ constructor(signer, _wrappedProvider, config) {
27
+ super(_wrappedProvider);
28
+ this._wrappedProvider = _wrappedProvider;
29
+ this.signer = signer;
30
+ this.config = {
31
+ ...config,
32
+ authSignatureType: config?.authSignatureType ?? SignatureType.Raw
33
+ };
34
+ log("HardhatSilentDataRollupProvider initialized");
35
+ }
36
+ async request(args) {
37
+ log("Request: %s", args);
38
+ const requiresAuthHeaders = SIGN_RPC_METHODS.includes(args.method);
39
+ if (requiresAuthHeaders) {
40
+ log("Requesting auth headers for method: %s", args.method);
41
+ const clonedProvider = this.cloneWrappedProvider();
42
+ const rpcRequest = clonedProvider._getJsonRpcRequest(
43
+ args.method,
44
+ args.params
45
+ );
46
+ clonedProvider._extraHeaders = await this.getAuthHeaders(rpcRequest);
47
+ return clonedProvider.request(args);
48
+ }
49
+ log("Forwarding request to wrapped provider");
50
+ return this._wrappedProvider.request(args);
51
+ }
52
+ /**
53
+ * Creates a clone of the wrapped provider with a modified _getJsonRpcRequest method.
54
+ *
55
+ * This method is necessary due to the way the wrapped provider handles headers.
56
+ * The original provider uses a shared _extraHeaders property, which can lead to race conditions
57
+ * in concurrent calls, potentially resulting in requests with incorrect headers.
58
+ *
59
+ * By cloning the provider and assigning a unique ID to each request, we ensure that:
60
+ * 1. Each request uses its own set of headers
61
+ * 2. Concurrent calls don't interfere with each other's header information
62
+ *
63
+ * This approach effectively prevents race conditions and ensures the integrity of each request's headers.
64
+ */
65
+ cloneWrappedProvider() {
66
+ const clonedProvider = Object.create(
67
+ Object.getPrototypeOf(this._wrappedProvider),
68
+ Object.getOwnPropertyDescriptors(this._wrappedProvider)
69
+ );
70
+ const payloadId = Math.floor(Math.random() * 1e10);
71
+ clonedProvider._getJsonRpcRequest = (method, params = []) => {
72
+ return {
73
+ jsonrpc: "2.0",
74
+ method,
75
+ params,
76
+ id: payloadId
77
+ };
78
+ };
79
+ return clonedProvider;
80
+ }
81
+ async getAuthHeaders(request) {
82
+ log("Getting auth headers for request", JSON.stringify(request, null, 2));
83
+ const headers = await getAuthHeaders(
84
+ this.signer,
85
+ request,
86
+ this.config.authSignatureType
87
+ );
88
+ log("Auth headers generated successfully", headers);
89
+ return headers;
90
+ }
91
+ };
92
+
93
+ // src/index.ts
94
+ var log2 = debug2(DEBUG_NAMESPACE2);
95
+ extendProvider(
96
+ async (provider, config, network) => {
97
+ const networkConfig = config.networks[network];
98
+ const httpNetworkConfig = networkConfig;
99
+ if (!httpNetworkConfig.silentdata) {
100
+ log2(
101
+ "SilentData configuration not found. Returning the original provider."
102
+ );
103
+ return provider;
104
+ }
105
+ if (!("url" in networkConfig)) {
106
+ throw new Error("Network config is not an HTTP network");
107
+ }
108
+ const accounts = httpNetworkConfig.accounts;
109
+ if (!Array.isArray(accounts) || accounts.length === 0) {
110
+ throw new Error("No accounts found in network config");
111
+ }
112
+ if (accounts.length > 1) {
113
+ throw new Error("Multiple accounts not supported");
114
+ }
115
+ const account = accounts[0];
116
+ if (typeof account !== "string") {
117
+ throw new Error("Account is not a private key string");
118
+ }
119
+ const signer = new Wallet(account);
120
+ const newProvider = new HardhatSilentDataRollupProvider(
121
+ signer,
122
+ provider,
123
+ httpNetworkConfig.silentdata
124
+ );
125
+ return newProvider;
126
+ }
127
+ );
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@appliedblockchain/silentdatarollup-hardhat-plugin",
3
+ "version": "1.0.0",
4
+ "description": "Hardhat plugin for Silent Data [Rollup]",
5
+ "author": "Applied Blockchain",
6
+ "homepage": "https://github.com/appliedblockchain/silent-data-rollup-providers#readme",
7
+ "keywords": [
8
+ "ethereum",
9
+ "provider",
10
+ "silentdata",
11
+ "rollup",
12
+ "hardhat"
13
+ ],
14
+ "license": "MIT",
15
+ "repository": "https://github.com/appliedblockchain/silent-data-rollup-providers",
16
+ "main": "dist/index.js",
17
+ "module": "dist/index.mjs",
18
+ "types": "dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "import": "./dist/index.mjs",
22
+ "require": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
30
+ "check-exports": "attw --pack . --profile node16",
31
+ "prepack": "npm run build"
32
+ },
33
+ "dependencies": {
34
+ "@appliedblockchain/silentdatarollup-core": "1.0.0",
35
+ "@nomicfoundation/hardhat-ethers": "3.0.8",
36
+ "debug": "4.3.7",
37
+ "ethers": "6.13.2"
38
+ },
39
+ "devDependencies": {
40
+ "@types/debug": "4.1.12",
41
+ "@types/node": "22.5.4",
42
+ "hardhat": "2.22.10",
43
+ "ts-node": "10.9.2",
44
+ "typescript": "5.6.2"
45
+ },
46
+ "peerDependencies": {
47
+ "ethers": "6.13.2",
48
+ "hardhat": "2.22.10"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ }
53
+ }