add submission method for validators

This commit is contained in:
Barry Gitarts 2021-04-26 15:19:16 -04:00
parent b0742db4e2
commit 1a5a0ce240
4 changed files with 105 additions and 48 deletions

View File

@ -84,6 +84,7 @@ function App() {
provider={provider}
sntEthereum={sntEthereum}
sntAvalanche={sntAvalanche}
avalancheBridge={avalancheBridge}
ethereumBridge={ethereumBridge} />}
</div>
</Symfoni>

View File

@ -4,23 +4,25 @@ import { Wallet, providers, Contract, VoidSigner, BigNumberish } from "ethers";
import Typography from '@material-ui/core/Typography';
import { Bridge as IBridge } from "../types/Bridge"
import { SNT_ADDRESS } from "../constants/goerliAddress";
import { SNT_ADDRESS as AVA_SNT_ADDRESS } from "../constants/avalanche";
import { Formik, FormikProps } from 'formik';
import StatusTextField from './base/TextField';
import useStyles from '../styles/adminBridge';
import StatusButton from './base/Button';
import { ETHEREUM_CHAIN_ID, AVA_CHAIN_ID } from '../constants/networks';
import { createResourceID, createERCDepositData, toWei } from '../utils/helpers';
import { createResourceID, createERCDepositData, toWei, generateDepositDataHash } from '../utils/helpers';
import { Web3Provider } from '@ethersproject/providers';
import { ERC20 } from "../types/ERC20";
import { fromWei } from "../utils/helpers"
import { getSetBalance } from "../utils/contracts";
import { ethereumSNTHandlerAddress } from "../constants/bridges";
import { ethereumSNTHandlerAddress, avalancheSNTHandlerAddress } from "../constants/bridges";
import { getDepositEvents, EnrichedDepositEvent } from "../utils/events";
import Deposit from "./Deposit";
type IBridgeInfo = {
amount: string,
account: string,
selectedDeposit: string
}
interface Props {
@ -29,8 +31,9 @@ interface Props {
sntEthereum: ERC20 | undefined,
sntAvalanche: ERC20 | undefined,
ethereumBridge: IBridge | undefined,
avalancheBridge: IBridge | undefined,
}
export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, sntAvalanche, ethereumBridge }) => {
export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, sntAvalanche, ethereumBridge, avalancheBridge }) => {
const classes: any = useStyles()
const bridge: SymfoniBridge = useContext(BridgeContext);
const [message, setMessage] = useState("");
@ -42,7 +45,7 @@ export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, s
const [deposits, setDeposits] = useState<EnrichedDepositEvent[]>();
const { fieldWidth } = classes;
useEffect(() => {
getDepositEvents(ethereumBridge, setDeposits)
getDepositEvents(ethereumBridge, avalancheBridge, setDeposits)
}, [bridge])
useEffect(() => {
@ -53,40 +56,46 @@ export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, s
getSetBalance(sntAvalanche, account, setSntAvalancheBalance);
}, [account])
console.log({deposits})
return (
<Formik
initialValues={{
amount: '',
account
account: '',
selectedDeposit: ''
}}
onSubmit={async (values) => {
const { amount, account } = values;
const weiAmount = toWei(amount);
const resourceId = createResourceID(SNT_ADDRESS, ETHEREUM_CHAIN_ID);
const encodedData = createERCDepositData(toWei(amount), account);
if (!provider) return;
const signer = provider.getSigner()
const sntActiveProvider = sntEthereum?.connect(signer);
const activeBridge = ethereumBridge?.connect(signer);
if(!bridge || !bridge.instance) return
const approved = await sntActiveProvider?.allowance(account, ethereumSNTHandlerAddress);
if (approved?.lt(weiAmount)) {
const amt = approved.eq(0) ? weiAmount : toWei('0');
//TODO approve handler not bridge
await sntActiveProvider?.approve(ethereumSNTHandlerAddress, amt);
const { amount, account, selectedDeposit } = values;
if (!deposits) return
const deposit = deposits.find(d => d.decoded?.depositNonce.eq(selectedDeposit))
if (!provider || !deposit) return
const { depositRecord } = deposit
if (!depositRecord) return
const hasPassed = deposit.proposal?.status || 0
const signer = provider.getSigner();
const activeBridge = avalancheBridge?.connect(signer);
const sntAvalancheResourceId = createResourceID(AVA_SNT_ADDRESS, AVA_CHAIN_ID);
const { _destinationRecipientAddress, _amount } = depositRecord
const encodedMetaData = createERCDepositData(_amount, _destinationRecipientAddress)
const depositDataHash = generateDepositDataHash(avalancheSNTHandlerAddress, encodedMetaData);
const depositNonce = deposit.decoded?.depositNonce;
const destinationId: number | undefined = deposit.decoded?.destinationChainID;
if (!depositNonce || !destinationId) return
const originationId: number = destinationId === ETHEREUM_CHAIN_ID ? AVA_CHAIN_ID : ETHEREUM_CHAIN_ID;
if (hasPassed) {
//TODO update UI state on success or fail
const vote = await activeBridge?.executeProposal(
originationId,
depositNonce,
encodedMetaData,
sntAvalancheResourceId
)
} else {
console.log({AVA_CHAIN_ID, resourceId, encodedData});
const deposit = await activeBridge?.deposit(
AVA_CHAIN_ID,
resourceId,
encodedData
);
if (deposit) {
const receipt = await deposit.wait(1);
console.log({receipt});
}
const vote = await activeBridge?.voteProposal(
originationId,
depositNonce,
sntAvalancheResourceId,
depositDataHash
)
}
}}
>
@ -100,8 +109,8 @@ export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, s
}: FormikProps<IBridgeInfo>) => {
return (
<form className={classes.root} onSubmit={handleSubmit}>
<StatusTextField
className={fieldWidth}
<StatusTextField
className={fieldWidth}
name="amount"
label="Enter amount of SNT to send across bridge"
idFor="amount"
@ -118,14 +127,16 @@ export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, s
onBlur={handleBlur}
value={values.account}
/>
{deposits?.map((d: EnrichedDepositEvent) => <Deposit
key={d.data}
deposit={d} />)}
<StatusButton
className={fieldWidth}
buttonText="Submit"
onClick={handleSubmit}
/>
{deposits?.map((d: EnrichedDepositEvent) => <Deposit
key={d.data}
checked={d.decoded?.depositNonce.toString() === values.selectedDeposit}
setFieldValue={setFieldValue}
deposit={d} />)}
<StatusButton
className={fieldWidth}
buttonText="Submit"
onClick={handleSubmit}
/>
</form>
)}
}

View File

@ -1,19 +1,30 @@
import React, { Fragment } from 'react';
import React, { Fragment, ChangeEvent } from 'react';
import { EnrichedDepositEvent } from "../utils/events"
import Typography from '@material-ui/core/Typography';
import Checkbox from '@material-ui/core/Checkbox';
import useStyles from '../styles/deposit';
import { chainIDToName } from '../constants/networks';
interface Props {
deposit: EnrichedDepositEvent
deposit: EnrichedDepositEvent,
checked: boolean,
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void
}
const Deposit: React.FC<Props> = ({ deposit }) => {
const Deposit: React.FC<Props> = ({ deposit, checked, setFieldValue }) => {
const classes: any = useStyles();
const { cellText } = classes;
const { decoded, depositRecord } = deposit;
const { decoded, depositRecord, proposal } = deposit;
const depositNonce = decoded?.depositNonce.toString()
return (
<Fragment>
<Checkbox
name={depositNonce}
checked={checked}
onChange={() => setFieldValue('selectedDeposit', depositNonce)}
inputProps={{ 'aria-label': 'primary checkbox' }}
/>
<Typography className={cellText}>Status: {proposal?.statusName}</Typography>
<Typography className={cellText}>Deposit Nonce: {decoded?.depositNonce.toNumber()}</Typography>
{!!decoded && <Typography className={cellText}>Destination Chain: {chainIDToName[decoded?.destinationChainID]}</Typography>}
<Typography className={cellText}>Depositer: {depositRecord?._depositer.toString()}</Typography>

View File

@ -2,6 +2,23 @@ import { Bridge as IBridge } from "../types/Bridge";
import { ERC20Handler } from "../types/ERC20Handler";
import { getERC20Handler } from "./contracts";
import { Event, BigNumber } from "ethers";
import { ETHEREUM_CHAIN_ID } from "../constants/networks";
import { generateDepositDataHash, createERCDepositData } from "./helpers"
import { avalancheSNTHandlerAddress } from "../constants/bridges"
enum ProposalStatus {
Inactive,
Active,
Passed,
Executed,
Cancelled
}
type Proposal = {
status: ProposalStatus,
yesVotesTotal: number,
statusName: string
}
type DecodedDeposit = {
depositNonce: BigNumber,
@ -16,23 +33,40 @@ type DepositRecord = {
}
export interface EnrichedDepositEvent extends Event {
decoded?: DecodedDeposit,
depositRecord?: DepositRecord
depositRecord?: DepositRecord,
proposal?: Proposal
}
export const getDepositEvents = async (ethereumBridge: IBridge|undefined, setState: Function) => {
export const getDepositEvents = async (
ethereumBridge: IBridge|undefined,
avalancheBridge: IBridge|undefined,
setState: Function
) => {
if(!ethereumBridge) return
const events = ethereumBridge.filters.Deposit(null,null,null)
const deposits: Event[] = await ethereumBridge.queryFilter(events)
const enriched = deposits.map(async d => {
const { data, topics, decode } = d
if (!decode) return
const decoded = decode(data, topics)
const decoded: DecodedDeposit = decode(data, topics)
const newD: EnrichedDepositEvent = d
newD.decoded = decoded
const handlerAddress = await ethereumBridge._resourceIDToHandlerAddress(decoded.resourceID)
const erc20Handler: ERC20Handler = getERC20Handler(handlerAddress, ethereumBridge.provider);
const depositRecord = await erc20Handler._depositRecords(decoded.destinationChainID, decoded.depositNonce);
newD.depositRecord = depositRecord;
const { _amount, _destinationRecipientAddress } = depositRecord;
const encodedMetaData = createERCDepositData(_amount, _destinationRecipientAddress)
const hash = generateDepositDataHash(avalancheSNTHandlerAddress, encodedMetaData)
const proposal = await avalancheBridge?.getProposal(ETHEREUM_CHAIN_ID, decoded.depositNonce, hash)
let statusNum = proposal?._status
if (!statusNum) statusNum = 0;
const proposalStatus: string = ProposalStatus[statusNum]
newD.proposal = {
status: statusNum,
yesVotesTotal: proposal?._yesVotesTotal ? proposal._yesVotesTotal : 0,
statusName: proposalStatus
}
return newD
})
const resolved = await Promise.all(enriched)