Compare commits
2 Commits
c38b4ea2f7
...
d39cad9619
Author | SHA1 | Date |
---|---|---|
Ladd Hoffman | d39cad9619 | |
Ladd Hoffman | 27585b157e |
|
@ -13,6 +13,7 @@
|
|||
"axios": "^1.6.7",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootswatch": "^5.3.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.1",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"axios": "^1.6.7",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootswatch": "^5.3.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.1",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
useCallback, useEffect, useReducer, useState,
|
||||
useCallback, useEffect, useReducer, useState, useMemo,
|
||||
} from 'react';
|
||||
import { useSDK } from '@metamask/sdk-react';
|
||||
import { Web3 } from 'web3';
|
||||
|
@ -11,19 +11,11 @@ import Row from 'react-bootstrap/Row';
|
|||
import Col from 'react-bootstrap/Col';
|
||||
import Stack from 'react-bootstrap/Stack';
|
||||
|
||||
import Web3Context from './Web3Context';
|
||||
import contracts from './contracts';
|
||||
import DAOArtifact from './assets/DAO.json';
|
||||
import work1Artifact from './assets/Work1.json';
|
||||
|
||||
const contracts = {
|
||||
'0x539': { // Hardhat
|
||||
DAO: '0x76Dfe9F47f06112a1b78960bf37d87CfbB6D6133',
|
||||
Work1: '0xd2845aE812Ee42cF024fB4C55c052365792aBd78',
|
||||
},
|
||||
'0xaa36a7': { // Sepolia
|
||||
DAO: '0x39B7522Ee1A5B13aE5580C40114239D4cE0e7D29',
|
||||
Work1: '0xC0Bb36820Ba891DE4ed6D60f75066805361dbeB8',
|
||||
},
|
||||
};
|
||||
import AvailabilityStakes from './AvailabilityStakes';
|
||||
|
||||
const updateList = (list, action) => {
|
||||
switch (action.type) {
|
||||
|
@ -76,8 +68,8 @@ function App() {
|
|||
};
|
||||
|
||||
const fetchReputation = async () => {
|
||||
setReputation(Number(await DAOContract.methods.balanceOf(account).call()));
|
||||
setTotalReputation(Number(await DAOContract.methods.totalSupply().call()));
|
||||
setReputation(await DAOContract.methods.balanceOf(account).call());
|
||||
setTotalReputation(await DAOContract.methods.totalSupply().call());
|
||||
};
|
||||
|
||||
const fetchPost = async (postIndex) => {
|
||||
|
@ -322,11 +314,11 @@ function App() {
|
|||
// 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);
|
||||
setReputation((current) => current - BigInt(amount));
|
||||
}, [DAO, account, setReputation]);
|
||||
|
||||
const stakeAllInFavor = useCallback(async (poolIndex) => {
|
||||
await stake(poolIndex, reputation, true);
|
||||
const stakeHalfInFavor = useCallback(async (poolIndex) => {
|
||||
await stake(poolIndex, reputation / BigInt(2), true);
|
||||
}, [stake, reputation]);
|
||||
|
||||
const evaluateOutcome = useCallback(async (poolIndex) => {
|
||||
|
@ -336,30 +328,6 @@ function App() {
|
|||
});
|
||||
}, [DAO, account]);
|
||||
|
||||
const stakeAvailability = useCallback(async (duration) => {
|
||||
const target = contracts[chainId].Work1;
|
||||
await DAO.methods.stakeAvailability(target, reputation, duration).send({
|
||||
from: account,
|
||||
gas: 1000000,
|
||||
});
|
||||
// Note that as with validation pool stakes, we should keep track locally of our reputation
|
||||
setReputation(0);
|
||||
}, [DAO, account, chainId, reputation, setReputation]);
|
||||
|
||||
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]);
|
||||
|
||||
const requestWork = useCallback(async () => {
|
||||
const web3 = new Web3(provider);
|
||||
const priceWei = BigInt(web3.utils.toWei(work1Price, 'ether'));
|
||||
|
@ -395,8 +363,14 @@ function App() {
|
|||
/* --------------------------- END UI ACTIONS ------------------------------------- */
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
const web3ProviderValue = useMemo(() => ({
|
||||
DAO, work1, availabilityStakes, reputation, setReputation, account, chainId,
|
||||
}), [
|
||||
DAO, work1, availabilityStakes, reputation, setReputation, account, chainId,
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Web3Context.Provider value={web3ProviderValue}>
|
||||
{!connected && <Button onClick={() => connect()}>Connect</Button>}
|
||||
|
||||
{connected && (
|
||||
|
@ -429,10 +403,10 @@ function App() {
|
|||
<Col>
|
||||
<Stack>
|
||||
<div>
|
||||
{`Your REP: ${reputation}`}
|
||||
{`Your REP: ${reputation?.toString()}`}
|
||||
</div>
|
||||
<div>
|
||||
{`Total REP: ${totalReputation}`}
|
||||
{`Total REP: ${totalReputation?.toString()}`}
|
||||
</div>
|
||||
<div>
|
||||
<Button onClick={() => disconnect()}>Disconnect</Button>
|
||||
|
@ -520,8 +494,8 @@ function App() {
|
|||
<td>
|
||||
{!pool.resolved && reputation > 0 && pool.timeRemaining > 0 && (
|
||||
<>
|
||||
<Button onClick={() => stakeAllInFavor(pool.id)}>
|
||||
Stake
|
||||
<Button onClick={() => stakeHalfInFavor(pool.id)}>
|
||||
Stake 1/2 REP
|
||||
</Button>
|
||||
{' '}
|
||||
</>
|
||||
|
@ -542,66 +516,7 @@ function App() {
|
|||
<div>
|
||||
{`Price: ${work1Price} ETH`}
|
||||
</div>
|
||||
<div>
|
||||
Stake Availability:
|
||||
{' '}
|
||||
{!reputation && <>No reputation available to stake</>}
|
||||
{reputation > 0 && (
|
||||
<>
|
||||
<Button onClick={() => stakeAvailability(300)}>5 Min.</Button>
|
||||
{' '}
|
||||
<Button onClick={() => stakeAvailability(7200)}>2 Hr.</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
Availability Stake Count:
|
||||
{' '}
|
||||
{availabilityStakes.length}
|
||||
</div>
|
||||
<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>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{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>
|
||||
<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>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<AvailabilityStakes showActions={false} />
|
||||
<div>
|
||||
<Button onClick={() => requestWork()}>Request Work</Button>
|
||||
</div>
|
||||
|
@ -666,15 +581,23 @@ function App() {
|
|||
</div>
|
||||
</Tab>
|
||||
<Tab eventKey="worker" title="Worker">
|
||||
TBD
|
||||
<h2>Work Contract 1</h2>
|
||||
<div>
|
||||
{`Price: ${work1Price} ETH`}
|
||||
</div>
|
||||
<AvailabilityStakes />
|
||||
</Tab>
|
||||
<Tab eventKey="customer" title="Customer">
|
||||
TBD
|
||||
<h2>Work Contract 1</h2>
|
||||
<div>
|
||||
{`Price: ${work1Price} ETH`}
|
||||
</div>
|
||||
<AvailabilityStakes showActions={false} showAmount={false} onlyShowAvailable />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</Web3Context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
import { useCallback, useContext } from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
|
||||
import Web3Context from './Web3Context';
|
||||
import contracts from './contracts';
|
||||
|
||||
const getAvailabilityStatus = (stake) => {
|
||||
if (stake.reclaimed) return 'Reclaimed';
|
||||
if (stake.assigned) return 'Assigned';
|
||||
if (new Date() < new Date(Number(stake.endTime) * 1000)) return 'Available';
|
||||
return 'Expired';
|
||||
};
|
||||
|
||||
function AvailabilityStakes({ showActions, showAmount, onlyShowAvailable }) {
|
||||
const {
|
||||
DAO, work1, availabilityStakes, reputation, setReputation, account, chainId,
|
||||
} = useContext(Web3Context);
|
||||
|
||||
const stakeAvailability = useCallback(async (duration) => {
|
||||
const target = contracts[chainId].Work1;
|
||||
await DAO.methods.stakeAvailability(target, reputation / BigInt(2), duration).send({
|
||||
from: account,
|
||||
gas: 999999,
|
||||
});
|
||||
// Note that as with validation pool stakes, we should keep track locally of our reputation
|
||||
setReputation(reputation / BigInt(2));
|
||||
}, [DAO, account, chainId, reputation, setReputation]);
|
||||
|
||||
const reclaimAvailabilityStake = useCallback(async (stakeIndex) => {
|
||||
await work1.methods.reclaimAvailability(stakeIndex).send({
|
||||
from: account,
|
||||
gas: 999999,
|
||||
});
|
||||
}, [work1, account]);
|
||||
|
||||
const extendAvailabilityStake = useCallback(async (stakeIndex, duration) => {
|
||||
await work1.methods.extendAvailability(stakeIndex, duration).send({
|
||||
from: account,
|
||||
gas: 999999,
|
||||
});
|
||||
}, [work1, account]);
|
||||
|
||||
const displayData = availabilityStakes.filter((stake) => {
|
||||
if (!onlyShowAvailable) return true;
|
||||
if (getAvailabilityStatus(stake) === 'Available') return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{showActions && (
|
||||
<div>
|
||||
Stake Availability:
|
||||
{' '}
|
||||
{!reputation && <>No reputation available to stake</>}
|
||||
{reputation > 0 && (
|
||||
<>
|
||||
<Button onClick={() => stakeAvailability(300)}>5 Min.</Button>
|
||||
{' '}
|
||||
<Button onClick={() => stakeAvailability(7200)}>2 Hr.</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
Availability Stake Count:
|
||||
{' '}
|
||||
{displayData?.length}
|
||||
</div>
|
||||
<div>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Worker</th>
|
||||
{showAmount && <th>Amount</th>}
|
||||
<th>End Time</th>
|
||||
<th>Status</th>
|
||||
{showActions && <th>Actions</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{displayData?.filter((x) => !!x).map((s) => (
|
||||
<tr key={s.id}>
|
||||
<td>{s.id.toString()}</td>
|
||||
<td>{s.worker.toString()}</td>
|
||||
{showAmount && <td>{s.amount.toString()}</td>}
|
||||
<td>{new Date(Number(s.endTime) * 1000).toLocaleString()}</td>
|
||||
<td>{getAvailabilityStatus(s)}</td>
|
||||
{showActions && (
|
||||
<td>
|
||||
{s.currentUserIsWorker() && !s.assigned && !s.reclaimed && (
|
||||
<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>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
AvailabilityStakes.propTypes = {
|
||||
showActions: PropTypes.bool,
|
||||
showAmount: PropTypes.bool,
|
||||
onlyShowAvailable: PropTypes.bool,
|
||||
};
|
||||
|
||||
AvailabilityStakes.defaultProps = {
|
||||
showActions: true,
|
||||
showAmount: true,
|
||||
onlyShowAvailable: false,
|
||||
};
|
||||
|
||||
export default AvailabilityStakes;
|
|
@ -0,0 +1,5 @@
|
|||
import { createContext } from 'react';
|
||||
|
||||
const Web3Context = createContext({});
|
||||
|
||||
export default Web3Context;
|
|
@ -0,0 +1,12 @@
|
|||
const contracts = {
|
||||
'0x539': { // Hardhat
|
||||
DAO: '0x76Dfe9F47f06112a1b78960bf37d87CfbB6D6133',
|
||||
Work1: '0xd2845aE812Ee42cF024fB4C55c052365792aBd78',
|
||||
},
|
||||
'0xaa36a7': { // Sepolia
|
||||
DAO: '0x39B7522Ee1A5B13aE5580C40114239D4cE0e7D29',
|
||||
Work1: '0xC0Bb36820Ba891DE4ed6D60f75066805361dbeB8',
|
||||
},
|
||||
};
|
||||
|
||||
export default contracts;
|
Loading…
Reference in New Issue