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),