add submission method for validators
This commit is contained in:
parent
b0742db4e2
commit
1a5a0ce240
|
@ -84,6 +84,7 @@ function App() {
|
|||
provider={provider}
|
||||
sntEthereum={sntEthereum}
|
||||
sntAvalanche={sntAvalanche}
|
||||
avalancheBridge={avalancheBridge}
|
||||
ethereumBridge={ethereumBridge} />}
|
||||
</div>
|
||||
</Symfoni>
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue