111 lines
3.5 KiB
Solidity
111 lines
3.5 KiB
Solidity
// SPDX-License-Identifier: Unlicense
|
|
pragma solidity ^0.8.24;
|
|
|
|
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
|
import "./ReputationHolder.sol";
|
|
|
|
struct Stake {
|
|
bool inFavor;
|
|
uint256 amount;
|
|
address sender;
|
|
}
|
|
|
|
enum ValidationPoolStatus {
|
|
Open,
|
|
Closed
|
|
}
|
|
|
|
struct ValidationPool {
|
|
mapping(uint => Stake) stakes;
|
|
uint stakeCount;
|
|
ValidationPoolStatus status;
|
|
uint duration;
|
|
uint endTime;
|
|
}
|
|
|
|
struct StakeData {
|
|
uint validationPoolIndex;
|
|
bool inFavor;
|
|
}
|
|
|
|
/// This contract must manage validation pools and reputation,
|
|
/// because otherwise there's no way to enforce appropriate permissions on
|
|
/// transfer of value between reputation NFTs.
|
|
contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
|
|
mapping(uint256 tokenId => uint256) tokenValues;
|
|
uint256 nextTokenId;
|
|
mapping(uint => ValidationPool) validationPools;
|
|
uint validationPoolCount;
|
|
|
|
event ValidationPoolInitiated(uint validationPoolIndex);
|
|
|
|
/// Inspect the value of a given reputation NFT
|
|
function valueOf(uint256 tokenId) public view returns (uint256 value) {
|
|
value = tokenValues[tokenId];
|
|
}
|
|
|
|
/// Confirm ownership of a token and return its value.
|
|
/// This should be used when receiving an NFT transfer, because otherwise
|
|
/// someone could send any NFT with a tokenId matching one of ours.
|
|
function verifiedValueOf(
|
|
address owner,
|
|
uint256 tokenId
|
|
) public view returns (uint256 value) {
|
|
require(ownerOf(tokenId) == owner);
|
|
value = valueOf(tokenId);
|
|
}
|
|
|
|
/// Internal function to mint a new reputation NFT
|
|
function mint() 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);
|
|
}
|
|
|
|
/// Internal function to transfer value from one reputation token to another
|
|
function transferValueFrom(
|
|
uint256 fromTokenId,
|
|
uint256 toTokenId,
|
|
uint256 amount
|
|
) internal {
|
|
require(amount >= 0);
|
|
require(valueOf(fromTokenId) >= amount);
|
|
tokenValues[fromTokenId] -= amount;
|
|
tokenValues[toTokenId] += amount;
|
|
}
|
|
|
|
/// Accept fee to initiate a validation pool
|
|
function initiateValidationPool(uint duration) public {
|
|
uint validationPoolIndex = validationPoolCount++;
|
|
ValidationPool storage pool = validationPools[validationPoolIndex];
|
|
pool.duration = duration;
|
|
pool.endTime = block.timestamp + duration;
|
|
emit ValidationPoolInitiated(validationPoolIndex);
|
|
}
|
|
|
|
/// Accept reputation stakes toward a validation pool
|
|
function onERC721Received(
|
|
address,
|
|
address from,
|
|
uint256 tokenId,
|
|
bytes calldata data
|
|
) public override returns (bytes4) {
|
|
// `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
|
|
];
|
|
Stake storage stake = pool.stakes[pool.stakeCount++];
|
|
stake.sender = from;
|
|
stake.inFavor = stakeParameters.inFavor;
|
|
stake.amount = verifiedValueOf(from, tokenId);
|
|
return super.onERC721Received.selector;
|
|
}
|
|
|
|
/// Evaluate outcome of a validation pool
|
|
function evaluateOutcome(
|
|
uint validationPoolIndex
|
|
) public returns (bool outcome) {}
|
|
}
|