@lazy-sol/access-control 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/.editorconfig +21 -0
- package/.solcover.js +39 -0
- package/CONTRIBUTING.md +200 -0
- package/CRIBBED_CODE.txt +26 -0
- package/LICENSE.txt +22 -0
- package/README.md +162 -0
- package/artifacts/contracts/OwnableToAccessControlAdapter.sol/OwnableToAccessControlAdapter.json +342 -0
- package/contracts/AccessControl.sol +305 -0
- package/contracts/AdapterFactory.sol +56 -0
- package/contracts/OwnableToAccessControlAdapter.sol +231 -0
- package/contracts/mocks/AccessControlMock.sol +14 -0
- package/contracts/mocks/TetherToken.sol +443 -0
- package/deploy/deploy-AdapterFactory.js +59 -0
- package/deployments/goerli/.chainId +1 -0
- package/deployments/goerli/AdapterFactory.json +104 -0
- package/deployments/goerli/solcInputs/9f8f20c7b4fd0796d45c56d37e790191.json +42 -0
- package/docs/commit_policy.md +201 -0
- package/docs/pull_request_template.md +40 -0
- package/docs/style_guides.md +240 -0
- package/hardhat.config.js +359 -0
- package/package.json +39 -0
- package/test/adapter_factory.js +54 -0
- package/test/include/deployment_routines.js +150 -0
- package/test/include/features_roles.js +42 -0
- package/test/include/rbac.behaviour.js +315 -0
- package/test/ownable_to_rbac_adapter.js +100 -0
- package/test/ownable_to_rbac_adapter_rbac.js +57 -0
- package/test/rbac_core.js +24 -0
- package/test/rbac_modifier.js +53 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
# Style Guides
|
2
|
+
|
3
|
+
A programming style guide is an opinionated guide of programming conventions, style, and best practices for a
|
4
|
+
team or project.
|
5
|
+
|
6
|
+
This section breaks into several subsections depending on the programming, scripting, and markup languages used.
|
7
|
+
When new language is added to the project, one should also add a corresponding style guide subsection to this section.
|
8
|
+
|
9
|
+
For each language we use, a style guide is based on one or more widely used style guides. When several reference
|
10
|
+
guides are used, we assume that the first one is a basic one, and next ones supplement it (contradicting rules
|
11
|
+
in the next ones are ignored).
|
12
|
+
|
13
|
+
There are always controversial rules leading to endless debates, these rules are more a matter of taste, than a
|
14
|
+
rational thing. One of the examples is a famous endless "tabs vs spaces debate".
|
15
|
+
For each style guide we maintain the list of these controversial rules together with overridden rules.
|
16
|
+
|
17
|
+
This is yet another element for encouraging people to lead a project.
|
18
|
+
You get a chance to demonstrate in practice how the rules you've chosen help the development, readability, maintainability, etc.
|
19
|
+
|
20
|
+
## JavaScript
|
21
|
+
|
22
|
+
JavaScript is a non-class based object oriented programming language that is one of the core technologies of the
|
23
|
+
World Wide Web.
|
24
|
+
JavaScript was developed in September 1995 by a Netscape programmer Brandan Eich.
|
25
|
+
It was originally named Mocha, but quickly became known as LiveScript and, later, JavaScript.
|
26
|
+
|
27
|
+
JavaScript's syntax and naming conventions are similar to Java, for example both languages use camelCase to name
|
28
|
+
functions and variables, PascalCase for class names, UPPER_CASE for constants.
|
29
|
+
JavaScript, however, is not so strict: programs using snake_case instead of camelCase can also be seen widely.
|
30
|
+
|
31
|
+
We use [Airbnb Javascript Style Guide](https://github.com/airbnb/javascript) as a base.
|
32
|
+
Following rules are considered contentious (to be extended) and/or are overridden:
|
33
|
+
|
34
|
+
- [Whitespace](https://github.com/airbnb/javascript#whitespace)
|
35
|
+
- use of soft tabs (space character) set to 2 spaces (eslint: indent)
|
36
|
+
- **no** spaces inside curly braces (eslint: object-curly-spacing: **"never"**)
|
37
|
+
**reason:** monospace fonts have already enough spare space in braces, commas, dots, etc.
|
38
|
+
to make these symbols clearly distinguishable from the literals' symbols
|
39
|
+
- characters per line limit (eslint: max-len): **120**
|
40
|
+
**reason:**: most of the screens allow to easily see 120 characters in one line
|
41
|
+
- [Blocks](https://github.com/airbnb/javascript#blocks)
|
42
|
+
- `else` statements in an `if-else` construct, as well as `catch` and `finally`,
|
43
|
+
must be **on its own line** after the preceding closing brace (eslint: brace-style: **"stroustrup"**)
|
44
|
+
**reason:** this makes `if-else` blocks better distinguishable when statements inside are very short
|
45
|
+
- [Naming Conventions](https://github.com/airbnb/javascript#naming-conventions)
|
46
|
+
- camelCase naming for objects, functions, and instances (eslint: camelcase)
|
47
|
+
|
48
|
+
## TypeScript
|
49
|
+
|
50
|
+
TypeScript is a strongly typed programming language that builds on JavaScript, developed by Microsoft, published
|
51
|
+
in 2012.
|
52
|
+
|
53
|
+
TypeScript style guide inherits from [JavaScript](#javascript) and is enriched with
|
54
|
+
[Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html), which is used basically
|
55
|
+
to cover areas not covered in [Airbnb Javascript Style Guide](https://github.com/airbnb/javascript).
|
56
|
+
|
57
|
+
## Solidity
|
58
|
+
|
59
|
+
Solidity is an object-oriented programming language for implementing smart contracts.
|
60
|
+
Solidity was proposed in August 2014 by Dr. Gavin Wood.
|
61
|
+
As specified by Dr. Gavin Wood, Solidity is designed around the JavaScript syntax to make it familiar for existing web
|
62
|
+
developers.
|
63
|
+
|
64
|
+
Solidity inherits its syntax and naming conventions from JavaScript. Both languages use camelCase naming for
|
65
|
+
functions and variables, PascalCase for class names, UPPER_CASE for constants.
|
66
|
+
|
67
|
+
We use [Official Solidity Style Guide](https://docs.soliditylang.org/en/v0.8.16/style-guide.html) as a base,
|
68
|
+
enriched with [Official Java Code Conventions](https://www.oracle.com/technetwork/java/codeconventions-150003.pdf)
|
69
|
+
(for example, Official Solidity Guide misses ideas on interface naming).
|
70
|
+
Following rules are considered contentious and/or are overridden:
|
71
|
+
|
72
|
+
- Tabs or Spaces: spaces are the preferred indentation method
|
73
|
+
- `else` statements in an `if-else` construct must be **on its own line** after the preceding closing brace
|
74
|
+
|
75
|
+
Prefer `Interface` naming to Zeppelin's `IInterface` one.
|
76
|
+
Name the interface by answering the question "what it is?", based on functional requirements. A `Truck`.
|
77
|
+
Name the implementation contract by answering the question "how it works?", or "what it looks like?",
|
78
|
+
based on non-functional requirements. A `RedTruck`.
|
79
|
+
ERC standards like ERC20, ERC721, and others are effectively interfaces already and do not require an "I" prefix.
|
80
|
+
|
81
|
+
Bad:
|
82
|
+
|
83
|
+
```
|
84
|
+
interface IPriceOracle {
|
85
|
+
...
|
86
|
+
}
|
87
|
+
contract PriceOracle is IPriceOracle {
|
88
|
+
...
|
89
|
+
}
|
90
|
+
```
|
91
|
+
|
92
|
+
Good:
|
93
|
+
|
94
|
+
```
|
95
|
+
interface PriceOracle {
|
96
|
+
...
|
97
|
+
}
|
98
|
+
contract PriceOracleV1 is PriceOracle {
|
99
|
+
...
|
100
|
+
}
|
101
|
+
```
|
102
|
+
|
103
|
+
Bad:
|
104
|
+
|
105
|
+
```
|
106
|
+
interface IERC20 {
|
107
|
+
...
|
108
|
+
}
|
109
|
+
contract Token is IERC20 {
|
110
|
+
...
|
111
|
+
}
|
112
|
+
```
|
113
|
+
|
114
|
+
Good:
|
115
|
+
|
116
|
+
```
|
117
|
+
interface ERC20 {
|
118
|
+
...
|
119
|
+
}
|
120
|
+
contract Token is ERC20 {
|
121
|
+
...
|
122
|
+
}
|
123
|
+
```
|
124
|
+
|
125
|
+
## Markdown
|
126
|
+
|
127
|
+
Markdown is a lightweight markup language created by John Gruber and Aaron Swartz in 2004 with the goal to be
|
128
|
+
appealing to human readers in its source code form. Markdown was standardized in 2012-2016.
|
129
|
+
|
130
|
+
We use [Google Markdown Style Guide](https://google.github.io/styleguide/docguide/style.html) as a base,
|
131
|
+
enriched with [Matt Cone Markdown Style Guide](https://www.markdownguide.org/basic-syntax/).
|
132
|
+
Following rules are considered contentious and/or are overridden:
|
133
|
+
|
134
|
+
- [Trailing whitespace](https://google.github.io/styleguide/docguide/style.html#trailing-whitespace)
|
135
|
+
/ [Line Breaks Best Practices](https://www.markdownguide.org/basic-syntax/#line-break-best-practices):
|
136
|
+
don't use the trailing backslash, use trailing whitespace and ensure .editorconfig has
|
137
|
+
`trim_trailing_whitespace = false` for `*.md` files
|
138
|
+
|
139
|
+
## Automating Formatting Standards
|
140
|
+
|
141
|
+
The above standards can be more easily met by automating their implementation.
|
142
|
+
Many repositories will have a `.editorconfig` file, which tells editors how to interpret inputs, such as tab.
|
143
|
+
The EditorConfig file is read automatically by many IDEs, including WebStorm, IntellijIDEA and Visual Studio,
|
144
|
+
but is **not** picked up automatically by many even related tools including PHPStorm, Sublime, Eclipse,
|
145
|
+
and Visual Studio Code: a [supporting plugin](https://editorconfig.org/) should be used.
|
146
|
+
You should ensure your IDE setup supports these editor expectations.
|
147
|
+
|
148
|
+
Optionally you may additionally use Prettier or a similar formatter.
|
149
|
+
Prettier is an opinionated code formatter, which uses sensible defaults that can often (but not always)
|
150
|
+
be overridden in a `.prettierrc` file.
|
151
|
+
Prettier will also inspect `.editorconfig` files and use those settings as its defaults.
|
152
|
+
Note that Visual Studio Code includes Prettier formatter by default, and its Format command triggers it.
|
153
|
+
It can also be configured to trigger on-save.
|
154
|
+
|
155
|
+
Prettier should **not** be used on existing projects that already have an established standard.
|
156
|
+
|
157
|
+
Finally, a _linter_ such as eslint or solhint may be a good option to be used.
|
158
|
+
Linters dynamically inspect code and point out potential issues.
|
159
|
+
This can include style issues as above but also code quality issues like unused variables,
|
160
|
+
deprecated functions, unreachable code, etc.
|
161
|
+
Installing the solidity plugin for Visual Studio Code automatically installs a linter.
|
162
|
+
|
163
|
+
Note that the above tools can all be used together. EditorConfig works as you type, ensuring you meet standards,
|
164
|
+
Prettier formats your code after you write it, while linters highlight, but do not fix, potential quality issues.
|
165
|
+
|
166
|
+
## Testing Standards and Style Guidelines
|
167
|
+
|
168
|
+
Testing smart contracts is of critical importance. Tests are used to validate security requirements,
|
169
|
+
and to confirm behaviour to be as expected and intended.
|
170
|
+
Proper testing of any software is a difficult skill that takes a long time to learn. Here are some important guides.
|
171
|
+
|
172
|
+
**Unit testing** is intended to test a single, specific behaviour, such as a function.
|
173
|
+
In the context of smart contracts this typically means to execute a function and then check the resulting state
|
174
|
+
and events emitted.
|
175
|
+
|
176
|
+
Unit testing forms the vast majority of test cases and requires large numbers of simple tests,
|
177
|
+
with each test verifying a single aspect of behaviour.
|
178
|
+
It should be possible for any failed test to immediately identify the error.
|
179
|
+
|
180
|
+
Unit tests are often built in a way phrased as _arrange-act-assert_.
|
181
|
+
Arrange is the process to set up the contract to a suitable initial state.
|
182
|
+
Act is executing the desired function.
|
183
|
+
Assert is verifying the state changes occurred and events emitted.
|
184
|
+
|
185
|
+
Arrange steps **do not belong to the test function** and should be implemented as part of a `beforeEach` or similar
|
186
|
+
hook which sets up the state for all the tests.
|
187
|
+
Use `describe` blocks to separate test functionality that has different state setup.
|
188
|
+
|
189
|
+
It is vitally important that tests are not an afterthought, but a key part of the development deliverable.
|
190
|
+
This means that the test should cover not just "the behaviour", but edge cases, error handling, permission checking,
|
191
|
+
bounds-checking and other similar difficulties. "Happy path" testing is of minimal value.
|
192
|
+
|
193
|
+
Some important points on unit tests:
|
194
|
+
|
195
|
+
- Only test one thing at a time - do not run compound tests
|
196
|
+
- Each test must be independent
|
197
|
+
- Consider making utility functions for things like state setup to ensure simplicity and consistency
|
198
|
+
- Separate contracts by a file and only test one contract per file
|
199
|
+
- Separate functionality areas with `describe` blocks, and note you can nest these blocks for sub-functionality
|
200
|
+
- Tests should be as small as possible, ideally only one line, or a few lines
|
201
|
+
- You can append `.only` to a test case while implementing it, to isolate that one test (not to run the whole suite
|
202
|
+
during the test development), though keep in mind that the entire suite must also work
|
203
|
+
- Do not add suite setup to `beforeEach`, as this will run before every test.
|
204
|
+
For example, getting all the accounts from the provider can be implemented either as global function, or if
|
205
|
+
using async mode - can be run in the `before` hook, which runs one single time.
|
206
|
+
- Ensure the test checks function execution constraints (contract state, function input params, access control), smart
|
207
|
+
contract state change(s), event emission(s)
|
208
|
+
- Favour constants (or TypeScript enums) for testing values, as they can convey meaning and be reused as the
|
209
|
+
assertion value
|
210
|
+
|
211
|
+
Many areas of functionality may also implement an end-to-end test, where multiple steps are undertaken in order
|
212
|
+
to ensure a cohesive and correct workflow.
|
213
|
+
These typically act as a "sanity check" to verify complex behaviours work as intended.
|
214
|
+
Such tests supplement, but do not replace, comprehensive unit tests.
|
215
|
+
|
216
|
+
Code Coverage reports can be generated with `npm run coverage`.
|
217
|
+
Reports show the coverage as a percentage of lines covered with tests.
|
218
|
+
It is important to ensure this is not reduced by your modifications.
|
219
|
+
It is also important the testing is not done **solely** to increase the test coverage percentage.
|
220
|
+
Instead, the code coverage outputs are used to highlight areas where tests are lacking.
|
221
|
+
The coverage reports generate output artifacts that show line-by-line where code is untested,
|
222
|
+
as well as summaries by files overall.
|
223
|
+
|
224
|
+
When beginning a new block of work you should ensure that you run the coverage report prior to starting
|
225
|
+
to ensure your changes do not lower the code coverage.
|
226
|
+
|
227
|
+
See also: [Gitlab Testing Standards](https://docs.gitlab.com/ee/development/testing_guide/)
|
228
|
+
|
229
|
+
## References
|
230
|
+
1. Srđan Popić, Gordana Velikić at al.
|
231
|
+
The Benefits of the Coding Standards Enforcement and it's Influence on the
|
232
|
+
Developers' Coding Behaviour: A Case Study on Two Small Projects
|
233
|
+
2. [Coding standards: what are they, and why do you need
|
234
|
+
them](https://blog.codacy.com/coding-standards-what-are-they-and-why-do-you-need-them/)
|
235
|
+
|
236
|
+
## About
|
237
|
+
|
238
|
+
Prepared by Basil Gorin
|
239
|
+
|
240
|
+
(c) 2017–2024 Basil Gorin
|
@@ -0,0 +1,359 @@
|
|
1
|
+
/**
|
2
|
+
* default Hardhat configuration which uses account mnemonic to derive accounts
|
3
|
+
* script expects following environment variables to be set:
|
4
|
+
* - P_KEY1 – mainnet private key, should start with 0x
|
5
|
+
* or
|
6
|
+
* - MNEMONIC1 – mainnet mnemonic, 12 words
|
7
|
+
*
|
8
|
+
* - P_KEY3 – ropsten private key, should start with 0x
|
9
|
+
* or
|
10
|
+
* - MNEMONIC3 – ropsten mnemonic, 12 words
|
11
|
+
*
|
12
|
+
* - P_KEY4 – rinkeby private key, should start with 0x
|
13
|
+
* or
|
14
|
+
* - MNEMONIC4 – rinkeby mnemonic, 12 words
|
15
|
+
*
|
16
|
+
* - P_KEY41 – kovan private key, should start with 0x
|
17
|
+
* or
|
18
|
+
* - MNEMONIC41 – kovan mnemonic, 12 words
|
19
|
+
*
|
20
|
+
* - P_KEY5 – goerli private key, should start with 0x
|
21
|
+
* or
|
22
|
+
* - MNEMONIC5 – goerli mnemonic, 12 words
|
23
|
+
*
|
24
|
+
* - P_KEY137 – polygon/matic private key, should start with 0x
|
25
|
+
* or
|
26
|
+
* - MNEMONIC137 – polygon/matic mnemonic, 12 words
|
27
|
+
*
|
28
|
+
* - P_KEY80001 – mumbai (polygon testnet) private key, should start with 0x
|
29
|
+
* or
|
30
|
+
* - MNEMONIC80001 – mumbai (polygon testnet) mnemonic, 12 words
|
31
|
+
*
|
32
|
+
* - P_KEY56 – Binance Smart Chain (BSC) mainnet private key, should start with 0x
|
33
|
+
* or
|
34
|
+
* - MNEMONIC56 – Binance Smart Chain (BSC) mainnet mnemonic, 12 words
|
35
|
+
*
|
36
|
+
* - P_KEY97 – Binance Smart Chain (BSC) testnet private key, should start with 0x
|
37
|
+
* or
|
38
|
+
* - MNEMONIC97 – Binance Smart Chain (BSC) testnet mnemonic, 12 words
|
39
|
+
*
|
40
|
+
* - ALCHEMY_KEY – Alchemy API key
|
41
|
+
* or
|
42
|
+
* - INFURA_KEY – Infura API key (Project ID)
|
43
|
+
*
|
44
|
+
* - ETHERSCAN_KEY – Etherscan API key
|
45
|
+
*
|
46
|
+
* - POLYSCAN_KEY – polygonscan API key
|
47
|
+
*
|
48
|
+
* - BSCSCAN_KEY – BscScan API key
|
49
|
+
*
|
50
|
+
* - REPORT_GAS - optional, set it to true to print gas usage info
|
51
|
+
*/
|
52
|
+
|
53
|
+
// Enable Truffle 5 plugin for tests
|
54
|
+
// https://hardhat.org/guides/truffle-testing.html
|
55
|
+
require("@nomiclabs/hardhat-truffle5");
|
56
|
+
|
57
|
+
// enable Solidity-coverage
|
58
|
+
// https://hardhat.org/plugins/solidity-coverage.html
|
59
|
+
require("solidity-coverage");
|
60
|
+
|
61
|
+
// enable hardhat-gas-reporter
|
62
|
+
// https://github.com/cgewecke/hardhat-gas-reporter
|
63
|
+
require("hardhat-gas-reporter");
|
64
|
+
|
65
|
+
// adds a mechanism to deploy contracts to any network,
|
66
|
+
// keeping track of them and replicating the same environment for testing
|
67
|
+
// https://www.npmjs.com/package/hardhat-deploy
|
68
|
+
require("hardhat-deploy");
|
69
|
+
|
70
|
+
// verify environment setup, display warning if required, replace missing values with fakes
|
71
|
+
const FAKE_MNEMONIC = "test test test test test test test test test test test junk";
|
72
|
+
if(!process.env.MNEMONIC1 && !process.env.P_KEY1) {
|
73
|
+
console.warn("neither MNEMONIC1 nor P_KEY1 is not set. Mainnet deployments won't be available");
|
74
|
+
process.env.MNEMONIC1 = FAKE_MNEMONIC;
|
75
|
+
}
|
76
|
+
else if(process.env.P_KEY1 && !process.env.P_KEY1.startsWith("0x")) {
|
77
|
+
console.warn("P_KEY1 doesn't start with 0x. Appended 0x");
|
78
|
+
process.env.P_KEY1 = "0x" + process.env.P_KEY1;
|
79
|
+
}
|
80
|
+
if(!process.env.MNEMONIC3 && !process.env.P_KEY3) {
|
81
|
+
console.warn("neither MNEMONIC3 nor P_KEY3 is not set. Ropsten deployments won't be available");
|
82
|
+
process.env.MNEMONIC3 = FAKE_MNEMONIC;
|
83
|
+
}
|
84
|
+
else if(process.env.P_KEY3 && !process.env.P_KEY3.startsWith("0x")) {
|
85
|
+
console.warn("P_KEY3 doesn't start with 0x. Appended 0x");
|
86
|
+
process.env.P_KEY3 = "0x" + process.env.P_KEY3;
|
87
|
+
}
|
88
|
+
if(!process.env.MNEMONIC4 && !process.env.P_KEY4) {
|
89
|
+
console.warn("neither MNEMONIC4 nor P_KEY4 is not set. Rinkeby deployments won't be available");
|
90
|
+
process.env.MNEMONIC4 = FAKE_MNEMONIC;
|
91
|
+
}
|
92
|
+
else if(process.env.P_KEY4 && !process.env.P_KEY4.startsWith("0x")) {
|
93
|
+
console.warn("P_KEY4 doesn't start with 0x. Appended 0x");
|
94
|
+
process.env.P_KEY4 = "0x" + process.env.P_KEY4;
|
95
|
+
}
|
96
|
+
if(!process.env.MNEMONIC42 && !process.env.P_KEY42) {
|
97
|
+
console.warn("neither MNEMONIC42 nor P_KEY42 is not set. Kovan deployments won't be available");
|
98
|
+
process.env.MNEMONIC42 = FAKE_MNEMONIC;
|
99
|
+
}
|
100
|
+
else if(process.env.P_KEY42 && !process.env.P_KEY42.startsWith("0x")) {
|
101
|
+
console.warn("P_KEY42 doesn't start with 0x. Appended 0x");
|
102
|
+
process.env.P_KEY42 = "0x" + process.env.P_KEY42;
|
103
|
+
}
|
104
|
+
if(!process.env.MNEMONIC5 && !process.env.P_KEY5) {
|
105
|
+
console.warn("neither MNEMONIC5 nor P_KEY5 is not set. Goerli deployments won't be available");
|
106
|
+
process.env.MNEMONIC5 = FAKE_MNEMONIC;
|
107
|
+
}
|
108
|
+
else if(process.env.P_KEY5 && !process.env.P_KEY5.startsWith("0x")) {
|
109
|
+
console.warn("P_KEY5 doesn't start with 0x. Appended 0x");
|
110
|
+
process.env.P_KEY5 = "0x" + process.env.P_KEY5;
|
111
|
+
}
|
112
|
+
if(!process.env.MNEMONIC137 && !process.env.P_KEY137) {
|
113
|
+
console.warn("neither MNEMONIC137 nor P_KEY137 is not set. Polygon mainnet deployments won't be available");
|
114
|
+
process.env.MNEMONIC137 = FAKE_MNEMONIC;
|
115
|
+
}
|
116
|
+
else if(process.env.P_KEY137 && !process.env.P_KEY137.startsWith("0x")) {
|
117
|
+
console.warn("P_KEY137 doesn't start with 0x. Appended 0x");
|
118
|
+
process.env.P_KEY137 = "0x" + process.env.P_KEY137;
|
119
|
+
}
|
120
|
+
if(!process.env.MNEMONIC80001 && !process.env.P_KEY80001) {
|
121
|
+
console.warn("neither MNEMONIC80001 nor P_KEY80001 is not set. Mumbai (matic/polygon L2 testnet) deployments won't be available");
|
122
|
+
process.env.MNEMONIC80001 = FAKE_MNEMONIC;
|
123
|
+
}
|
124
|
+
else if(process.env.P_KEY80001 && !process.env.P_KEY80001.startsWith("0x")) {
|
125
|
+
console.warn("P_KEY80001 doesn't start with 0x. Appended 0x");
|
126
|
+
process.env.P_KEY80001 = "0x" + process.env.P_KEY80001;
|
127
|
+
}
|
128
|
+
if(!process.env.MNEMONIC56 && !process.env.P_KEY56) {
|
129
|
+
console.warn("neither MNEMONIC56 nor P_KEY56 is not set. Binance Smart Chain (BSC) mainnet deployments won't be available");
|
130
|
+
process.env.MNEMONIC56 = FAKE_MNEMONIC;
|
131
|
+
}
|
132
|
+
else if(process.env.P_KEY56 && !process.env.P_KEY56.startsWith("0x")) {
|
133
|
+
console.warn("P_KEY56 doesn't start with 0x. Appended 0x");
|
134
|
+
process.env.P_KEY56 = "0x" + process.env.P_KEY56;
|
135
|
+
}
|
136
|
+
if(!process.env.MNEMONIC97 && !process.env.P_KEY97) {
|
137
|
+
console.warn("neither MNEMONIC97 nor P_KEY97 is not set. Binance Smart Chain (BSC) testnet deployments won't be available");
|
138
|
+
process.env.MNEMONIC97 = FAKE_MNEMONIC;
|
139
|
+
}
|
140
|
+
else if(process.env.P_KEY97 && !process.env.P_KEY97.startsWith("0x")) {
|
141
|
+
console.warn("P_KEY97 doesn't start with 0x. Appended 0x");
|
142
|
+
process.env.P_KEY97 = "0x" + process.env.P_KEY97;
|
143
|
+
}
|
144
|
+
if(!process.env.INFURA_KEY && !process.env.ALCHEMY_KEY) {
|
145
|
+
console.warn("neither INFURA_KEY nor ALCHEMY_KEY is not set. Deployments may not be available");
|
146
|
+
process.env.INFURA_KEY = "";
|
147
|
+
process.env.ALCHEMY_KEY = "";
|
148
|
+
}
|
149
|
+
if(!process.env.ETHERSCAN_KEY) {
|
150
|
+
console.warn("ETHERSCAN_KEY is not set. Deployed smart contract code verification won't be available");
|
151
|
+
process.env.ETHERSCAN_KEY = "";
|
152
|
+
}
|
153
|
+
if(!process.env.POLYSCAN_KEY) {
|
154
|
+
console.warn("POLYSCAN_KEY is not set. Deployed smart contract code verification won't be available on polyscan");
|
155
|
+
process.env.POLYSCAN_KEY = "";
|
156
|
+
}
|
157
|
+
if(!process.env.BSCSCAN_KEY) {
|
158
|
+
console.warn("BSCSCAN_KEY is not set. Deployed smart contract code verification won't be available on BscScan");
|
159
|
+
process.env.BSCSCAN_KEY = "";
|
160
|
+
}
|
161
|
+
|
162
|
+
/**
|
163
|
+
* @type import('hardhat/config').HardhatUserConfig
|
164
|
+
*/
|
165
|
+
module.exports = {
|
166
|
+
defaultNetwork: "hardhat",
|
167
|
+
networks: {
|
168
|
+
// https://hardhat.org/hardhat-network/
|
169
|
+
hardhat: {
|
170
|
+
// set networkId to 0xeeeb04de as for all local networks
|
171
|
+
chainId: 0xeeeb04de,
|
172
|
+
// set the gas price to one for convenient tx costs calculations in tests
|
173
|
+
// gasPrice: 1,
|
174
|
+
// London hard fork fix: impossible to set gas price lower than baseFeePerGas (875,000,000)
|
175
|
+
initialBaseFeePerGas: 0,
|
176
|
+
accounts: {
|
177
|
+
count: 35,
|
178
|
+
},
|
179
|
+
/*
|
180
|
+
forking: {
|
181
|
+
url: "https://mainnet.infura.io/v3/" + process.env.INFURA_KEY, // create a key: https://infura.io/
|
182
|
+
enabled: !!(process.env.HARDHAT_FORK),
|
183
|
+
},
|
184
|
+
*/
|
185
|
+
},
|
186
|
+
// https://etherscan.io/
|
187
|
+
mainnet: {
|
188
|
+
url: get_endpoint_url("mainnet"),
|
189
|
+
accounts: get_accounts(process.env.P_KEY1, process.env.MNEMONIC1),
|
190
|
+
},
|
191
|
+
// https://ropsten.etherscan.io/
|
192
|
+
ropsten: {
|
193
|
+
url: get_endpoint_url("ropsten"),
|
194
|
+
accounts: get_accounts(process.env.P_KEY3, process.env.MNEMONIC3),
|
195
|
+
},
|
196
|
+
// https://rinkeby.etherscan.io/
|
197
|
+
rinkeby: {
|
198
|
+
url: get_endpoint_url("rinkeby"),
|
199
|
+
accounts: get_accounts(process.env.P_KEY4, process.env.MNEMONIC4),
|
200
|
+
},
|
201
|
+
// https://kovan.etherscan.io/
|
202
|
+
kovan: {
|
203
|
+
url: get_endpoint_url("kovan"),
|
204
|
+
accounts: get_accounts(process.env.P_KEY42, process.env.MNEMONIC42),
|
205
|
+
},
|
206
|
+
// https://goerli.etherscan.io/
|
207
|
+
goerli: {
|
208
|
+
url: get_endpoint_url("goerli"),
|
209
|
+
accounts: get_accounts(process.env.P_KEY5, process.env.MNEMONIC5),
|
210
|
+
},
|
211
|
+
// matic/polygon L2 mainnet
|
212
|
+
// https://polygonscan.com/
|
213
|
+
polygon: {
|
214
|
+
url: "https://polygon-rpc.com/",
|
215
|
+
accounts: get_accounts(process.env.P_KEY137, process.env.MNEMONIC137),
|
216
|
+
},
|
217
|
+
// matic/polygon L1 testnet – Mumbai
|
218
|
+
// https://mumbai.polygonscan.com/
|
219
|
+
mumbai: {
|
220
|
+
url: "https://rpc-mumbai.maticvigil.com",
|
221
|
+
accounts: get_accounts(process.env.P_KEY80001, process.env.MNEMONIC80001),
|
222
|
+
},
|
223
|
+
// Binance Smart Chain (BSC) L2 mainnet
|
224
|
+
binance: {
|
225
|
+
url: "https://bsc-dataseed1.binance.org/",
|
226
|
+
accounts: get_accounts(process.env.P_KEY56, process.env.MNEMONIC56),
|
227
|
+
},
|
228
|
+
// Binance Smart Chain (BSC) L2 testnet
|
229
|
+
binance_testnet: {
|
230
|
+
url: "https://data-seed-prebsc-1-s3.binance.org:8545/",
|
231
|
+
accounts: get_accounts(process.env.P_KEY97, process.env.MNEMONIC97),
|
232
|
+
},
|
233
|
+
},
|
234
|
+
|
235
|
+
// Configure Solidity compiler
|
236
|
+
solidity: {
|
237
|
+
// https://hardhat.org/guides/compile-contracts.html
|
238
|
+
compilers: [
|
239
|
+
{
|
240
|
+
version: "0.8.21",
|
241
|
+
settings: {
|
242
|
+
optimizer: {
|
243
|
+
enabled: true,
|
244
|
+
runs: 200
|
245
|
+
}
|
246
|
+
}
|
247
|
+
},
|
248
|
+
{
|
249
|
+
version: "0.6.2",
|
250
|
+
settings: {
|
251
|
+
optimizer: {
|
252
|
+
enabled: true,
|
253
|
+
runs: 200
|
254
|
+
}
|
255
|
+
}
|
256
|
+
},
|
257
|
+
{
|
258
|
+
version: "0.4.22",
|
259
|
+
settings: {
|
260
|
+
optimizer: {
|
261
|
+
enabled: true,
|
262
|
+
runs: 200
|
263
|
+
}
|
264
|
+
}
|
265
|
+
},
|
266
|
+
{
|
267
|
+
version: "0.4.11",
|
268
|
+
settings: {
|
269
|
+
optimizer: {
|
270
|
+
enabled: true,
|
271
|
+
runs: 200
|
272
|
+
}
|
273
|
+
}
|
274
|
+
},
|
275
|
+
]
|
276
|
+
},
|
277
|
+
|
278
|
+
// Set default mocha options here, use special reporters etc.
|
279
|
+
mocha: {
|
280
|
+
// timeout: 100000,
|
281
|
+
|
282
|
+
// disable mocha timeouts:
|
283
|
+
// https://mochajs.org/api/mocha#enableTimeouts
|
284
|
+
enableTimeouts: false,
|
285
|
+
// https://github.com/mochajs/mocha/issues/3813
|
286
|
+
timeout: false,
|
287
|
+
},
|
288
|
+
|
289
|
+
// hardhat-gas-reporter will be disabled by default, use REPORT_GAS environment variable to enable it
|
290
|
+
// https://hardhat.org/plugins/hardhat-gas-reporter.html
|
291
|
+
gasReporter: {
|
292
|
+
enabled: !!(process.env.REPORT_GAS)
|
293
|
+
},
|
294
|
+
}
|
295
|
+
|
296
|
+
/**
|
297
|
+
* Determines a JSON-RPC endpoint to use to connect to the node
|
298
|
+
* based on the requested network name and environment variables set
|
299
|
+
*
|
300
|
+
* Tries to use custom RPC URL first (MAINNET_RPC_URL/ROPSTEN_RPC_URL/RINKEBY_RPC_URL/KOVAN_RPC_URL)
|
301
|
+
* Tries to use alchemy RPC URL next (if ALCHEMY_KEY is set)
|
302
|
+
* Fallbacks to infura RPC URL
|
303
|
+
*
|
304
|
+
* @param network_name one of mainnet/ropsten/rinkeby/kovan
|
305
|
+
* @return JSON-RPC endpoint URL
|
306
|
+
*/
|
307
|
+
function get_endpoint_url(network_name) {
|
308
|
+
// try custom RPC endpoint first (private node, quicknode, etc.)
|
309
|
+
// create a quicknode key: https://www.quicknode.com/
|
310
|
+
if(process.env.MAINNET_RPC_URL && network_name === "mainnet") {
|
311
|
+
return process.env.MAINNET_RPC_URL;
|
312
|
+
}
|
313
|
+
if(process.env.ROPSTEN_RPC_URL && network_name === "ropsten") {
|
314
|
+
return process.env.ROPSTEN_RPC_URL;
|
315
|
+
}
|
316
|
+
if(process.env.RINKEBY_RPC_URL && network_name === "rinkeby") {
|
317
|
+
return process.env.RINKEBY_RPC_URL;
|
318
|
+
}
|
319
|
+
if(process.env.KOVAN_RPC_URL && network_name === "kovan") {
|
320
|
+
return process.env.KOVAN_RPC_URL;
|
321
|
+
}
|
322
|
+
if(process.env.GOERLI_RPC_URL && network_name === "goerli") {
|
323
|
+
return process.env.GOERLI_RPC_URL;
|
324
|
+
}
|
325
|
+
|
326
|
+
// try the alchemy next
|
327
|
+
// create a key: https://www.alchemy.com/
|
328
|
+
if(process.env.ALCHEMY_KEY) {
|
329
|
+
switch(network_name) {
|
330
|
+
case "mainnet": return "https://eth-mainnet.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
|
331
|
+
case "ropsten": return "https://eth-ropsten.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
|
332
|
+
case "rinkeby": return "https://eth-rinkeby.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
|
333
|
+
case "kovan": return "https://eth-kovan.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
|
334
|
+
case "goerli": return "https://eth-goerli.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
|
335
|
+
}
|
336
|
+
}
|
337
|
+
|
338
|
+
// fallback to infura
|
339
|
+
// create a key: https://infura.io/
|
340
|
+
switch(network_name) {
|
341
|
+
case "mainnet": return "https://mainnet.infura.io/v3/" + process.env.INFURA_KEY;
|
342
|
+
case "ropsten": return "https://ropsten.infura.io/v3/" + process.env.INFURA_KEY;
|
343
|
+
case "rinkeby": return "https://rinkeby.infura.io/v3/" + process.env.INFURA_KEY;
|
344
|
+
case "kovan": return "https://kovan.infura.io/v3/" + process.env.INFURA_KEY;
|
345
|
+
case "goerli": return "https://goerli.infura.io/v3/" + process.env.INFURA_KEY;
|
346
|
+
}
|
347
|
+
}
|
348
|
+
|
349
|
+
/**
|
350
|
+
* Depending on which of the inputs are available (private key or mnemonic),
|
351
|
+
* constructs an account object for use in the hardhat config
|
352
|
+
*
|
353
|
+
* @param p_key account private key, export private key from mnemonic: https://metamask.io/
|
354
|
+
* @param mnemonic 12 words mnemonic, create 12 words: https://metamask.io/
|
355
|
+
* @return either [p_key] if p_key is defined, or {mnemonic} if mnemonic is defined
|
356
|
+
*/
|
357
|
+
function get_accounts(p_key, mnemonic) {
|
358
|
+
return p_key? [p_key]: mnemonic? {mnemonic, initialIndex: 0}: undefined;
|
359
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
{
|
2
|
+
"name": "@lazy-sol/access-control",
|
3
|
+
"version": "1.0.3",
|
4
|
+
"description": "Enable the modular plug and play (PnP) architecture for your dapp by incorporating the role-based access control (RBAC) into the smart contracts",
|
5
|
+
"main": "index.js",
|
6
|
+
"scripts": {
|
7
|
+
"clean": "hardhat clean",
|
8
|
+
"compile": "hardhat compile",
|
9
|
+
"test": "hardhat test",
|
10
|
+
"coverage": "hardhat coverage",
|
11
|
+
"deploy": "hardhat deploy"
|
12
|
+
},
|
13
|
+
"engines": {
|
14
|
+
"node": ">=16.0.0"
|
15
|
+
},
|
16
|
+
"keywords": [
|
17
|
+
"RBAC",
|
18
|
+
"Solidity",
|
19
|
+
"access control",
|
20
|
+
"modular architecture"
|
21
|
+
],
|
22
|
+
"author": "Basil Gorin",
|
23
|
+
"license": "MIT",
|
24
|
+
"dependencies": {
|
25
|
+
"@lazy-sol/a-missing-gem": "^1.0.0",
|
26
|
+
"@nomiclabs/hardhat-truffle5": "^2.0.7",
|
27
|
+
"hardhat": "^2.16.0",
|
28
|
+
"hardhat-deploy": "^0.11.45"
|
29
|
+
},
|
30
|
+
"devDependencies": {
|
31
|
+
"@lazy-sol/zeppelin-test-helpers": "^1.0.0",
|
32
|
+
"hardhat-gas-reporter": "^1.0.10",
|
33
|
+
"solidity-coverage": "^0.8.10"
|
34
|
+
},
|
35
|
+
"overrides": {
|
36
|
+
"tough-cookie": "^4.1.3",
|
37
|
+
"yargs-parser": "^5.0.1"
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
// AdapterFactory tests
|
2
|
+
|
3
|
+
// Zeppelin test helpers
|
4
|
+
const {
|
5
|
+
BN,
|
6
|
+
constants,
|
7
|
+
expectEvent,
|
8
|
+
expectRevert,
|
9
|
+
} = require("@openzeppelin/test-helpers");
|
10
|
+
const {
|
11
|
+
assert,
|
12
|
+
expect,
|
13
|
+
} = require("chai");
|
14
|
+
const {
|
15
|
+
ZERO_ADDRESS,
|
16
|
+
ZERO_BYTES32,
|
17
|
+
MAX_UINT256,
|
18
|
+
} = constants;
|
19
|
+
|
20
|
+
// deployment routines in use
|
21
|
+
const {
|
22
|
+
deploy_usdt,
|
23
|
+
deploy_adapter_factory,
|
24
|
+
factory_deploy_ownable_to_ac_adapter,
|
25
|
+
} = require("./include/deployment_routines");
|
26
|
+
|
27
|
+
// run AdapterFactory tests
|
28
|
+
contract("AdapterFactory tests", function(accounts) {
|
29
|
+
// extract accounts to be used:
|
30
|
+
// A0 – special default zero account accounts[0] used by Truffle, reserved
|
31
|
+
// a0 – deployment account having all the permissions, reserved
|
32
|
+
// H0 – initial token holder account
|
33
|
+
// a1, a2,... – working accounts to perform tests on
|
34
|
+
const [A0, a0, H0, a1, a2, a3] = accounts;
|
35
|
+
|
36
|
+
let usdt, factory;
|
37
|
+
beforeEach(async function() {
|
38
|
+
usdt = await deploy_usdt(a1);
|
39
|
+
factory = await deploy_adapter_factory();
|
40
|
+
});
|
41
|
+
|
42
|
+
it("adapter deployment fails if executed not by the ownable owner", async function() {
|
43
|
+
await expectRevert(factory_deploy_ownable_to_ac_adapter(a2, factory, usdt), "not an owner");
|
44
|
+
});
|
45
|
+
describe("adapter deployment succeeds if executed by the ownable owner", async function() {
|
46
|
+
let adapter;
|
47
|
+
beforeEach(async function() {
|
48
|
+
({adapter} = await factory_deploy_ownable_to_ac_adapter(a1, factory, usdt));
|
49
|
+
});
|
50
|
+
it("adapter's target is set correctly", async function() {
|
51
|
+
expect(await adapter.target()).to.be.equal(usdt.address);
|
52
|
+
});
|
53
|
+
});
|
54
|
+
});
|