event subscriptions
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 39s Details

This commit is contained in:
Ladd Hoffman 2024-03-10 11:55:59 -05:00
parent 395092b1fd
commit fa1dbb897a
13 changed files with 225 additions and 90 deletions

View File

@ -15,7 +15,7 @@
"react": "^18.2.0",
"react-bootstrap": "^2.10.1",
"react-dom": "^18.2.0",
"web3": "^4.5.0"
"web3": "^4.6.0"
},
"devDependencies": {
"@stylistic/eslint-plugin": "^1.6.3",
@ -7942,6 +7942,11 @@
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz",
"integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg=="
},
"node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
},
"node_modules/evp_bytestokey": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
@ -14371,25 +14376,25 @@
}
},
"node_modules/web3": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/web3/-/web3-4.5.0.tgz",
"integrity": "sha512-qWvmuFwmu1b4IVZz1/vahEP1VrRlnXLJJO6s88oRcOgOf21Q26rIyxqIDtKgKe7a4X29TqBocC1eP4CtZulAGA==",
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/web3/-/web3-4.6.0.tgz",
"integrity": "sha512-hoI6r29B4kjxINI21rBVaE0Bz0hwtW+Sbppn5ZDTWn5PSQpBW4ecYFDVKVE6K3gbmSjY2fknu2cjBTqha7S53A==",
"dependencies": {
"web3-core": "^4.3.2",
"web3-errors": "^1.1.4",
"web3-eth": "^4.4.0",
"web3-eth": "^4.5.0",
"web3-eth-abi": "^4.2.0",
"web3-eth-accounts": "^4.1.1",
"web3-eth-contract": "^4.2.0",
"web3-eth-ens": "^4.0.8",
"web3-eth-ens": "^4.1.0",
"web3-eth-iban": "^4.0.7",
"web3-eth-personal": "^4.0.8",
"web3-net": "^4.0.7",
"web3-providers-http": "^4.1.0",
"web3-providers-ws": "^4.0.7",
"web3-rpc-methods": "^1.1.4",
"web3-types": "^1.4.0",
"web3-utils": "^4.2.0",
"web3-rpc-methods": "^1.2.0",
"web3-types": "^1.5.0",
"web3-utils": "^4.2.1",
"web3-validator": "^2.0.4"
},
"engines": {
@ -14432,9 +14437,9 @@
}
},
"node_modules/web3-eth": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.4.0.tgz",
"integrity": "sha512-HswKdzF44wUrciRAtEJaml9O7rDYDxElHmFs+27WcO3nel2zku+n0xs4e2ZAehfrCZ+05/y7TgnOZnaDU8Fb/A==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.5.0.tgz",
"integrity": "sha512-crisE46o/SHMVm+XHAXEaR8k76NCImq+hi0QQEJ+VaLZbDobI/Gvog1HwTukDUDRgnYSAFGqD0cTRyAwDurwpA==",
"dependencies": {
"setimmediate": "^1.0.5",
"web3-core": "^4.3.2",
@ -14443,9 +14448,9 @@
"web3-eth-accounts": "^4.1.1",
"web3-net": "^4.0.7",
"web3-providers-ws": "^4.0.7",
"web3-rpc-methods": "^1.1.4",
"web3-types": "^1.3.1",
"web3-utils": "^4.1.1",
"web3-rpc-methods": "^1.2.0",
"web3-types": "^1.5.0",
"web3-utils": "^4.2.1",
"web3-validator": "^2.0.4"
},
"engines": {
@ -14506,19 +14511,19 @@
}
},
"node_modules/web3-eth-ens": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-4.0.8.tgz",
"integrity": "sha512-nj0JfeD45BbzVJcVYpUJnSo8iwDcY9CQ7CZhhIVVOFjvpMAPw0zEwjTvZEIQyCW61OoDG9xcBzwxe2tZoYhMRw==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-4.1.0.tgz",
"integrity": "sha512-B+QsXXJb/gJkHb1ZGfErNLeFI9zUf2TsQcvi2+NsSuzFwvjIO5IyrrGtqBmXMLWC8ZikMOHuc8ZfFuGrELl31Q==",
"dependencies": {
"@adraffy/ens-normalize": "^1.8.8",
"web3-core": "^4.3.0",
"web3-errors": "^1.1.3",
"web3-eth": "^4.3.1",
"web3-eth-contract": "^4.1.2",
"web3-core": "^4.3.2",
"web3-errors": "^1.1.4",
"web3-eth": "^4.5.0",
"web3-eth-contract": "^4.2.0",
"web3-net": "^4.0.7",
"web3-types": "^1.3.0",
"web3-utils": "^4.0.7",
"web3-validator": "^2.0.3"
"web3-types": "^1.5.0",
"web3-utils": "^4.2.1",
"web3-validator": "^2.0.4"
},
"engines": {
"node": ">=14",
@ -14628,13 +14633,13 @@
}
},
"node_modules/web3-rpc-methods": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/web3-rpc-methods/-/web3-rpc-methods-1.1.4.tgz",
"integrity": "sha512-LTFNg4LFaeU8K9ecuT8fHDp/LOXyxCneeZjCrRYIW1u82Ly52SrY55FIzMIISGoG/iT5Wh7UiHOB3CQsWLBmbQ==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/web3-rpc-methods/-/web3-rpc-methods-1.2.0.tgz",
"integrity": "sha512-CWJ/g4I4WyYvLkf21wCZAehdhU/VjX/OAPHnqF5/FPDJlogOsOnGXHqi1Z5AP+ocdt395PNubd8jyMMJoYGSBA==",
"dependencies": {
"web3-core": "^4.3.2",
"web3-types": "^1.3.1",
"web3-validator": "^2.0.3"
"web3-types": "^1.5.0",
"web3-validator": "^2.0.4"
},
"engines": {
"node": ">=14",
@ -14642,22 +14647,23 @@
}
},
"node_modules/web3-types": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.4.0.tgz",
"integrity": "sha512-QnGDNredYqtZ49YD1pIPhsQTJJTOnYPCOnvrUs4/3XzeQLuDM+bAJ8fZ6U2nGEV77h81z2Ins6RE/f40yltvww==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.5.0.tgz",
"integrity": "sha512-geWuMIeegQ8AedKAO6wO4G4j1gyQ1F/AyKLMw2vud4bsfZayyzWJgCMDZtjYMm5uo2a7i8j1W3/4QFmzlSy5cw==",
"engines": {
"node": ">=14",
"npm": ">=6.12.0"
}
},
"node_modules/web3-utils": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.2.0.tgz",
"integrity": "sha512-UE7tmqPnC6sD0kpHhZiO9Zu8q7hiBItCQhnmxoMxk8OI91qlBWw6L7w1VNZo7TMBWH1Qe4R5l8h2vaoQCizVyA==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.2.1.tgz",
"integrity": "sha512-Fk29BlEqD9Q9Cnw4pBkKw7czcXiRpsSco/BzEUl4ye0ZTSHANQFfjsfQmNm4t7uY11u6Ah+8F3tNjBeU4CA80A==",
"dependencies": {
"ethereum-cryptography": "^2.0.0",
"eventemitter3": "^5.0.1",
"web3-errors": "^1.1.4",
"web3-types": "^1.4.0",
"web3-types": "^1.5.0",
"web3-validator": "^2.0.4"
},
"engines": {

View File

@ -17,7 +17,7 @@
"react": "^18.2.0",
"react-bootstrap": "^2.10.1",
"react-dom": "^18.2.0",
"web3": "^4.5.0"
"web3": "^4.6.0"
},
"devDependencies": {
"@stylistic/eslint-plugin": "^1.6.3",

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useSDK } from '@metamask/sdk-react';
import { Web3 } from 'web3';
import Button from 'react-bootstrap/Button';
@ -6,8 +6,8 @@ import Button from 'react-bootstrap/Button';
import DAOArtifact from './assets/DAO.json';
import work1Artifact from './assets/Work1.json';
const work1Address = '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853';
const DAOAddress = '0x0165878A594ca255338adfa4d48449f69242Eb8F';
const DAOAddress = '0x91ffddC013E2Df43E8FB177922d762bC8D776e79';
const work1Address = '0x08673dE03e1e9b4c9A0aF99463fa4DEFD3891987';
function App() {
const {
@ -20,28 +20,60 @@ function App() {
const [balanceEther, setBalanceEther] = useState();
const [reputation, setReputation] = useState();
const [validationPoolCount, setValidationPoolCount] = useState();
const [latestPoolIndex, setLatestPoolIndex] = useState();
const [votePasses, setVotePasses] = useState();
const watchReputationNFT = useCallback(async (tokenId) => {
await provider.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC721',
options: {
address: DAOAddress,
tokenId: BigInt(tokenId).toString(),
},
},
});
}, [provider]);
useEffect(() => {
if (!provider) return;
const web3 = new Web3(provider);
const work1Contract = new web3.eth.Contract(work1Artifact.abi, work1Address);
const DAOContract = new web3.eth.Contract(DAOArtifact.abi, DAOAddress);
const getPrice = async () => {
const fetchPrice = async () => {
const priceWei = await work1Contract.methods.price().call();
setWork1Price(web3.utils.fromWei(priceWei, 'ether'));
};
const getReputation = async () => {
const fetchReputation = async () => {
setReputation(await DAOContract.methods.valueOf(0).call());
};
const getValidationPoolCount = async () => {
const fetchValidationPoolCount = async () => {
setValidationPoolCount(await DAOContract.methods.validationPoolCount().call());
};
getPrice();
getReputation();
getValidationPoolCount();
fetchPrice();
fetchReputation();
fetchValidationPoolCount();
setWork1(work1Contract);
setDAO(DAOContract);
}, [provider]);
DAOContract.events.ValidationPoolInitiated({ fromBlock: 'latest' }).on('data', (event) => {
console.log('event: validation pool initiated', event);
setLatestPoolIndex(event.returnValues.poolIndex);
fetchValidationPoolCount();
});
DAOContract.events.ValidationPoolResolved({ fromBlock: 'latest' }).on('data', (event) => {
console.log('event: validation pool resolved', event);
setVotePasses(event.returnValues.votePasses);
if (event.returnValues.votePasses) {
watchReputationNFT(event.returnValues.newTokenId);
}
});
}, [provider, watchReputationNFT]);
useEffect(() => {
if (provider && balance) {
@ -67,8 +99,6 @@ function App() {
};
const initiateValidationPool = async () => {
const subscription = await DAO.events.ValidationPoolInitiated({ fromBlock: 'latest' });
subscription.once('data', (event) => console.log('event: validation pool initiated', event));
const poolDuration = 0;
await DAO.methods.initiateValidationPool(account, poolDuration).send({
from: account,
@ -78,7 +108,7 @@ function App() {
};
const evaluateOutcome = async () => {
await DAO.methods.evaluateOutcome(0).send({
await DAO.methods.evaluateOutcome(latestPoolIndex).send({
from: account,
gas: 1000000,
});
@ -86,15 +116,15 @@ function App() {
// const stakeAvailability = async () => { }
const requestWork = async () => {
work1.events.WorkAssigned(() => {
console.log('event callback');
});
await work1.methods.requestWork().send({
from: account,
gas: 1000000,
});
};
// const requestWork = async () => {
// work1.events.WorkAssigned(() => {
// console.log('event callback');
// });
// await work1.methods.requestWork().send({
// from: account,
// gas: 1000000,
// });
// };
return (
<>
@ -126,11 +156,14 @@ function App() {
<div>
<Button onClick={() => evaluateOutcome()}>Evaluate Outcome</Button>
</div>
<div>
{`Outcome: ${votePasses}`}
</div>
<div>
{`Work1 Price: ${work1Price} ETH`}
</div>
<div>
<Button onClick={() => requestWork()}>Request Work</Button>
{ /* <Button onClick={() => requestWork()}>Request Work</Button> */ }
</div>
</>
)}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,9 +16,9 @@ ReactDOM.createRoot(document.getElementById('root')).render(
url: window.location.href,
},
enableAnalytics: false,
infuraAPIKey: '579d264c5f534aa1aefd6be323cb1a35',
// infuraAPIKey: '579d264c5f534aa1aefd6be323cb1a35',
readonlyRPCMap: {
'0x7a69': 'http://127.0.0.1:8545/',
'0x539': 'http://127.0.0.1:8545/',
},
}}
>

View File

@ -6,7 +6,6 @@ module.exports = {
'airbnb',
'plugin:chai-friendly/recommended',
],
ignorePatterns: ['hardhat.config.js'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: [
@ -16,7 +15,7 @@ module.exports = {
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: ['test/**', 'scripts/**'],
devDependencies: ['hardhat.config.js', 'test/**', 'scripts/**'],
optionalDependencies: false,
peerDependencies: false,
},

4
ethereum/.mocharc.json Normal file
View File

@ -0,0 +1,4 @@
{
"require": "hardhat/register",
"timeout": 40000
}

View File

@ -47,6 +47,7 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
// TODO: Add forum parameters
event ValidationPoolInitiated(uint poolIndex);
event ValidationPoolResolved(bool votePasses, uint256 newTokenId);
/// Inspect the value of a given reputation NFT
function valueOf(uint256 tokenId) public view returns (uint256 value) {
@ -98,6 +99,7 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
address author,
uint duration
) public payable returns (uint poolIndex) {
require(msg.value > 0, "Fee is required to initiate validation pool");
poolIndex = validationPoolCount++;
ValidationPool storage pool = validationPools[poolIndex];
pool.author = author;
@ -174,6 +176,7 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
// when no reputation has yet been minted.
votePasses = amountFor >= amountAgainst;
pool.resolved = true;
emit ValidationPoolResolved(votePasses, pool.tokenIdFor);
// If the outcome is true, value of all stakes against the pool should be distributed among the stakes in favor.
// If the outcome is false, value of all stakes for the pool should be distributed among the stakes against.
uint256 amountFromWinners;
@ -241,8 +244,10 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
}
// Distribute fee proportionatly among all reputation holders
for (uint tokenId = 0; tokenId < nextTokenId; tokenId++) {
uint256 share = (pool.fee * valueOf(tokenId)) / totalValue;
address recipient = ownerOf(tokenId);
// Don't count tokens owned by this contract, as these are part of validation pools in progress
if (recipient == address(this)) continue;
uint256 share = (pool.fee * valueOf(tokenId)) / totalValue;
// TODO: For efficiency this could be modified to hold the funds for recipients to withdraw
payable(recipient).transfer(share);
}

View File

@ -1,6 +1,15 @@
require('@nomicfoundation/hardhat-toolbox');
require('dotenv').config();
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: '0.8.24',
networks: {
hardhat: {
accounts: {
mnemonic: process.env.SEED_PHRASE,
},
chainId: 1337,
},
},
};

View File

@ -9,11 +9,13 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@openzeppelin/contracts": "^5.0.2"
"@openzeppelin/contracts": "^5.0.2",
"dotenv": "^16.4.5"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.6",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"chai": "^4.4.1",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-chai-friendly": "^0.7.4",
@ -22,6 +24,7 @@
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0",
"hardhat": "^2.20.1",
"mocha": "^10.3.0",
"prettier": "^3.2.5",
"prettier-plugin-solidity": "^1.3.1"
}
@ -2722,7 +2725,6 @@
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true,
"peer": true,
"engines": {
"node": "*"
}
@ -3131,7 +3133,6 @@
"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
"integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
"dev": true,
"peer": true,
"dependencies": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.3",
@ -3753,6 +3754,17 @@
"node": ">=6.0.0"
}
},
"node_modules/dotenv": {
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/elliptic": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
@ -6670,7 +6682,6 @@
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
"integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
"dev": true,
"peer": true,
"dependencies": {
"get-func-name": "^2.0.1"
}
@ -7438,7 +7449,6 @@
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true,
"peer": true,
"engines": {
"node": "*"
}

View File

@ -11,6 +11,7 @@
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.6",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"chai": "^4.4.1",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-chai-friendly": "^0.7.4",
@ -19,10 +20,12 @@
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react-hooks": "^4.6.0",
"hardhat": "^2.20.1",
"mocha": "^10.3.0",
"prettier": "^3.2.5",
"prettier-plugin-solidity": "^1.3.1"
},
"dependencies": {
"@openzeppelin/contracts": "^5.0.2"
"@openzeppelin/contracts": "^5.0.2",
"dotenv": "^16.4.5"
}
}

View File

@ -1,4 +1,5 @@
const {
time,
loadFixture,
} = require('@nomicfoundation/hardhat-toolbox/network-helpers');
const { expect } = require('chai');
@ -18,23 +19,69 @@ describe('DAO', () => {
return { dao, account1, account2 };
}
it('Should deploy', async () => {
const { dao } = await loadFixture(deployDAO);
expect(dao).to.exist;
expect(await dao.totalValue()).to.equal(0);
});
describe('Validation Pool', () => {
it('Should deploy', async () => {
const { dao } = await loadFixture(deployDAO);
expect(dao).to.exist;
expect(await dao.totalValue()).to.equal(0);
let dao;
let account1;
const POOL_DURATION = 3600; // 1 hour
const fee = 100;
beforeEach(async () => {
const setup = await loadFixture(deployDAO);
dao = setup.dao;
account1 = setup.account1;
const init = () => dao.initiateValidationPool(account1, POOL_DURATION, { value: fee });
await expect(init()).to.emit(dao, 'ValidationPoolInitiated').withArgs(0);
expect(await dao.validationPoolCount()).to.equal(1);
expect(await dao.ownerOf(0)).to.equal(dao.target);
});
describe('Initiate validation pool', () => {
it('Should initiate', async () => {
const POOL_DURATION = 3600; // 1 hour
const { dao, account1 } = await loadFixture(deployDAO);
const init = () => dao.initiateValidationPool(account1, POOL_DURATION);
await expect(init()).to.emit(dao, 'ValidationPoolInitiated').withArgs(0);
const pool = await dao.validationPools(0);
expect(pool).to.exist;
expect(pool.duration).to.equal(POOL_DURATION);
});
it('should not be able to initiate a validation pool without a fee', async () => {
const setup = await loadFixture(deployDAO);
const init = () => setup.dao.initiateValidationPool(setup.account1, POOL_DURATION);
await expect(init()).to.be.revertedWith('Fee is required to initiate validation pool');
});
it('should be able to initiate a second validation pool', async () => {
const init = () => dao.initiateValidationPool(account1, POOL_DURATION, { value: fee });
await expect(init()).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
expect(await dao.validationPoolCount()).to.equal(2);
});
it('Should be able to fetch pool instance', async () => {
const pool = await dao.validationPools(0);
expect(pool).to.exist;
expect(pool.duration).to.equal(POOL_DURATION);
});
it('should not be able to evaluate outcome before duration has elapsed', async () => {
await expect(dao.evaluateOutcome(0)).to.be.revertedWith('Pool end time has not yet arrived');
});
it('should be able to evaluate outcome after duration has elapsed', async () => {
time.increase(POOL_DURATION + 1);
await expect(dao.evaluateOutcome(0)).to.emit(dao, 'ValidationPoolResolved').withArgs(true, 0);
expect(await dao.ownerOf(0)).to.equal(account1);
});
it('should not be able to evaluate outcome more than once', async () => {
time.increase(POOL_DURATION + 1);
await expect(dao.evaluateOutcome(0)).to.emit(dao, 'ValidationPoolResolved').withArgs(true, 0);
await expect(dao.evaluateOutcome(0)).to.be.revertedWith('Pool is already resolved');
});
it('should be able to evaluate outcome of second validation pool', async () => {
const init = () => dao.initiateValidationPool(account1, POOL_DURATION, { value: fee });
await expect(init()).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
expect(await dao.validationPoolCount()).to.equal(2);
time.increase(POOL_DURATION + 1);
await expect(dao.evaluateOutcome(1)).to.emit(dao, 'ValidationPoolResolved').withArgs(true, 2);
expect(await dao.ownerOf(2)).to.equal(account1);
});
});
});