From 1a5a0ce24049a740b5d5d70ad8a9f63b4063a77c Mon Sep 17 00:00:00 2001 From: Barry Gitarts Date: Mon, 26 Apr 2021 15:19:16 -0400 Subject: [PATCH] add submission method for validators --- frontend/src/App.tsx | 1 + frontend/src/components/AdminBridge.tsx | 93 ++++++++++++++----------- frontend/src/components/Deposit.tsx | 19 +++-- frontend/src/utils/events.ts | 40 ++++++++++- 4 files changed, 105 insertions(+), 48 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index faf3f08..78d81e4 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -84,6 +84,7 @@ function App() { provider={provider} sntEthereum={sntEthereum} sntAvalanche={sntAvalanche} + avalancheBridge={avalancheBridge} ethereumBridge={ethereumBridge} />} diff --git a/frontend/src/components/AdminBridge.tsx b/frontend/src/components/AdminBridge.tsx index cb4e93c..2efd967 100644 --- a/frontend/src/components/AdminBridge.tsx +++ b/frontend/src/components/AdminBridge.tsx @@ -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 = ({ account, provider, sntEthereum, sntAvalanche, ethereumBridge }) => { +export const AdminBridge: React.FC = ({ 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 = ({ account, provider, sntEthereum, s const [deposits, setDeposits] = useState(); const { fieldWidth } = classes; useEffect(() => { - getDepositEvents(ethereumBridge, setDeposits) + getDepositEvents(ethereumBridge, avalancheBridge, setDeposits) }, [bridge]) useEffect(() => { @@ -53,40 +56,46 @@ export const AdminBridge: React.FC = ({ account, provider, sntEthereum, s getSetBalance(sntAvalanche, account, setSntAvalancheBalance); }, [account]) - console.log({deposits}) - return ( { - 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 = ({ account, provider, sntEthereum, s }: FormikProps) => { return (
- = ({ account, provider, sntEthereum, s onBlur={handleBlur} value={values.account} /> - {deposits?.map((d: EnrichedDepositEvent) => )} - + {deposits?.map((d: EnrichedDepositEvent) => )} + )} } diff --git a/frontend/src/components/Deposit.tsx b/frontend/src/components/Deposit.tsx index 74f332f..7953ee1 100644 --- a/frontend/src/components/Deposit.tsx +++ b/frontend/src/components/Deposit.tsx @@ -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 = ({ deposit }) => { +const Deposit: React.FC = ({ 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 ( + setFieldValue('selectedDeposit', depositNonce)} + inputProps={{ 'aria-label': 'primary checkbox' }} + /> + Status: {proposal?.statusName} Deposit Nonce: {decoded?.depositNonce.toNumber()} {!!decoded && Destination Chain: {chainIDToName[decoded?.destinationChainID]}} Depositer: {depositRecord?._depositer.toString()} diff --git a/frontend/src/utils/events.ts b/frontend/src/utils/events.ts index 8c1900c..e25005f 100644 --- a/frontend/src/utils/events.ts +++ b/frontend/src/utils/events.ts @@ -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)