-
Notifications
You must be signed in to change notification settings - Fork 6
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
Feat/airlock (WIP) #53
Merged
Merged
Changes from 46 commits
Commits
Show all changes
141 commits
Select commit
Hold shift + click to select a range
8131f40
forge install: solady
clemlak ada4347
build: add Solady remapping
clemlak 3aabf45
feat: add DERC20
clemlak 02e2193
feat: add TokenFactory
clemlak 5ec5d1f
feat: change token name to DERC20
clemlak 52eca8b
feat: add Airlock contract
clemlak 6288a83
feat: add setFactoryState
clemlak 632a5c8
feat: add stageLiquidity function to Airlock
clemlak 0286c57
feat: add TokenState enum
clemlak 32789c5
feat: add a mapping to track the hook of each deployed token
clemlak 9f6c08d
chore: add comment about stageLiquidity
clemlak 842bac0
feat: call PoolManager in stageLiquidity
clemlak f71f2c0
chore: add TODOs
clemlak b2171ed
feat: update create, add Token struct
clemlak 41b6bdb
feat: rename liquidityFactory to hook, tokenAddress to token
clemlak 11e413f
chore: add initialization sequence diagram to README
clemlak a21169b
feat: add wip migrate function
clemlak 9f7f061
feat: add IMigrator
clemlak 470bef0
feat: add UniswapV2Migrator
clemlak 17e887e
build: add Open Zeppelin remapping
clemlak 561765d
feat: use Open Zeppelin ERC20 instead of Solady
clemlak 5cd302b
build: remove Solady
clemlak 9d8b90b
feat: use Open Zeppelin Ownable contract
clemlak 21f3826
feat: inherit from ERC20Votes
clemlak 9e14a6b
feat: add fee on transfer
clemlak ca00fab
feat: add minting start date, inherit Ownable
clemlak 199f8c8
chore: update DERC20 TODO list
clemlak e137c82
feat: add ERC20Permit
clemlak 7bf27ee
feat: override clock and clock mode in DERC20
clemlak 24e85fc
feat: add basic Governor contract
clemlak 233e8de
chore: rename to Governance, remove unused imports
clemlak 0429375
feat: update TokenFactory
clemlak 85fea52
feat: add GovernanceFactory
clemlak 11308ef
feat: add IHookFactory
clemlak 11855d3
feat: add DopplerFactory
clemlak ea1e4ab
feat: add IGovernanceFactory
clemlak ec1af55
feat: inherit from IGovernanceFactory
clemlak 3d69808
feat: add ITokenFactory
clemlak 7e989ca
feat: add default parameters to ITokenFactory
clemlak f479a3a
feat: inherit ITokenFactory
clemlak c3bbf30
feat: add token default parameter
clemlak 6d34d56
feat: change create parameters, use new factory patterns
clemlak 74992ea
feat: add name parameter
clemlak aa87065
feat: add name parameter to IGovernanceFactory
clemlak c1d1672
feat: pass name parameter to Governance
clemlak c1ca9ae
feat: store recipients and amounts, pass name to Governance factory
clemlak 9819956
feat: add HookMiner library
clemlak 1185d47
feat: use HookMiner to get Hook address, deploy using create2
clemlak d166531
feat: add predict to IHookFactory
clemlak fcdd062
feat: add predict to DopplerFactory
clemlak 0a4fc0c
feat: use HookFactory predict to deploy the hook at the correct address
clemlak 3a507ae
test: add AirlockTest
clemlak a5c404b
feat: set minimum sqrt price
clemlak ca3df6f
test: add test_Airlock_create
clemlak 16a1ef2
feat: change default HookFactory parameters
clemlak 4ffeaaf
feat: update DopplerFactory with new parameters
clemlak 57d4e41
feat: change create parameters, add non-ETH support, fix pool init
clemlak 04ab1b9
test: fix create test
clemlak bce7f4c
feat: append Governance to Governance contract name
clemlak b8bec22
feat: grant roles in GovernanceFactory
clemlak c45fa02
feat: transfer ownership of the token to governance
clemlak a590f60
test: add balance checks
clemlak 1484adb
chore: add TODO tests
clemlak e39a918
Merge branch 'main' into feat/airlock
clemlak 880aac8
build: remove remappings from foundry.toml (already present in remapp…
clemlak bae1935
chore: fix imports
clemlak bbbe325
feat: rename totalSupply to initialSupply
clemlak 4043a99
chore: clean up Open Zeppelin remappings and fix imports
clemlak cfbb426
feat: remove poolKey from constructor, move tick spacing checks to be…
clemlak eedbb0a
chore: rename totalSupply to initialSupply
clemlak 9c0830f
feat: add missing Doppler constructor params
clemlak b14a2e5
feat: remove FoT
clemlak 859101f
test: remove poolKey constructor parameter
clemlak 3231b1a
feat: return address instead of TimelockController type
clemlak ff2ea28
chore: rename TokenData type and getTokenData mapping
clemlak f550358
feat: update Governance and ERC20 voting token following OZ examples
clemlak 2a08414
feat: add new params to migrate in IMigrator
clemlak 95daaaf
feat: add IHook interface with migrate function
clemlak 1523381
feat: add migrate to UniswapV2Migrator
clemlak 8654a00
feat: update create function in GovernanceFactory
clemlak 3426fad
feat: add migrate function in Doppler
clemlak 8ae52f6
feat: implement migrate function, add Migrate event, add new params t…
clemlak 7f85209
chore: add NatSpec to ITokenFactory
clemlak 0924ea9
feat: change FactoryState to ModuleState, update event and related fu…
clemlak cfa5676
feat: add team allocation distribution
clemlak 8162f9b
feat: add liquidity returned parameter to migrate function
clemlak 691656c
feat: add ETH case in migrate, transfer LP tokens to recipient
clemlak 77e0cc8
feat: pass timelock address as LP tokens recipient
clemlak 9b247f4
chore: add dust tokens case TODO comment
clemlak caa5836
test: add Airlock test file
clemlak 3869fde
test: delete previous Airlock test file
clemlak 7010d5f
test: update Airlock test setup
clemlak a139ed6
test: add test_setModuleState_EmitsEvent
clemlak 41ddda5
test: add test_setModuleState_RevertsWhenSenderNotOwner
clemlak 8c0f28e
feat: use module types instead of address
clemlak c3a1b81
test: add constants
clemlak f8cafe7
feat: flip beforeInitialize bool
clemlak b21b395
feat: add isInitialized boolean
clemlak b1c0a36
chore: fix typo in initialSupply
clemlak f56da8e
test: add AirlockMiner
clemlak 7057a57
feat: delete HookMiner
clemlak 4121091
feat: add salt param to ITokenFactory create function
clemlak 540f65a
feat: delete predict in IHookFactory, clean up create params
clemlak 0125203
feat: add salt to TokenFactory create function
clemlak 959e623
feat: remove predict function from DopplerFactory, clean up create fu…
clemlak 47f78d2
feat: remove parameters from create function in IHookFactory
clemlak 6098e67
feat: clean up create function parameters in DopplerFactory
clemlak f200990
feat: rename migrate function parameters in IMigrator
clemlak 6e11efd
feat: refactor migrate function in UniswapV2Migrator
clemlak e0977d2
feat: refactor TokenData, create function and migrate function in Air…
clemlak d653deb
chore: delete unused IHooks import in Airlock contract
clemlak 57d751d
test: turn mine into free function, add computeCreate2Address function
clemlak 4b5a453
feat: rename migrate function returned parameters
clemlak e0ef9ca
feat: add missing numPDSlugs param, add deployer param
clemlak 1eef929
test: update Airlock create test and base test file
clemlak b34b6a9
test: remove recipient and owner from MineParams, fix token init hash…
clemlak b7e4fd4
test: fix test_create_Deploys test
clemlak dde5675
test: use initialSupply for token init hash
clemlak f5e3744
feat: check initialSupply and numTokensToSell in Airlock
clemlak 96feb40
test: add internal _create function in Airlock tests
clemlak b59592b
test: add test_create_RevertsIfWrongTokenFactory
clemlak 0af001c
test: add test_create_RevertsIfWrongGovernanceFactory
clemlak f627fd8
test: add test_create_RevertsIfWrongHookFactory
clemlak fe9b520
test: add test_create_RevertsIfWrongMigrator
clemlak 96526b2
test: add test_create_RevertsIfWrongInitialSupply
clemlak 7e0d115
feat: add ArrayLengthsMismatch error and related check
clemlak df39733
test: add _getDefaultMineParams, refactor _create, add test_create_Mi…
clemlak d605fb3
chore: add Airlock README
clemlak fa55916
feat: implement migrate function
clemlak ef6f2f7
test: update CallbackData test
clemlak 8ac5c2f
feat: fix ETH pair creation in UniswapV2Migrator
clemlak 8e47c10
feat: remove ERC20 transfer when token0 is ETH
clemlak 633eb7e
test: add migrate test
clemlak 05ee04f
Merge branch 'main' into feat/airlock
clemlak 33df61a
fix: add back some missing code after resolving conflicts
clemlak 3c82ea0
test: skip broken tests
clemlak a3641d6
test: skip maxProceeds test
clemlak 8864fe7
test: fix test_create_MintsTokens
clemlak e8e9b9e
feat: add Create event
clemlak c8e2d99
feat: add airlock immutable variable, fix migrate function condition
clemlak 6a13852
fix: remove duplicate transfer
clemlak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,27 @@ | ||
## Foundry | ||
|
||
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** | ||
|
||
Foundry consists of: | ||
|
||
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). | ||
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. | ||
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. | ||
- **Chisel**: Fast, utilitarian, and verbose solidity REPL. | ||
|
||
## Documentation | ||
|
||
https://book.getfoundry.sh/ | ||
|
||
## Usage | ||
|
||
### Build | ||
|
||
```shell | ||
$ forge build | ||
``` | ||
|
||
### Test | ||
|
||
```shell | ||
$ forge test | ||
``` | ||
|
||
### Format | ||
|
||
```shell | ||
$ forge fmt | ||
``` | ||
|
||
### Gas Snapshots | ||
|
||
```shell | ||
$ forge snapshot | ||
``` | ||
|
||
### Anvil | ||
|
||
```shell | ||
$ anvil | ||
``` | ||
|
||
### Deploy | ||
|
||
```shell | ||
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key> | ||
``` | ||
|
||
### Cast | ||
|
||
```shell | ||
$ cast <subcommand> | ||
``` | ||
|
||
### Help | ||
|
||
```shell | ||
$ forge --help | ||
$ anvil --help | ||
$ cast --help | ||
``` | ||
# Doppler | ||
|
||
## Initialization | ||
|
||
This sequence diagram explains how a new pair of token and pool is created: | ||
|
||
```mermaid | ||
sequenceDiagram | ||
participant U as User | ||
participant A as Airlock | ||
participant F as TokenFactory | ||
participant P as PoolManager | ||
participant H as Hook | ||
|
||
U->>A: calls create() | ||
A->>F: calls deploy() | ||
F-->>A: send tokens | ||
A->>P: initialize() | ||
P->>H: beforeInitialize() | ||
H-->>A: take tokens | ||
H->>P: unlock() | ||
P->>+H: unlockCallback() | ||
H->>P: modifyLiquidity() | ||
H->>P: ... | ||
H->>P: sync() | ||
H->>-P: settle() | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
v4-core/=lib/v4-periphery/lib/v4-core/ | ||
v4-periphery/=lib/v4-periphery/ | ||
v4-periphery/=lib/v4-periphery/ | ||
openzeppelin/=lib/v4-core/lib/openzeppelin-contracts/contracts/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import {IPoolManager, PoolKey, Currency, IHooks} from "v4-core/src/PoolManager.sol"; | ||
import {Ownable} from "openzeppelin/access/Ownable.sol"; | ||
import {ITokenFactory} from "src/interfaces/ITokenFactory.sol"; | ||
import {IGovernanceFactory} from "src/interfaces/IGovernanceFactory.sol"; | ||
import {IHookFactory} from "src/interfaces/IHookFactory.sol"; | ||
|
||
enum FactoryState { | ||
NotWhitelisted, | ||
TokenFactory, | ||
GovernanceFactory, | ||
HookFactory | ||
} | ||
|
||
error WrongFactoryState(); | ||
|
||
struct Token { | ||
address governance; | ||
bool hasMigrated; | ||
address hook; | ||
address[] recipients; | ||
uint256[] amounts; | ||
} | ||
|
||
contract Airlock is Ownable { | ||
IPoolManager public immutable poolManager; | ||
|
||
mapping(address => FactoryState) public getFactoryState; | ||
mapping(address => Token) public getToken; | ||
|
||
constructor(IPoolManager poolManager_) Ownable(msg.sender) { | ||
poolManager = poolManager_; | ||
} | ||
|
||
/** | ||
* TODO: | ||
* - Creating a token should incur fees (platform and frontend fees) | ||
* | ||
* @param tokenFactory Address of the factory contract deploying the ERC20 token | ||
* @param governanceFactory Address of the factory contract deploying the governance | ||
* @param hookFactory Address of the factory contract deploying the Uniswap v4 hook | ||
*/ | ||
function create( | ||
address tokenFactory, | ||
string memory name, | ||
string memory symbol, | ||
uint256 totalSupply, | ||
address owner, | ||
bytes memory tokenData, | ||
address governanceFactory, | ||
bytes memory governanceData, | ||
address hookFactory, | ||
bytes memory hookData, | ||
uint256 liquidityAmount, // TODO: Maybe we should use an amount of tokens instead of liquidity? | ||
address stageAdmin, | ||
address[] memory recipients, | ||
uint256[] memory amounts | ||
) external returns (address token, address governance, address hook) { | ||
require(getFactoryState[tokenFactory] == FactoryState.TokenFactory, WrongFactoryState()); | ||
require(getFactoryState[governanceFactory] == FactoryState.GovernanceFactory, WrongFactoryState()); | ||
require(getFactoryState[hookFactory] == FactoryState.HookFactory, WrongFactoryState()); | ||
|
||
// FIXME: Address of the hook is unknown at this point | ||
token = ITokenFactory(tokenFactory).create(name, symbol, totalSupply, hook, owner, tokenData); | ||
(governance,) = IGovernanceFactory(governanceFactory).create(name, token, governanceData); | ||
hook = IHookFactory(hookFactory).create(poolManager, hookData); | ||
|
||
getToken[token] = | ||
Token({governance: governance, hasMigrated: false, hook: hook, recipients: recipients, amounts: amounts}); | ||
|
||
PoolKey memory key = PoolKey({ | ||
// TODO: Currently only ETH pairs are supported | ||
currency0: Currency.wrap(address(0)), | ||
currency1: Currency.wrap(token), | ||
fee: 0, // TODO: Do we want users to have the ability to set the fee? | ||
tickSpacing: 60, // TODO: Do we want users to have the ability to set the tickSpacing? | ||
hooks: IHooks(hook) | ||
}); | ||
|
||
uint160 sqrtPriceX96; | ||
|
||
poolManager.initialize(key, sqrtPriceX96, new bytes(0)); | ||
} | ||
|
||
/** | ||
* TODO: This function will be callable later by the hook contract itself, in order to move the liquidity | ||
* from the Uniswap v4 pool to a v2 pool. The flow would be something like: | ||
* 1) Enough tokens were sold to trigger the migration | ||
* 2) Hook contract will remove its positions | ||
*/ | ||
function migrate() external {} | ||
|
||
function setFactoryState(address factory, FactoryState state) external onlyOwner { | ||
getFactoryState[factory] = state; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import {ERC20} from "openzeppelin/token/ERC20/ERC20.sol"; | ||
import {ERC20Votes} from "openzeppelin/token/ERC20/extensions/ERC20Votes.sol"; | ||
import {EIP712} from "openzeppelin/utils/cryptography/EIP712.sol"; | ||
import {Ownable} from "openzeppelin/access/Ownable.sol"; | ||
import {ERC20Permit} from "openzeppelin/token/ERC20/extensions/ERC20Permit.sol"; | ||
import {Nonces} from "openzeppelin/utils/Nonces.sol"; | ||
|
||
/** | ||
* TODO: | ||
* - Add mint cap: bounded annual max inflation which can only go down | ||
*/ | ||
error MintingNotStartedYet(); | ||
|
||
contract DERC20 is ERC20Votes, ERC20Permit, Ownable { | ||
uint256 public feeOnTransfer; | ||
mapping(address => bool) public isExemptFromFees; | ||
address public feeCollector; | ||
|
||
uint256 public immutable mintStartDate; | ||
uint256 public immutable yearlyMintCap; | ||
|
||
constructor( | ||
string memory name_, | ||
string memory symbol_, | ||
uint256 totalSupply_, | ||
address recipient, | ||
uint256 feeOnTransfer_, | ||
address[] memory exemptFromFees, | ||
address feeCollector_, | ||
address owner_ | ||
) ERC20(name_, symbol_) ERC20Permit(name_) Ownable(owner_) { | ||
_mint(recipient, totalSupply_); | ||
feeOnTransfer = feeOnTransfer_; | ||
|
||
for (uint256 i = 0; i < exemptFromFees.length; i++) { | ||
isExemptFromFees[exemptFromFees[i]] = true; | ||
} | ||
|
||
feeCollector = feeCollector_; | ||
isExemptFromFees[feeCollector_] = true; // Just in case | ||
|
||
mintStartDate = block.timestamp + 365 days; | ||
} | ||
|
||
function mint(address to, uint256 value) external onlyOwner { | ||
require(block.timestamp >= mintStartDate, MintingNotStartedYet()); | ||
_mint(to, value); | ||
} | ||
|
||
function clock() public view override returns (uint48) { | ||
return uint48(block.timestamp); | ||
} | ||
|
||
function CLOCK_MODE() public pure override returns (string memory) { | ||
return "mode=timestamp"; | ||
} | ||
|
||
function nonces(address owner) public view virtual override(ERC20Permit, Nonces) returns (uint256) { | ||
return super.nonces(owner); | ||
} | ||
|
||
function _update(address from, address to, uint256 value) internal virtual override(ERC20, ERC20Votes) { | ||
super._update(from, to, value); | ||
|
||
// TODO: Check when should we charge / NOT charge the fee? | ||
if (feeOnTransfer > 0 && !isExemptFromFees[from] && !isExemptFromFees[to]) { | ||
uint256 fee = feeOnTransfer * value / 10_000; | ||
_transfer(to, feeCollector, fee); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.13; | ||
|
||
import {IPoolManager} from "v4-core/src/interfaces/IPoolManager.sol"; | ||
import {IHookFactory} from "src/interfaces/IHookFactory.sol"; | ||
import {Doppler} from "src/Doppler.sol"; | ||
|
||
contract DopplerFactory is IHookFactory { | ||
function create(IPoolManager poolManager, bytes memory hookData) external returns (address) { | ||
( | ||
uint256 numTokensToSell, | ||
uint256 startingTime, | ||
uint256 endingTime, | ||
int24 startingTick, | ||
int24 endingTick, | ||
uint256 epochLength, | ||
uint256 gamma, | ||
bool isToken0 | ||
) = abi.decode(hookData, (uint256, uint256, uint256, int24, int24, uint256, uint256, bool)); | ||
|
||
return address( | ||
new Doppler( | ||
poolManager, | ||
numTokensToSell, | ||
startingTime, | ||
endingTime, | ||
startingTick, | ||
endingTick, | ||
epochLength, | ||
gamma, | ||
isToken0 | ||
) | ||
); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emit Create(...)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we haven't really added the events yet. If you have feedback for events that are helpful from a ux pov would you mind adding them to the sdk doc/making a quick issue? I can also help build context here if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added to #95