parent
02a4db6b80
commit
0c14af3a47
|
@ -7,6 +7,7 @@ import { Provider, Web3Provider } from '@ethersproject/providers'
|
|||
import { Symfoni } from "./hardhat/SymfoniContext";
|
||||
import { Greeter } from './components/Greeter';
|
||||
import { Bridge } from './components/Bridge';
|
||||
import { AdminBridge } from './components/AdminBridge';
|
||||
import { getAndSetProvider } from './utils/network';
|
||||
import { ERC20 } from './types/ERC20';
|
||||
import { Bridge as IBridge } from './types/Bridge';
|
||||
|
@ -26,6 +27,7 @@ function App() {
|
|||
const [sntAvalanche, setSntAvalanche] = useState<ERC20>();
|
||||
const [ethereumBridge, setEthereumBridge] = useState<IBridge>();
|
||||
const [avalancheBridge, setAvalancheBridge] = useState<IBridge>();
|
||||
const [isRelayer, setIsRelayer] = useState<boolean>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!provider) getAndSetProvider(setProvider);
|
||||
|
@ -44,10 +46,11 @@ function App() {
|
|||
}, [provider])
|
||||
|
||||
useEffect(() => {
|
||||
//TODO use ethereum provider
|
||||
if (!provider) return
|
||||
//TODO implement ava bridge
|
||||
const avalancheBridge: IBridge = getBridge(fujiAddress, fujiProvider);
|
||||
avalancheBridge.isRelayer(account).then(isRelayer => {
|
||||
setIsRelayer(isRelayer)
|
||||
});
|
||||
const ethereumBridge: IBridge = getBridge(ethereumAddress, provider);
|
||||
setEthereumBridge(ethereumBridge);
|
||||
setAvalancheBridge(avalancheBridge);
|
||||
|
@ -77,6 +80,12 @@ function App() {
|
|||
sntAvalanche={sntAvalanche}
|
||||
ethereumBridge={ethereumBridge}
|
||||
/>}
|
||||
{!!isRelayer && <AdminBridge
|
||||
account={account}
|
||||
provider={provider}
|
||||
sntEthereum={sntEthereum}
|
||||
sntAvalanche={sntAvalanche}
|
||||
ethereumBridge={ethereumBridge} />}
|
||||
</div>
|
||||
</Symfoni>
|
||||
</ThemeProvider>
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { BridgeContext, SymfoniBridge } from "./../hardhat/SymfoniContext";
|
||||
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 { 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 { 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 { getDepositEvents, EnrichedEvent } from "../utils/events";
|
||||
|
||||
type IBridgeInfo = {
|
||||
amount: string,
|
||||
account: string,
|
||||
}
|
||||
const wallet = Wallet.createRandom();
|
||||
|
||||
interface Props {
|
||||
account: string,
|
||||
provider: Web3Provider | undefined,
|
||||
sntEthereum: ERC20 | undefined,
|
||||
sntAvalanche: ERC20 | undefined,
|
||||
ethereumBridge: IBridge | undefined,
|
||||
}
|
||||
const FUJI_BRIDGE = '0xE57Eb49689bCAE4dE61D326F7E79Bd14aB527f0f';
|
||||
const GOERLI_BRIDGE = '0xD0E461b1Dc56503fC72565FA964C28E274146D44';
|
||||
const fujiProvider = new providers.JsonRpcProvider("https://api.avax-test.network/ext/bc/C/rpc");
|
||||
const goerliProvider = new providers.InfuraProvider("goerli");
|
||||
const fujiSigner = new Wallet(wallet.privateKey, fujiProvider);
|
||||
const fujiVoidSigner = new VoidSigner(wallet.address, fujiProvider);
|
||||
const goerliVoidsigner = new VoidSigner(wallet.address, goerliProvider);
|
||||
|
||||
export const AdminBridge: React.FC<Props> = ({ account, provider, sntEthereum, sntAvalanche, ethereumBridge }) => {
|
||||
const classes: any = useStyles()
|
||||
const bridge: SymfoniBridge = useContext(BridgeContext);
|
||||
const [message, setMessage] = useState("");
|
||||
const [inputGreeting, setInputGreeting] = useState("");
|
||||
const [goerliBridge, setGoerliBridge] = useState<IBridge>();
|
||||
const [fujiBridge, setFujiBridge] = useState<IBridge>();
|
||||
const [sntEthereumBalance, setSntEthereumBalance] = useState<BigNumberish>();
|
||||
const [sntAvalancheBalance, setSntAvalancheBalance] = useState<BigNumberish>();
|
||||
const [deposits, setDeposits] = useState<EnrichedEvent[]>();
|
||||
const { fieldWidth } = classes;
|
||||
useEffect(() => {
|
||||
getDepositEvents(ethereumBridge, setDeposits)
|
||||
const doAsync = async () => {
|
||||
if (!bridge.instance) return
|
||||
console.log("Bridge is deployed at ", bridge.instance.address)
|
||||
let gBridge = new Contract(
|
||||
GOERLI_BRIDGE,
|
||||
bridge.instance.interface,
|
||||
goerliVoidsigner
|
||||
) as IBridge;
|
||||
setGoerliBridge(gBridge);
|
||||
let fBridge = new Contract(
|
||||
FUJI_BRIDGE,
|
||||
bridge.instance.interface,
|
||||
fujiVoidSigner
|
||||
) as IBridge;
|
||||
setFujiBridge(fBridge);
|
||||
};
|
||||
doAsync();
|
||||
}, [bridge])
|
||||
|
||||
useEffect(() => {
|
||||
getSetBalance(sntEthereum, account, setSntEthereumBalance);
|
||||
}, [account])
|
||||
|
||||
useEffect(() => {
|
||||
getSetBalance(sntAvalanche, account, setSntAvalancheBalance);
|
||||
}, [account])
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
amount: '',
|
||||
account
|
||||
}}
|
||||
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);
|
||||
} 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});
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({
|
||||
values,
|
||||
errors,
|
||||
handleSubmit,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
setFieldValue
|
||||
}: FormikProps<IBridgeInfo>) => {
|
||||
return (
|
||||
<form className={classes.root} onSubmit={handleSubmit}>
|
||||
<StatusTextField
|
||||
className={fieldWidth}
|
||||
name="amount"
|
||||
label="Enter amount of SNT to send across bridge"
|
||||
idFor="amount"
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
value={values.amount}
|
||||
/>
|
||||
<StatusTextField
|
||||
className={fieldWidth}
|
||||
name="account"
|
||||
label="account receiving across bridge"
|
||||
idFor="account"
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
value={values.account}
|
||||
/>
|
||||
<StatusButton
|
||||
className={fieldWidth}
|
||||
buttonText="Submit"
|
||||
onClick={handleSubmit}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
}
|
||||
</Formik>
|
||||
|
||||
)
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import { makeStyles } from '@material-ui/core/styles'
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(48, [col] 1fr)',
|
||||
gridColumn: '3 / 45',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
gridTemplateRows: '3rem 6rem 6rem 5rem',
|
||||
gridColumn: '8 / 42',
|
||||
},
|
||||
marginTop: '3rem'
|
||||
},
|
||||
adornmentText: {
|
||||
cursor: 'pointer',
|
||||
color: '#4360DF'
|
||||
},
|
||||
balanceText: {
|
||||
color: '#025ea2',
|
||||
gridColumn: '3 / 49',
|
||||
fontSize: '1.5rem'
|
||||
},
|
||||
title: {
|
||||
gridColumn: '3 / 49'
|
||||
},
|
||||
fieldWidth: {
|
||||
gridColumn: '3 / 49'
|
||||
},
|
||||
datePicker: {
|
||||
borderRadius: '25px'
|
||||
}
|
||||
}))
|
||||
|
||||
export default useStyles
|
|
@ -6,7 +6,7 @@ const useStyles = makeStyles(theme => ({
|
|||
gridTemplateColumns: 'repeat(48, [col] 1fr)',
|
||||
gridTemplateRows: '3rem 5rem auto auto',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
gridTemplateRows: '4rem 4rem auto auto 6rem'
|
||||
gridTemplateRows: '3rem 25rem'
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { Bridge as IBridge } from "../types/Bridge";
|
||||
import { Event } from "ethers";
|
||||
|
||||
export interface EnrichedEvent extends Event {
|
||||
decoded?: Array<any>
|
||||
}
|
||||
|
||||
export const getDepositEvents = async (ethereumBridge: 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(d => {
|
||||
const { data, topics, decode } = d
|
||||
if (!decode) return
|
||||
const decoded = decode(data, topics)
|
||||
const newD: EnrichedEvent = d
|
||||
newD.decoded = decoded
|
||||
return newD
|
||||
})
|
||||
setState(enriched)
|
||||
}
|
Loading…
Reference in New Issue