add multichain asset tracking
This commit is contained in:
parent
8893e767bf
commit
07912aef80
|
@ -8,14 +8,19 @@ import { Symfoni } from "./hardhat/SymfoniContext";
|
|||
import { Greeter } from './components/Greeter';
|
||||
import { Bridge } from './components/Bridge';
|
||||
import { getAndSetProvider } from './utils/network';
|
||||
import { ERC20 } from './types/ERC20';
|
||||
import Header from './components/Header';
|
||||
import { getISntEthereum } from './utils/contracts';
|
||||
import { goerliProvider } from './utils/providers'
|
||||
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
const classes: any = useStyles();
|
||||
const [provider, setProvider] = useState<Provider>();
|
||||
const [ethereumProvider, setEthereumProvider] = useState<Provider>();
|
||||
const [account, setAccount] = useState<string>('');
|
||||
const [sntEthereum, setSntEthereum] = useState<ERC20>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!provider) getAndSetProvider(setProvider);
|
||||
|
@ -24,12 +29,19 @@ function App() {
|
|||
})
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (provider) {
|
||||
const snt: ERC20 = getISntEthereum(goerliProvider)
|
||||
setSntEthereum(snt);
|
||||
}
|
||||
}, [provider])
|
||||
|
||||
useEffect(() => {
|
||||
if (window.ethereum && window.ethereum.selectedAddress) setAccount(window.ethereum.selectedAddress);
|
||||
window.ethereum.on('accountsChanged', function (accounts: Array<string>) {
|
||||
setAccount(accounts[0]);
|
||||
});
|
||||
}, [window.ethereum.selectedAddress])
|
||||
})
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
|
@ -39,8 +51,13 @@ function App() {
|
|||
account={account}
|
||||
provider={provider}
|
||||
enableEthereum={undefined}
|
||||
sntEthereum={sntEthereum}
|
||||
/>
|
||||
<Bridge
|
||||
account={account}
|
||||
provider={provider}
|
||||
sntEthereum={sntEthereum}
|
||||
/>
|
||||
<Bridge></Bridge>
|
||||
</div>
|
||||
</Symfoni>
|
||||
</ThemeProvider>
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { BridgeContext, SymfoniBridge } from "./../hardhat/SymfoniContext";
|
||||
import { Wallet, providers, Contract, VoidSigner } from "ethers";
|
||||
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 } from "../constants/goerliAddress";
|
||||
import { Formik, FormikProps } from 'formik';
|
||||
import StatusTextField from './base/TextField';
|
||||
import useStyles from '../styles/bridge';
|
||||
import StatusButton from './base/Button';
|
||||
|
||||
import { ETHEREUM_CHAIN_ID, AVA_CHAIN_ID } from '../constants/networks';
|
||||
import { createResourceID, createERCDepositData, toWei } from '../utils/helpers';
|
||||
import { Provider } from '@ethersproject/providers';
|
||||
import { getISntEthereum } from '../utils/contracts';
|
||||
import { ERC20 } from "../types/ERC20";
|
||||
import { fromWei } from "../utils/helpers"
|
||||
import { getSetBalance } from "../utils/contracts";
|
||||
|
||||
type IBridgeInfo = {
|
||||
amount: string,
|
||||
account: string,
|
||||
}
|
||||
const wallet = Wallet.createRandom();
|
||||
|
||||
interface Props { }
|
||||
interface Props {
|
||||
account: string,
|
||||
provider: Provider | undefined,
|
||||
sntEthereum: ERC20 | undefined
|
||||
}
|
||||
const FUJI_BRIDGE = '0xE57Eb49689bCAE4dE61D326F7E79Bd14aB527f0f';
|
||||
const GOERLI_BRIDGE = '0xD0E461b1Dc56503fC72565FA964C28E274146D44';
|
||||
const fujiProvider = new providers.JsonRpcProvider("https://api.avax-test.network/ext/bc/C/rpc");
|
||||
|
@ -24,13 +36,14 @@ const fujiVoidSigner = new VoidSigner(wallet.address, fujiProvider);
|
|||
const goerliVoidsigner = new VoidSigner(wallet.address, goerliProvider);
|
||||
|
||||
|
||||
export const Bridge: React.FC<Props> = () => {
|
||||
export const Bridge: React.FC<Props> = ({ account, provider, sntEthereum }) => {
|
||||
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 { fieldWidth } = classes;
|
||||
useEffect(() => {
|
||||
const doAsync = async () => {
|
||||
|
@ -52,6 +65,10 @@ export const Bridge: React.FC<Props> = () => {
|
|||
doAsync();
|
||||
}, [bridge])
|
||||
|
||||
useEffect(() => {
|
||||
getSetBalance(sntEthereum, account, setSntEthereumBalance);
|
||||
}, [account])
|
||||
|
||||
const handleSetGreeting = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.preventDefault()
|
||||
if (!bridge.instance) throw Error("Bridge instance not ready")
|
||||
|
@ -67,8 +84,18 @@ export const Bridge: React.FC<Props> = () => {
|
|||
<Formik
|
||||
initialValues={{
|
||||
amount: '',
|
||||
account
|
||||
}}
|
||||
onSubmit={async (values) => {
|
||||
const { amount, account } = values;
|
||||
const resourceId = createResourceID(SNT_ADDRESS, ETHEREUM_CHAIN_ID);
|
||||
const encodedData = createERCDepositData(toWei(amount), account);
|
||||
const tx = await bridge.instance?.deposit(
|
||||
AVA_CHAIN_ID,
|
||||
resourceId,
|
||||
encodedData
|
||||
);
|
||||
}}
|
||||
onSubmit={async (values) => {}}
|
||||
>
|
||||
{({
|
||||
values,
|
||||
|
@ -80,15 +107,27 @@ export const Bridge: React.FC<Props> = () => {
|
|||
}: FormikProps<IBridgeInfo>) => {
|
||||
return (
|
||||
<form className={classes.root} onSubmit={handleSubmit}>
|
||||
{!!sntEthereumBalance && <Typography className={classes.balanceText}>
|
||||
SNT Ethereum balance: {fromWei(sntEthereumBalance)}
|
||||
</Typography>}
|
||||
<StatusTextField
|
||||
className={fieldWidth}
|
||||
name="amount"
|
||||
label="Enter amount of SNT to send across bridge"
|
||||
idFor="Title"
|
||||
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"
|
||||
|
|
|
@ -5,7 +5,7 @@ import { EnableEthereum } from '../localTypes'
|
|||
import useStyles from '../styles/header'
|
||||
import { getNetwork } from '../utils/network'
|
||||
import { Provider } from '@ethersproject/providers'
|
||||
|
||||
import { ERC20 } from "../types/ERC20";
|
||||
|
||||
const formatAccount = (account: string): string => {
|
||||
const start = account.slice(0,6)
|
||||
|
@ -16,10 +16,12 @@ const formatAccount = (account: string): string => {
|
|||
type HeaderProps = {
|
||||
account: string,
|
||||
enableEthereum: EnableEthereum | undefined,
|
||||
provider: Provider | undefined
|
||||
provider: Provider | undefined,
|
||||
sntEthereum: ERC20 | undefined
|
||||
}
|
||||
|
||||
function Header({account, enableEthereum, provider}: HeaderProps) {
|
||||
|
||||
function Header({account, enableEthereum, provider, sntEthereum}: HeaderProps) {
|
||||
const classes: any = useStyles()
|
||||
const [network, sNetwork] = useState<string>()
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
export const ETHEREUM_CHAIN_ID: number = 1;
|
||||
export const AVA_CHAIN_ID: number = 2;
|
|
@ -6,7 +6,7 @@ const useStyles = makeStyles(theme => ({
|
|||
gridTemplateColumns: 'repeat(48, [col] 1fr)',
|
||||
gridColumn: '3 / 45',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
gridTemplateRows: '4rem 4rem auto auto 6rem',
|
||||
gridTemplateRows: '3rem 6rem 6rem 5rem',
|
||||
gridColumn: '8 / 42',
|
||||
}
|
||||
},
|
||||
|
@ -14,6 +14,11 @@ const useStyles = makeStyles(theme => ({
|
|||
cursor: 'pointer',
|
||||
color: '#4360DF'
|
||||
},
|
||||
balanceText: {
|
||||
color: '#025ea2',
|
||||
gridColumn: '3 / 49',
|
||||
fontSize: '1.5rem'
|
||||
},
|
||||
title: {
|
||||
gridColumn: '3 / 49'
|
||||
},
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { Wallet, providers, Contract, VoidSigner } from "ethers";
|
||||
import { SNT_ADDRESS } from "../constants/goerliAddress";
|
||||
import { ERC20 } from "../types/ERC20";
|
||||
import { ERC20__factory } from "../types/factories/ERC20__factory"
|
||||
import { Provider } from '@ethersproject/providers'
|
||||
|
||||
export const getISntEthereum = (provider: Provider) => {
|
||||
return ERC20__factory.connect(SNT_ADDRESS, provider);
|
||||
}
|
||||
|
||||
export const getSetBalance = async (token: ERC20|undefined, account: string, setState: Function) => {
|
||||
const balance = await token?.balanceOf(account);
|
||||
setState(balance);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import { Address } from "cluster";
|
||||
import { BigNumberish, BytesLike, utils } from "ethers";
|
||||
const {
|
||||
hexZeroPad,
|
||||
hexlify,
|
||||
formatBytes32String,
|
||||
keccak256,
|
||||
formatEther
|
||||
} = utils;
|
||||
|
||||
export const fromWei = (x: BigNumberish) => Number(formatEther(x));
|
||||
const AbiCoder = new utils.AbiCoder;
|
||||
export const toHex = (covertThis: any, padding: any) => {
|
||||
return hexZeroPad(hexlify(covertThis), padding);
|
||||
};
|
||||
|
||||
export const createResourceID = (contractAddress: string, chainID: number) => {
|
||||
const str = chainID.toString() + contractAddress
|
||||
return formatBytes32String(str.slice(0, 31));
|
||||
};
|
||||
|
||||
export const abiEncode = (valueTypes: any[], values: any[]) => {
|
||||
return AbiCoder.encode(valueTypes, values)
|
||||
};
|
||||
|
||||
export const generateDepositMetaData = (amount: number, recipientAddress: string) => {
|
||||
console.log({recipientAddress})
|
||||
const addressLength = 20;
|
||||
return abiEncode(
|
||||
['uint256', 'uint256', 'bytes'],
|
||||
[1, addressLength, recipientAddress]
|
||||
);
|
||||
}
|
||||
|
||||
export const toWei = (x: string) => utils.parseEther(x);
|
||||
|
||||
export const createERCDepositData = (
|
||||
tokenAmountOrID: BigNumberish,
|
||||
recipientAddress: string
|
||||
): string => {
|
||||
const lenRecipientAddress = 20;
|
||||
return '0x' +
|
||||
toHex(tokenAmountOrID, 32).substr(2) + // Token amount or ID to deposit (32 bytes)
|
||||
toHex(lenRecipientAddress, 32).substr(2) + // len(recipientAddress) (32 bytes)
|
||||
recipientAddress.substr(2); // recipientAddress (?? bytes)
|
||||
};
|
||||
|
||||
export const generateDepositDataHash = (handler: string, depositData: string): BytesLike => keccak256(handler + depositData.substr(2));
|
|
@ -0,0 +1,8 @@
|
|||
import { Wallet, providers, Contract, VoidSigner } from "ethers";
|
||||
|
||||
const wallet = Wallet.createRandom();
|
||||
export const goerliProvider = new providers.InfuraProvider("goerli");
|
||||
export const fujiProvider = new providers.JsonRpcProvider("https://api.avax-test.network/ext/bc/C/rpc");
|
||||
const fujiSigner = new Wallet(wallet.privateKey, fujiProvider);
|
||||
export const fujiVoidSigner = new VoidSigner(wallet.address, fujiProvider);
|
||||
export const goerliVoidsigner = new VoidSigner(wallet.address, goerliProvider);
|
|
@ -22,7 +22,6 @@ export const abiEncode = (valueTypes: any[], values: any[]) => {
|
|||
};
|
||||
|
||||
export const generateDepositMetaData = (amount: number, recipientAddress: string) => {
|
||||
console.log({recipientAddress})
|
||||
const addressLength = 20;
|
||||
return abiEncode(
|
||||
['uint256', 'uint256', 'bytes'],
|
||||
|
|
Loading…
Reference in New Issue