+
+
+ To
+
+ {CHAINS.map(({ id, name }) => (
+
+ ))}
+
+
+ {ethBalance}
+
+
+ →
+
+
+ From
+
+ {CHAINS.map(({ id, name }) => (
+
+ ))}
+
+
+
+
+
+
+
+ {canAttemptTransfer ? null : (
+
+ {!isTransferImplemented
+ ? `Transfer is not yet implemented for ${CHAINS[fromChain]}`
+ : !isProviderConnected
+ ? "The source wallet is not connected"
+ : !isRecipientAvailable
+ ? "The receiving wallet is not connected"
+ : !isAddressDefined
+ ? "Please provide an asset address"
+ : !isAmountPositive
+ ? "The amount must be positive"
+ : !isBalanceAtLeastAmount
+ ? "The amount may not be greater than the balance"
+ : !isBalanceAtLeastAmount
+ ? "The amount may not be greater than the balance"
+ : ""}
+
+ )}
+
+ );
+}
+
+export default Transfer;
diff --git a/bridge_ui/src/hooks/useEthereumBalance.ts b/bridge_ui/src/hooks/useEthereumBalance.ts
new file mode 100644
index 00000000..336716e1
--- /dev/null
+++ b/bridge_ui/src/hooks/useEthereumBalance.ts
@@ -0,0 +1,37 @@
+import { ethers } from "ethers";
+import { formatUnits } from "ethers/lib/utils";
+import { useEffect, useState } from "react";
+import { TokenImplementation__factory } from "../ethers-contracts";
+
+function useEthereumBalance(address: string, provider?: ethers.providers.Web3Provider) {
+ //TODO: should this check allowance too or subtract allowance?
+ const [balance, setBalance] = useState('')
+ useEffect(()=>{
+ if (!address || !provider) {
+ setBalance('')
+ return
+ }
+ let cancelled = false
+ const token = TokenImplementation__factory.connect(address, provider);
+ token.decimals().then((decimals) => {
+ console.log(decimals);
+ provider
+ ?.getSigner()
+ .getAddress()
+ .then((pk) => {
+ console.log(pk)
+ token.balanceOf(pk).then((n) => {
+ if (!cancelled) {
+ setBalance(formatUnits(n,decimals))
+ }
+ });
+ });
+ });
+ return () => {
+ cancelled = true
+ }
+ },[address, provider])
+ return balance
+}
+
+export default useEthereumBalance
\ No newline at end of file
diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts
index 0c78dd2b..f0e431fd 100644
--- a/bridge_ui/src/utils/consts.ts
+++ b/bridge_ui/src/utils/consts.ts
@@ -1,2 +1,32 @@
+export type ChainId = 1 | 2 | 3 | 4
+export const CHAIN_ID_SOLANA: ChainId = 1
+export const CHAIN_ID_ETH: ChainId = 2
+export const CHAIN_ID_TERRA: ChainId = 3
+export const CHAIN_ID_BSC: ChainId = 4
+export interface ChainInfo {
+ id: ChainId
+ name: string
+}
+export const CHAINS = [
+ {
+ id: CHAIN_ID_BSC,
+ name: 'Binance Smart Chain'
+ },
+ {
+ id: CHAIN_ID_ETH,
+ name: 'Ethereum'
+ },
+ {
+ id: CHAIN_ID_SOLANA,
+ name: 'Solana'
+ },
+ {
+ id: CHAIN_ID_TERRA,
+ name: 'Terra'
+ },
+]
export const SOLANA_HOST = 'http://localhost:8899'
-export const ETH_TOKEN_BRIDGE_ADDRESS = "0x254dffcd3277c0b1660f6d42efbb754edababc2b"
\ No newline at end of file
+export const ETH_TEST_TOKEN_ADDRESS = "0x0290FB167208Af455bB137780163b7B7a9a10C16"
+export const ETH_TOKEN_BRIDGE_ADDRESS = "0xe982e462b094850f12af94d21d470e21be9d0e9c"
+export const SOL_TEST_TOKEN_ADDRESS = "2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ"
+export const SOL_TOKEN_BRIDGE_ADDRESS = "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE"
\ No newline at end of file
diff --git a/bridge_ui/src/utils/transferFrom.ts b/bridge_ui/src/utils/transferFrom.ts
new file mode 100644
index 00000000..8e23dbd6
--- /dev/null
+++ b/bridge_ui/src/utils/transferFrom.ts
@@ -0,0 +1,66 @@
+import { ethers } from "ethers";
+import { formatUnits, parseUnits } from "ethers/lib/utils";
+import { Bridge__factory, TokenImplementation__factory } from "../ethers-contracts";
+import { ChainId, CHAIN_ID_ETH, ETH_TOKEN_BRIDGE_ADDRESS } from "./consts";
+
+// TODO: this should probably be extended from the context somehow so that the signatures match
+// TODO: allow for / handle cancellation?
+// TODO: overall better input checking and error handling
+function transferFromEth(provider: ethers.providers.Web3Provider | undefined, tokenAddress: string, amount: string, recipientChain: ChainId, recipientAddress: Uint8Array | undefined) {
+ if (!provider || !recipientAddress) return;
+ const signer = provider.getSigner();
+ if (!signer) return;
+ //TODO: check if token attestation exists on the target chain
+ //TODO: don't hardcode, fetch decimals / share them with balance, how do we determine recipient chain?
+ //TODO: more catches
+ const amountParsed = parseUnits(amount, 18);
+ signer.getAddress().then((signerAddress) => {
+ console.log("Signer:", signerAddress);
+ console.log("Token:", tokenAddress)
+ const token = TokenImplementation__factory.connect(
+ tokenAddress,
+ signer
+ );
+ token
+ .allowance(signerAddress, ETH_TOKEN_BRIDGE_ADDRESS)
+ .then((allowance) => {
+ console.log("Allowance", allowance.toString()); //TODO: should we check that this is zero and warn if it isn't?
+ token
+ .approve(ETH_TOKEN_BRIDGE_ADDRESS, amountParsed)
+ .then((transaction) => {
+ console.log(transaction);
+ const fee = 0; // for now, this won't do anything, we may add later
+ const nonceConst = Math.random() * 100000;
+ const nonceBuffer = Buffer.alloc(4);
+ nonceBuffer.writeUInt32LE(nonceConst, 0);
+ console.log("Initiating transfer");
+ console.log("Amount:", formatUnits(amountParsed, 18));
+ console.log("To chain:", recipientChain);
+ console.log("To address:", recipientAddress);
+ console.log("Fees:", fee);
+ console.log("Nonce:", nonceBuffer);
+ const bridge = Bridge__factory.connect(
+ ETH_TOKEN_BRIDGE_ADDRESS,
+ signer
+ );
+ bridge
+ .transferTokens(
+ tokenAddress,
+ amountParsed,
+ recipientChain,
+ recipientAddress,
+ fee,
+ nonceBuffer
+ )
+ .then((v) => console.log("Success:", v))
+ .catch((r) => console.error(r)); //TODO: integrate toast messages
+ });
+ });
+ });
+}
+
+const transferFrom = {
+ [CHAIN_ID_ETH]: transferFromEth
+}
+
+export default transferFrom
\ No newline at end of file