From 3a6d05850dd871184717830ad1da53fc23bc22e2 Mon Sep 17 00:00:00 2001 From: Mehdi Djendar Date: Mon, 26 Jun 2023 03:31:44 +0200 Subject: [PATCH] feat: add beginning of superfluid token --- .gitmodules | 3 ++ dao/lib/superfluid-protocol-monorepo | 1 + dao/remappings.txt | 1 + dao/src/SuperFluidToken.sol | 33 ------------- .../{SuperFluidDao.sol => SuperfluidDao.sol} | 32 ++++++------- dao/src/SuperfluidDaoToken.sol | 46 +++++++++++++++++++ ...uperFluidDao.t.sol => SuperfluidDao.t.sol} | 36 +++++++-------- 7 files changed, 84 insertions(+), 68 deletions(-) create mode 160000 dao/lib/superfluid-protocol-monorepo delete mode 100644 dao/src/SuperFluidToken.sol rename dao/src/{SuperFluidDao.sol => SuperfluidDao.sol} (81%) create mode 100644 dao/src/SuperfluidDaoToken.sol rename dao/test/{SuperFluidDao.t.sol => SuperfluidDao.t.sol} (73%) diff --git a/.gitmodules b/.gitmodules index f4fed14..e42ec84 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "dao/lib/openzeppelin-contracts"] path = dao/lib/openzeppelin-contracts url = https://github.com/Openzeppelin/openzeppelin-contracts +[submodule "dao/lib/superfluid-protocol-monorepo"] + path = dao/lib/superfluid-protocol-monorepo + url = https://github.com/superfluid-finance/protocol-monorepo diff --git a/dao/lib/superfluid-protocol-monorepo b/dao/lib/superfluid-protocol-monorepo new file mode 160000 index 0000000..079150a --- /dev/null +++ b/dao/lib/superfluid-protocol-monorepo @@ -0,0 +1 @@ +Subproject commit 079150a75dec0ee2f731f81c0280689ca7b30513 diff --git a/dao/remappings.txt b/dao/remappings.txt index 81da917..36bcdca 100644 --- a/dao/remappings.txt +++ b/dao/remappings.txt @@ -1,3 +1,4 @@ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ @openzeppelin/=lib/openzeppelin-contracts/ +@superfluid-finance/=lib/superfluid-protocol-monorepo/ diff --git a/dao/src/SuperFluidToken.sol b/dao/src/SuperFluidToken.sol deleted file mode 100644 index 34db4d7..0000000 --- a/dao/src/SuperFluidToken.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract SuperFluidAdmin { - address private _admin; - - constructor() { - _admin = msg.sender; - } - - modifier onlyAdmin() { - require(msg.sender == _admin, "SuperFluidAdmin/NotAuthorized"); - _; - } - - function setAdmin(address admin) public onlyAdmin { - _admin = admin; - } -} - -contract SuperFluidToken is ERC20, SuperFluidAdmin { - constructor() ERC20("SuperFluidToken", "SFT") SuperFluidAdmin() {} - - function mint(address to, uint256 amount) public onlyAdmin { - _mint(to, amount); - } - - function burn(address to, uint256 amount) public onlyAdmin { - _burn(to, amount); - } -} diff --git a/dao/src/SuperFluidDao.sol b/dao/src/SuperfluidDao.sol similarity index 81% rename from dao/src/SuperFluidDao.sol rename to dao/src/SuperfluidDao.sol index 9d6cdd7..fb2524b 100644 --- a/dao/src/SuperFluidDao.sol +++ b/dao/src/SuperfluidDao.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -// import {ISuperToken} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol"; +import {SuperfluidDaoToken} from "./SuperfluidDaoToken.sol"; -import {SuperFluidToken} from "./SuperFluidToken.sol"; - -interface ISuperFluidDao { +interface ISuperfluidDao { struct Proposal { uint256 voteFor; uint256 voteAgainst; @@ -25,8 +23,8 @@ interface ISuperFluidDao { // error error InvalidProposalId(); error AlreadyVoted(); - error NotEnoughSuperfluidToken(); - error ZeroSuperfluidToken(); + error NotEnoughSuperfluidDaoToken(); + error ZeroSuperfluidDaoToken(); error ProposalAlreadyExecuted(); error ProposalDueDateNotReached(); error ProposalDueDatePassed(); @@ -43,7 +41,7 @@ interface ISuperFluidDao { // functions function postProposal(bytes32 descriptionCID, uint64 timeSpan) external; - function getToken() external view returns (SuperFluidToken); + function getToken() external view returns (SuperfluidDaoToken); function getProposal( uint _proposalId @@ -52,13 +50,13 @@ interface ISuperFluidDao { function getProposals() external view returns (Proposal[] memory); } -contract SuperFluidDao is ISuperFluidDao { +contract SuperfluidDao is ISuperfluidDao { mapping(address => mapping(uint256 => VoteStatus)) private _votes; Proposal[] private _proposals; - SuperFluidToken private _superFluidToken; + SuperfluidDaoToken private _superfluidToken; constructor() { - _superFluidToken = new SuperFluidToken(); + _superfluidToken = new SuperfluidDaoToken(); } function postProposal(bytes32 descriptionCID, uint64 timeSpan) public { @@ -77,8 +75,8 @@ contract SuperFluidDao is ISuperFluidDao { emit ProposalSubmitted(_proposals.length - 1); } - function getToken() public view returns (SuperFluidToken) { - return _superFluidToken; + function getToken() public view returns (SuperfluidDaoToken) { + return _superfluidToken; } function getProposal( @@ -105,10 +103,10 @@ contract SuperFluidDao is ISuperFluidDao { revert ProposalDueDatePassed(); } - uint256 voteWeight = _superFluidToken.balanceOf(msg.sender); + uint256 voteWeight = _superfluidToken.balanceOf(msg.sender); if (voteWeight == 0) { - revert ZeroSuperfluidToken(); + revert ZeroSuperfluidDaoToken(); } if (voteChoice) { @@ -119,7 +117,7 @@ contract SuperFluidDao is ISuperFluidDao { _votes[msg.sender][proposalId] = VoteStatus.VotedAgainst; } - _superFluidToken.burn(msg.sender, 1); + _superfluidToken.burn(msg.sender, 1); emit CastVote(msg.sender, proposalId, voteWeight); } @@ -141,10 +139,10 @@ contract SuperFluidDao is ISuperFluidDao { _proposals[proposalId].executed = true; if (_proposals[proposalId].voteFor > _proposals[proposalId].voteAgainst) { - _superFluidToken.mint(msg.sender, _proposals[proposalId].voteFor); + _superfluidToken.mint(msg.sender, _proposals[proposalId].voteFor); } if (_proposals[proposalId].voteFor < _proposals[proposalId].voteAgainst) { - _superFluidToken.burn(msg.sender, 1); + _superfluidToken.burn(msg.sender, 1); } } } diff --git a/dao/src/SuperfluidDaoToken.sol b/dao/src/SuperfluidDaoToken.sol new file mode 100644 index 0000000..0b1aa1b --- /dev/null +++ b/dao/src/SuperfluidDaoToken.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ISuperfluid } from "@superfluid-finance/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; +import { IConstantFlowAgreementV1 } from "@superfluid-finance/packages/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol"; +import { ISuperToken } from "@superfluid-finance/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol"; +import { ISuperfluidToken } from "@superfluid-finance/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidToken.sol"; + +contract SuperfluidAdmin { + address private _admin; + + constructor() { + _admin = msg.sender; + } + + modifier onlyAdmin() { + require(msg.sender == _admin, "SuperfluidAdmin/NotAuthorized"); + _; + } + + function setAdmin(address admin) public onlyAdmin { + _admin = admin; + } +} + +contract SuperfluidDaoToken is ERC20, SuperfluidAdmin { + + // ISuperfluid private _host; // Contrat hôte Superfluid + // IConstantFlowAgreementV1 private _cfa; // Contrat d'accord de flux constant + // ISuperToken private _superToken; // Contrat Super Token + + constructor() ERC20("SuperfluidDaoToken", "SFT") SuperfluidAdmin() { + // _host = ISuperfluid(msg.sender) + // _cfa = IConstantFlowAgreementV1(); + // _superToke + } + + function mint(address to, uint256 amount) public onlyAdmin { + _mint(to, amount); + } + + function burn(address to, uint256 amount) public onlyAdmin { + _burn(to, amount); + } +} diff --git a/dao/test/SuperFluidDao.t.sol b/dao/test/SuperfluidDao.t.sol similarity index 73% rename from dao/test/SuperFluidDao.t.sol rename to dao/test/SuperfluidDao.t.sol index 9b0ee8a..c700fe9 100644 --- a/dao/test/SuperFluidDao.t.sol +++ b/dao/test/SuperfluidDao.t.sol @@ -2,21 +2,21 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import "../src/SuperFluidDao.sol"; -import {SuperFluidToken} from "../src/SuperFluidToken.sol"; +import "../src/SuperfluidDao.sol"; +import {SuperfluidDaoToken} from "../src/SuperfluidDaoToken.sol"; -contract SuperFluidDaoTest is Test { +contract SuperfluidDaoTest is Test { address Isma = vm.addr(0x1); - SuperFluidDao Dao; + SuperfluidDao Dao; function setUp() public { - Dao = new SuperFluidDao(); + Dao = new SuperfluidDao(); } function mintTo(address to, uint256 amount) public { vm.startPrank(address(Dao)); - SuperFluidToken token = Dao.getToken(); + SuperfluidDaoToken token = Dao.getToken(); token.mint(to, amount); vm.stopPrank(); } @@ -27,7 +27,7 @@ contract SuperFluidDaoTest is Test { } function test_VoteInvalidProposalId() public { - vm.expectRevert(ISuperFluidDao.InvalidProposalId.selector); + vm.expectRevert(ISuperfluidDao.InvalidProposalId.selector); Dao.vote(0, true); } @@ -35,7 +35,7 @@ contract SuperFluidDaoTest is Test { vm.startPrank(Isma); Dao.postProposal("Donnez moins d'argent a Isma", 0); Dao.executeProposal(0); - vm.expectRevert(ISuperFluidDao.ProposalAlreadyExecuted.selector); + vm.expectRevert(ISuperfluidDao.ProposalAlreadyExecuted.selector); Dao.vote(0, true); vm.stopPrank(); } @@ -45,7 +45,7 @@ contract SuperFluidDaoTest is Test { Dao.postProposal("Donnez moins d'argent a Isma", 10); vm.startPrank(Isma); Dao.vote(0, false); - vm.expectRevert(ISuperFluidDao.AlreadyVoted.selector); + vm.expectRevert(ISuperfluidDao.AlreadyVoted.selector); Dao.vote(0, false); vm.stopPrank(); } @@ -54,15 +54,15 @@ contract SuperFluidDaoTest is Test { mintTo(Isma, 2); Dao.postProposal("Donnez moins d'argent a Isma", 0); vm.startPrank(Isma); - vm.expectRevert(ISuperFluidDao.ProposalDueDatePassed.selector); + vm.expectRevert(ISuperfluidDao.ProposalDueDatePassed.selector); Dao.vote(0, true); vm.stopPrank(); } - function test_VoteZeroSuperfluidToken() public { + function test_VoteZeroSuperfluidDaoToken() public { Dao.postProposal("Donnez moins d'argent a Isma", 10); vm.startPrank(Isma); - vm.expectRevert(ISuperFluidDao.ZeroSuperfluidToken.selector); + vm.expectRevert(ISuperfluidDao.ZeroSuperfluidDaoToken.selector); Dao.vote(0, true); vm.stopPrank(); } @@ -72,13 +72,13 @@ contract SuperFluidDaoTest is Test { vm.startPrank(Isma); Dao.postProposal("Donnez moins d'argent a Isma", 10); Dao.vote(0, true); - ISuperFluidDao.Proposal memory proposal = Dao.getProposal(0); + ISuperfluidDao.Proposal memory proposal = Dao.getProposal(0); assertEq(proposal.voteFor, 1); vm.stopPrank(); } function test_ExecuteProposalInvalidProposalId() public { - vm.expectRevert(ISuperFluidDao.InvalidProposalId.selector); + vm.expectRevert(ISuperfluidDao.InvalidProposalId.selector); Dao.executeProposal(0); } @@ -86,7 +86,7 @@ contract SuperFluidDaoTest is Test { vm.startPrank(Isma); Dao.postProposal("Donnez moins d'argent a Isma", 0); Dao.executeProposal(0); - vm.expectRevert(ISuperFluidDao.ProposalAlreadyExecuted.selector); + vm.expectRevert(ISuperfluidDao.ProposalAlreadyExecuted.selector); Dao.executeProposal(0); vm.stopPrank(); } @@ -94,7 +94,7 @@ contract SuperFluidDaoTest is Test { function test_ExecuteProposalProposalDueDateNotReached() public { vm.startPrank(Isma); Dao.postProposal("Donnez moins d'argent a Isma", 100000000000); - vm.expectRevert(ISuperFluidDao.ProposalDueDateNotReached.selector); + vm.expectRevert(ISuperfluidDao.ProposalDueDateNotReached.selector); Dao.executeProposal(0); vm.stopPrank(); } @@ -102,7 +102,7 @@ contract SuperFluidDaoTest is Test { function test_ExecuteProposalProposalExecutedByNonAuthor() public { Dao.postProposal("Donnez moins d'argent a Isma", 0); vm.startPrank(Isma); - vm.expectRevert(ISuperFluidDao.ProposalExecutedByNonAuthor.selector); + vm.expectRevert(ISuperfluidDao.ProposalExecutedByNonAuthor.selector); Dao.executeProposal(0); vm.stopPrank(); } @@ -112,7 +112,7 @@ contract SuperFluidDaoTest is Test { vm.startPrank(Isma); Dao.postProposal("Donnez moins d'argent a Isma", 1); Dao.vote(0, true); - ISuperFluidDao.Proposal memory proposal = Dao.getProposal(0); + ISuperfluidDao.Proposal memory proposal = Dao.getProposal(0); while (block.timestamp >= proposal.dueDate)