refactor and stub for rollup
This commit is contained in:
parent
b175a34b9f
commit
8e272bf2e8
|
@ -0,0 +1,86 @@
|
|||
// 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);
|
||||
event WorkAssigned(uint requestIndex, 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(uint requestIndex) internal returns (uint stakeIndex) {
|
||||
stakeIndex = randomWeightedSelection();
|
||||
AvailabilityStake storage stake = stakes[stakeIndex];
|
||||
stake.assigned = true;
|
||||
emit WorkAssigned(requestIndex, stakeIndex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import "./WorkContract.sol";
|
||||
import "./Rollup.sol";
|
||||
|
||||
abstract contract RollableWorkContract is WorkContract {
|
||||
constructor(
|
||||
DAO dao,
|
||||
Proposals proposalsContract,
|
||||
uint price,
|
||||
Rollup rollupContract_
|
||||
) WorkContract(dao, proposalsContract, price) {}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import "./core/DAO.sol";
|
||||
import "./Availability.sol";
|
||||
|
||||
contract Rollup is Availability {
|
||||
constructor(DAO dao) Availability(dao) {}
|
||||
}
|
|
@ -3,22 +3,11 @@ pragma solidity ^0.8.24;
|
|||
|
||||
import "./core/DAO.sol";
|
||||
import "./core/Forum.sol";
|
||||
import "./Availability.sol";
|
||||
import "./Proposals.sol";
|
||||
import "./interfaces/IAcceptAvailability.sol";
|
||||
import "./interfaces/IOnProposalAccepted.sol";
|
||||
|
||||
abstract contract WorkContract is
|
||||
DAOContract,
|
||||
IAcceptAvailability,
|
||||
IOnProposalAccepted
|
||||
{
|
||||
struct AvailabilityStake {
|
||||
address worker;
|
||||
uint256 amount;
|
||||
uint endTime;
|
||||
bool assigned;
|
||||
}
|
||||
|
||||
abstract contract WorkContract is Availability, IOnProposalAccepted {
|
||||
enum WorkStatus {
|
||||
Requested,
|
||||
EvidenceSubmitted,
|
||||
|
@ -46,15 +35,11 @@ abstract contract WorkContract is
|
|||
uint public price;
|
||||
mapping(uint => PriceProposal) public priceProposals;
|
||||
uint public priceProposalCount;
|
||||
mapping(uint => AvailabilityStake) public stakes;
|
||||
uint public stakeCount;
|
||||
mapping(uint => WorkRequest) public requests;
|
||||
uint public requestCount;
|
||||
|
||||
uint constant POOL_DURATION = 20;
|
||||
|
||||
event AvailabilityStaked(uint stakeIndex);
|
||||
event WorkAssigned(uint requestIndex, uint stakeIndex);
|
||||
event WorkEvidenceSubmitted(uint requestIndex);
|
||||
event WorkApprovalSubmitted(uint requestIndex, bool approval);
|
||||
event PriceChangeProposed(uint priceProposalIndex);
|
||||
|
@ -64,71 +49,11 @@ abstract contract WorkContract is
|
|||
DAO dao,
|
||||
Proposals proposalsContract_,
|
||||
uint price_
|
||||
) DAOContract(dao) {
|
||||
) Availability(dao) {
|
||||
price = price_;
|
||||
proposalsContract = proposalsContract_;
|
||||
}
|
||||
|
||||
/// Accept availability stakes as reputation token transfer
|
||||
function acceptAvailability(
|
||||
address sender,
|
||||
uint256 amount,
|
||||
uint duration
|
||||
) external {
|
||||
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(uint requestIndex) internal returns (uint stakeIndex) {
|
||||
stakeIndex = randomWeightedSelection();
|
||||
AvailabilityStake storage stake = stakes[stakeIndex];
|
||||
stake.assigned = true;
|
||||
emit WorkAssigned(requestIndex, stakeIndex);
|
||||
}
|
||||
|
||||
/// Accept work request with fee
|
||||
function requestWork(string calldata requestContentId) external payable {
|
||||
require(msg.value >= price, "Insufficient fee");
|
||||
|
|
|
@ -78,6 +78,10 @@ describe('Work1', () => {
|
|||
await expect(dao.stakeAvailability(work1.target, 0, STAKE_DURATION)).to.be.revertedWith('No stake provided');
|
||||
});
|
||||
|
||||
it('should not be able to call acceptAvailability directly', async () => {
|
||||
await expect(work1.acceptAvailability(account1, 50, STAKE_DURATION)).to.be.revertedWith('acceptAvailability must only be called by DAO contract');
|
||||
});
|
||||
|
||||
it('should be able to extend the duration of an availability stake before it expires', async () => {
|
||||
await time.increase(STAKE_DURATION / 2);
|
||||
await expect(work1.extendAvailability(0, STAKE_DURATION)).to.emit(work1, 'AvailabilityStaked').withArgs(0);
|
||||
|
|
Loading…
Reference in New Issue