InvestorDAO is a protocol that enables users to invest in an investment fund publicly governed by its investors.
They can invest DAI in the DAO and receive IDAO tokens that represents their share in the fund.
Investors are then able to make investment proposals to swap the DAI in the fund for another token. If accepted by the community, the amount of DAI voted will be traded against the token thanks to a UniswapV2 integration and then detained by the DAO. The investors can later make a proposal to trade the tokens back against DAI.
The IDAO tokens subsequently represent the total value of all tokens detained by the DAO. They can be traded or used to redeem DAI tokens, depending on the amount available. Considering that the DAO's funds will be invested most of the time, withdrawing DAI will always be done at the expense of a premium. Thus, the point is to rather trade the IDAO token for a price that depends on the token basket in the DAO.
To incentivise actors to trigger proposal execution at the end of a successful vote, transaction fees are refunded for it and a 100 DAI reward is sent.
The protocol is currently made of three contracts :
- IDAO.sol, the ERC20 token that represents the shares
- InvestorDao.sol, the main contract that handles the investments, IDAO generation & proposals
The constructor the the InvestorDao contract expects the following parameters.
uint256 contributionTime
: number of seconds while the investment in the DAO will be open, starting from the moment the contract is deployed
uint256 _voteTime
: number of seconds while the vote for proposals will be open
uint256 _proposalValidity
: number of seconds while the proposal will be executable after vote time ended
address _idao
: address of the IDAO token
address _dai
: address of the DAI token
address _weth
: address of the WETH token
address _uniswapRouter
: address of the AMM router token (can be any fork of Uniswap)
uint256 _sendEthToExecutorGas
: gas consumed by the sendEthToExecutor
function. Can be approximative since the shift in price is likely to be compensated by the DAI reward
idao() view returns (address)
Returns the address of the IDAO token used by the contract.
dai() view returns (address)
Returns the address of the DAI token used by the contract.
weth() view returns (address)
Returns the address of the WETH token used by the contract.
uniswapRouter() view returns (address)
Returns the address of the AMM router used by the contract.
contributionEnd() view returns (uint256)
Returns the timestamp after which no one can invest in the DAO anymore.
voteTime() view returns (uint256)
Returns the amount of seconds proposals are open for votes.
proposalValidity() view returns (uint256)
Returns the amount of seconds proposals are open for execution after voting period.
proposals(uint256 id) view returns (Proposal)
Returns data about a specific proposal.
getProposalsAmount() view returns (uint256)
Returns the amount of proposals that has been created so far.
invest(uint256 amount)
Enables to deposit DAI during the investment time and get IDAO in return. Emits a "LiquidityInvested" event.
withdraw(uint256 idaoAmount)
Enables to withdraw DAI in exchange of IDAO. The amount of DAI received depends on the amount that is available at the moment. Emits a "LiquidityWithdrew" event.
createProposal(address[] memory path, uint256 amountIn)
Enables to create a proposal. Requires to be an investor. Path is an array of the addressess of the tokens to swap, according to the Uniswap format (see Uniswap V2 documentation) Emits a "ProposalCreated" event.
voteProposal(uint256 id, Vote answer)
Enables to vote for a proposal. The vote is weighted, each IDAO the voter owns represent 1 point. Provided 0 for the answer parameter represents a Yes, 1 a No. Emits a "InvestorVoted" event.
executeProposal(uint256 id)
Enables to trigger the trade in the targeted proposal once the vote time is over, if there is strictly more yes votes than no votes. The gas consumed by the function is tracked so at the end of it, some of the reserve DAI is swaped against ETH to refund the caller. A 100 DAI reward is also sent to him/her. Emits a "ProposalExecuted" event.
- LiquidityInvested(address indexed user, uint256 amount)
- LiquidityWithdrew(address indexed user, uint256 idaoAmount, uint256 weiAmount)
- ProposalCreated( uint256 indexed id, address indexed proposer, address[] path, uint256 amountIn)
- InvestorVoted(uint256 indexed id, address indexed voter, Vote answer, uint256 investorWeight)
- ProposalExecuted(uint256 indexed id)
This is a Hardhat environment. First, run npm i
. Second, copy .env.example
, rename it to .env
and fill the fields.
npm test
You adapt the different parameters of the contructor in the scripts/deploy.ts
file.
Then run
npx hardhat run scripts/deploy.ts --network <TARGETED_NETWORK>
Copy the deployment address and paste it in to replace DEPLOYED_CONTRACT_ADDRESS
in this command:
npx hardhat verify --network <TARGETED_NETWORK> <DEPLOYED_CONTRACT_ADDRESS> "constructor argument 1" "constructor argument 2" "constructor argument 3" "constructor argument 4" "constructor argument 5" "constructor argument 6" "constructor argument 7" "constructor argument 8"
For faster runs of your tests and scripts, consider skipping ts-node's type checking by using
npm run test:optimized