dgf-prototype/ethereum/contracts/Proposal.sol

120 lines
3.7 KiB
Solidity
Raw Normal View History

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.24;
import "./DAO.sol";
2024-03-26 21:32:41 -05:00
import "hardhat/console.sol";
contract Proposals is DAOContract {
struct Attestation {
address sender;
uint amount;
}
enum Stage {
Proposal,
Referendum0,
Referendum1,
Referendum100,
Closed
}
2024-03-26 21:32:41 -05:00
struct Referendum {
uint duration;
uint poolIndex;
}
struct Proposal {
address sender;
2024-03-26 21:32:41 -05:00
uint fee;
uint feeRemaining;
uint postIndex;
uint startTime;
Stage stage;
mapping(uint => Attestation) attestations;
uint attestationCount;
2024-03-26 21:32:41 -05:00
Referendum[3] referenda;
}
2024-03-26 21:32:41 -05:00
mapping(uint => Proposal) public proposals;
uint public proposalCount;
constructor(DAO dao) DAOContract(dao) {}
function propose(
2024-03-26 21:32:41 -05:00
uint postIndex,
uint referendum0Duration,
uint referendum1Duration,
uint referendum100Duration
) external payable returns (uint proposalIndex) {
proposalIndex = proposalCount++;
Proposal storage proposal = proposals[proposalIndex];
2024-03-26 21:32:41 -05:00
proposal.postIndex = postIndex;
proposal.startTime = block.timestamp;
2024-03-26 21:32:41 -05:00
proposal.referenda[0].duration = referendum0Duration;
proposal.referenda[1].duration = referendum1Duration;
proposal.referenda[2].duration = referendum100Duration;
proposal.fee = msg.value;
proposal.feeRemaining = proposal.fee;
}
function attest(uint proposalIndex, uint amount) external {
// Since this is non-binding, non-encumbering, we only need to verify that
// the sender actually has the rep they claim to stake.
require(
dao.balanceOf(msg.sender) >= amount,
"Sender has insufficient REP balance"
);
Proposal storage proposal = proposals[proposalIndex];
uint attestationIndex = proposal.attestationCount++;
Attestation storage attestation = proposal.attestations[
attestationIndex
];
attestation.sender = msg.sender;
attestation.amount = amount;
}
2024-03-26 21:32:41 -05:00
// todo onValidate() {
// This callback will get proposalIndex
// todo }
function evaluateAttestation(uint proposalIndex) external returns (bool) {
Proposal storage proposal = proposals[proposalIndex];
require(
proposal.stage == Stage.Proposal,
"Attestation only pertains to Proposal stage"
);
uint totalAttestation;
for (uint i = 0; i < proposal.attestationCount; i++) {
totalAttestation += proposal.attestations[i].amount;
}
bool meetsAttestation = 10 * totalAttestation >= dao.totalSupply();
2024-03-26 21:32:41 -05:00
bool expired = block.timestamp > proposal.startTime + 365 days;
if (!meetsAttestation) {
2024-03-26 21:32:41 -05:00
if (expired) {
proposal.stage = Stage.Closed;
return false;
}
return false;
}
// Initiate validation pool
proposal.stage = Stage.Referendum0;
2024-03-26 21:32:41 -05:00
uint thisFee = proposal.fee / 3;
proposal.feeRemaining -= thisFee;
proposal.referenda[0].poolIndex = dao.initiateValidationPool{
value: thisFee
}(
proposal.postIndex, // uint postIndex,
proposal.referenda[0].duration, // uint duration,
1, // uint quorumNumerator,
3, // uint quorumDenominator,
0, // uint bindingPercent,
false, // bool redistributeLosingStakes,
false, // TODO bool callbackOnValidate : true,
"" // TODO bytes calldata callbackData : This should probably be proposalIndex
);
return true;
}
}