From ed9814fdcb20def9c237fab12b88e5f38b59fa04 Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Tue, 5 Mar 2024 12:25:07 -0600 Subject: [PATCH] validation pool progress --- ethereum/contracts/DAO.sol | 93 +++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/ethereum/contracts/DAO.sol b/ethereum/contracts/DAO.sol index 6dd115f..fb0f9bf 100644 --- a/ethereum/contracts/DAO.sol +++ b/ethereum/contracts/DAO.sol @@ -10,21 +10,17 @@ struct Stake { address sender; } -enum ValidationPoolStatus { - Open, - Closed -} - struct ValidationPool { mapping(uint => Stake) stakes; uint stakeCount; - ValidationPoolStatus status; uint duration; uint endTime; + bool resolved; + bool outcome; } struct StakeData { - uint validationPoolIndex; + uint poolIndex; bool inFavor; } @@ -34,10 +30,18 @@ struct StakeData { contract DAO is ERC721("Reputation", "REP"), ReputationHolder { mapping(uint256 tokenId => uint256) tokenValues; uint256 nextTokenId; + uint256 totalValue; mapping(uint => ValidationPool) validationPools; uint validationPoolCount; - event ValidationPoolInitiated(uint validationPoolIndex); + // ufixed8x1 constant mintingRatio = 1; + // ufixed8x1 constant quorum = 0; + // ufixed8x1 constant stakeForAuthor = 0.5; + // ufixed8x1 constant winningRatio = 0.5; + // TODO: Make parameters adjustable + // TODO: Add forum parameters + + event ValidationPoolInitiated(uint poolIndex); /// Inspect the value of a given reputation NFT function valueOf(uint256 tokenId) public view returns (uint256 value) { @@ -56,11 +60,15 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder { } /// Internal function to mint a new reputation NFT - function mint() internal returns (uint256 tokenId) { + function mint(uint256 value) internal returns (uint256 tokenId) { // Generate a new (sequential) ID for the token tokenId = nextTokenId++; // Mint the token, initially to be owned by the current contract. _mint(address(this), tokenId); + tokenValues[tokenId] = value; + // Keep track of total value minted + // TODO: More sophisticated logic can compute total _available_, _active_ reputation + totalValue += value; } /// Internal function to transfer value from one reputation token to another @@ -76,12 +84,36 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder { } /// Accept fee to initiate a validation pool - function initiateValidationPool(uint duration) public { - uint validationPoolIndex = validationPoolCount++; - ValidationPool storage pool = validationPools[validationPoolIndex]; + function initiateValidationPool(uint duration) public payable { + uint poolIndex = validationPoolCount++; + ValidationPool storage pool = validationPools[poolIndex]; pool.duration = duration; pool.endTime = block.timestamp + duration; - emit ValidationPoolInitiated(validationPoolIndex); + // Because we need to stake part of the mited value for the pool an part against, + // we mint two new tokens. + // Here we assume a minting ratio of 1, and a stakeForAuthor ratio of 0.5 + // Implementing this with adjustable parameters will require more advanced fixed point math. + // TODO: Make minting ratio an adjustable parameter + // TODO: Make stakeForAuthor an adjustable parameter + uint256 tokenIdFor = mint(msg.value / 2); + uint256 tokenIdAgainst = mint(msg.value / 2); + stake(pool, address(this), true, tokenIdFor); + stake(pool, address(this), false, tokenIdAgainst); + emit ValidationPoolInitiated(poolIndex); + } + + /// Internal function to register a stake for/against a validation pool + function stake( + ValidationPool storage pool, + address sender, + bool inFavor, + uint256 tokenId + ) internal { + require(block.timestamp < pool.endTime); + Stake storage _stake = pool.stakes[pool.stakeCount++]; + _stake.sender = sender; + _stake.inFavor = inFavor; + _stake.amount = verifiedValueOf(sender, tokenId); } /// Accept reputation stakes toward a validation pool @@ -94,17 +126,36 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder { // `data` needs to encode the target validation pool, and the for/again boolean StakeData memory stakeParameters = abi.decode(data, (StakeData)); ValidationPool storage pool = validationPools[ - stakeParameters.validationPoolIndex + stakeParameters.poolIndex ]; - Stake storage stake = pool.stakes[pool.stakeCount++]; - stake.sender = from; - stake.inFavor = stakeParameters.inFavor; - stake.amount = verifiedValueOf(from, tokenId); + stake(pool, from, stakeParameters.inFavor, tokenId); return super.onERC721Received.selector; } /// Evaluate outcome of a validation pool - function evaluateOutcome( - uint validationPoolIndex - ) public returns (bool outcome) {} + function evaluateOutcome(uint poolIndex) public returns (bool outcome) { + ValidationPool storage pool = validationPools[poolIndex]; + require(block.timestamp >= pool.endTime); + require(pool.resolved == false); + uint256 amountFor; + uint256 amountAgainst; + Stake memory _stake; + for (uint i = 0; i < pool.stakeCount; i++) { + _stake = pool.stakes[i]; + if (_stake.inFavor) { + amountFor += _stake.amount; + } else { + amountAgainst += _stake.amount; + } + } + // Here we assume a quorum of 0 + // TODO: Make quorum an adjustable parameter + // A tie is resolved in favor of the validation pool. + // This is especially important so that the DAO's first pool can pass, + // when no reputation has yet been minted. + outcome = amountFor >= amountAgainst; + pool.resolved = true; + // Distribute reputation + // Distribute fee + } }