Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#DEV-22 build: core contracts (deploy, init, and configuration) #4

Open
wants to merge 71 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
aa633b3
build: update solc version
ryanycw Jul 4, 2023
5b627dd
chore: pause husky hook
ryanycw Jul 4, 2023
cb076cc
forge install: openzeppelin-contracts-upgradeable
ryanycw Jul 4, 2023
eb7089c
forge install: v3-core
ryanycw Jul 4, 2023
e823809
forge install: v3-periphery
ryanycw Jul 4, 2023
0ff317e
chore: adjust remappings
ryanycw Jul 5, 2023
b434de3
refactor: adjust import
ryanycw Jul 5, 2023
e45faa3
refactor: remove unuse file
ryanycw Jul 5, 2023
50197a6
refactor: enable optimizer
ryanycw Jul 5, 2023
1a175bb
refactor: adjust max uint init to newer solc method
ryanycw Jul 5, 2023
e38dc0b
refactor: reinstall husky
ryanycw Jul 5, 2023
35e16e9
refactor: add license
ryanycw Jul 5, 2023
364bca6
refactor: remove unuse parameters or variables
ryanycw Jul 5, 2023
006b110
refactor: adjust function visibility
ryanycw Jul 5, 2023
3d68f79
refactor: remove unuse parameter
ryanycw Jul 5, 2023
639b624
refactor: adjust variables name to avoid shadow declaration
ryanycw Jul 5, 2023
6fca6fd
chore: adjust layer
ryanycw Jul 18, 2023
ee1acff
Merge branch 'forked-contracts' into build/core-contracts
ryanycw Jul 18, 2023
5cf16c3
build: import external protocols interfaces
ryanycw Jul 22, 2023
7216c6e
build: create configuration module
ryanycw Jul 22, 2023
772ab5c
build: init position interaction related modules
ryanycw Jul 22, 2023
29c133c
build: implement governance and upgrade related module
ryanycw Jul 22, 2023
5529d70
build: init info module
ryanycw Jul 22, 2023
19206d4
build: create unified contract for all the storage of the system
ryanycw Jul 22, 2023
cda2141
build: all in one contract of modifiers
ryanycw Jul 22, 2023
30490ab
build: create the core diamond contract
ryanycw Jul 22, 2023
973ee92
build: interface of modules
ryanycw Jul 22, 2023
3400b68
build: libraries of core contracts
ryanycw Jul 22, 2023
f3ee674
build: the function selector router that handles all the modules and …
ryanycw Jul 22, 2023
871add9
chore: adjust .gitignore
ryanycw Jul 23, 2023
fb61ac0
chore: create guidelines of imports
ryanycw Jul 23, 2023
3873b0e
chore: create docs on references
ryanycw Jul 23, 2023
c59ebfb
build: change file name
ryanycw Jul 23, 2023
137da2e
build: change file name
ryanycw Jul 23, 2023
15b5023
refactor: adjust import style
ryanycw Jul 23, 2023
3148bd2
build: add events
ryanycw Jul 23, 2023
8d9b400
build: create internal libraries for NonFungibleManager
ryanycw Jul 23, 2023
dcd82d2
build: create governance module for upgrade
ryanycw Jul 23, 2023
5cae1ae
build: init zap module for the zap features
ryanycw Jul 23, 2023
5331753
build: create configure module to set parameters
ryanycw Jul 23, 2023
2c54f08
build: create initVault to init the diamond after deploying
ryanycw Jul 23, 2023
731071e
test: init test files
ryanycw Jul 23, 2023
8f5bcab
chore: lint check
ryanycw Jul 24, 2023
da19e23
docs: add new info
ryanycw Jul 27, 2023
8c7b964
build: init submodules
ryanycw Jul 27, 2023
f274933
build: add new interfaces
ryanycw Jul 27, 2023
9bbb4ef
build: add interfaces
ryanycw Jul 27, 2023
f089539
build: init vault module
ryanycw Jul 27, 2023
016665c
refactor: adjust struct type
ryanycw Jul 27, 2023
5632d36
refactor: change file name
ryanycw Jul 27, 2023
9f66b4c
build: init submodules
ryanycw Jul 27, 2023
9cb7095
refactor: move init to initVault.sol
ryanycw Jul 27, 2023
c33b54b
build: create function info submodule
ryanycw Jul 27, 2023
f257115
fix: adjust contract name
ryanycw Jul 27, 2023
bb167e8
refactor: add interface to the submodule
ryanycw Jul 27, 2023
2546410
build: create upgrade submodule
ryanycw Jul 27, 2023
602faa3
refactor: adjust file layer
ryanycw Jul 27, 2023
e598880
build: test setup
ryanycw Jul 27, 2023
8c60c6e
test: deploy test
ryanycw Jul 27, 2023
d8fc001
chore: set rpc
ryanycw Jul 31, 2023
d051a70
build: init vault module
ryanycw Jul 31, 2023
6460622
build: add init set
ryanycw Jul 31, 2023
470ecc2
build: add error
ryanycw Jul 31, 2023
994a529
refactor: move the error to LibError
ryanycw Jul 31, 2023
388bcb9
test: deploy and init test
ryanycw Jul 31, 2023
dff6408
refactor: move init test to deploy
ryanycw Jul 31, 2023
fbc22cc
refactor: adjust parameters
ryanycw Jul 31, 2023
1d9444f
chore: add docs
ryanycw Aug 4, 2023
04b7f53
refactor: remove unused module
ryanycw Aug 4, 2023
fd22b37
test: add mocks to test diamond standard
ryanycw Aug 4, 2023
bd5d467
test: change test
ryanycw Aug 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ out/
/broadcast/*/31337/
/broadcast/**/dry-run/

# Docs
docs/

# Dotenv file
.env

Expand Down
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,12 @@
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/openZeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/v3-core"]
path = lib/v3-core
url = https://github.com/Uniswap/v3-core
[submodule "lib/v3-periphery"]
path = lib/v3-periphery
url = https://github.com/Uniswap/v3-periphery
19 changes: 19 additions & 0 deletions docs/code_standards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Code Standards

## Import Order

- Packages
- Interfaces
- Libraries
- Submodules
- Helpers

## Library Order

- LibFunctionRouter
- LibHelpers
- LibBytes
- LibDataTypes
- LibErrors
- LibEvents
- LibConstants
8 changes: 8 additions & 0 deletions docs/references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# References

## Table of Contents

- [PancakeSwap MasterChefV3](https://etherscan.io/address/0x556b9306565093c855aea9ae92a594704c2cd59e)
- [PancakeSwap NonfungiblePositionManager](https://etherscan.io/address/0x46a15b0b27311cedf172ab29e4f4766fbe7f4364)
- [Intro. of diamond standard in Ethereum Forum](https://forum.openzeppelin.com/t/introduction-to-the-diamond-standard-eip-2535-diamonds/12505)
- [Testing Position](https://etherscan.io/tx/0x77a9e9f12f3cbf31d64de0f0fb5c75e410d96819a4f992c2fbe0039ea7c8404a)
5 changes: 4 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[profile.default]
solc_version = '0.8.17'
optimizer = false
optimizer = true
fs_permissions = [{ access = "read-write", path = "./"}]

[profile.optimized]
Expand All @@ -13,4 +13,7 @@ line_length=130
tab_width=4
func_attrs_with_params_multiline=true

[rpc_endpoints]
mainnet = "https://eth-mainnet.g.alchemy.com/v2/${ALCHEMEY_KEY}"

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts-upgradeable
1 change: 1 addition & 0 deletions lib/v3-core
Submodule v3-core added at 6562c5
1 change: 1 addition & 0 deletions lib/v3-periphery
Submodule v3-periphery added at b325bb
8 changes: 5 additions & 3 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
ds-test/=lib/forge-std/lib/ds-test/src/
erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/
erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/
forge-std/=lib/forge-std/src/
openzeppelin-contracts/=lib/openzeppelin-contracts/
openzeppelin/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@uniswap/v3-core/=lib/v3-core/
@uniswap/v3-periphery/=lib/v3-periphery/
47 changes: 47 additions & 0 deletions src/core/InitVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// External Packages
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

// Libraries
import {AppStorage, LibAppStorage} from "../libraries/LibAppStorage.sol";
import {LibPostionManager} from "../libraries/LibPostionManager.sol";

contract InitVault is Initializable, ERC20Upgradeable {
function initialize(address _nftPositionManager, address _masterchef, uint256 _tokenId, string calldata _vaultName)
public
initializer
{
AppStorage storage s = LibAppStorage.systemStorage();
s.systemInitialized = true;
s.tokenId = _tokenId;
s.nonFungibleTokenPositionManager = _nftPositionManager;
s.masterChef = _masterchef;

// stake position
LibPostionManager.stake();

// fetch info from position manager
(address _token0, address _token1, uint24 _fee, int24 _tickLower, int24 _tickUpper, uint256 _initialLiquidity) =
LibPostionManager.positionInfo(_tokenId);

// initialize the state variables
s.token0 = _token0;
s.token1 = _token1;
s.fee = _fee;
s.tickLower = _tickLower;
s.tickUpper = _tickUpper;
s.initialLiquidity = _initialLiquidity;

// initializing the vault token. By default, it has 18 decimals.
__ERC20_init_unchained(
string(abi.encodePacked(_vaultName, ERC20Upgradeable(_token0).symbol(), "_", ERC20Upgradeable(_token1).symbol())),
string(abi.encodePacked(_vaultName, ERC20Upgradeable(_token0).symbol(), "_", ERC20Upgradeable(_token1).symbol()))
);

// mint the initial shares and send them to the specified recipient, as well as overflow of the tokens
_mint(msg.sender, uint256(_initialLiquidity));
}
}
62 changes: 62 additions & 0 deletions src/core/Modifiers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/// @notice modifiers

// Packages
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";

// Libraries
import {AppStorage, LibAppStorage} from "../libraries/LibAppStorage.sol";
import {LibHelpers} from "../libraries/LibHelpers.sol";
import {LibErrors} from "../libraries/LibErrors.sol";
import {LibConstants} from "../libraries/LibConstants.sol";

/**
* @title Modifiers
* @notice Function modifiers to control access
* @dev Function modifiers to control access
*/

contract Modifiers {
modifier initialized() {
if (!LibAppStorage.systemStorage().systemInitialized) {
revert LibErrors.Initialized();
}
_;
}

modifier onlyGovernance() {
if (LibAppStorage.systemStorage().governance != msg.sender) {
revert LibErrors.NotGovernance();
}
_;
}

modifier onlyGovernanceOrController() {
if (LibAppStorage.systemStorage().governance != msg.sender || LibAppStorage.systemStorage().controller != msg.sender) {
revert LibErrors.NotGovernanceOrController();
}
_;
}

modifier checkSqrtPriceX96(uint256 offChainSqrtPriceX96, uint256 tolerance) {
address poolAddr = IUniswapV3Factory(LibConstants._UNI_POOL_FACTORY).getPool(
LibAppStorage.systemStorage().token0, LibAppStorage.systemStorage().token1, LibAppStorage.systemStorage().fee
);
(uint160 sqrtPriceX96,,,,,,) = IUniswapV3Pool(poolAddr).slot0();
uint256 current = uint256(sqrtPriceX96);
uint256 step = offChainSqrtPriceX96 * tolerance / 1000;
require(current < offChainSqrtPriceX96 + step, "Price too high");
require(current > offChainSqrtPriceX96 - step, "Price too low");
_;
}

modifier checkVaultNotPaused() {
if (LibAppStorage.systemStorage().vaultPause) {
revert LibErrors.Paused();
}
_;
}
}
54 changes: 54 additions & 0 deletions src/core/NonFungiblePositionVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {LibFunctionRouter} from "../libraries/LibFunctionRouter.sol";

// Submodules
import {ConfigureSubmodule} from "../submodules/ConfigureSubmodule.sol";
import {UpgradeSubmodule} from "../submodules/UpgradeSubmodule.sol";
import {GovernanceSubmodule} from "../submodules/GovernanceSubmodule.sol";
import {FunctionInfoSubmodule} from "../submodules/FunctionInfoSubmodule.sol";

contract NonFungiblePositionVault {
constructor(address _contractOwner, address _governance, address _controller) payable {
LibFunctionRouter.setContractOwner(_contractOwner);
LibFunctionRouter.setGovernance(_governance);
LibFunctionRouter.setController(_controller);
LibFunctionRouter.setUpgradeExpiration();
LibFunctionRouter.addSubmoduleFunctions(
address(new UpgradeSubmodule()),
address(new FunctionInfoSubmodule()),
address(new ConfigureSubmodule()),
address(new GovernanceSubmodule())
);
}

// Find submodule for function that is called and execute the
// function if a submodule is found and return any value.
// solhint-disable no-complex-fallback
fallback() external payable {
LibFunctionRouter.FunctionRouterStorage storage frs = LibFunctionRouter.functionRouterStorage();

// get submodule from function selector
address submodule = address(bytes20(frs.submodules[msg.sig]));
// require(submodule != address(0), "FunctionRouter: Function does not exist"); - don't need to do this since we check for code below
LibFunctionRouter.enforceHasContractCode(submodule, "FunctionRouter: Submodule has no code");
// Execute external function from submodule using delegatecall and return any value.
assembly {
// copy function selector and any arguments
calldatacopy(0, 0, calldatasize())
// execute function call using the submodule
let result := delegatecall(gas(), submodule, 0, calldatasize(), 0, 0)
// get any return value
returndatacopy(0, 0, returndatasize())
// return any return value or error back to the caller
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}

// solhint-disable no-empty-blocks
receive() external payable {}
}
17 changes: 17 additions & 0 deletions src/interfaces/core/INonFungiblePositionVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Submodules
import {IConfigureSubmodule} from "../submodules/IConfigureSubmodule.sol";
import {IUpgradeSubmodule} from "../submodules/IUpgradeSubmodule.sol";
import {IGovernanceSubmodule} from "../submodules/IGovernanceSubmodule.sol";
import {IFunctionInfoSubmodule} from "../submodules/IFunctionInfoSubmodule.sol";
import {IInvestSubmodule} from "../submodules/IInvestSubmodule.sol";

interface INonFungiblePositionVault is
IConfigureSubmodule,
IUpgradeSubmodule,
IGovernanceSubmodule,
IFunctionInfoSubmodule,
IInvestSubmodule
{}
18 changes: 18 additions & 0 deletions src/interfaces/protocols/pancake/IERC20Metadata.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title IERC20Metadata
/// @title Interface for ERC20 Metadata
/// @notice Extension to IERC20 that includes token metadata
interface IERC20Metadata is IERC20 {
/// @return The name of the token
function name() external view returns (string memory);

/// @return The symbol of the token
function symbol() external view returns (string memory);

/// @return The number of decimal places the token has
function decimals() external view returns (uint8);
}
25 changes: 25 additions & 0 deletions src/interfaces/protocols/pancake/IERC721Permit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/// @title ERC721 with permit
/// @notice Extension to ERC721 that includes a permit function for signature based approvals
interface IERC721Permit is IERC721 {
/// @notice The permit typehash used in the permit signature
/// @return The typehash for the permit
function PERMIT_TYPEHASH() external pure returns (bytes32);

/// @notice The domain separator used in the permit signature
/// @return The domain seperator used in encoding of permit signature
function DOMAIN_SEPARATOR() external view returns (bytes32);

/// @notice Approve of a specific token ID for spending by spender via signature
/// @param spender The account that is being approved
/// @param tokenId The ID of the token that is being approved for spending
/// @param deadline The deadline timestamp by which the call must be mined for the approve to work
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`
function permit(address spender, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable;
}
13 changes: 13 additions & 0 deletions src/interfaces/protocols/pancake/IMulticall.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

/// @title Multicall interface
/// @notice Enables calling multiple methods in a single call to the contract
interface IMulticall {
/// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
/// @dev The `msg.value` should not be trusted for any method callable from multicall.
/// @param data The encoded function data for each of the calls to make to this contract
/// @return results The results from each of the calls passed in via data
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}
Loading