Skip to content

Commit

Permalink
feat(bridge-ui): release token button (#13203)
Browse files Browse the repository at this point in the history
Co-authored-by: jeff <[email protected]>
  • Loading branch information
shadab-taiko and cyberhorsey authored Feb 24, 2023
1 parent 0113490 commit 4052aad
Show file tree
Hide file tree
Showing 15 changed files with 671 additions and 101 deletions.
2 changes: 1 addition & 1 deletion packages/bridge-ui/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default {
statements: 95,
branches: 72,
functions: 89,
lines: 96,
lines: 95,
},
},
modulePathIgnorePatterns: ["<rootDir>/public/build/"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
message, and you must retry the processing yourself.
</li>
<li class="mb-2">
<strong>Failed</strong>: Your bridged asset is unable to be processed
<strong>Release</strong>: Your bridged asset is unable to be processed
and is available to you on the source chain.
</li>
</ul>
Expand Down
129 changes: 101 additions & 28 deletions packages/bridge-ui/src/components/Transaction.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { ArrowTopRightOnSquare } from "svelte-heros-v2";
import { MessageStatus } from "../domain/message";
import { Contract, ethers } from "ethers";
import { bridges } from "../store/bridge";
import { bridges, chainIdToTokenVaultAddress } from "../store/bridge";
import { signer } from "../store/signer";
import {
pendingTransactions,
Expand All @@ -27,37 +27,43 @@
import { fetchSigner, switchNetwork } from "@wagmi/core";
import Bridge from "../constants/abi/Bridge";
import ButtonWithTooltip from "./ButtonWithTooltip.svelte";
import TokenVault from "../constants/abi/TokenVault";
export let transaction: BridgeTransaction;
export let fromChain: Chain;
export let toChain: Chain;
let loading: boolean;
let processable: boolean = false;
onMount(async () => {
processable = await isProcessable();
});
async function claim(bridgeTx: BridgeTransaction) {
if (fromChain.id !== bridgeTx.message.destChainId.toNumber()) {
const chain = chains[bridgeTx.message.destChainId.toNumber()];
await switchNetwork({
chainId: chain.id,
});
const provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
async function switchChainAndSetSigner(chain: Chain) {
await switchNetwork({
chainId: chain.id,
});
const provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
fromChainStore.set(chain);
if (chain === CHAIN_MAINNET) {
toChainStore.set(CHAIN_TKO);
} else {
toChainStore.set(CHAIN_MAINNET);
}
const wagmiSigner = await fetchSigner();
signer.set(wagmiSigner);
fromChainStore.set(chain);
if (chain === CHAIN_MAINNET) {
toChainStore.set(CHAIN_TKO);
} else {
toChainStore.set(CHAIN_MAINNET);
}
const wagmiSigner = await fetchSigner();
signer.set(wagmiSigner);
}
async function claim(bridgeTx: BridgeTransaction) {
try {
loading = true;
if (fromChain.id !== bridgeTx.message.destChainId.toNumber()) {
const chain = chains[bridgeTx.message.destChainId.toNumber()];
await switchChainAndSetSigner(chain)
}
const tx = await $bridges
.get(bridgeTx.message.data === "0x" ? BridgeType.ETH : BridgeType.ERC20)
.Claim({
Expand All @@ -79,6 +85,43 @@
} catch (e) {
console.log(e);
errorToast($_("toast.errorSendingTransaction"));
} finally {
loading = false;
}
}
async function releaseTokens(bridgeTx: BridgeTransaction) {
try {
loading = true;
if (fromChain.id !== bridgeTx.message.srcChainId.toNumber()) {
const chain = chains[bridgeTx.message.srcChainId.toNumber()];
await switchChainAndSetSigner(chain)
}
const tx = await $bridges
.get(bridgeTx.message.data === "0x" ? BridgeType.ETH : BridgeType.ERC20)
.ReleaseTokens({
signer: $signer,
message: bridgeTx.message,
msgHash: bridgeTx.msgHash,
destBridgeAddress:
chains[bridgeTx.message.destChainId.toNumber()].bridgeAddress,
srcBridgeAddress:
chains[bridgeTx.message.srcChainId.toNumber()].bridgeAddress,
destProvider: $providers.get(bridgeTx.message.destChainId.toNumber()),
srcTokenVaultAddress: $chainIdToTokenVaultAddress.get(bridgeTx.message.srcChainId.toNumber())
});
pendingTransactions.update((store) => {
store.push(tx);
return store;
});
successToast($_("toast.transactionSent"));
} catch (e) {
console.log(e);
errorToast($_("toast.errorSendingTransaction"));
} finally {
loading = false;
}
}
Expand Down Expand Up @@ -109,6 +152,29 @@
);
transaction.status = await contract.getMessageStatus(transaction.msgHash);
if(transaction.status === MessageStatus.Failed) {
if(transaction.message.data !== "0x") {
const srcTokenVaultContract = new ethers.Contract(
$chainIdToTokenVaultAddress.get(transaction.fromChainId),
TokenVault,
$providers.get(chains[transaction.message.srcChainId.toNumber()].id)
)
const {token, amount} = await srcTokenVaultContract.messageDeposits(transaction.msgHash);
if(token === ethers.constants.AddressZero && amount.eq(0)) {
transaction.status = MessageStatus.FailedReleased;
}
} else {
const srcBridgeContract = new ethers.Contract(
chains[transaction.fromChainId].bridgeAddress,
Bridge,
$providers.get(chains[transaction.message.srcChainId.toNumber()].id)
)
const isFailedMessageResolved = await srcBridgeContract.isEtherReleased(transaction.msgHash);
if(isFailedMessageResolved) {
transaction.status = MessageStatus.FailedReleased;
}
}
}
transaction = transaction;
if (transaction.status === MessageStatus.Done) clearInterval(interval);
}, 20 * 1000);
Expand All @@ -135,7 +201,7 @@
<span slot="buttonText">
{#if !processable}
Pending
{:else if !transaction.receipt && transaction.status === MessageStatus.New}
{:else if (!transaction.receipt && transaction.status === MessageStatus.New) || loading}
<div class="inline-block">
<LottiePlayer
src="/lottie/loader.json"
Expand All @@ -150,24 +216,31 @@
/>
</div>
{:else if transaction.receipt && transaction.status === MessageStatus.New}
<span
class="cursor-pointer border rounded p-1"
<button
class="cursor-pointer border rounded p-1 btn btn-sm border-white"
on:click={async () => await claim(transaction)}
>
Claim
</span>
</button>
{:else if transaction.status === MessageStatus.Retriable}
<span
class="cursor-pointer border rounded p-1"
on:click={async () => await claim(transaction)}
>
Retry
</span>
<button
class="cursor-pointer border rounded p-1 btn btn-sm border-white"
on:click={async () => await claim(transaction)}
>
Retry
</button>
{:else if transaction.status === MessageStatus.Failed}
<!-- todo: releaseTokens() on src bridge with proof from destBridge-->
Failed
<button
class="cursor-pointer border rounded p-1 btn btn-sm border-white"
on:click={async () => await releaseTokens(transaction)}
>
Release
</button>
{:else if transaction.status === MessageStatus.Done}
<span class="border border-transparent p-0">Claimed</span>
{:else if transaction.status === MessageStatus.FailedReleased}
<span class="border border-transparent p-0">Released</span>
{/if}
</span>
</ButtonWithTooltip>
Expand Down
19 changes: 19 additions & 0 deletions packages/bridge-ui/src/constants/abi/Bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,25 @@ export default [
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "msgHash",
"type": "bytes32"
}
],
"name": "isEtherReleased",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
Expand Down
76 changes: 35 additions & 41 deletions packages/bridge-ui/src/constants/abi/HeaderSync.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,53 @@
export default [
{
anonymous: false,
inputs: [
"anonymous": false,
"inputs": [
{
indexed: true,
internalType: "uint256",
name: "height",
type: "uint256",
"indexed": true,
"internalType": "uint256",
"name": "srcHeight",
"type": "uint256"
},
{
indexed: true,
internalType: "uint256",
name: "srcHeight",
type: "uint256",
},
{
indexed: false,
internalType: "bytes32",
name: "srcHash",
type: "bytes32",
},
"indexed": false,
"internalType": "bytes32",
"name": "srcHash",
"type": "bytes32"
}
],
name: "HeaderSynced",
type: "event",
"name": "HeaderSynced",
"type": "event"
},
{
inputs: [],
name: "getLatestSyncedHeader",
outputs: [
"inputs": [],
"name": "getLatestSyncedHeader",
"outputs": [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
stateMutability: "view",
type: "function",
"stateMutability": "view",
"type": "function"
},
{
inputs: [
"inputs": [
{
internalType: "uint256",
name: "number",
type: "uint256",
},
"internalType": "uint256",
"name": "number",
"type": "uint256"
}
],
name: "getSyncedHeader",
outputs: [
"name": "getSyncedHeader",
"outputs": [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
stateMutability: "view",
type: "function",
"stateMutability": "view",
"type": "function"
},
];
Loading

0 comments on commit 4052aad

Please sign in to comment.