Skip to content

Commit

Permalink
feat(bridge-ui): ERC20 Bridge + approval (#353)
Browse files Browse the repository at this point in the history
* erc20 bridge + approve + requires allowance

* bridge form checks allowance, disables button

* if allowance is required, show approve button instead

* set allowance required to false after successful approval

* requiresallowance should take approveopts, not bridgeopts

* show Approve text appropriatley

* Update packages/bridge-ui/src/components/form/BridgeForm.svelte

Co-authored-by: David <104078303+davidtaikocha@users.noreply.github.com>

* Update packages/bridge-ui/src/eth/bridge.ts

Co-authored-by: David <104078303+davidtaikocha@users.noreply.github.com>

* Update packages/bridge-ui/src/components/form/BridgeForm.svelte

Co-authored-by: David <104078303+davidtaikocha@users.noreply.github.com>

* Update packages/bridge-ui/src/components/form/BridgeForm.svelte

Co-authored-by: David <104078303+davidtaikocha@users.noreply.github.com>

* inverse approve logic

Co-authored-by: David <104078303+davidtaikocha@users.noreply.github.com>
  • Loading branch information
cyberhorsey and davidtaikocha committed Dec 1, 2022
1 parent cd34f17 commit 0652595
Show file tree
Hide file tree
Showing 10 changed files with 661 additions and 18 deletions.
10 changes: 3 additions & 7 deletions packages/bridge-ui/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@
import Navbar from "./components/Navbar.svelte";
import { SvelteToast } from "@zerodevx/svelte-toast";
import { onMount } from "svelte";
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 { CHAIN_MAINNET, CHAIN_TKO } from "./domain/chain";
const { chains, provider } = configureChains(
[mainnet, taiko],
[publicProvider()]
);
import ERC20Bridge from "./erc20/bridge";
setupI18n({ withLocale: "en" });
const ethBridge = new ETHBridge();
const erc20Bridge = new ERC20Bridge();
bridges.update((store) => {
store.set(BridgeType.ETH, ethBridge);
store.set(BridgeType.ERC20, erc20Bridge);
return store;
});
Expand All @@ -46,7 +43,6 @@
<main>
<Navbar />
<Router {routes} />
<Footer />
</main>
<SvelteToast />
</QueryProvider>
Expand Down
9 changes: 8 additions & 1 deletion packages/bridge-ui/src/components/buttons/SelectToken.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<script lang="ts">
import { token } from "../../store/token";
import { tokens } from "../../domain/token";
import { bridgeType } from "../../store/bridge";
import { ETH, tokens } from "../../domain/token";
import type { Token } from "../../domain/token";
import { toast } from "@zerodevx/svelte-toast";
import { BridgeType } from "../../domain/bridge";
async function select(t: Token) {
if (t === $token) return;
token.set(t);
if (t.symbol.toLowerCase() == ETH.symbol.toLowerCase()) {
bridgeType.set(BridgeType.ETH);
} else {
bridgeType.set(BridgeType.ERC20);
}
toast.push(`Token changed to ${t.symbol.toUpperCase()}`);
}
</script>
Expand Down
83 changes: 75 additions & 8 deletions packages/bridge-ui/src/components/form/BridgeForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,87 @@
import { _ } from "svelte-i18n";
import { token } from "../../store/token";
import { fromChain, toChain } from "../../store/chain";
import { activeBridge, chainIdToBridgeAddress } from "../../store/bridge";
import {
activeBridge,
chainIdToBridgeAddress,
bridgeType,
} from "../../store/bridge";
import { signer } from "../../store/signer";
import { BigNumber, ethers, Signer } from "ethers";
import { toast } from "@zerodevx/svelte-toast";
import type { Token } from "../../domain/token";
import type { BridgeType } from "../../domain/bridge";
import type { Chain } from "../../domain/chain";
let amount: string;
let requiresAllowance: boolean = true;
let btnDisabled: boolean = true;
$: isBtnDisabled($signer, amount)
.then((d) => (btnDisabled = d))
.catch((e) => console.log(e));
$: checkAllowance(amount, $token, $bridgeType, $fromChain, $signer)
.then((a) => (requiresAllowance = a))
.catch((e) => console.log(e));
async function checkAllowance(
amt: string,
token: Token,
bridgeType: BridgeType,
fromChain: Chain,
signer: Signer
) {
if (!signer || !amt || !token || !fromChain) return true;
return await $activeBridge.RequiresAllowance({
amountInWei: amt
? ethers.utils.parseUnits(amt, token.decimals)
: BigNumber.from(0),
signer: signer,
contractAddress: token.address,
spenderAddress: $chainIdToBridgeAddress.get(fromChain.id),
});
}
async function isBtnDisabled(signer: Signer, amount: string) {
if (!signer) return true;
if (!amount) return true;
if (requiresAllowance) return true;
const balance = await signer.getBalance("latest");
if (balance.lt(ethers.utils.parseUnits(amount, $token.decimals)))
return true;
return false;
}
async function approve() {
try {
if (!requiresAllowance)
throw Error("does not require additional allowance");
const tx = await $activeBridge.Approve({
amountInWei: ethers.utils.parseUnits(amount, $token.decimals),
signer: $signer,
contractAddress: $token.address,
spenderAddress: $chainIdToBridgeAddress.get($fromChain.id),
});
console.log("approved, waiting for confirmations ", tx);
await $signer.provider.waitForTransaction(tx.hash, 3);
requiresAllowance = false;
toast.push($_("toast.transactionSent"));
} catch (e) {
console.log(e);
toast.push($_("toast.errorSendingTransaction"));
}
}
async function bridge() {
try {
if (requiresAllowance) throw Error("requires additional allowance");
const tx = await $activeBridge.Bridge({
amountInWei: ethers.utils.parseUnits(amount, $token.decimals),
signer: $signer,
Expand Down Expand Up @@ -76,10 +133,20 @@
</label>
</div>

<button
class="btn btn-accent"
on:click={async () => await bridge()}
disabled={btnDisabled}
>
{$_("home.bridge")}
</button>
{#if !requiresAllowance}
<button
class="btn btn-accent"
on:click={bridge}
disabled={btnDisabled}
>
{$_("home.bridge")}
</button>
{:else}
<button
class="btn btn-accent"
on:click={approve}
disabled={btnDisabled}
>
{$_("home.approve")}
</button>
{/if}
222 changes: 222 additions & 0 deletions packages/bridge-ui/src/constants/abi/ERC20.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
export default [
{
constant: true,
inputs: [],
name: "name",
outputs: [
{
name: "",
type: "string",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: false,
inputs: [
{
name: "_spender",
type: "address",
},
{
name: "_value",
type: "uint256",
},
],
name: "approve",
outputs: [
{
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "nonpayable",
type: "function",
},
{
constant: true,
inputs: [],
name: "totalSupply",
outputs: [
{
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: false,
inputs: [
{
name: "_from",
type: "address",
},
{
name: "_to",
type: "address",
},
{
name: "_value",
type: "uint256",
},
],
name: "transferFrom",
outputs: [
{
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "nonpayable",
type: "function",
},
{
constant: true,
inputs: [],
name: "decimals",
outputs: [
{
name: "",
type: "uint8",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
name: "_owner",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
name: "balance",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "symbol",
outputs: [
{
name: "",
type: "string",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: false,
inputs: [
{
name: "_to",
type: "address",
},
{
name: "_value",
type: "uint256",
},
],
name: "transfer",
outputs: [
{
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "nonpayable",
type: "function",
},
{
constant: true,
inputs: [
{
name: "_owner",
type: "address",
},
{
name: "_spender",
type: "address",
},
],
name: "allowance",
outputs: [
{
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
payable: true,
stateMutability: "payable",
type: "fallback",
},
{
anonymous: false,
inputs: [
{
indexed: true,
name: "owner",
type: "address",
},
{
indexed: true,
name: "spender",
type: "address",
},
{
indexed: false,
name: "value",
type: "uint256",
},
],
name: "Approval",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
name: "from",
type: "address",
},
{
indexed: true,
name: "to",
type: "address",
},
{
indexed: false,
name: "value",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
];

0 comments on commit 0652595

Please sign in to comment.