progress with UI contract interaction
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 41s Details

This commit is contained in:
Ladd Hoffman 2024-03-07 21:27:37 -06:00
parent c909f43310
commit 395092b1fd
9 changed files with 10969 additions and 186 deletions

View File

@ -11,12 +11,13 @@ module.exports = {
ignorePatterns: ['dist', '.eslintrc.cjs', 'vite.config.js'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
plugins: ['react-refresh', '@stylistic'],
rules: {
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'no-console': 0
},
}

10087
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,13 +10,17 @@
"preview": "vite preview"
},
"dependencies": {
"@metamask/sdk-react": "^0.16.0",
"axios": "^1.6.7",
"backend": "file://../backend",
"bootstrap": "^5.3.3",
"bootswatch": "^5.3.3",
"react": "^18.2.0",
"react-bootstrap": "^2.10.1",
"react-dom": "^18.2.0",
"web3": "^4.5.0"
},
"devDependencies": {
"@stylistic/eslint-plugin": "^1.6.3",
"@types/react": "^18.2.56",
"@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^4.2.1",

View File

@ -1,58 +1,138 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useSDK } from '@metamask/sdk-react';
import { Web3 } from 'web3';
import './App.css';
import Button from 'react-bootstrap/Button';
// import './App.css';
import DAOArtifact from './assets/DAO.json';
import work1Artifact from './assets/Work1.json';
const work1Address = '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853';
const DAOAddress = '0x0165878A594ca255338adfa4d48449f69242Eb8F';
function App() {
// react state to store and show the connected account
const [connectedAccounts, setConnectedAccounts] = useState([]);
const {
sdk, connected, provider, chainId, account, balance,
} = useSDK();
async function connectMetamask() {
// instantiate Web3 with the injected provider
const web3 = new Web3(window.ethereum);
const [work1, setWork1] = useState();
const [DAO, setDAO] = useState();
const [work1Price, setWork1Price] = useState();
const [balanceEther, setBalanceEther] = useState();
const [reputation, setReputation] = useState();
const [validationPoolCount, setValidationPoolCount] = useState();
// request user to connect accounts (Metamask will prompt)
await window.ethereum.request({ method: 'eth_requestAccounts' });
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 priceWei = await work1Contract.methods.price().call();
setWork1Price(web3.utils.fromWei(priceWei, 'ether'));
};
const getReputation = async () => {
setReputation(await DAOContract.methods.valueOf(0).call());
};
const getValidationPoolCount = async () => {
setValidationPoolCount(await DAOContract.methods.validationPoolCount().call());
};
getPrice();
getReputation();
getValidationPoolCount();
setWork1(work1Contract);
setDAO(DAOContract);
}, [provider]);
// get the connected accounts
const accounts = await web3.eth.getAccounts();
useEffect(() => {
if (provider && balance) {
const web3 = new Web3(provider);
setBalanceEther(web3.utils.fromWei(balance, 'ether'));
}
}, [provider, balance]);
// show the first connected account in the react page
setConnectedAccounts(accounts);
}
const connect = async () => {
try {
await sdk?.connect();
} catch (err) {
console.warn('failed to connect..', err);
}
};
async function disconnectMetamask() {
await window.ethereum.request({
method: 'wallet_revokePermissions',
params: [
{
eth_accounts: {},
},
],
const disconnect = async () => {
try {
sdk?.terminate();
} catch (err) {
console.warn('failed to disconnect..', err);
}
};
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,
gas: 1000000,
value: 100,
});
};
setConnectedAccounts([]);
}
const evaluateOutcome = async () => {
await DAO.methods.evaluateOutcome(0).send({
from: account,
gas: 1000000,
});
};
// const stakeAvailability = async () => { }
const requestWork = async () => {
work1.events.WorkAssigned(() => {
console.log('event callback');
});
await work1.methods.requestWork().send({
from: account,
gas: 1000000,
});
};
return (
<>
{!window.ethereum && (
<>
Please download Metamask
</>
)}
{window.ethereum && (
<>
{/* Button to trigger Metamask connection */}
<button type="button" onClick={() => connectMetamask()}>Connect to Metamask</button>
{!connected && <Button onClick={() => connect()}>Connect</Button>}
{/* Button to disconnect Metamask */}
<button type="button" onClick={() => disconnectMetamask()}>Disconnect from Metamask</button>
{/* Display the connected account */}
{connectedAccounts.map(
(connectedAccount) => <h2 key={connectedAccount}>{connectedAccount}</h2>,
)}
</>
{connected && (
<>
<div>
<div>
{chainId && `Chain ID: ${chainId}`}
</div>
<div>
{`Account: ${account}`}
</div>
<div>
{`Balance: ${balanceEther} ETH`}
</div>
<div>
{`REP: ${reputation}`}
</div>
<Button onClick={() => disconnect()}>Disconnect</Button>
</div>
<div>
{`Validation Pool Count: ${validationPoolCount}`}
</div>
<div>
<Button onClick={() => initiateValidationPool()}>Initiate Validation Pool</Button>
</div>
<div>
<Button onClick={() => evaluateOutcome()}>Evaluate Outcome</Button>
</div>
<div>
{`Work1 Price: ${work1Price} ETH`}
</div>
<div>
<Button onClick={() => requestWork()}>Request Work</Button>
</div>
</>
)}
</>
);

662
client/src/assets/DAO.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,28 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { MetaMaskProvider } from '@metamask/sdk-react';
import App from './App';
import './index.css';
// import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootswatch/dist/slate/bootstrap.min.css';
// import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
<MetaMaskProvider
debug={false}
sdkOptions={{
dappMetadata: {
name: 'DGF Prototype',
url: window.location.href,
},
enableAnalytics: false,
infuraAPIKey: '579d264c5f534aa1aefd6be323cb1a35',
readonlyRPCMap: {
'0x7a69': 'http://127.0.0.1:8545/',
},
}}
>
<App />
</MetaMaskProvider>
</React.StrictMode>,
);

View File

@ -1,6 +0,0 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.24;
import "./ReputationHolder.sol";
contract Availability is ReputationHolder {}

View File

@ -60,7 +60,7 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
address owner,
uint256 tokenId
) public view returns (uint256 value) {
require(ownerOf(tokenId) == owner);
require(ownerOf(tokenId) == owner, "NFT owner mismatch");
value = valueOf(tokenId);
}
@ -82,14 +82,18 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
uint256 toTokenId,
uint256 amount
) internal {
require(amount >= 0);
require(valueOf(fromTokenId) >= amount);
require(amount >= 0, "Value transfer amount must be positive");
require(
valueOf(fromTokenId) >= amount,
"Source token has insufficient value"
);
tokenValues[fromTokenId] -= amount;
tokenValues[toTokenId] += amount;
}
/// Accept fee to initiate a validation pool
/// TODO: Rather than accept author as a parameter, accept a reference to a forum post
/// TODO: Constrain duration to allowable range
function initiateValidationPool(
address author,
uint duration
@ -120,7 +124,7 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
bool inFavor,
uint256 tokenId
) internal {
require(block.timestamp < pool.endTime);
require(block.timestamp <= pool.endTime, "Pool end time has passed");
Stake storage _stake = pool.stakes[pool.stakeCount++];
_stake.sender = sender;
_stake.inFavor = inFavor;
@ -147,8 +151,11 @@ contract DAO is ERC721("Reputation", "REP"), ReputationHolder {
/// Evaluate outcome of a validation pool
function evaluateOutcome(uint poolIndex) public returns (bool votePasses) {
ValidationPool storage pool = validationPools[poolIndex];
require(block.timestamp >= pool.endTime);
require(pool.resolved == false);
require(
block.timestamp > pool.endTime,
"Pool end time has not yet arrived"
);
require(pool.resolved == false, "Pool is already resolved");
uint256 amountFor;
uint256 amountAgainst;
Stake storage _stake;