|
|
|
@ -1,12 +1,14 @@
|
|
|
|
|
const {
|
|
|
|
|
time,
|
|
|
|
|
loadFixture,
|
|
|
|
|
// setPrevRandao,
|
|
|
|
|
} = require('@nomicfoundation/hardhat-toolbox/network-helpers');
|
|
|
|
|
const { expect } = require('chai');
|
|
|
|
|
const { ethers } = require('hardhat');
|
|
|
|
|
|
|
|
|
|
describe('Work1', () => {
|
|
|
|
|
const WORK1_PRICE = 100;
|
|
|
|
|
const STAKE_DURATION = 60;
|
|
|
|
|
async function deploy() {
|
|
|
|
|
// Contracts are deployed using the first signer/account by default
|
|
|
|
|
const [account1, account2] = await ethers.getSigners();
|
|
|
|
@ -34,15 +36,173 @@ describe('Work1', () => {
|
|
|
|
|
expect(await work1.stakeCount()).to.equal(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('Should be able to receive availability stake', async () => {
|
|
|
|
|
const { dao, work1, account1 } = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, 60);
|
|
|
|
|
expect(await dao.balanceOf(account1)).to.equal(50);
|
|
|
|
|
expect(await dao.balanceOf(work1.target)).to.equal(50);
|
|
|
|
|
expect(await work1.stakeCount()).to.equal(1);
|
|
|
|
|
const stake = await work1.stakes(0);
|
|
|
|
|
expect(stake.worker).to.equal(account1);
|
|
|
|
|
expect(stake.amount).to.equal(50);
|
|
|
|
|
expect(stake.endTime).to.equal(await time.latest() + 60);
|
|
|
|
|
describe('Stake availability', () => {
|
|
|
|
|
let dao;
|
|
|
|
|
let work1;
|
|
|
|
|
let account1;
|
|
|
|
|
let account2;
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
|
const setup = await loadFixture(deploy);
|
|
|
|
|
dao = setup.dao;
|
|
|
|
|
work1 = setup.work1;
|
|
|
|
|
account1 = setup.account1;
|
|
|
|
|
account2 = setup.account2;
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('Should be able to stake availability', async () => {
|
|
|
|
|
expect(await dao.balanceOf(account1)).to.equal(50);
|
|
|
|
|
expect(await dao.balanceOf(work1.target)).to.equal(50);
|
|
|
|
|
expect(await work1.stakeCount()).to.equal(1);
|
|
|
|
|
const stake = await work1.stakes(0);
|
|
|
|
|
expect(stake.worker).to.equal(account1);
|
|
|
|
|
expect(stake.amount).to.equal(50);
|
|
|
|
|
expect(stake.endTime).to.equal(await time.latest() + STAKE_DURATION);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to reclaim staked availability after duration elapses', async () => {
|
|
|
|
|
expect(await dao.balanceOf(account1)).to.equal(50);
|
|
|
|
|
time.increase(STAKE_DURATION + 1);
|
|
|
|
|
await work1.reclaimAvailability(0);
|
|
|
|
|
expect(await dao.balanceOf(account1)).to.equal(100);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to reclaim staked availability before duration elapses', async () => {
|
|
|
|
|
await expect(work1.reclaimAvailability(0)).to.be.revertedWith('Stake duration has not yet elapsed');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to reclaim availability staked by another account', async () => {
|
|
|
|
|
time.increase(STAKE_DURATION + 1);
|
|
|
|
|
await expect(work1.connect(account2).reclaimAvailability(0)).to.be.revertedWith('Worker can only reclaim their own availability stake');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to extend the duration of an availability stake before it expires', async () => {
|
|
|
|
|
await time.increase(STAKE_DURATION / 2);
|
|
|
|
|
await work1.extendAvailability(0, STAKE_DURATION);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to extend the duration of an availability stake after it expires', async () => {
|
|
|
|
|
await time.increase(STAKE_DURATION * 2);
|
|
|
|
|
await work1.extendAvailability(0, STAKE_DURATION);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to extend the duration of another worker\'s availability stake', async () => {
|
|
|
|
|
await time.increase(STAKE_DURATION * 2);
|
|
|
|
|
await expect(work1.connect(account2).extendAvailability(0, STAKE_DURATION)).to.be.revertedWith('Worker can only extend their own availability stake');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Request and assign work', () => {
|
|
|
|
|
it('should be able to request work and assign to a worker', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(requestWork()).to.emit(work1, 'WorkAssigned').withArgs(account1, 0);
|
|
|
|
|
expect(await work1.requestCount()).to.equal(1);
|
|
|
|
|
const request = await work1.requests(0);
|
|
|
|
|
expect(request.customer).to.equal(account2);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to request work if there are no availability stakes', async () => {
|
|
|
|
|
const {
|
|
|
|
|
work1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not assign work to an expired availability stake', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await time.increase(61);
|
|
|
|
|
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not assign work to the same availability stake twice', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(requestWork()).to.emit(work1, 'WorkAssigned').withArgs(account1, 0);
|
|
|
|
|
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Work evidence and approval/disapproval', () => {
|
|
|
|
|
it('should be able to submit work evidence', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(work1.submitWorkEvidence(0)).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to submit work evidence twice', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(work1.submitWorkEvidence(0)).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
|
|
|
|
|
await expect(work1.submitWorkEvidence(0)).to.be.revertedWith('Status must be Requested');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to submit work evidence for a different worker', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(work1.connect(account2).submitWorkEvidence(0)).to.be.revertedWith('Worker can only submit evidence for work they are assigned');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be able to submit work approval', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await work1.submitWorkEvidence(0);
|
|
|
|
|
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to submit work approval/disapproval twice', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await work1.submitWorkEvidence(0);
|
|
|
|
|
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
|
|
|
|
|
await expect(work1.submitWorkApproval(0, true)).to.be.revertedWith('Status must be EvidenceSubmitted');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to submit work evidence after work approval', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await work1.submitWorkEvidence(0);
|
|
|
|
|
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
|
|
|
|
|
await expect(work1.submitWorkEvidence(0)).to.be.revertedWith('Status must be Requested');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not be able to submit work approval/disapproval before work evidence', async () => {
|
|
|
|
|
const {
|
|
|
|
|
dao, work1, account1, account2,
|
|
|
|
|
} = await loadFixture(deploy);
|
|
|
|
|
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
|
|
|
|
|
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
|
|
|
|
|
await expect(work1.submitWorkApproval(0, true)).to.be.revertedWith('Status must be EvidenceSubmitted');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|