From d1850e4c598795d5c07b2159172e64596bc1158b Mon Sep 17 00:00:00 2001 From: Hendrik Hofstadt Date: Thu, 20 Aug 2020 16:53:25 +0200 Subject: [PATCH] Improve webinterface --- web/public/manifest.json | 14 +-- web/src/config.ts | 2 +- web/src/pages/Transfer.tsx | 183 +++++++++++++++++++------------ web/src/pages/TransferSolana.tsx | 12 +- 4 files changed, 124 insertions(+), 87 deletions(-) diff --git a/web/public/manifest.json b/web/public/manifest.json index 080d6c77a..bdfb10021 100644 --- a/web/public/manifest.json +++ b/web/public/manifest.json @@ -1,21 +1,11 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "Wormhole Bridge", + "name": "Solana token bridge", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" } ], "start_url": ".", diff --git a/web/src/config.ts b/web/src/config.ts index cbb0e81a1..749b8a857 100644 --- a/web/src/config.ts +++ b/web/src/config.ts @@ -2,7 +2,7 @@ import {PublicKey} from "@solana/web3.js"; const BRIDGE_ADDRESS = "0xac3eB48829fFC3C37437ce4459cE63F1F4d4E0b4"; -const SOLANA_BRIDGE_PROGRAM = new PublicKey("C2MtMo3upLePs5Sumkw61aBgcgpCw9Q84KyJMovLbXu6"); +const SOLANA_BRIDGE_PROGRAM = new PublicKey("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"); const TOKEN_PROGRAM = new PublicKey("TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"); diff --git a/web/src/pages/Transfer.tsx b/web/src/pages/Transfer.tsx index 7d241288e..7b9a5f963 100644 --- a/web/src/pages/Transfer.tsx +++ b/web/src/pages/Transfer.tsx @@ -2,19 +2,18 @@ import React, {useContext, useEffect, useState} from 'react'; import ClientContext from "../providers/ClientContext"; import * as solanaWeb3 from '@solana/web3.js'; import {Account, Connection, PublicKey, Transaction} from '@solana/web3.js'; -import {Button, Col, Form, Input, InputNumber, message, Row, Select, Space} from "antd"; +import {Button, Card, Col, Divider, Form, Input, InputNumber, List, message, Row, Select} from "antd"; import {ethers} from "ethers"; import {Erc20Factory} from "../contracts/Erc20Factory"; import {Arrayish, BigNumber, BigNumberish} from "ethers/utils"; import {WormholeFactory} from "../contracts/WormholeFactory"; import {WrappedAssetFactory} from "../contracts/WrappedAssetFactory"; import {BRIDGE_ADDRESS} from "../config"; -import {SlotContext} from "../providers/SlotContext"; import {SolanaTokenContext} from "../providers/SolanaTokenContext"; import {BridgeContext} from "../providers/BridgeContext"; -import SplBalances from "../components/SplBalances"; import {AssetMeta, SolanaBridge} from "../utils/bridge"; import KeyContext from "../providers/KeyContext"; +import {FormInstance} from "antd/lib/form"; // @ts-ignore @@ -79,7 +78,6 @@ async function createWrapped(c: Connection, b: SolanaBridge, key: Account, meta: function Transfer() { let c = useContext(ClientContext); let tokenAccounts = useContext(SolanaTokenContext); - let slot = useContext(SlotContext); let bridge = useContext(BridgeContext); let k = useContext(KeyContext); @@ -91,20 +89,63 @@ function Transfer() { chainID: 0, assetAddress: new Buffer("") }); - let [amount, setAmount] = useState(0); + let [amount, setAmount] = useState(new BigNumber(0)); + let [amountValid, setAmountValid] = useState(false); + let [address, setAddress] = useState(""); let [addressValid, setAddressValid] = useState(false) - let [solanaAccount, setSolanaAccount] = useState(false) + + let [solanaAccount, setSolanaAccount] = useState({ + valid: false, + message: "" + }) let [wrappedMint, setWrappedMint] = useState("") + let [recipient, setRecipient] = useState("") + + let formRef = React.createRef(); useEffect(() => { + let fetchBalance = async (token: string) => { + try { + let e = WrappedAssetFactory.connect(token, provider); + let addr = await signer.getAddress(); + let balance = await e.balanceOf(addr); + let decimals = await e.decimals(); + let allowance = await e.allowance(addr, BRIDGE_ADDRESS); + + let info = { + balance: balance.div(new BigNumber(10).pow(decimals)), + allowance: allowance.div(new BigNumber(10).pow(decimals)), + decimals: decimals, + isWrapped: false, + chainID: 2, + assetAddress: new Buffer(token.slice(2), "hex") + } + + let b = WormholeFactory.connect(BRIDGE_ADDRESS, provider); + + let isWrapped = await b.isWrappedAsset(token) + if (isWrapped) { + info.chainID = await e.assetChain() + info.assetAddress = new Buffer((await e.assetAddress()).slice(2), "hex") + info.isWrapped = true + } + setCoinInfo(info) + setAddressValid(true) + } catch (e) { + setAddressValid(false) + } + } fetchBalance(address) }, [address]) useEffect(() => { if (!addressValid) { setWrappedMint("") - setSolanaAccount(false) + setSolanaAccount({ + valid: false, + message: "" + }) return } @@ -116,62 +157,39 @@ function Transfer() { setWrappedMint(wrappedMint.toString()) for (let account of tokenAccounts.balances) { - if (account.mint == wrappedMint.toString()) { - setSolanaAccount(true) + if (account.account.toString() == recipient) { + setSolanaAccount({ + valid: true, + message: "" + }) return; } } - setSolanaAccount(false) + setSolanaAccount({ + valid: false, + message: "Not a valid wrapped token account" + }) } getWrappedInfo(); }, [address, addressValid, tokenAccounts, bridge]) - async function fetchBalance(token: string) { - try { - let e = WrappedAssetFactory.connect(token, provider); - let addr = await signer.getAddress(); - let balance = await e.balanceOf(addr); - let decimals = await e.decimals(); - let allowance = await e.allowance(addr, BRIDGE_ADDRESS); - - let info = { - balance: balance.div(new BigNumber(10).pow(decimals)), - allowance: allowance.div(new BigNumber(10).pow(decimals)), - decimals: decimals, - isWrapped: false, - chainID: 2, - assetAddress: new Buffer(token.slice(2), "hex") - } - - let b = WormholeFactory.connect(BRIDGE_ADDRESS, provider); - - let isWrapped = await b.isWrappedAsset(token) - if (isWrapped) { - info.chainID = await e.assetChain() - info.assetAddress = new Buffer((await e.assetAddress()).slice(2), "hex") - info.isWrapped = true - } - setCoinInfo(info) - setAddressValid(true) - } catch (e) { - setAddressValid(false) - } - } + useEffect(() => { + setAmountValid(amount.lte(coinInfo.balance)) + }, [amount, coinInfo]) return ( <> -

Slot: {slot}

- +
{ let recipient = new solanaWeb3.PublicKey(values["recipient"]).toBuffer() let transferAmount = new BigNumber(values["amount"]).mul(new BigNumber(10).pow(coinInfo.decimals)); - if (coinInfo.allowance.toNumber() >= amount || coinInfo.isWrapped) { + if (coinInfo.allowance.gte(amount) || coinInfo.isWrapped) { lockAssets(values["address"], transferAmount, recipient, values["target_chain"]) } else { approveAssets(values["address"], transferAmount) } - }} style={{width: "100%"}}> + }} style={{width: "100%"}} ref={formRef}> - { - let big = new BigNumber(value); - callback(big.lte(coinInfo.balance) ? undefined : "Amount exceeds balance") - } - }]}> - { - // @ts-ignore - setAmount(value || 0) - }}/> + + { + // @ts-ignore + setAmount(new BigNumber(value) || 0) + }}/> - Solana - - + + { + setRecipient(v.target.value) + }}/> + + + + Token Accounts on Solana: + + + + + + + { + tokenAccounts.balances + .filter(value => value.mint == wrappedMint) + .map(v => ( + { + setRecipient(v.account.toString()) + formRef.current?.setFieldsValue({ + "recipient": v.account.toString() + }) + }}>use)]}> + {v.account.toString()} + + )) + } + + + + +
- - -

Mint: {wrappedMint}

- - ); } diff --git a/web/src/pages/TransferSolana.tsx b/web/src/pages/TransferSolana.tsx index f98e6afa1..0703b1379 100644 --- a/web/src/pages/TransferSolana.tsx +++ b/web/src/pages/TransferSolana.tsx @@ -3,7 +3,7 @@ import ClientContext from "../providers/ClientContext"; import * as solanaWeb3 from '@solana/web3.js'; import {PublicKey, Transaction} from '@solana/web3.js'; import * as spl from '@solana/spl-token'; -import {Button, Col, Form, Input, InputNumber, message, Row, Select} from "antd"; +import {Button, Card, Col, Divider, Form, Input, InputNumber, List, message, Row, Select} from "antd"; import {BigNumber} from "ethers/utils"; import SplBalances from "../components/SplBalances"; import {SlotContext} from "../providers/SlotContext"; @@ -58,9 +58,9 @@ function TransferSolana() { return ( <> -

Slot: {slot}

- + +

Transfer from Solana:

{ let recipient = new Buffer(values["recipient"].slice(2), "hex"); @@ -114,7 +114,7 @@ function TransferSolana() { - Ethereum @@ -129,7 +129,7 @@ function TransferSolana() { callback() } } - },]}> + }]}> @@ -139,6 +139,8 @@ function TransferSolana() {
+
+