2024-03-13 17:34:07 -05:00
|
|
|
import {
|
2024-03-14 14:40:27 -05:00
|
|
|
useCallback, useEffect, useReducer, useState,
|
2024-03-13 17:34:07 -05:00
|
|
|
} from 'react';
|
2024-03-07 21:27:37 -06:00
|
|
|
import { useSDK } from '@metamask/sdk-react';
|
2024-03-07 10:58:55 -06:00
|
|
|
import { Web3 } from 'web3';
|
2024-03-07 21:27:37 -06:00
|
|
|
import Button from 'react-bootstrap/Button';
|
2024-03-13 16:14:59 -05:00
|
|
|
|
2024-03-07 21:27:37 -06:00
|
|
|
import DAOArtifact from './assets/DAO.json';
|
2024-03-13 17:34:07 -05:00
|
|
|
import work1Artifact from './assets/Work1.json';
|
2024-03-10 19:39:15 -05:00
|
|
|
|
|
|
|
const contracts = {
|
|
|
|
'0x539': { // Hardhat
|
2024-03-14 16:05:02 -05:00
|
|
|
DAO: '0x635F46Ea745a14431B27c5dd5838306Be289B747',
|
|
|
|
Work1: '0xEAefe601Aad7422307B99be65bbE005aeA966012',
|
2024-03-10 19:39:15 -05:00
|
|
|
},
|
|
|
|
'0xaa36a7': { // Sepolia
|
2024-03-14 16:05:02 -05:00
|
|
|
DAO: '0x38AE4ABD47B10f6660CD70Cc8FF3401341E13d9e',
|
|
|
|
Work1: '0x358A07B26F4c556140872ecdB69c58e8807E7178',
|
2024-03-10 19:39:15 -05:00
|
|
|
},
|
|
|
|
};
|
2024-02-21 18:01:41 -06:00
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
const getPoolStatus = (pool) => {
|
|
|
|
if (pool.resolved) {
|
|
|
|
return pool.outcome ? 'Accepted' : 'Rejected';
|
|
|
|
}
|
|
|
|
return pool.timeRemaining > 0 ? 'In Progress' : 'Ready to Evaluate';
|
|
|
|
};
|
|
|
|
|
|
|
|
const getRequestStatus = (request) => {
|
|
|
|
switch (Number(request.status)) {
|
|
|
|
case 0:
|
|
|
|
return 'Requested';
|
|
|
|
case 1:
|
|
|
|
return 'Evidence Submitted';
|
|
|
|
case 2:
|
|
|
|
return 'Approval Submitted';
|
|
|
|
case 3:
|
|
|
|
return 'Complete';
|
|
|
|
default:
|
|
|
|
return 'Unknown';
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-03-14 14:47:34 -05:00
|
|
|
const updateList = (list, action) => {
|
|
|
|
switch (action.type) {
|
|
|
|
case 'update': {
|
|
|
|
const newList = [...list];
|
|
|
|
newList[Number(action.item.id)] = action.item;
|
|
|
|
return newList;
|
|
|
|
}
|
|
|
|
case 'refresh':
|
|
|
|
default:
|
|
|
|
return [];
|
|
|
|
}
|
2024-03-14 14:40:27 -05:00
|
|
|
};
|
|
|
|
|
2024-02-21 18:01:41 -06:00
|
|
|
function App() {
|
2024-03-07 21:27:37 -06:00
|
|
|
const {
|
|
|
|
sdk, connected, provider, chainId, account, balance,
|
|
|
|
} = useSDK();
|
|
|
|
|
|
|
|
const [DAO, setDAO] = useState();
|
2024-03-13 17:34:07 -05:00
|
|
|
const [work1, setWork1] = useState();
|
|
|
|
const [work1Price, setWork1Price] = useState();
|
2024-03-07 21:27:37 -06:00
|
|
|
const [balanceEther, setBalanceEther] = useState();
|
2024-03-14 14:40:27 -05:00
|
|
|
const [reputation, setReputation] = useState();
|
2024-03-10 19:39:15 -05:00
|
|
|
const [totalReputation, setTotalReputation] = useState();
|
2024-03-14 14:47:34 -05:00
|
|
|
const [posts, dispatchPost] = useReducer(updateList, []);
|
|
|
|
const [validationPools, dispatchValidationPool] = useReducer(updateList, []);
|
|
|
|
const [availabilityStakes, dispatchAvailabilityStake] = useReducer(updateList, []);
|
|
|
|
const [workRequests, dispatchWorkRequest] = useReducer(updateList, []);
|
2024-03-10 11:55:59 -05:00
|
|
|
|
2024-03-10 19:39:15 -05:00
|
|
|
// const watchReputationToken = useCallback(async () => {
|
|
|
|
// await provider.request({
|
|
|
|
// method: 'wallet_watchAsset',
|
|
|
|
// params: {
|
|
|
|
// type: 'ERC20',
|
|
|
|
// options: {
|
|
|
|
// address: DAOAddress,
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// });
|
|
|
|
// }, [provider]);
|
2024-03-07 21:27:37 -06:00
|
|
|
|
2024-03-13 17:34:07 -05:00
|
|
|
// In this effect, we initialize everything and add contract event listeners.
|
|
|
|
// TODO: Refactor -- make separate, functional components?
|
2024-03-07 21:27:37 -06:00
|
|
|
useEffect(() => {
|
2024-03-14 14:40:27 -05:00
|
|
|
if (!provider || !chainId || !account || balance === undefined) return;
|
2024-03-10 19:39:15 -05:00
|
|
|
if (!contracts[chainId]) return;
|
2024-03-14 14:40:27 -05:00
|
|
|
|
|
|
|
console.log('INITIALIZATION EFFECT', {
|
|
|
|
provider, chainId, account,
|
|
|
|
});
|
|
|
|
|
2024-03-07 21:27:37 -06:00
|
|
|
const web3 = new Web3(provider);
|
2024-03-10 19:39:15 -05:00
|
|
|
const DAOContract = new web3.eth.Contract(DAOArtifact.abi, contracts[chainId].DAO);
|
2024-03-13 17:34:07 -05:00
|
|
|
const work1Contract = new web3.eth.Contract(work1Artifact.abi, contracts[chainId].Work1);
|
2024-03-10 19:39:15 -05:00
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
/* --------------------------- BEGIN FETCHERS ------------------------------------- */
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
|
2024-03-13 17:34:07 -05:00
|
|
|
const fetchPrice = async () => {
|
|
|
|
const fetchedPrice = await work1Contract.methods.price().call();
|
|
|
|
setWork1Price(web3.utils.fromWei(fetchedPrice, 'ether'));
|
|
|
|
};
|
2024-03-10 11:55:59 -05:00
|
|
|
|
|
|
|
const fetchReputation = async () => {
|
2024-03-14 14:40:27 -05:00
|
|
|
setReputation(Number(await DAOContract.methods.balanceOf(account).call()));
|
|
|
|
setTotalReputation(Number(await DAOContract.methods.totalSupply().call()));
|
|
|
|
};
|
|
|
|
|
|
|
|
const fetchPost = async (postIndex) => {
|
|
|
|
const p = await DAOContract.methods.posts(postIndex).call();
|
|
|
|
p.id = Number(p.id);
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchPost({ type: 'update', item: p });
|
2024-03-14 14:40:27 -05:00
|
|
|
return p;
|
2024-03-07 21:27:37 -06:00
|
|
|
};
|
2024-03-10 11:55:59 -05:00
|
|
|
|
2024-03-12 17:53:04 -05:00
|
|
|
const fetchPosts = async () => {
|
|
|
|
const count = await DAOContract.methods.postCount().call();
|
|
|
|
const promises = [];
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchPost({ type: 'refresh' });
|
2024-03-12 17:53:04 -05:00
|
|
|
for (let i = 0; i < count; i += 1) {
|
2024-03-14 14:40:27 -05:00
|
|
|
promises.push(fetchPost(i));
|
2024-03-12 17:53:04 -05:00
|
|
|
}
|
2024-03-14 14:40:27 -05:00
|
|
|
await Promise.all(promises);
|
2024-03-12 17:53:04 -05:00
|
|
|
};
|
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
const fetchValidationPool = async (poolIndex) => {
|
|
|
|
const pool = await DAOContract.methods.validationPools(poolIndex).call();
|
|
|
|
pool.id = Number(pool.id);
|
|
|
|
pool.timeRemaining = new Date(Number(pool.endTime) * 1000) - new Date();
|
|
|
|
pool.status = getPoolStatus(pool);
|
2024-03-14 15:02:23 -05:00
|
|
|
dispatchValidationPool({ type: 'update', item: pool });
|
2024-03-14 14:40:27 -05:00
|
|
|
|
|
|
|
// When remaing time expires, we want to update the status for this pool
|
|
|
|
if (pool.timeRemaining > 0) {
|
|
|
|
setTimeout(() => {
|
|
|
|
pool.timeRemaining = 0;
|
|
|
|
pool.status = getPoolStatus(pool);
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchValidationPool({ type: 'update', item: pool });
|
2024-03-14 14:40:27 -05:00
|
|
|
}, pool.timeRemaining);
|
|
|
|
}
|
2024-03-13 12:02:08 -05:00
|
|
|
};
|
|
|
|
|
2024-03-12 17:53:04 -05:00
|
|
|
const fetchValidationPools = async () => {
|
2024-03-13 12:02:08 -05:00
|
|
|
// TODO: Pagination
|
|
|
|
// TODO: Memoization
|
|
|
|
// TODO: Caching
|
2024-03-12 17:53:04 -05:00
|
|
|
const count = await DAOContract.methods.validationPoolCount().call();
|
|
|
|
const promises = [];
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchValidationPool({ type: 'refresh' });
|
2024-03-12 17:53:04 -05:00
|
|
|
for (let i = 0; i < count; i += 1) {
|
2024-03-14 14:40:27 -05:00
|
|
|
promises.push(fetchValidationPool(i));
|
2024-03-12 17:53:04 -05:00
|
|
|
}
|
2024-03-14 14:40:27 -05:00
|
|
|
await Promise.all(promises);
|
|
|
|
};
|
|
|
|
|
|
|
|
const fetchAvailabilityStake = async (stakeIndex) => {
|
|
|
|
const s = await work1Contract.methods.stakes(stakeIndex).call();
|
|
|
|
Object.assign(s, {
|
|
|
|
id: Number(stakeIndex),
|
|
|
|
currentUserIsWorker: () => s.worker.toLowerCase() === account.toString().toLowerCase(),
|
2024-03-14 16:05:02 -05:00
|
|
|
timeRemaining: new Date(Number(s.endTime) * 1000) - new Date(),
|
2024-03-13 12:02:08 -05:00
|
|
|
});
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchAvailabilityStake({ type: 'update', item: s });
|
2024-03-14 16:05:02 -05:00
|
|
|
if (s.timeRemaining > 0) {
|
|
|
|
setTimeout(() => {
|
|
|
|
s.timeRemaining = 0;
|
|
|
|
dispatchAvailabilityStake({ type: 'update', item: s });
|
|
|
|
}, s.timeRemaining);
|
|
|
|
}
|
2024-03-14 14:40:27 -05:00
|
|
|
return s;
|
2024-03-07 21:27:37 -06:00
|
|
|
};
|
2024-03-10 11:55:59 -05:00
|
|
|
|
2024-03-13 17:34:07 -05:00
|
|
|
const fetchAvailabilityStakes = async () => {
|
|
|
|
const count = await work1Contract.methods.stakeCount().call();
|
|
|
|
const promises = [];
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchAvailabilityStake({ type: 'refresh' });
|
2024-03-13 17:34:07 -05:00
|
|
|
for (let i = 0; i < count; i += 1) {
|
2024-03-14 14:40:27 -05:00
|
|
|
promises.push(fetchAvailabilityStake(i));
|
2024-03-13 17:34:07 -05:00
|
|
|
}
|
2024-03-14 14:40:27 -05:00
|
|
|
await Promise.all(promises);
|
|
|
|
};
|
|
|
|
|
|
|
|
const fetchWorkRequest = async (requestIndex) => {
|
|
|
|
const r = await work1Contract.methods.requests(requestIndex).call();
|
|
|
|
Object.assign(r, {
|
|
|
|
id: Number(requestIndex),
|
|
|
|
statusString: getRequestStatus(r),
|
|
|
|
feeEther: web3.utils.fromWei(r.fee, 'ether'),
|
|
|
|
currentUserIsCustomer: () => r.customer.toLowerCase()
|
|
|
|
=== account.toString().toLowerCase(),
|
2024-03-13 17:34:07 -05:00
|
|
|
});
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchWorkRequest({ type: 'update', item: r });
|
2024-03-14 14:40:27 -05:00
|
|
|
return r;
|
2024-03-13 17:34:07 -05:00
|
|
|
};
|
|
|
|
|
2024-03-13 17:56:29 -05:00
|
|
|
const fetchWorkRequests = async () => {
|
|
|
|
const count = await work1Contract.methods.requestCount().call();
|
|
|
|
const promises = [];
|
2024-03-14 14:47:34 -05:00
|
|
|
dispatchWorkRequest({ type: 'refresh' });
|
2024-03-13 17:56:29 -05:00
|
|
|
for (let i = 0; i < count; i += 1) {
|
2024-03-14 14:40:27 -05:00
|
|
|
promises.push(fetchWorkRequest(i));
|
2024-03-13 17:56:29 -05:00
|
|
|
}
|
2024-03-14 14:40:27 -05:00
|
|
|
await Promise.all(promises);
|
2024-03-13 17:56:29 -05:00
|
|
|
};
|
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
/* --------------------------- END FETCHERS --------------------------------------- */
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
|
2024-03-13 17:34:07 -05:00
|
|
|
fetchPrice();
|
2024-03-10 11:55:59 -05:00
|
|
|
fetchReputation();
|
2024-03-12 17:53:04 -05:00
|
|
|
fetchPosts();
|
|
|
|
fetchValidationPools();
|
2024-03-13 17:34:07 -05:00
|
|
|
fetchAvailabilityStakes();
|
2024-03-13 17:56:29 -05:00
|
|
|
fetchWorkRequests();
|
2024-03-13 17:34:07 -05:00
|
|
|
|
|
|
|
setWork1(work1Contract);
|
2024-03-07 21:27:37 -06:00
|
|
|
setDAO(DAOContract);
|
2024-03-10 11:55:59 -05:00
|
|
|
|
2024-03-12 18:02:07 -05:00
|
|
|
DAOContract.events.PostAdded({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: post added', event);
|
2024-03-14 14:40:27 -05:00
|
|
|
fetchPost(event.returnValues.postIndex);
|
2024-03-12 18:02:07 -05:00
|
|
|
});
|
|
|
|
|
2024-03-10 11:55:59 -05:00
|
|
|
DAOContract.events.ValidationPoolInitiated({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: validation pool initiated', event);
|
2024-03-14 14:40:27 -05:00
|
|
|
fetchValidationPool(event.returnValues.poolIndex);
|
2024-03-10 11:55:59 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
DAOContract.events.ValidationPoolResolved({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: validation pool resolved', event);
|
2024-03-10 19:39:15 -05:00
|
|
|
fetchReputation();
|
2024-03-14 14:40:27 -05:00
|
|
|
fetchValidationPool(event.returnValues.poolIndex);
|
|
|
|
});
|
|
|
|
|
2024-03-14 16:05:02 -05:00
|
|
|
work1Contract.events.AvailabilityStaked({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: availability staked', event);
|
|
|
|
fetchAvailabilityStake(event.returnValues.stakeIndex);
|
|
|
|
fetchReputation();
|
|
|
|
});
|
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
work1Contract.events.WorkAssigned({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: work assigned', event);
|
|
|
|
const r = fetchWorkRequest(event.returnValues.requestIndex);
|
|
|
|
fetchAvailabilityStake(r.stakeIndex);
|
|
|
|
});
|
|
|
|
|
|
|
|
work1Contract.events.WorkEvidenceSubmitted({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: work evidence submitted', event);
|
|
|
|
fetchWorkRequest(event.returnValues.requestIndex);
|
2024-03-10 11:55:59 -05:00
|
|
|
});
|
2024-03-14 16:05:02 -05:00
|
|
|
|
|
|
|
work1Contract.events.WorkApprovalSubmitted({ fromBlock: 'latest' }).on('data', (event) => {
|
|
|
|
console.log('event: work approval submitted', event);
|
|
|
|
fetchWorkRequest(event.returnValues.requestIndex);
|
|
|
|
});
|
2024-03-14 14:40:27 -05:00
|
|
|
}, [provider, account, chainId, balance, setReputation, dispatchAvailabilityStake,
|
|
|
|
dispatchValidationPool, dispatchWorkRequest]);
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
/* --------------------------- END MAIN INITIALIZION EFFECT ----------------------- */
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
2024-03-07 21:27:37 -06:00
|
|
|
|
|
|
|
useEffect(() => {
|
2024-03-10 19:39:15 -05:00
|
|
|
if (!provider || balance === undefined) return;
|
|
|
|
const web3 = new Web3(provider);
|
|
|
|
setBalanceEther(web3.utils.fromWei(balance, 'ether'));
|
2024-03-07 21:27:37 -06:00
|
|
|
}, [provider, balance]);
|
|
|
|
|
|
|
|
const connect = async () => {
|
|
|
|
try {
|
|
|
|
await sdk?.connect();
|
|
|
|
} catch (err) {
|
|
|
|
console.warn('failed to connect..', err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const disconnect = async () => {
|
|
|
|
try {
|
|
|
|
sdk?.terminate();
|
|
|
|
} catch (err) {
|
|
|
|
console.warn('failed to disconnect..', err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
/* --------------------------- BEGIN UI ACTIONS ----------------------------------- */
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
const addPost = useCallback(async () => {
|
2024-03-12 17:53:04 -05:00
|
|
|
await DAO.methods.addPost(account).send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
2024-03-14 14:40:27 -05:00
|
|
|
}, [DAO, account]);
|
2024-03-12 17:53:04 -05:00
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
const initiateValidationPool = useCallback(async (postIndex, poolDuration) => {
|
2024-03-13 16:14:59 -05:00
|
|
|
await DAO.methods.initiateValidationPool(postIndex, poolDuration ?? 3600).send({
|
2024-03-07 21:27:37 -06:00
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
value: 100,
|
2024-03-07 10:58:55 -06:00
|
|
|
});
|
2024-03-14 14:40:27 -05:00
|
|
|
}, [DAO, account]);
|
2024-03-07 10:58:55 -06:00
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
const stake = useCallback(async (poolIndex, amount, inFavor) => {
|
|
|
|
console.log(`Attempting to stake ${amount} ${inFavor ? 'for' : 'against'} pool ${poolIndex}`);
|
|
|
|
await DAO.methods.stake(poolIndex, amount, inFavor).send({
|
|
|
|
from: account,
|
|
|
|
gas: 999999,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Since this is the result we expect from the server, we preemptively set it here.
|
|
|
|
// We can let this value be negative -- this would just mean we'll be getting
|
|
|
|
// at least one error from the server, and a corrected reputation.
|
|
|
|
setReputation((current) => current - stake);
|
|
|
|
}, [DAO, account, setReputation]);
|
|
|
|
|
|
|
|
const stakeAllInFavor = useCallback(async (poolIndex) => {
|
|
|
|
await stake(poolIndex, reputation, true);
|
|
|
|
}, [stake, reputation]);
|
|
|
|
|
|
|
|
const evaluateOutcome = useCallback(async (poolIndex) => {
|
2024-03-12 17:53:04 -05:00
|
|
|
await DAO.methods.evaluateOutcome(poolIndex).send({
|
2024-03-07 21:27:37 -06:00
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
2024-03-14 14:40:27 -05:00
|
|
|
}, [DAO, account]);
|
2024-03-07 21:27:37 -06:00
|
|
|
|
2024-03-14 16:05:02 -05:00
|
|
|
const stakeAvailability = useCallback(async (duration) => {
|
2024-03-13 17:34:07 -05:00
|
|
|
const target = contracts[chainId].Work1;
|
2024-03-14 14:40:27 -05:00
|
|
|
await DAO.methods.stakeAvailability(target, reputation, duration).send({
|
2024-03-13 17:34:07 -05:00
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
|
|
|
// Note that as with validation pool stakes, we should keep track locally of our reputation
|
2024-03-14 14:40:27 -05:00
|
|
|
setReputation(0);
|
|
|
|
}, [DAO, account, chainId, reputation, setReputation]);
|
2024-03-07 21:27:37 -06:00
|
|
|
|
2024-03-14 16:05:02 -05:00
|
|
|
const reclaimAvailabilityStake = useCallback(async (stakeIndex) => {
|
|
|
|
await work1.methods.reclaimAvailability(stakeIndex).send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
|
|
|
}, [work1, account]);
|
|
|
|
|
|
|
|
const extendAvailabilityStake = useCallback(async (stakeIndex, duration) => {
|
|
|
|
await work1.methods.extendAvailability(stakeIndex, duration).send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
|
|
|
}, [work1, account]);
|
|
|
|
|
2024-03-13 17:34:07 -05:00
|
|
|
const requestWork = useCallback(async () => {
|
|
|
|
const web3 = new Web3(provider);
|
|
|
|
const priceWei = BigInt(web3.utils.toWei(work1Price, 'ether'));
|
|
|
|
await work1.methods.requestWork().send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
value: priceWei,
|
|
|
|
});
|
|
|
|
}, [provider, work1, account, work1Price]);
|
2024-03-07 10:58:55 -06:00
|
|
|
|
2024-03-14 14:40:27 -05:00
|
|
|
const submitWorkEvidence = useCallback(async (requestIndex) => {
|
|
|
|
await work1.methods.submitWorkEvidence(requestIndex).send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
|
|
|
}, [work1, account]);
|
|
|
|
|
|
|
|
const submitWorkApproval = useCallback(async (requestIndex) => {
|
|
|
|
await work1.methods.submitWorkApproval(requestIndex, true).send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
|
|
|
}, [work1, account]);
|
|
|
|
|
|
|
|
const submitWorkDisapproval = useCallback(async (requestIndex) => {
|
|
|
|
await work1.methods.submitWorkApproval(requestIndex, false).send({
|
|
|
|
from: account,
|
|
|
|
gas: 1000000,
|
|
|
|
});
|
|
|
|
}, [work1, account]);
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
/* --------------------------- END UI ACTIONS ------------------------------------- */
|
|
|
|
/* -------------------------------------------------------------------------------- */
|
|
|
|
|
2024-02-21 18:01:41 -06:00
|
|
|
return (
|
|
|
|
<>
|
2024-03-07 21:27:37 -06:00
|
|
|
{!connected && <Button onClick={() => connect()}>Connect</Button>}
|
|
|
|
|
|
|
|
{connected && (
|
|
|
|
<>
|
|
|
|
<div>
|
2024-03-10 19:39:15 -05:00
|
|
|
{!contracts[chainId] && (
|
|
|
|
<div>
|
|
|
|
Please switch MetaMask to Sepolia testnet!
|
|
|
|
</div>
|
|
|
|
)}
|
2024-03-07 21:27:37 -06:00
|
|
|
<div>
|
|
|
|
{chainId && `Chain ID: ${chainId}`}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
{`Account: ${account}`}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
{`Balance: ${balanceEther} ETH`}
|
|
|
|
</div>
|
|
|
|
<div>
|
2024-03-14 14:40:27 -05:00
|
|
|
{`Your REP: ${reputation}`}
|
2024-03-10 19:39:15 -05:00
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
{`Total REP: ${totalReputation}`}
|
2024-03-07 21:27:37 -06:00
|
|
|
</div>
|
|
|
|
<Button onClick={() => disconnect()}>Disconnect</Button>
|
|
|
|
</div>
|
|
|
|
<div>
|
2024-03-12 17:53:04 -05:00
|
|
|
{`Posts count: ${posts.length}`}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<table className="table">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>ID</th>
|
|
|
|
<th>Author</th>
|
|
|
|
<th>Actions</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
2024-03-14 14:40:27 -05:00
|
|
|
{posts.filter((x) => !!x).map((post) => (
|
2024-03-12 17:53:04 -05:00
|
|
|
<tr key={post.id}>
|
|
|
|
<td>{post.id.toString()}</td>
|
|
|
|
<td>{post.author}</td>
|
|
|
|
<td>
|
2024-03-13 16:14:59 -05:00
|
|
|
Initiate Validation Pool
|
|
|
|
{' '}
|
|
|
|
<Button onClick={() => initiateValidationPool(post.id, 60)}>
|
|
|
|
1 Min.
|
|
|
|
</Button>
|
|
|
|
{' '}
|
|
|
|
<Button onClick={() => initiateValidationPool(post.id, 3600)}>
|
|
|
|
1 Hr.
|
|
|
|
</Button>
|
|
|
|
{' '}
|
|
|
|
<Button onClick={() => initiateValidationPool(post.id, 86400)}>
|
|
|
|
1 Day
|
2024-03-12 17:53:04 -05:00
|
|
|
</Button>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
2024-03-07 21:27:37 -06:00
|
|
|
</div>
|
|
|
|
<div>
|
2024-03-12 17:53:04 -05:00
|
|
|
<Button onClick={() => addPost()}>Add Post</Button>
|
2024-03-07 21:27:37 -06:00
|
|
|
</div>
|
|
|
|
<div>
|
2024-03-12 17:53:04 -05:00
|
|
|
{`Validation Pool Count: ${validationPools.length}`}
|
2024-03-07 21:27:37 -06:00
|
|
|
</div>
|
2024-03-10 11:55:59 -05:00
|
|
|
<div>
|
2024-03-12 17:53:04 -05:00
|
|
|
<table className="table">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>ID</th>
|
|
|
|
<th>Post ID</th>
|
|
|
|
<th>Fee</th>
|
|
|
|
<th>Duration</th>
|
|
|
|
<th>End Time</th>
|
2024-03-13 12:02:08 -05:00
|
|
|
<th>
|
|
|
|
Stake
|
|
|
|
<br />
|
|
|
|
Count
|
|
|
|
</th>
|
2024-03-12 17:53:04 -05:00
|
|
|
<th>Status</th>
|
|
|
|
<th>Actions</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
2024-03-14 14:40:27 -05:00
|
|
|
{validationPools.filter((x) => !!x).map((pool) => (
|
2024-03-12 17:53:04 -05:00
|
|
|
<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>
|
2024-03-13 12:02:08 -05:00
|
|
|
<td>{pool.stakeCount.toString()}</td>
|
|
|
|
<td>{pool.status}</td>
|
2024-03-12 17:53:04 -05:00
|
|
|
<td>
|
2024-03-14 14:40:27 -05:00
|
|
|
{!pool.resolved && reputation > 0 && pool.timeRemaining > 0 && (
|
|
|
|
<>
|
|
|
|
<Button onClick={() => stakeAllInFavor(pool.id)}>
|
|
|
|
Stake
|
|
|
|
</Button>
|
|
|
|
{' '}
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
{!pool.resolved && pool.timeRemaining <= 0 && (
|
2024-03-12 17:53:04 -05:00
|
|
|
<Button onClick={() => evaluateOutcome(pool.id)}>
|
|
|
|
Evaluate Outcome
|
|
|
|
</Button>
|
|
|
|
)}
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
2024-03-10 11:55:59 -05:00
|
|
|
</div>
|
2024-03-07 21:27:37 -06:00
|
|
|
<div>
|
2024-03-13 17:34:07 -05:00
|
|
|
<h2>Work Contract 1</h2>
|
|
|
|
<div>
|
2024-03-14 16:05:02 -05:00
|
|
|
{`Price: ${work1Price} ETH`}
|
2024-03-13 17:34:07 -05:00
|
|
|
</div>
|
|
|
|
<div>
|
2024-03-14 16:05:02 -05:00
|
|
|
Stake Availability:
|
|
|
|
{' '}
|
|
|
|
{!reputation && <>No reputation available to stake</>}
|
|
|
|
{reputation > 0 && (
|
|
|
|
<>
|
|
|
|
<Button onClick={() => stakeAvailability(300)}>5 Min.</Button>
|
|
|
|
{' '}
|
|
|
|
<Button onClick={() => stakeAvailability(7200)}>2 Hr.</Button>
|
|
|
|
</>
|
|
|
|
)}
|
2024-03-13 17:34:07 -05:00
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
Availability Stake Count:
|
|
|
|
{' '}
|
|
|
|
{availabilityStakes.length}
|
|
|
|
</div>
|
2024-03-13 17:56:29 -05:00
|
|
|
<div>
|
|
|
|
<table className="table">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>ID</th>
|
|
|
|
<th>Worker</th>
|
|
|
|
<th>Amount</th>
|
|
|
|
<th>End Time</th>
|
|
|
|
<th>Assigned</th>
|
|
|
|
<th>Reclaimed</th>
|
2024-03-14 16:05:02 -05:00
|
|
|
<th>Actions</th>
|
2024-03-13 17:34:07 -05:00
|
|
|
</tr>
|
2024-03-13 17:56:29 -05:00
|
|
|
</thead>
|
|
|
|
<tbody>
|
2024-03-14 14:40:27 -05:00
|
|
|
{availabilityStakes.filter((x) => !!x).map((s) => (
|
|
|
|
<tr key={s.id}>
|
|
|
|
<td>{s.id.toString()}</td>
|
|
|
|
<td>{s.worker.toString()}</td>
|
|
|
|
<td>{s.amount.toString()}</td>
|
|
|
|
<td>{new Date(Number(s.endTime) * 1000).toLocaleString()}</td>
|
|
|
|
<td>{s.assigned.toString()}</td>
|
|
|
|
<td>{s.reclaimed.toString()}</td>
|
2024-03-14 16:05:02 -05:00
|
|
|
<td>
|
|
|
|
{s.currentUserIsWorker() && (
|
|
|
|
<Button onClick={() => extendAvailabilityStake(s.id, 3600)}>
|
|
|
|
Extend 1 Hr.
|
|
|
|
</Button>
|
|
|
|
)}
|
|
|
|
{s.currentUserIsWorker() && s.timeRemaining <= 0
|
|
|
|
&& !s.assigned && !s.reclaimed && (
|
|
|
|
<>
|
|
|
|
{' '}
|
|
|
|
<Button onClick={() => reclaimAvailabilityStake(s.id)}>
|
|
|
|
Reclaim
|
|
|
|
</Button>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</td>
|
2024-03-13 17:56:29 -05:00
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
2024-03-13 17:34:07 -05:00
|
|
|
<div>
|
|
|
|
<Button onClick={() => requestWork()}>Request Work</Button>
|
|
|
|
</div>
|
2024-03-13 17:56:29 -05:00
|
|
|
<div>
|
|
|
|
Work Request Count:
|
|
|
|
{' '}
|
|
|
|
{workRequests.length}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<table className="table">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>ID</th>
|
|
|
|
<th>Customer</th>
|
|
|
|
<th>Fee</th>
|
|
|
|
<th>Status</th>
|
|
|
|
<th>Stake ID</th>
|
|
|
|
<th>Approval</th>
|
|
|
|
<th>Pool ID</th>
|
2024-03-14 14:40:27 -05:00
|
|
|
<th>Actions</th>
|
2024-03-13 17:56:29 -05:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
2024-03-14 14:40:27 -05:00
|
|
|
{workRequests.filter((x) => !!x).map((request) => (
|
2024-03-13 17:56:29 -05:00
|
|
|
<tr key={request.id}>
|
|
|
|
<td>{request.id.toString()}</td>
|
|
|
|
<td>{request.customer.toString()}</td>
|
|
|
|
<td>
|
|
|
|
{request.feeEther}
|
|
|
|
{' '}
|
|
|
|
ETH
|
|
|
|
</td>
|
|
|
|
<td>{request.statusString}</td>
|
|
|
|
<td>{request.stakeIndex.toString()}</td>
|
|
|
|
<td>{request.approval.toString()}</td>
|
|
|
|
<td>{request.poolIndex.toString()}</td>
|
2024-03-14 14:40:27 -05:00
|
|
|
<td>
|
|
|
|
{availabilityStakes.length > 0
|
|
|
|
&& availabilityStakes[Number(request.stakeIndex)]?.currentUserIsWorker()
|
|
|
|
&& Number(request.status) === 0 && (
|
|
|
|
<Button onClick={() => submitWorkEvidence(request.id)}>
|
|
|
|
Submit Work Evidence
|
|
|
|
</Button>
|
|
|
|
)}
|
|
|
|
{request.currentUserIsCustomer()
|
|
|
|
&& Number(request.status) === 1 && (
|
|
|
|
<>
|
|
|
|
<Button onClick={() => submitWorkApproval(request.id)}>
|
|
|
|
Submit Approval
|
|
|
|
</Button>
|
|
|
|
<Button onClick={() => submitWorkDisapproval(request.id)}>
|
|
|
|
Submit Dispproval
|
|
|
|
</Button>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</td>
|
2024-03-13 17:56:29 -05:00
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
2024-03-07 21:27:37 -06:00
|
|
|
</div>
|
|
|
|
</>
|
2024-03-07 10:58:55 -06:00
|
|
|
)}
|
2024-02-21 18:01:41 -06:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default App;
|