dgf-prototype/ethereum/contracts/Availability.sol

85 lines
3.0 KiB
Solidity
Raw Normal View History

2024-04-28 15:06:10 -05:00
// 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;
mapping(address worker => uint stakeIndex) activeWorkerStakes;
2024-04-28 15:06:10 -05:00
uint public stakeCount;
event AvailabilityStaked(uint stakeIndex);
constructor(DAO dao) DAOContract(dao) {}
/// Accept availability stakes as reputation token transfer
function acceptAvailability(
address worker,
2024-04-28 15:06:10 -05:00
uint256 amount,
uint duration
) external returns (uint refund) {
2024-04-28 15:06:10 -05:00
require(
msg.sender == address(dao),
"acceptAvailability must only be called by DAO contract"
);
require(amount > 0, "No stake provided");
// If we already have a stake for this worker, replace it
uint stakeIndex = activeWorkerStakes[worker];
if (stakeIndex == 0 && stakes[stakeIndex].worker != worker) {
// We don't have an existing stake for this worker
stakeIndex = stakeCount++;
activeWorkerStakes[worker] = stakeIndex;
} else if (stakes[stakeIndex].assigned) {
// Stake has already been assigned; We need to create a new one
stakeIndex = stakeCount++;
activeWorkerStakes[worker] = stakeIndex;
} else {
// We are replacing an existing stake.
// That means we can refund some of the granted allowance
refund = stakes[stakeIndex].amount;
}
2024-04-28 15:06:10 -05:00
AvailabilityStake storage stake = stakes[stakeIndex];
stake.worker = worker;
2024-04-28 15:06:10 -05:00
stake.amount = amount;
stake.endTime = block.timestamp + 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
2024-04-28 16:51:35 -05:00
function assignWork() internal returns (uint stakeIndex) {
2024-04-28 15:06:10 -05:00
stakeIndex = randomWeightedSelection();
AvailabilityStake storage stake = stakes[stakeIndex];
stake.assigned = true;
}
}