add citations to Post

This commit is contained in:
Ladd Hoffman 2024-04-10 15:47:25 -05:00
parent 57b64f7977
commit 5c712f350a
9 changed files with 62 additions and 32 deletions

View File

@ -83,7 +83,7 @@ class Post {
// Upload hash to blockchain
async publish(DAO, account) {
await DAO.methods.addPost(account, this.hash).send({
await DAO.methods.addPost(account, this.hash, []).send({
from: account,
gas: 1000000,
});

View File

@ -2,6 +2,7 @@
pragma solidity ^0.8.24;
import "./DAO.sol";
import "./core/Forum.sol";
import "./WorkContract.sol";
import "./interfaces/IOnValidate.sol";
@ -26,7 +27,11 @@ contract Onboarding is WorkContract, IOnValidate {
request.status = WorkStatus.ApprovalSubmitted;
request.approval = approval;
// Make work evidence post
uint postIndex = dao.addPost(stake.worker, request.evidenceContentId);
uint postIndex = dao.addPost(
stake.worker,
request.evidenceContentId,
request.citations
);
emit WorkApprovalSubmitted(requestIndex, approval);
// Initiate validation pool
uint poolIndex = dao.initiateValidationPool{
@ -69,9 +74,11 @@ contract Onboarding is WorkContract, IOnValidate {
payable(request.customer).transfer(request.fee / 10);
return 1;
}
Citation[] memory emptyCitations;
uint postIndex = dao.addPost(
request.customer,
request.requestContentId
request.requestContentId,
emptyCitations
);
dao.initiateValidationPool{value: request.fee / 10}(
postIndex,

View File

@ -71,7 +71,9 @@ contract Proposals is DAOContract, IOnValidate {
// TODO: Consider taking author as a parameter,
// or else accepting a postIndex instead of contentId,
// or support post lookup by contentId
uint postIndex = dao.addPost(author, contentId);
// TODO: Take citations as a parameter
Citation[] memory emptyCitations;
uint postIndex = dao.addPost(author, contentId, emptyCitations);
proposalIndex = proposalCount++;
Proposal storage proposal = proposals[proposalIndex];
proposal.sender = msg.sender;

View File

@ -3,6 +3,7 @@ pragma solidity ^0.8.24;
import "./DAO.sol";
import "./Proposals.sol";
import "./core/Forum.sol";
import "./interfaces/IAcceptAvailability.sol";
import "./interfaces/IOnProposalAccepted.sol";
import "hardhat/console.sol";
@ -33,6 +34,7 @@ abstract contract WorkContract is
uint stakeIndex;
string requestContentId;
string evidenceContentId;
Citation[] citations;
bool approval;
}
@ -142,7 +144,8 @@ abstract contract WorkContract is
/// Accept work evidence from worker
function submitWorkEvidence(
uint requestIndex,
string calldata evidenceContentId
string calldata evidenceContentId,
Citation[] calldata citations
) external {
WorkRequest storage request = requests[requestIndex];
require(
@ -156,6 +159,9 @@ abstract contract WorkContract is
);
request.status = WorkStatus.EvidenceSubmitted;
request.evidenceContentId = evidenceContentId;
for (uint i = 0; i < citations.length; i++) {
request.citations.push(citations[i]);
}
emit WorkEvidenceSubmitted(requestIndex);
}
@ -173,7 +179,11 @@ abstract contract WorkContract is
request.status = WorkStatus.ApprovalSubmitted;
request.approval = approval;
// Make work evidence post
uint postIndex = dao.addPost(stake.worker, request.evidenceContentId);
uint postIndex = dao.addPost(
stake.worker,
request.evidenceContentId,
request.citations
);
emit WorkApprovalSubmitted(requestIndex, approval);
// Initiate validation pool
uint poolIndex = dao.initiateValidationPool{value: request.fee}(

View File

@ -3,13 +3,18 @@ pragma solidity ^0.8.24;
import "./Reputation.sol";
struct Citation {
int[2] weight;
uint targetPostIndex;
}
struct Post {
uint id;
address sender;
address author;
string contentId;
uint reputation;
// TODO: citations
Citation[] citations;
}
contract Forum is Reputation {
@ -20,7 +25,8 @@ contract Forum is Reputation {
function addPost(
address author,
string calldata contentId
string calldata contentId,
Citation[] calldata citations
) external returns (uint postIndex) {
postIndex = postCount++;
Post storage post = posts[postIndex];
@ -28,6 +34,9 @@ contract Forum is Reputation {
post.sender = msg.sender;
post.id = postIndex;
post.contentId = contentId;
for (uint i = 0; i < citations.length; i++) {
post.citations.push(citations[i]);
}
emit PostAdded(postIndex);
}
@ -36,4 +45,6 @@ contract Forum is Reputation {
post.reputation = amount;
_update(address(this), post.author, amount);
}
function _propagateValue() internal {}
}

View File

@ -23,7 +23,7 @@ describe('DAO', () => {
it('should be able to add a post', async () => {
const { dao, account1 } = await loadFixture(deploy);
const contentId = 'some-id';
await expect(dao.addPost(account1, contentId)).to.emit(dao, 'PostAdded').withArgs(0);
await expect(dao.addPost(account1, contentId, [])).to.emit(dao, 'PostAdded').withArgs(0);
const post = await dao.posts(0);
expect(post.author).to.equal(account1);
expect(post.sender).to.equal(account1);
@ -33,7 +33,7 @@ describe('DAO', () => {
it('should be able to add a post on behalf of another account', async () => {
const { dao, account1, account2 } = await loadFixture(deploy);
const contentId = 'some-id';
await dao.addPost(account2, contentId);
await dao.addPost(account2, contentId, []);
const post = await dao.posts(0);
expect(post.author).to.equal(account2);
expect(post.sender).to.equal(account1);
@ -68,7 +68,7 @@ describe('DAO', () => {
beforeEach(async () => {
({ dao, account1, account2 } = await loadFixture(deploy));
await dao.addPost(account1, 'content-id');
await dao.addPost(account1, 'content-id', []);
const init = () => initiateValidationPool({ fee: POOL_FEE });
await expect(init()).to.emit(dao, 'ValidationPoolInitiated').withArgs(0);
expect(await dao.validationPoolCount()).to.equal(1);
@ -232,7 +232,7 @@ describe('DAO', () => {
beforeEach(async () => {
time.increase(POOL_DURATION + 1);
await dao.evaluateOutcome(0);
await dao.addPost(account2, 'content-id');
await dao.addPost(account2, 'content-id', []);
const init = () => initiateValidationPool({ postIndex: 1 });
await expect(init()).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
time.increase(POOL_DURATION + 1);

View File

@ -19,7 +19,7 @@ describe('Onboarding', () => {
const Onboarding = await ethers.getContractFactory('Onboarding');
const onboarding = await Onboarding.deploy(dao.target, proposals.target, PRICE);
await dao.addPost(account1, 'content-id');
await dao.addPost(account1, 'content-id', []);
const callbackData = ethers.AbiCoder.defaultAbiCoder().encode([], []);
await dao.initiateValidationPool(
0,
@ -66,7 +66,7 @@ describe('Onboarding', () => {
it('should be able to submit work approval', async () => {
await onboarding.connect(account2).requestWork('req-content-id', { value: PRICE });
await onboarding.submitWorkEvidence(0, 'evidence-content-id');
await onboarding.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(onboarding.submitWorkApproval(0, true))
.to.emit(dao, 'ValidationPoolInitiated').withArgs(1)
.to.emit(onboarding, 'WorkApprovalSubmitted').withArgs(0, true);
@ -82,7 +82,7 @@ describe('Onboarding', () => {
it('should be able to submit work disapproval', async () => {
await onboarding.connect(account2).requestWork('req-content-id', { value: PRICE });
await onboarding.submitWorkEvidence(0, 'evidence-content-id');
await onboarding.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(onboarding.submitWorkApproval(0, false))
.to.emit(dao, 'ValidationPoolInitiated').withArgs(1)
.to.emit(onboarding, 'WorkApprovalSubmitted').withArgs(0, false);
@ -90,16 +90,16 @@ describe('Onboarding', () => {
it('should not be able to submit work approval/disapproval twice', async () => {
await onboarding.connect(account2).requestWork('req-content-id', { value: PRICE });
await onboarding.submitWorkEvidence(0, 'evidence-content-id');
await onboarding.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(onboarding.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await expect(onboarding.submitWorkApproval(0, true)).to.be.revertedWith('Status must be EvidenceSubmitted');
});
it('should not be able to submit work evidence after work approval', async () => {
await onboarding.connect(account2).requestWork('req-content-id', { value: PRICE });
await onboarding.submitWorkEvidence(0, 'evidence-content-id');
await onboarding.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(onboarding.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await expect(onboarding.submitWorkEvidence(0, 'evidence-content-id')).to.be.revertedWith('Status must be Requested');
await expect(onboarding.submitWorkEvidence(0, 'evidence-content-id', [])).to.be.revertedWith('Status must be Requested');
});
it('should not be able to submit work approval/disapproval before work evidence', async () => {
@ -115,7 +115,7 @@ describe('Onboarding', () => {
} = await loadFixture(deploy);
await dao.stakeAvailability(onboarding.target, 50, STAKE_DURATION);
await onboarding.connect(account2).requestWork('req-content-id', { value: PRICE });
await onboarding.submitWorkEvidence(0, 'evidence-content-id');
await onboarding.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(onboarding.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await time.increase(86401);
await expect(dao.evaluateOutcome(1)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
@ -137,7 +137,7 @@ describe('Onboarding', () => {
} = await loadFixture(deploy);
await dao.stakeAvailability(onboarding.target, 40, STAKE_DURATION);
await onboarding.connect(account2).requestWork('req-content-id', { value: PRICE });
await onboarding.submitWorkEvidence(0, 'evidence-content-id');
await onboarding.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(onboarding.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await dao.stakeOnValidationPool(1, 60, false);
await time.increase(86401);

View File

@ -16,8 +16,8 @@ describe('Proposal', () => {
const Proposals = await ethers.getContractFactory('Proposals');
const proposals = await Proposals.deploy(dao.target);
await dao.addPost(account1, 'some-content-id');
await dao.addPost(account2, 'some-other-content-id');
await dao.addPost(account1, 'some-content-id', []);
await dao.addPost(account2, 'some-other-content-id', []);
const callbackData = ethers.AbiCoder.defaultAbiCoder().encode([], []);
await dao.initiateValidationPool(
0,

View File

@ -19,7 +19,7 @@ describe('Work1', () => {
const Work1 = await ethers.getContractFactory('Work1');
const work1 = await Work1.deploy(dao.target, proposals.target, WORK1_PRICE);
await dao.addPost(account1, 'some-content-id');
await dao.addPost(account1, 'some-content-id', []);
const callbackData = ethers.AbiCoder.defaultAbiCoder().encode([], []);
await dao.initiateValidationPool(
0,
@ -186,24 +186,24 @@ describe('Work1', () => {
it('should be able to submit work evidence', async () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await expect(work1.submitWorkEvidence(0, 'evidence-content-id')).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
await expect(work1.submitWorkEvidence(0, 'evidence-content-id', [])).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
});
it('should not be able to submit work evidence twice', async () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await expect(work1.submitWorkEvidence(0, 'evidence-content-id')).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
await expect(work1.submitWorkEvidence(0, 'evidence-content-id')).to.be.revertedWith('Status must be Requested');
await expect(work1.submitWorkEvidence(0, 'evidence-content-id', [])).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
await expect(work1.submitWorkEvidence(0, 'evidence-content-id', [])).to.be.revertedWith('Status must be Requested');
});
it('should not be able to submit work evidence for a different worker', async () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await expect(work1.connect(account2).submitWorkEvidence(0, 'evidence-content-id'))
await expect(work1.connect(account2).submitWorkEvidence(0, 'evidence-content-id', []))
.to.be.revertedWith('Worker can only submit evidence for work they are assigned');
});
it('should be able to submit work approval', async () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await work1.submitWorkEvidence(0, 'evidence-content-id');
await work1.submitWorkEvidence(0, 'evidence-content-id', []);
expect(await dao.balanceOf(account1)).to.equal(100);
expect(await dao.balanceOf(work1.target)).to.equal(0);
await expect(work1.submitWorkApproval(0, true))
@ -227,7 +227,7 @@ describe('Work1', () => {
it('should be able to submit work disapproval', async () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await work1.submitWorkEvidence(0, 'evidence-content-id');
await work1.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(work1.submitWorkApproval(0, false))
.to.emit(dao, 'ValidationPoolInitiated').withArgs(1)
.to.emit(work1, 'WorkApprovalSubmitted').withArgs(0, false);
@ -235,16 +235,16 @@ describe('Work1', () => {
it('should not be able to submit work approval/disapproval twice', async () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await work1.submitWorkEvidence(0, 'evidence-content-id');
await work1.submitWorkEvidence(0, 'evidence-content-id', []);
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 () => {
await work1.connect(account2).requestWork('req-content-id', { value: WORK1_PRICE });
await work1.submitWorkEvidence(0, 'evidence-content-id');
await work1.submitWorkEvidence(0, 'evidence-content-id', []);
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await expect(work1.submitWorkEvidence(0, 'evidence-content-id')).to.be.revertedWith('Status must be Requested');
await expect(work1.submitWorkEvidence(0, 'evidence-content-id', [])).to.be.revertedWith('Status must be Requested');
});
it('should not be able to submit work approval/disapproval before work evidence', async () => {