Skip to content

Commit aed4003

Browse files
authored
Merge pull request #3 from violetprotocol/dev
1.0.0
2 parents 380e58a + 4e4cabd commit aed4003

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+12578
-0
lines changed

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
REPORT_GAS=
2+
PRIVATE_KEY=
3+
RINKEBY_NODE_URL=
4+
KOVAN_NODE_URL=
5+
TENDERLY_USERNAME=
6+
TENDERLY_PROJECT_NAME=

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
node_modules
2+
.DS_Store
3+
.env
4+
5+
#Hardhat files
6+
cache
7+
artifacts
8+
9+
#Release build
10+
contracts/build
11+
contracts/README.md
12+
build
13+
14+
coverage*

.prettierignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# directories
2+
.yarn/
3+
**/.coverage_artifacts
4+
**/.coverage_cache
5+
**/.coverage_contracts
6+
**/artifacts
7+
**/build
8+
**/cache
9+
**/coverage
10+
**/dist
11+
**/node_modules
12+
**/types
13+
14+
# files
15+
*.env
16+
*.log
17+
.pnp.*
18+
coverage.json
19+
npm-debug.log*
20+
yarn-debug.log*
21+
yarn-error.log*

.solhint.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "solhint:recommended",
3+
"plugins": ["prettier"],
4+
"rules": {
5+
"compiler-version": ["error", "^0.8.0"],
6+
"no-inline-assembly": "off",
7+
"avoid-low-level-calls": "off",
8+
"no-empty-blocks": "off"
9+
}
10+
}

.solhintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# directories
2+
**/artifacts
3+
**/node_modules

README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,103 @@
1+
# Extendable Contract Pattern
12

3+
Upgradeable, modular, extensible smart contracts using Extendable<>Extension architecture.
4+
5+
Add and remove selectively modular parts of functional logic known as Extensions, accessing modular storage definitions.
6+
7+
```solidity
8+
contract YourContract is Extendable {
9+
...
10+
}
11+
```
12+
13+
```
14+
> deploy(YourContract)
15+
> YourContract.extend(extension);
16+
```
17+
18+
## Architecture
19+
20+
Contracts are given their functionality by _extending_ them with new functions. The first function that is added is the _Extend_ function which provides the contract the ability to be extended.
21+
22+
### Extendable
23+
24+
All contracts must inherit the _Extendable_ contract.
25+
26+
_Extendable_ contracts have a unique interaction with the _ExtendLogic_ contract where Extensions are added. _Extendable_ contracts access the state written by the _ExtendLogic_ extension in order to perform delegate calls to each extension. All calls are done from the context of the _Extendable_ contract which is handled by `delegatecall`.
27+
28+
_Extendable_ contracts have an evolving interface which is accessible through the `getCurrentInterface` function supplied by the _ExtendLogic_ extension. This allows developers to easily determine the current interface of an evolving _Extendable_ contract directly on-chain without having to query separate processes that may not be in sync (GitHub, Documentation, Twitter etc.).
29+
30+
### Extensions
31+
32+
_Extension_ logic contracts implement functional logic that is called by the _Extendable_ contract. Following extension principles of modularity and updateability, it is recommended to separate logic contracts into the most divisible units possible: single function contracts. Where logic contracts encompass more than a single function for dependency or cohesive reasons, it can envelope more functions but with the trade-off of being less modular; any upgrades to a single function require the entire logic extension to be updated and re-registered.
33+
34+
_Extension_ logic contracts can mutate state by accessing the storage of the delegator through custom storage slot access. Various different _Extension_ logic contracts can access the same state but extensions should be written and extended mindfully to avoid incorrect state mutability.
35+
36+
```solidity
37+
import "@violetprotocol/extendable/extensions/Extension.sol";
38+
39+
contract YourExtension is IYourExtension, Extension {
40+
...
41+
}
42+
```
43+
44+
```
45+
> deploy(YourExtension)
46+
0x7F5b1b0a4929BF2bD9502CBF714c166931FC85dD
47+
> YourContract.extend(0x7F5b1b0a4929BF2bD9502CBF714c166931FC85dD)
48+
```
49+
50+
### Storage
51+
52+
_Storage_ contracts define state variables that intend to be stored and used by an _Extendable_ contract and accessed by _Extension_ logic contracts. It uses a storage slot locator model where storage is allocated and accessed by address and different structures/types are located in different places to avoid collision.
53+
54+
_Storage_ contracts are libraries that are imported by the contract that requires access to storage state. These contracts can include reusable functions that might be useful related to computation over state (such as modifiers or _get_ functions).
55+
56+
```solidity
57+
struct YourState {
58+
// State variables are declared here
59+
}
60+
61+
library YourStorage {
62+
bytes32 constant private STORAGE_NAME = keccak256("your_unique_storage_identifier");
63+
64+
function _getStorage()
65+
internal
66+
view
67+
returns (YourState storage state)
68+
{
69+
bytes32 position = keccak256(abi.encodePacked(address(this), STORAGE_NAME));
70+
assembly {
71+
state.slot := position
72+
}
73+
}
74+
}
75+
```
76+
77+
```solidity
78+
import "@violetprotocol/extendable/extensions/Extension.sol";
79+
import "./YourStorage.sol";
80+
81+
contract YourExtension is IYourExtension, Extension {
82+
function readStorage() public view {
83+
YourState storage state = YourStorage._getStorage();
84+
85+
// access properties of state with `state.yourVar`
86+
// re-assign state properties with `state.yourVar = <value>`
87+
}
88+
}
89+
```
90+
91+
## Requirements
92+
93+
`nodejs >=12.0`
94+
95+
## Build
96+
97+
`yarn install` to install all dependencies.
98+
99+
`yarn hardhat compile` to build all contract artifacts.
100+
101+
## Test
102+
103+
`yarn hardhat test` to run tests.

RELEASING.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Releasing
2+
3+
To cut a new release, first create a pull request from `dev` into `main` with the [semver](https://semver.org/) naming convention. For example `1.0.0-rc1`. This will enter wider team review and further testing where necessary to ensure bug-free code and presentableness to public.
4+
5+
## Testing
6+
7+
Run tests and coverage:
8+
```bash
9+
$ yarn test
10+
$ yarn coverage
11+
```
12+
13+
Manual testing using hardhat tasks and public testnets are encouraged.
14+
15+
Mock development by using the library is also encouraged (or the use of bug bounties).
16+
17+
## Preparing for NPM
18+
19+
Enter the contracts directory:
20+
21+
```bash
22+
$ cd contracts
23+
```
24+
25+
Test the npm package with:
26+
```bash
27+
$ yarn pack
28+
```
29+
Ensure the resulting tarball includes all files that you expect the package to have.
30+
31+
Then create a new folder with a test project and install your package:
32+
```bash
33+
$ mkdir test-project
34+
$ cd test-project
35+
$ npm init
36+
$ npm install <path/to/contractsdir>
37+
```
38+
The package should now be installed in your project's `node_modules` and the contracts should be accessible through imports `import "@violetprotocol/extendable/extendable/Extendable.sol";`
39+
40+
## Merge and Release
41+
42+
Once checks and reviews pass, the release can be merged to `main` and then tagged with the normal release number without the release candidate tagging e.g. `1.0.0`.
43+
44+
Then perform the publishing step to npm:
45+
46+
```bash
47+
$ cd contracts
48+
$ yarn prepare
49+
$ npm login --scope=@violetprotocol
50+
$ npm publish --access public --tag <version>
51+
```
52+
53+
Ensure that the tag includes a changelog that documents the feature changes/additions/fixes that were included in the version that diff from the previous release.

contracts/errors/Errors.sol

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
/**
5+
* @dev ExtensionNotImplemented error is emitted by Extendable and Extensions
6+
* where no implementation for a specified function signature exists
7+
* in the contract
8+
*/
9+
error ExtensionNotImplemented();
10+
11+
12+
/**
13+
* @dev Utility library for contracts to catch custom errors
14+
* Pass in a return `result` from a call, and the selector for your error message
15+
* and the `catchCustomError` function will return `true` if the error was found
16+
* or `false` otherwise
17+
*/
18+
library Errors {
19+
function catchCustomError(bytes memory result, bytes4 errorSelector) internal pure returns(bool) {
20+
bytes4 caught;
21+
assembly {
22+
caught := mload(add(result, 0x20))
23+
}
24+
25+
return caught == errorSelector;
26+
}
27+
}

0 commit comments

Comments
 (0)