// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.24; import "./core/DAO.sol"; import "./interfaces/IAcceptAvailability.sol"; contract Availability is IAcceptAvailability, DAOContract { struct AvailabilityStake { address worker; uint256 amount; uint endTime; bool assigned; } mapping(uint => AvailabilityStake) public stakes; uint public stakeCount; event AvailabilityStaked(uint stakeIndex); constructor(DAO dao) DAOContract(dao) {} /// Accept availability stakes as reputation token transfer function acceptAvailability( address sender, uint256 amount, uint duration ) external { require( msg.sender == address(dao), "acceptAvailability must only be called by DAO contract" ); require(amount > 0, "No stake provided"); uint stakeIndex = stakeCount++; AvailabilityStake storage stake = stakes[stakeIndex]; stake.worker = sender; stake.amount = amount; stake.endTime = block.timestamp + duration; emit AvailabilityStaked(stakeIndex); } function extendAvailability(uint stakeIndex, uint duration) external { AvailabilityStake storage stake = stakes[stakeIndex]; require( msg.sender == stake.worker, "Worker can only extend their own availability stake" ); require(!stake.assigned, "Stake has already been assigned work"); if (block.timestamp > stake.endTime) { stake.endTime = block.timestamp + duration; } else { stake.endTime = stake.endTime + duration; } emit AvailabilityStaked(stakeIndex); } /// Select a worker randomly from among the available workers, weighted by amount staked function randomWeightedSelection() internal view returns (uint stakeIndex) { uint totalStakes; for (uint i = 0; i < stakeCount; i++) { if (stakes[i].assigned) continue; if (block.timestamp > stakes[i].endTime) continue; totalStakes += stakes[i].amount; } require(totalStakes > 0, "No available worker stakes"); uint select = block.prevrandao % totalStakes; uint acc; for (uint i = 0; i < stakeCount; i++) { if (stakes[i].assigned) continue; if (block.timestamp > stakes[i].endTime) continue; acc += stakes[i].amount; if (acc > select) { stakeIndex = i; break; } } } /// Assign a random available worker function assignWork() internal returns (uint stakeIndex) { stakeIndex = randomWeightedSelection(); AvailabilityStake storage stake = stakes[stakeIndex]; stake.assigned = true; } }