UI: list posts and pools
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 38s
Details
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 38s
Details
This commit is contained in:
parent
cb8d430d71
commit
123138935d
|
@ -8,8 +8,8 @@ import DAOArtifact from './assets/DAO.json';
|
|||
|
||||
const contracts = {
|
||||
'0x539': { // Hardhat
|
||||
DAO: '0x7209aa5b0B91700615bA982e4E4F1Eb967E31cf1',
|
||||
Work1: '0x4a3f03f50b542BD27DbcaDAF9A3d608AE4f5AACc',
|
||||
DAO: '0x8d914D38dD301FC4606f5aa9fEcF8A76389020d3',
|
||||
Work1: '0x050C420Cc4995B41217Eba1B54B82Fd5687e9139',
|
||||
},
|
||||
'0xaa36a7': { // Sepolia
|
||||
DAO: '0x8d914D38dD301FC4606f5aa9fEcF8A76389020d3',
|
||||
|
@ -28,9 +28,8 @@ function App() {
|
|||
const [balanceEther, setBalanceEther] = useState();
|
||||
const [reputation, setReputation] = useState();
|
||||
const [totalReputation, setTotalReputation] = useState();
|
||||
const [validationPoolCount, setValidationPoolCount] = useState();
|
||||
const [latestPoolIndex, setLatestPoolIndex] = useState();
|
||||
const [votePasses, setVotePasses] = useState();
|
||||
const [posts, setPosts] = useState([]);
|
||||
const [validationPools, setValidationPools] = useState([]);
|
||||
|
||||
// const watchReputationToken = useCallback(async () => {
|
||||
// await provider.request({
|
||||
|
@ -57,31 +56,47 @@ function App() {
|
|||
// };
|
||||
|
||||
const fetchReputation = async () => {
|
||||
console.log(`fetchReputation, account: ${account}`);
|
||||
setReputation(await DAOContract.methods.balanceOf(account).call());
|
||||
setTotalReputation(await DAOContract.methods.totalSupply().call());
|
||||
};
|
||||
|
||||
const fetchValidationPoolCount = async () => {
|
||||
setValidationPoolCount(await DAOContract.methods.validationPoolCount().call());
|
||||
const fetchPosts = async () => {
|
||||
const count = await DAOContract.methods.postCount().call();
|
||||
const promises = [];
|
||||
for (let i = 0; i < count; i += 1) {
|
||||
promises.push(DAOContract.methods.posts(i).call());
|
||||
}
|
||||
const fetchedPosts = await Promise.all(promises);
|
||||
setPosts(fetchedPosts);
|
||||
};
|
||||
|
||||
const fetchValidationPools = async () => {
|
||||
const count = await DAOContract.methods.validationPoolCount().call();
|
||||
const promises = [];
|
||||
for (let i = 0; i < count; i += 1) {
|
||||
promises.push(DAOContract.methods.validationPools(i).call());
|
||||
}
|
||||
const pools = await Promise.all(promises);
|
||||
setValidationPools(pools);
|
||||
};
|
||||
|
||||
// fetchPrice();
|
||||
fetchReputation();
|
||||
fetchValidationPoolCount();
|
||||
fetchPosts();
|
||||
fetchValidationPools();
|
||||
// setWork1(work1Contract);
|
||||
setDAO(DAOContract);
|
||||
|
||||
DAOContract.events.ValidationPoolInitiated({ fromBlock: 'latest' }).on('data', (event) => {
|
||||
console.log('event: validation pool initiated', event);
|
||||
setLatestPoolIndex(event.returnValues.poolIndex);
|
||||
fetchValidationPoolCount();
|
||||
fetchPosts();
|
||||
fetchValidationPools();
|
||||
});
|
||||
|
||||
DAOContract.events.ValidationPoolResolved({ fromBlock: 'latest' }).on('data', (event) => {
|
||||
console.log('event: validation pool resolved', event);
|
||||
setVotePasses(event.returnValues.votePasses);
|
||||
fetchReputation();
|
||||
fetchValidationPools();
|
||||
});
|
||||
}, [provider, account, chainId]);
|
||||
|
||||
|
@ -107,17 +122,24 @@ function App() {
|
|||
}
|
||||
};
|
||||
|
||||
const initiateValidationPool = async () => {
|
||||
const addPost = async () => {
|
||||
await DAO.methods.addPost(account).send({
|
||||
from: account,
|
||||
gas: 1000000,
|
||||
});
|
||||
};
|
||||
|
||||
const initiateValidationPool = async (postIndex) => {
|
||||
const poolDuration = 0;
|
||||
await DAO.methods.initiateValidationPool(account, poolDuration).send({
|
||||
await DAO.methods.initiateValidationPool(postIndex, poolDuration).send({
|
||||
from: account,
|
||||
gas: 1000000,
|
||||
value: 100,
|
||||
});
|
||||
};
|
||||
|
||||
const evaluateOutcome = async () => {
|
||||
await DAO.methods.evaluateOutcome(latestPoolIndex).send({
|
||||
const evaluateOutcome = async (poolIndex) => {
|
||||
await DAO.methods.evaluateOutcome(poolIndex).send({
|
||||
from: account,
|
||||
gas: 1000000,
|
||||
});
|
||||
|
@ -165,16 +187,75 @@ function App() {
|
|||
<Button onClick={() => disconnect()}>Disconnect</Button>
|
||||
</div>
|
||||
<div>
|
||||
{`Validation Pool Count: ${validationPoolCount}`}
|
||||
{`Posts count: ${posts.length}`}
|
||||
</div>
|
||||
<div>
|
||||
<Button onClick={() => initiateValidationPool()}>Initiate Validation Pool</Button>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Author</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{posts.map((post) => (
|
||||
<tr key={post.id}>
|
||||
<td>{post.id.toString()}</td>
|
||||
<td>{post.author}</td>
|
||||
<td>
|
||||
<Button onClick={() => initiateValidationPool(post.id)}>
|
||||
Initiate Validation Pool
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<Button onClick={() => evaluateOutcome()}>Evaluate Outcome</Button>
|
||||
<Button onClick={() => addPost()}>Add Post</Button>
|
||||
</div>
|
||||
<div>
|
||||
{`Outcome: ${votePasses}`}
|
||||
{`Validation Pool Count: ${validationPools.length}`}
|
||||
</div>
|
||||
<div>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Post ID</th>
|
||||
<th>Fee</th>
|
||||
<th>Duration</th>
|
||||
<th>End Time</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{validationPools.map((pool) => (
|
||||
<tr key={pool.id}>
|
||||
<td>{pool.id.toString()}</td>
|
||||
<td>{pool.postIndex.toString()}</td>
|
||||
<td>{pool.fee.toString()}</td>
|
||||
<td>{pool.duration.toString()}</td>
|
||||
<td>{new Date(Number(pool.endTime) * 1000).toLocaleString()}</td>
|
||||
<td>
|
||||
{pool.resolved && (pool.outcome ? 'Accepted' : 'Rejected')}
|
||||
{!pool.resolved && new Date() < new Date(Number(pool.endTime) * 1000) && 'In Progress'}
|
||||
{!pool.resolved && new Date() >= new Date(Number(pool.endTime) * 1000) && 'Ready to Evaluate'}
|
||||
</td>
|
||||
<td>
|
||||
{!pool.resolved && (
|
||||
<Button onClick={() => evaluateOutcome(pool.id)}>
|
||||
Evaluate Outcome
|
||||
</Button>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
{ /* `Work1 Price: ${work1Price} ETH` */ }
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -7,18 +7,21 @@ import "./IAcceptAvailability.sol";
|
|||
import "hardhat/console.sol";
|
||||
|
||||
struct Post {
|
||||
uint id;
|
||||
address sender;
|
||||
address author;
|
||||
}
|
||||
|
||||
struct Stake {
|
||||
uint id;
|
||||
bool inFavor;
|
||||
uint256 amount;
|
||||
address sender;
|
||||
}
|
||||
|
||||
struct ValidationPool {
|
||||
Post post;
|
||||
uint id;
|
||||
uint postIndex;
|
||||
mapping(uint => Stake) stakes;
|
||||
uint stakeCount;
|
||||
uint256 fee;
|
||||
|
@ -62,6 +65,7 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
Post storage post = posts[postIndex];
|
||||
post.author = author;
|
||||
post.sender = msg.sender;
|
||||
post.id = postIndex;
|
||||
}
|
||||
|
||||
/// Accept fee to initiate a validation pool
|
||||
|
@ -72,22 +76,25 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
uint duration
|
||||
) public payable returns (uint poolIndex) {
|
||||
require(msg.value > 0, "Fee is required to initiate validation pool");
|
||||
Post storage post = posts[postIndex];
|
||||
require(post.author != address(0), "Target post not found");
|
||||
poolIndex = validationPoolCount++;
|
||||
ValidationPool storage pool = validationPools[poolIndex];
|
||||
pool.post = posts[postIndex];
|
||||
pool.postIndex = postIndex;
|
||||
pool.fee = msg.value;
|
||||
pool.duration = duration;
|
||||
pool.endTime = block.timestamp + duration;
|
||||
pool.id = poolIndex;
|
||||
// Because we need to stake part of the mited value for the pool an part against,
|
||||
// we mint two new tokens.
|
||||
// Here we assume a minting ratio of 1, and a stakeForAuthor ratio of 0.5
|
||||
// Implementing this with adjustable parameters will require more advanced fixed point math.
|
||||
// TODO: Make minting ratio an adjustable parameter
|
||||
// TODO: Make stakeForAuthor an adjustable parameter
|
||||
_mint(pool.post.author, msg.value);
|
||||
_mint(post.author, msg.value);
|
||||
// TODO: We need a way to exclude this pending reputation from the total supply when computing fee distribution
|
||||
_stake(pool, pool.post.author, msg.value / 2, true);
|
||||
_stake(pool, pool.post.author, msg.value / 2, false);
|
||||
_stake(pool, post.author, msg.value / 2, true);
|
||||
_stake(pool, post.author, msg.value / 2, false);
|
||||
emit ValidationPoolInitiated(poolIndex);
|
||||
}
|
||||
|
||||
|
@ -100,10 +107,12 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
) internal {
|
||||
require(block.timestamp <= pool.endTime, "Pool end time has passed");
|
||||
_transfer(sender, address(this), amount);
|
||||
Stake storage s = pool.stakes[pool.stakeCount++];
|
||||
uint stakeIndex = pool.stakeCount++;
|
||||
Stake storage s = pool.stakes[stakeIndex];
|
||||
s.sender = sender;
|
||||
s.inFavor = inFavor;
|
||||
s.amount = amount;
|
||||
s.id = stakeIndex;
|
||||
}
|
||||
|
||||
/// Accept reputation stakes toward a validation pool
|
||||
|
@ -115,6 +124,7 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
/// Evaluate outcome of a validation pool
|
||||
function evaluateOutcome(uint poolIndex) public returns (bool votePasses) {
|
||||
ValidationPool storage pool = validationPools[poolIndex];
|
||||
Post storage post = posts[pool.postIndex];
|
||||
require(
|
||||
block.timestamp > pool.endTime,
|
||||
"Pool end time has not yet arrived"
|
||||
|
@ -137,11 +147,12 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
// This is especially important so that the DAO's first pool can pass,
|
||||
// when no reputation has yet been minted.
|
||||
votePasses = stakedFor >= stakedAgainst;
|
||||
if (votePasses && !isMember[pool.post.author]) {
|
||||
members[memberCount++] = pool.post.author;
|
||||
isMember[pool.post.author] = true;
|
||||
if (votePasses && !isMember[post.author]) {
|
||||
members[memberCount++] = post.author;
|
||||
isMember[post.author] = true;
|
||||
}
|
||||
pool.resolved = true;
|
||||
pool.outcome = votePasses;
|
||||
emit ValidationPoolResolved(poolIndex, votePasses);
|
||||
// Value of losing stakes should be di stributed among winners, in proportion to their stakes
|
||||
uint256 amountFromWinners = votePasses ? stakedFor : stakedAgainst;
|
||||
|
@ -159,7 +170,7 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
// Due to rounding, there may be some reward left over. Include this as a reward to the author.
|
||||
uint256 remainder = amountFromLosers - totalRewards;
|
||||
if (remainder > 0) {
|
||||
_transfer(address(this), pool.post.author, remainder);
|
||||
_transfer(address(this), post.author, remainder);
|
||||
}
|
||||
// Distribute fee proportionatly among all reputation holders
|
||||
for (uint i = 0; i < memberCount; i++) {
|
||||
|
|
|
@ -73,6 +73,8 @@ describe('DAO', () => {
|
|||
const pool = await dao.validationPools(0);
|
||||
expect(pool).to.exist;
|
||||
expect(pool.duration).to.equal(POOL_DURATION);
|
||||
expect(pool.postIndex).to.equal(0);
|
||||
expect(pool.resolved).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -86,6 +88,9 @@ describe('DAO', () => {
|
|||
await expect(dao.evaluateOutcome(0)).to.emit(dao, 'ValidationPoolResolved').withArgs(0, true);
|
||||
expect(await dao.memberCount()).to.equal(1);
|
||||
expect(await dao.balanceOf(account1)).to.equal(100);
|
||||
const pool = await dao.validationPools(0);
|
||||
expect(pool.resolved).to.be.true;
|
||||
expect(pool.outcome).to.be.true;
|
||||
});
|
||||
|
||||
it('should not be able to evaluate outcome more than once', async () => {
|
||||
|
@ -139,6 +144,8 @@ describe('DAO', () => {
|
|||
await expect(dao.evaluateOutcome(1)).to.emit(dao, 'ValidationPoolResolved').withArgs(1, false);
|
||||
expect(await dao.balanceOf(dao.target)).to.equal(0);
|
||||
expect(await dao.balanceOf(account1)).to.equal(200);
|
||||
const pool = await dao.validationPools(1);
|
||||
expect(pool.outcome).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue