Skip to content

Commit

Permalink
feat(bridge): bridge transactions (#411)
Browse files Browse the repository at this point in the history
* feat(bridge): add transaction list

* fix(bridge): remove console.log

* transaction impl

* test

* wip, local storage for transactons, claiming, new stores, deprecate relayer

* claim

* tests

* jest

* pending tx

* proof validation

* tests

* process message requires manual gas limit

* jest

* mm mobile code

* mm mobile

* custom fee

* value not data

* fee

* jest

* rm log

* tests

* tests

* erc20 bridging

* token vault address refactor

* bridge opts

* bridge fix

* get canonicalToBridged for cross layer tokens

* golang lint

* rm console log

* env rename, add bridge address and test erc20 dynamically, remove tko

* fix number input

* wip tx view

* reactive tx list

* show Pending state if message header is not synced

* tests

* Update packages/bridge-ui/.default.env

Co-authored-by: dave | d1onys1us <[email protected]>

* Update packages/bridge-ui/src/components/Loader.svelte

Co-authored-by: dave | d1onys1us <[email protected]>

* Update packages/bridge-ui/src/app.css

Co-authored-by: dave | d1onys1us <[email protected]>

* rm old way of doing bridge tx's

* unused css

* processable fix

* jest

* header removed in bridge form + margin on tabs

Co-authored-by: Jeffery Walsh <[email protected]>
Co-authored-by: jeff <[email protected]>
Co-authored-by: dave | d1onys1us <[email protected]>
  • Loading branch information
4 people authored Dec 15, 2022
1 parent ba3b73a commit 19dd7ab
Show file tree
Hide file tree
Showing 45 changed files with 1,345 additions and 252 deletions.
6 changes: 5 additions & 1 deletion packages/bridge-ui/.default.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ VITE_NODE_ENV=dev
VITE_L1_RPC_URL=""
VITE_L2_RPC_URL=""
VITE_TAIKO_BRIDGE_ADDRESS=""
VITE_MAINNET_BRIDGE_ADDRESS=""
VITE_MAINNET_BRIDGE_ADDRESS=""
VITE_TEST_ERC20_ADDRESS_MAINNET=""
VITE_MAINNET_TOKEN_VAULT_ADDRESS=""
VITE_TAIKO_TOKEN_VAULT_ADDRESS=""
VITE_TEST_ERC20_ADDRESS_MAINNET=""
6 changes: 3 additions & 3 deletions packages/bridge-ui/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ export default {
],
coverageThreshold: {
global: {
statements: 100,
branches: 97,
functions: 100,
statements: 98.45,
branches: 86,
functions: 96,
lines: 100,
},
},
Expand Down
85 changes: 73 additions & 12 deletions packages/bridge-ui/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,35 @@
import { wrap } from "svelte-spa-router/wrap";
import QueryProvider from "./components/providers/QueryProvider.svelte";
import Router from "svelte-spa-router";
import { SvelteToast, toast } from "@zerodevx/svelte-toast";
import { SvelteToast } from "@zerodevx/svelte-toast";
import type { SvelteToastOptions } from "@zerodevx/svelte-toast";
import Home from "./pages/home/Home.svelte";
import { setupI18n } from "./i18n";
import { BridgeType } from "./domain/bridge";
import ETHBridge from "./eth/bridge";
import { bridges, chainIdToBridgeAddress } from "./store/bridge";
import { bridges, chainIdToTokenVaultAddress } from "./store/bridge";
import ERC20Bridge from "./erc20/bridge";
import { pendingTransactions } from "./store/transactions";
import {
pendingTransactions,
transactioner,
transactions,
} from "./store/transactions";
import Navbar from "./components/Navbar.svelte";
import { signer } from "./store/signer";
import type { Transactioner } from "./domain/transactions";
import { RelayerService } from "./relayer/service";
setupI18n({ withLocale: "en" });
import { CHAIN_MAINNET, CHAIN_TKO } from "./domain/chain";
import { chains, CHAIN_MAINNET, CHAIN_TKO } from "./domain/chain";
import SwitchEthereumChainModal from "./components/modals/SwitchEthereumChainModal.svelte";
import { ProofService } from "./proof/service";
import { ethers } from "ethers";
import type { Prover } from "./domain/proof";
import { successToast } from "./utils/toast";
import { StorageService } from "./storage/service";
import { MessageStatus } from "./domain/message";
import BridgeABI from "./constants/abi/Bridge";
import { providers } from "./store/providers";
const providerMap: Map<number, ethers.providers.JsonRpcProvider> = new Map<
number,
Expand All @@ -38,6 +45,8 @@
new ethers.providers.JsonRpcProvider(import.meta.env.VITE_L2_RPC_URL)
);
providers.set(providerMap);
const prover: Prover = new ProofService(providerMap);
const ethBridge = new ETHBridge(prover);
Expand All @@ -49,26 +58,78 @@
return store;
});
chainIdToBridgeAddress.update((store) => {
store.set(CHAIN_TKO.id, import.meta.env.VITE_TAIKO_BRIDGE_ADDRESS);
store.set(CHAIN_MAINNET.id, import.meta.env.VITE_MAINNET_BRIDGE_ADDRESS);
chainIdToTokenVaultAddress.update((store) => {
store.set(CHAIN_TKO.id, import.meta.env.VITE_TAIKO_TOKEN_VAULT_ADDRESS);
store.set(
CHAIN_MAINNET.id,
import.meta.env.VITE_MAINNET_TOKEN_VAULT_ADDRESS
);
return store;
});
const relayerURL = import.meta.env.VITE_RELAYER_URL;
// const relayerURL = import.meta.env.VITE_RELAYER_URL;
const storageTransactioner: Transactioner = new StorageService(
window.localStorage,
providerMap
);
transactioner.set(storageTransactioner);
signer.subscribe(async (store) => {
if (store) {
const txs = await $transactioner.GetAllByAddress(
await store.getAddress()
);
const transactioner: Transactioner = new RelayerService(relayerURL);
transactions.set(txs);
}
return store;
});
pendingTransactions.subscribe((store) => {
store.forEach(async (tx) => {
await $signer.provider.waitForTransaction(tx.hash, 3);
await $signer.provider.waitForTransaction(tx.hash, 1);
successToast("Transaction completed!");
const s = store;
s.pop();
pendingTransactions.set(s);
transactions.set(
await $transactioner.GetAllByAddress(await $signer.getAddress())
);
});
});
transactions.subscribe((store) => {
if (store) {
store.forEach(async (tx) => {
if (tx.interval) clearInterval(tx.interval);
if (tx.status === MessageStatus.New) {
const provider = providerMap.get(tx.toChainId);
const interval = setInterval(async () => {
tx.interval = interval;
const contract = new ethers.Contract(
chains[tx.toChainId].bridgeAddress,
BridgeABI,
provider
);
const messageStatus: MessageStatus =
await contract.getMessageStatus(tx.signal);
if (messageStatus === MessageStatus.Done) {
successToast("Bridge message processed successfully");
clearInterval(tx.interval);
}
}, 30 * 1000);
}
});
}
});
const toastOptions: SvelteToastOptions = {
dismissable: false,
duration: 4000,
Expand All @@ -87,7 +148,7 @@
<QueryProvider>
<div class="lg:container lg:mx-auto lg:px-64">
<main>
<Navbar {transactioner} />
<Navbar />
<Router {routes} />
</main>
<SvelteToast options={toastOptions} />
Expand Down
6 changes: 5 additions & 1 deletion packages/bridge-ui/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@
.taiko-banner {
background-image: url('assets/taiko-banner.svg');
background-repeat: no-repeat;
}
}

.dropdown-content.address-dropdown-content {
border-radius: 6px;
}
78 changes: 53 additions & 25 deletions packages/bridge-ui/src/components/AddressDropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,32 @@
import { pendingTransactions } from "../store/transactions";
import ChevDown from "./icons/ChevDown.svelte";
import { getAddressAvatarFromIdenticon } from "../utils/addressAvatar";
import type { BridgeTransaction } from "../domain/transactions";
import { LottiePlayer } from "@lottiefiles/svelte-lottie-player";
import type { Signer } from "ethers";
import { ethers, Signer } from "ethers";
import { errorToast } from "../utils/toast";
export let transactions: BridgeTransaction[] = [];
import CopyIcon from "./icons/Copy.svelte";
import DisconnectIcon from "./icons/Disconnect.svelte";
import { slide } from "svelte/transition";
import { fromChain } from "../store/chain";
import { truncateString } from "../utils/truncateString";
let address: string;
let addressAvatarImgData: string;
let tokenBalance: string = "";
onMount(async () => {
setAddress($signer);
await setAddress($signer);
});
$: getUserBalance($signer);
async function getUserBalance(signer) {
if (signer) {
const userBalance = await signer.getBalance("latest");
tokenBalance = ethers.utils.formatEther(userBalance);
}
}
$: setAddress($signer).catch((e) => console.error(e));
async function setAddress(signer: Signer) {
Expand Down Expand Up @@ -78,26 +91,41 @@
</label>
<ul
tabindex="0"
class="dropdown-content menu p-2 shadow bg-dark-3 rounded-box w-[194px]"
class="dropdown-content address-dropdown-content menu shadow bg-dark-3 rounded-sm w-64 mt-2 pb-2"
>
<li class="inline-block md:hidden">
<span>{addressSubsection(address)}</span>
</li>
<li>
<span
class="cursor-pointer"
on:click={async () => await copyToClipboard(address)}>Copy Address</span
>
</li>
<li>
<span class="cursor-pointer" on:click={async () => await disconnect()}
>Disconnect</span
>
</li>
{#if transactions && transactions.length}
<li>
<span class="cursor-pointer"> {transactions.length} Transactions</span>
</li>
{/if}
<div class="p-5 pb-0 flex flex-col items-center" transition:slide>
{#if $fromChain && $signer}
<svelte:component this={$fromChain.icon} />
<div class="text-lg mt-2">
{tokenBalance.length > 10
? `${truncateString(tokenBalance)}...`
: tokenBalance} ETH
</div>
{/if}
</div>
<div class="divider" />
<div class="flex hover:bg-dark-5 items-center py-2 px-2">
<img
width="24"
height="24"
src="data:image/png;base64,{addressAvatarImgData}"
class="rounded-full mr-2 inline-block"
alt="avatar"
/>
{addressSubsection(address)}
</div>
<div
class="cursor-pointer flex hover:bg-dark-5 items-center py-2 px-2"
on:click={async () => await copyToClipboard(address)}
>
<CopyIcon />
Copy Address
</div>
<div
class="cursor-pointer flex hover:bg-dark-5 items-center py-2 px-2"
on:click={async () => await disconnect()}
>
<DisconnectIcon /> Disconnect
</div>
</ul>
</div>
4 changes: 4 additions & 0 deletions packages/bridge-ui/src/components/Loader.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM1.39211 7C1.39211 10.0972 3.90285 12.6079 7 12.6079C10.0972 12.6079 12.6079 10.0972 12.6079 7C12.6079 3.90285 10.0972 1.39211 7 1.39211C3.90285 1.39211 1.39211 3.90285 1.39211 7Z" fill="#B20F89"/>
<path d="M14 7C14 8.1941 13.6945 9.36835 13.1127 10.4111C12.5308 11.4538 11.6918 12.3304 10.6756 12.9574C9.65935 13.5844 8.49961 13.941 7.30665 13.9933C6.1137 14.0456 4.9272 13.7919 3.85998 13.2562L4.48444 12.012C5.33942 12.4411 6.28996 12.6444 7.24567 12.6025C8.20138 12.5606 9.13048 12.2749 9.94461 11.7726C10.7587 11.2703 11.4309 10.5681 11.897 9.73271C12.3632 8.89735 12.6079 7.95663 12.6079 7H14Z" fill="#FC0FC0"/>
</svg>
21 changes: 1 addition & 20 deletions packages/bridge-ui/src/components/Navbar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,7 @@
import Logo from "./icons/Logo.svelte";
import { signer } from "../store/signer";
import AddressDropdown from "./AddressDropdown.svelte";
import type {
BridgeTransaction,
Transactioner,
} from "../domain/transactions";
import type { Signer } from "ethers";
import { fromChain } from "../store/chain";
import ChainDropdown from "./ChainDropdown.svelte";
import type { Chain } from "../domain/chain";
export let transactioner: Transactioner;
let transactions: BridgeTransaction[];
$: getTransactions($signer, $fromChain);
async function getTransactions(signer: Signer, chain: Chain) {
if (!signer || !chain) return;
transactions = await transactioner.GetAllByAddress(
await signer.getAddress(),
chain.id
);
}
</script>

<nav class="navbar mb-4 md:h-[125px] pt-4 md:pt-0 md:px-4 w-full">
Expand All @@ -32,7 +13,7 @@
<div class="navbar-end">
{#if $signer}
<ChainDropdown />
<AddressDropdown {transactions} />
<AddressDropdown />
{:else}
<Connect />
{/if}
Expand Down
9 changes: 4 additions & 5 deletions packages/bridge-ui/src/components/TaikoBanner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import SelectChain from "./form/SelectChain.svelte";
</script>

<div class="taiko-banner bg-cover bg-center bg-no-repeat h-36 rounded-lg py-4 flex flex-col items-center justify-center md:w-[450px]">
<h1 class="text-2xl font-bold">
{$_("home.title")}
</h1>
<div
class="taiko-banner bg-cover bg-center bg-no-repeat h-36 rounded-lg py-4 flex flex-col items-center justify-center md:w-[450px]"
>
<SelectChain />
</div>
</div>
Loading

0 comments on commit 19dd7ab

Please sign in to comment.