Compare commits

..

2 Commits

Author SHA1 Message Date
Ladd Hoffman d39cad9619 move availability stakes component to separate file
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 30s Details
2024-03-16 21:19:57 -05:00
Ladd Hoffman 27585b157e refactored availability component 2024-03-16 20:34:36 -05:00
6 changed files with 181 additions and 109 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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>
);
}

View File

@ -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;

View File

@ -0,0 +1,5 @@
import { createContext } from 'react';
const Web3Context = createContext({});
export default Web3Context;

12
client/src/contracts.js Normal file
View File

@ -0,0 +1,12 @@
const contracts = {
'0x539': { // Hardhat
DAO: '0x76Dfe9F47f06112a1b78960bf37d87CfbB6D6133',
Work1: '0xd2845aE812Ee42cF024fB4C55c052365792aBd78',
},
'0xaa36a7': { // Sepolia
DAO: '0x39B7522Ee1A5B13aE5580C40114239D4cE0e7D29',
Work1: '0xC0Bb36820Ba891DE4ed6D60f75066805361dbeB8',
},
};
export default contracts;