From 3f5b73ddf47dd1c9853d5d2d9a75e8cd95ecccbf Mon Sep 17 00:00:00 2001 From: Korbinian Date: Sat, 8 Jun 2024 12:36:53 +0700 Subject: [PATCH] fix(bridge-ui): fix manual claim issue (#17518) --- .../src/components/Dialogs/Claim.svelte | 6 +-- .../Dialogs/ClaimDialog/ClaimDialog.svelte | 11 ++++- .../Dialogs/Shared/ClaimConfirmStep.svelte | 19 +++++++- packages/bridge-ui/src/libs/bridge/Bridge.ts | 43 ++++++++++--------- .../src/libs/relayer/RelayerAPIService.ts | 7 ++- 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/packages/bridge-ui/src/components/Dialogs/Claim.svelte b/packages/bridge-ui/src/components/Dialogs/Claim.svelte index 29ac2070a30..295a087f4b4 100644 --- a/packages/bridge-ui/src/components/Dialogs/Claim.svelte +++ b/packages/bridge-ui/src/components/Dialogs/Claim.svelte @@ -43,7 +43,7 @@ } } - export const claim = async (action: ClaimAction) => { + export const claim = async (action: ClaimAction, force: boolean = false) => { if (!$account.address) { throw new NotConnectedError('User is not connected'); } @@ -64,15 +64,13 @@ // Step 3: get the user's wallet const wallet = await getConnectedWallet(Number(bridgeTx.destChainId)); - log(`Claiming ${bridgeTx.tokenType} for transaction`, bridgeTx); - // Step 4: Call claim() method on the bridge let txHash: Hash; if ($selectedRetryMethod === RETRY_OPTION.RETRY_ONCE) { log('Claiming with lastAttempt flag'); txHash = await bridge.processMessage({ wallet, bridgeTx, lastAttempt: true }); } else { - txHash = await bridge.processMessage({ wallet, bridgeTx }); + txHash = await bridge.processMessage({ wallet, bridgeTx }, force); } dispatch('claimingTxSent', { txHash, action }); diff --git a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte b/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte index 20c6731de63..137d311eed9 100644 --- a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte +++ b/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte @@ -52,9 +52,11 @@ export const handleClaimClick = async () => { claiming = true; - await ClaimComponent.claim(ClaimAction.CLAIM); + await ClaimComponent.claim(ClaimAction.CLAIM, force); }; + let force = false; + let canForceTransaction = false; let canContinue = false; let claiming: boolean; let claimingDone = false; @@ -122,6 +124,7 @@ const handleClaimError = (event: CustomEvent<{ error: unknown; action: ClaimAction }>) => { //TODO: update this to display info alongside toasts const err = event.detail.error; + canForceTransaction = true; switch (true) { case err instanceof NotConnectedError: warningToast({ title: $t('messages.account.required') }); @@ -169,6 +172,7 @@ const reset = () => { activeStep = INITIAL_STEP; claimingDone = false; + canForceTransaction = false; }; let previousStep: ClaimSteps; @@ -210,6 +214,11 @@ on:claim={handleClaimClick} bind:claiming bind:canClaim={canContinue} + {canForceTransaction} + on:forceClaim={() => { + force = true; + handleClaimClick(); + }} bind:claimingDone /> {/if}
diff --git a/packages/bridge-ui/src/components/Dialogs/Shared/ClaimConfirmStep.svelte b/packages/bridge-ui/src/components/Dialogs/Shared/ClaimConfirmStep.svelte index 7c1fa690b03..f86aa869e60 100644 --- a/packages/bridge-ui/src/components/Dialogs/Shared/ClaimConfirmStep.svelte +++ b/packages/bridge-ui/src/components/Dialogs/Shared/ClaimConfirmStep.svelte @@ -20,12 +20,18 @@ export let txHash: Hash; + export let canForceTransaction = false; + const dispatch = createEventDispatcher(); const handleClaimClick = async () => { dispatch('claim'); }; + const handleForceClaim = async () => { + dispatch('forceClaim'); + }; + const getSuccessTitle = () => { return $t('bridge.step.confirm.success.claim'); }; @@ -80,14 +86,23 @@
{#if !claimingDone} -
+
handleClaimClick()} - disabled={claimDisabled}>{$t('transactions.claim.steps.confirm.claim_button')} + disabled={claimDisabled || canForceTransaction} + >{$t('transactions.claim.steps.confirm.claim_button')} + {#if canForceTransaction} + handleForceClaim()} + disabled={claimDisabled}>Force transaction + {/if}
{/if} diff --git a/packages/bridge-ui/src/libs/bridge/Bridge.ts b/packages/bridge-ui/src/libs/bridge/Bridge.ts index 54fabdc98d1..a84bae5ba91 100644 --- a/packages/bridge-ui/src/libs/bridge/Bridge.ts +++ b/packages/bridge-ui/src/libs/bridge/Bridge.ts @@ -166,7 +166,7 @@ export abstract class Bridge { abstract estimateGas(args: BridgeArgs): Promise; abstract bridge(args: BridgeArgs): Promise; - async processMessage(args: ClaimArgs): Promise { + async processMessage(args: ClaimArgs, force = false): Promise { const { messageStatus, destBridgeAddress } = await this.beforeProcessing(args); let blockNumber; @@ -203,7 +203,7 @@ export abstract class Bridge { // Initial claim await this.beforeClaiming({ ...args, messageStatus }); - txHash = await this.processNewMessage({ ...args, bridgeContract, client }); + txHash = await this.processNewMessage({ ...args, bridgeContract, client }, force); } else if (messageStatus === MessageStatus.RETRIABLE) { // Claiming after a failed attempt await this.beforeRetrying({ ...args, messageStatus }); @@ -225,7 +225,7 @@ export abstract class Bridge { } } - private async processNewMessage(args: ProcessMessageType): Promise { + private async processNewMessage(args: ProcessMessageType, force = false): Promise { const { bridgeTx, bridgeContract, client } = args; const { message } = bridgeTx; if (!message) throw new ProcessMessageError('Message is not defined'); @@ -260,25 +260,26 @@ export abstract class Bridge { console.error('Failed to estimate gas, using fallback', error); estimatedGas = 1_300_000n; } + if (force) { + return await writeContract(config, { + address: bridgeContract.address, + abi: bridgeContract.abi, + functionName: 'processMessage', + args: [message, proof], + gas: estimatedGas, + }); + } else { + const { request } = await simulateContract(config, { + address: bridgeContract.address, + abi: bridgeContract.abi, + functionName: 'processMessage', + args: [message, proof], + gas: estimatedGas, + }); + log('Simulate contract for processMessage', request); - const { request } = await simulateContract(config, { - address: bridgeContract.address, - abi: bridgeContract.abi, - functionName: 'processMessage', - args: [message, proof], - gas: estimatedGas, - }); - log('Simulate contract for processMessage', request); - - return await writeContract(config, request); - - // return await writeContract(config, { - // address: bridgeContract.address, - // abi: bridgeContract.abi, - // functionName: 'processMessage', - // args: [message, proof], - // gas: estimatedGas, - // }); + return await writeContract(config, request); + } } private async retryMessage(args: RetryMessageArgs): Promise { diff --git a/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts b/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts index 3e98f8754b1..6e773b80498 100644 --- a/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts +++ b/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts @@ -177,6 +177,9 @@ export class RelayerAPIService { data = `0x${buffer.toString('hex')}`; } + const tokenType: TokenType = _eventToTokenType(tx.eventType); + const value = tokenType === TokenType.ETH ? BigInt(tx.amount) : BigInt(0); + const transformedTx = { status: tx.status, amount: BigInt(tx.amount), @@ -187,7 +190,7 @@ export class RelayerAPIService { srcChainId: tx.data.Message.SrcChainId, destChainId: tx.data.Message.DestChainId, msgHash: tx.msgHash, - tokenType: _eventToTokenType(tx.eventType), + tokenType: tokenType, blockNumber: tx.data.Raw.blockNumber, canonicalTokenAddress: tx.canonicalTokenAddress, message: { @@ -198,7 +201,7 @@ export class RelayerAPIService { srcOwner: tx.data.Message.SrcOwner, from: tx.data.Message.From, gasLimit: Number(tx.data.Message.GasLimit), - value: BigInt(tx.amount), + value: value, srcChainId: BigInt(tx.data.Message.SrcChainId), destChainId: BigInt(tx.data.Message.DestChainId), fee: BigInt(tx.data.Message.Fee),