diff --git a/packages/bridge-ui/src/components/Bridge/FungibleBridgeComponents/ImportStep/ImportStep.svelte b/packages/bridge-ui/src/components/Bridge/FungibleBridgeComponents/ImportStep/ImportStep.svelte
index 7a86cff725..b928cf206c 100644
--- a/packages/bridge-ui/src/components/Bridge/FungibleBridgeComponents/ImportStep/ImportStep.svelte
+++ b/packages/bridge-ui/src/components/Bridge/FungibleBridgeComponents/ImportStep/ImportStep.svelte
@@ -1,7 +1,7 @@
+
+
+ {#if small}
+
+ {$t('destOwner.title')}
+ {#if displayedDestOwner}
+ {shortenAddress(displayedDestOwner, 8, 10)}
+ {#if displayedDestOwner !== $account?.address}
+ | {$t('common.customized')}
+ {/if}
+ {:else}
+ {$t('destOwner.placeholder')}
+ {/if}
+
+ {:else}
+
+
+ {$t('destOwner.title')}
+
+ {$t('destOwner.tooltip_title')}
+ {$t('destOwner.tooltip')}
+
+
+ {#if !disabled}
+
{$t('common.edit')}
+ {/if}
+
+
+
+ {#if displayedDestOwner}
+ {shortenAddress(displayedDestOwner, 15, 13)}
+ {#if displayedDestOwner !== $account?.address}
+ | {$t('common.customized')}
+ {/if}
+ {:else}
+ {$t('recipient.placeholder')}
+ {/if}
+
+
+
+
+
+
+
+
{$t('destOwner.title')}
+
+
{$t('destOwner.description')}
+
+
+
+ {#if destOwnerIsSmartContract}
+
+ You cannot set a smart contract as destination owner.
+
+ {/if}
+
+
+
+ {$t('common.cancel')}
+
+
+ {$t('common.confirm')}
+
+
+
+
+
+ {/if}
+
diff --git a/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/Recipient.svelte b/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/Recipient.svelte
index 75756392c9..86786da693 100644
--- a/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/Recipient.svelte
+++ b/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/Recipient.svelte
@@ -2,14 +2,15 @@
import { t } from 'svelte-i18n';
import type { Address } from 'viem';
- import { recipientAddress } from '$components/Bridge/state';
+ import { destNetwork, destOwnerAddress, recipientAddress } from '$components/Bridge/state';
import { ActionButton, CloseButton } from '$components/Button';
import { Tooltip } from '$components/Tooltip';
+ import { isSmartContract } from '$libs/util/isSmartContract';
import { shortenAddress } from '$libs/util/shortenAddress';
- import { uid } from '$libs/util/uid';
import { account } from '$stores/account';
import AddressInput from '../AddressInput/AddressInput.svelte';
+ // import Alert from '$components/Alert/Alert.svelte';
// Public API
export const clearRecipient = () => {
@@ -20,13 +21,18 @@
export let small = false;
export let disabled = false;
- let dialogId = `dialog-${uid()}`;
+ let dialogId = `dialog-${crypto.randomUUID()}`;
let addressInput: AddressInput;
+ let destOwnerAddressInput: AddressInput;
let modalOpen = false;
- let invalidAddress = false;
+ let invalidRecipient = false;
+ let invalidDestOwner = false;
let prevRecipientAddress: Maybe = null;
+ let recipientIsSmartContract = false;
+ // let destOwnerIsSmartContract = false;
+
function closeModal() {
modalOpen = false;
}
@@ -40,6 +46,7 @@
function cancelModal() {
// Revert change of recipient address
$recipientAddress = prevRecipientAddress;
+ $destOwnerAddress = recipientIsSmartContract ? $account?.address : null;
removeEscKeyListener();
closeModal();
}
@@ -51,16 +58,46 @@
}
}
- function onAddressValidation(event: CustomEvent<{ isValidEthereumAddress: boolean; addr: Address }>) {
+ async function onRecipientValidation(event: CustomEvent<{ isValidEthereumAddress: boolean; addr: Address }>) {
const { isValidEthereumAddress, addr } = event.detail;
+
if (isValidEthereumAddress) {
- $recipientAddress = addr;
- invalidAddress = false;
+ validateRecipient(addr);
} else {
- invalidAddress = true;
+ invalidRecipient = true;
}
}
+ const validateRecipient = async (addr: Address) => {
+ $recipientAddress = addr;
+ invalidRecipient = false;
+ if ($destNetwork?.id && (await isSmartContract(addr, $destNetwork.id))) {
+ recipientIsSmartContract = true;
+ } else {
+ recipientIsSmartContract = false;
+ }
+ };
+
+ async function onDestOwnerValidation(event: CustomEvent<{ isValidEthereumAddress: boolean; addr: Address }>) {
+ const { isValidEthereumAddress, addr } = event.detail;
+ if (isValidEthereumAddress) {
+ validateDestOwner(addr);
+ } else {
+ invalidDestOwner = true;
+ }
+ }
+
+ const validateDestOwner = async (addr: Address) => {
+ $destOwnerAddress = addr;
+ invalidDestOwner = false;
+ // if ($destNetwork?.id && (await isSmartContract(addr, $destNetwork.id))) {
+ // destOwnerIsSmartContract = true;
+ // // invalidDestOwner = true;
+ // } else {
+ // destOwnerIsSmartContract = false;
+ // }
+ };
+
let escKeyListener: (event: KeyboardEvent) => void;
const addEscKeyListener = () => {
@@ -79,6 +116,7 @@
$: modalOpenChange(modalOpen);
$: ethereumAddressBinding = $recipientAddress || undefined;
+ $: destOwnerAddressBinding = $destOwnerAddress || undefined;
$: displayedRecipient = $recipientAddress || $account?.address;
@@ -134,17 +172,40 @@
+ on:addressvalidation={onRecipientValidation}
+ onDialog
+ resettable />
+ {#if recipientIsSmartContract}
+
+ You are sending funds to a smart contract. Please provide an alternate address that can manually claim the
+ funds if the relayer doesn't or you configured it that way. Ensure this is an address you control, as you
+ cannot claim the funds as the smart contract directly.
+
+
+ {/if}
+
{$t('common.cancel')}
{$t('common.confirm')}
diff --git a/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/RecipientStep.svelte b/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/RecipientStep.svelte
index 143e1626eb..e187ec9b20 100644
--- a/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/RecipientStep.svelte
+++ b/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/RecipientStep/RecipientStep.svelte
@@ -4,7 +4,10 @@
import { Alert } from '$components/Alert';
import { ProcessingFee, Recipient } from '$components/Bridge/SharedBridgeComponents';
+ import DestOwner from './DestOwner.svelte';
+
let recipientComponent: Recipient;
+ let destOwnerComponent: DestOwner;
let processingFeeComponent: ProcessingFee;
export let hasEnoughEth: boolean = false;
@@ -18,6 +21,7 @@
diff --git a/packages/bridge-ui/src/components/Bridge/state.ts b/packages/bridge-ui/src/components/Bridge/state.ts
index f6089db261..c55af63702 100644
--- a/packages/bridge-ui/src/components/Bridge/state.ts
+++ b/packages/bridge-ui/src/components/Bridge/state.ts
@@ -29,6 +29,7 @@ export const processingFee = writable(BigInt(0));
export const gasLimitZero = writable(false);
export const processingFeeMethod = writable(ProcessingFeeMethod.RECOMMENDED);
export const recipientAddress = writable>(null);
+export const destOwnerAddress = writable>(null);
// Loading state
export const bridging = writable(false);
diff --git a/packages/bridge-ui/src/components/ChainSelectors/ChainPill/ChainPill.svelte b/packages/bridge-ui/src/components/ChainSelectors/ChainPill/ChainPill.svelte
index e4a8e6f496..6d2d882cba 100644
--- a/packages/bridge-ui/src/components/ChainSelectors/ChainPill/ChainPill.svelte
+++ b/packages/bridge-ui/src/components/ChainSelectors/ChainPill/ChainPill.svelte
@@ -8,7 +8,6 @@
import { DesktopOrLarger } from '$components/DesktopOrLarger';
import { classNames } from '$libs/util/classNames';
import { truncateString } from '$libs/util/truncateString';
- import { uid } from '$libs/util/uid';
import { account } from '$stores';
export let value: Maybe | null = null;
@@ -26,8 +25,8 @@
let iconSize = 'min-w-5 max-w-5 min-h-5 max-h-5';
- let buttonId = `button-${uid()}`;
- let dialogId = `dialog-${uid()}`;
+ let buttonId = `button-${crypto.randomUUID()}`;
+ let dialogId = `dialog-${crypto.randomUUID()}`;
let modalOpen = false;
const handlePillClick = () => {
diff --git a/packages/bridge-ui/src/components/ChainSelectors/SelectorDialogs/ChainsDialog.svelte b/packages/bridge-ui/src/components/ChainSelectors/SelectorDialogs/ChainsDialog.svelte
index 6317de54fa..126631bdc6 100644
--- a/packages/bridge-ui/src/components/ChainSelectors/SelectorDialogs/ChainsDialog.svelte
+++ b/packages/bridge-ui/src/components/ChainSelectors/SelectorDialogs/ChainsDialog.svelte
@@ -9,7 +9,6 @@
import { ActionButton } from '$components/Button';
import { chains } from '$libs/chain';
import { closeOnEscapeOrOutsideClick } from '$libs/customActions';
- import { uid } from '$libs/util/uid';
import { connectedSourceChain } from '$stores/network';
export let isOpen = false;
@@ -17,7 +16,7 @@
export let switchWallet = false;
let modalOpen = false;
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
const dispatch = createEventDispatcher();
diff --git a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte b/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte
index 146c838754..649a5d42d5 100644
--- a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte
+++ b/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte
@@ -24,7 +24,6 @@
} from '$libs/error';
import type { NFT } from '$libs/token';
import { getLogger } from '$libs/util/logger';
- import { uid } from '$libs/util/uid';
import { connectedSourceChain } from '$stores/network';
import { pendingTransactions } from '$stores/pendingTransactions';
@@ -37,7 +36,7 @@
const log = getLogger('ClaimDialog');
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
const dispatch = createEventDispatcher();
export let dialogOpen = false;
diff --git a/packages/bridge-ui/src/components/Dialogs/ReleaseDialog/ReleaseDialog.svelte b/packages/bridge-ui/src/components/Dialogs/ReleaseDialog/ReleaseDialog.svelte
index bf461a0c19..b09be8da5e 100644
--- a/packages/bridge-ui/src/components/Dialogs/ReleaseDialog/ReleaseDialog.svelte
+++ b/packages/bridge-ui/src/components/Dialogs/ReleaseDialog/ReleaseDialog.svelte
@@ -18,7 +18,6 @@
RetryError,
} from '$libs/error';
import { getLogger } from '$libs/util/logger';
- import { uid } from '$libs/util/uid';
import { connectedSourceChain } from '$stores/network';
import { pendingTransactions } from '$stores/pendingTransactions';
@@ -32,7 +31,7 @@
const log = getLogger('ReleaseDialog');
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
const dispatch = createEventDispatcher();
export let bridgeTx: BridgeTransaction;
diff --git a/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte b/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte
index 3a90c0a662..ef60ee478b 100644
--- a/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte
+++ b/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte
@@ -12,7 +12,6 @@
import type { BridgeTransaction } from '$libs/bridge';
import { closeOnEscapeOrOutsideClick } from '$libs/customActions';
import { getLogger } from '$libs/util/logger';
- import { uid } from '$libs/util/uid';
import { pendingTransactions } from '$stores/pendingTransactions';
import Claim from '../Claim.svelte';
@@ -35,7 +34,7 @@
const log = getLogger('RetryDialog');
const dispatch = createEventDispatcher();
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
let canContinue = false;
let retrying: boolean;
diff --git a/packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte b/packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte
index 3351c040dc..8004aef57c 100644
--- a/packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte
+++ b/packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte
@@ -104,8 +104,11 @@
$: hasPaidProcessingFee = tx.processingFee > 0;
$: differentRecipient = false;
- $: if (tx.message?.destOwner && $account?.address) {
- if (getAddress(tx.message.destOwner) === getAddress($account?.address)) {
+ $: if (tx.message?.to && $account?.address && tx.message.destOwner) {
+ if (
+ getAddress(tx.message.to) === getAddress($account.address) ||
+ getAddress($account.address) === getAddress(tx.message.destOwner)
+ ) {
differentRecipient = false;
} else {
differentRecipient = true;
diff --git a/packages/bridge-ui/src/components/Dialogs/Shared/ReviewStep.svelte b/packages/bridge-ui/src/components/Dialogs/Shared/ReviewStep.svelte
index 69f40fab2c..48b6f3b41f 100644
--- a/packages/bridge-ui/src/components/Dialogs/Shared/ReviewStep.svelte
+++ b/packages/bridge-ui/src/components/Dialogs/Shared/ReviewStep.svelte
@@ -58,7 +58,7 @@
{$t('common.recipient')}
{shortenAddress(tx.message?.destOwner, 5, 5)}
+ >{shortenAddress(tx.message?.to, 5, 5)}
{/if}
diff --git a/packages/bridge-ui/src/components/NFTs/NFTInfoDialog.svelte b/packages/bridge-ui/src/components/NFTs/NFTInfoDialog.svelte
index 668e817aba..d44164a01c 100644
--- a/packages/bridge-ui/src/components/NFTs/NFTInfoDialog.svelte
+++ b/packages/bridge-ui/src/components/NFTs/NFTInfoDialog.svelte
@@ -11,10 +11,9 @@
import type { NFT } from '$libs/token';
import { getTokenAddresses } from '$libs/token/getTokenAddresses';
import { shortenAddress } from '$libs/util/shortenAddress';
- import { uid } from '$libs/util/uid';
import { connectedSourceChain } from '$stores/network';
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
const placeholderUrl = '/placeholder.svg';
diff --git a/packages/bridge-ui/src/components/NotificationToast/NotificationToast.svelte b/packages/bridge-ui/src/components/NotificationToast/NotificationToast.svelte
index 34e7f0c8f8..ce60f9c22c 100644
--- a/packages/bridge-ui/src/components/NotificationToast/NotificationToast.svelte
+++ b/packages/bridge-ui/src/components/NotificationToast/NotificationToast.svelte
@@ -2,7 +2,6 @@
import { toast } from '@zerodevx/svelte-toast';
import { toastConfig } from '$config';
- import { uid } from '$libs/util/uid';
import ItemToast from './ItemToast.svelte';
import type { TypeToast } from './types';
@@ -28,7 +27,7 @@
}
export function notify(notificationType: NotificationType) {
- const id = Number(uid());
+ const id = Number(crypto.randomUUID());
const close = () => toast.pop(id);
const { title, message, type = 'unknown', closeManually = getDefaultCloseBehaviour(type) } = notificationType;
diff --git a/packages/bridge-ui/src/components/TokenDropdown/AddCustomERC20.svelte b/packages/bridge-ui/src/components/TokenDropdown/AddCustomERC20.svelte
index e9fd751376..9c72342e64 100644
--- a/packages/bridge-ui/src/components/TokenDropdown/AddCustomERC20.svelte
+++ b/packages/bridge-ui/src/components/TokenDropdown/AddCustomERC20.svelte
@@ -17,7 +17,6 @@
import { getTokenAddresses } from '$libs/token/getTokenAddresses';
import { getTokenWithInfoFromAddress } from '$libs/token/getTokenWithInfoFromAddress';
import { getLogger } from '$libs/util/logger';
- import { uid } from '$libs/util/uid';
import { config } from '$libs/wagmi';
import { account } from '$stores/account';
import { connectedSourceChain } from '$stores/network';
@@ -27,7 +26,7 @@
const dispatch = createEventDispatcher();
const log = getLogger('component:AddCustomERC20');
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
export let modalOpen = false;
export let loadingTokenDetails = false;
diff --git a/packages/bridge-ui/src/components/TokenDropdown/TokenDropdown.svelte b/packages/bridge-ui/src/components/TokenDropdown/TokenDropdown.svelte
index a39082eba1..27f734c21e 100644
--- a/packages/bridge-ui/src/components/TokenDropdown/TokenDropdown.svelte
+++ b/packages/bridge-ui/src/components/TokenDropdown/TokenDropdown.svelte
@@ -22,7 +22,6 @@
import { getTokenAddresses } from '$libs/token/getTokenAddresses';
import { getLogger } from '$libs/util/logger';
import { truncateString } from '$libs/util/truncateString';
- import { uid } from '$libs/util/uid';
import { type Account, account } from '$stores/account';
import { connectedSourceChain } from '$stores/network';
@@ -44,7 +43,7 @@
let customTokenModalOpen = false;
- let id = `menu-${uid()}`;
+ let id = `menu-${crypto.randomUUID()}`;
$: menuOpen = false;
let activeTab: TabTypes = TabTypes.TOKEN;
diff --git a/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte b/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte
index cf779ef53a..f69ca24573 100644
--- a/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte
+++ b/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte
@@ -4,12 +4,11 @@
import { Icon } from '$components/Icon';
import { classNames } from '$libs/util/classNames';
import { positionElementByTarget } from '$libs/util/positionElementByTarget';
- import { uid } from '$libs/util/uid';
export let position: Position = 'top';
export let tooltipOpen = false;
- let tooltipId = `tooltip-${uid()}`;
+ let tooltipId = `tooltip-${crypto.randomUUID()}`;
let tooltipClass = `block dialog-tooltip`;
let classes = classNames('flex z-10 ', $$props.class || 'relative');
diff --git a/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDialog.svelte b/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDialog.svelte
index b4a3827c85..4ed183dd43 100644
--- a/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDialog.svelte
+++ b/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDialog.svelte
@@ -3,11 +3,10 @@
import { ActionButton, CloseButton } from '$components/Button';
import { MessageStatus } from '$libs/bridge';
- import { uid } from '$libs/util/uid';
export let selectedStatus: MessageStatus | null = null;
- let dialogId = `dialog-${uid()}`;
+ let dialogId = `dialog-${crypto.randomUUID()}`;
export let menuOpen = false;
diff --git a/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDropdown.svelte b/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDropdown.svelte
index f2445651a8..4faea34358 100644
--- a/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDropdown.svelte
+++ b/packages/bridge-ui/src/components/Transactions/Filter/StatusFilterDropdown.svelte
@@ -5,13 +5,12 @@
import { MessageStatus } from '$libs/bridge';
import { closeOnEscapeOrOutsideClick } from '$libs/customActions';
import { classNames } from '$libs/util/classNames';
- import { uid } from '$libs/util/uid';
export let selectedStatus: MessageStatus | null = null;
let flipped = false;
let menuOpen = false;
- let uuid = `dropdown-${uid()}`;
+ let uuid = `dropdown-${crypto.randomUUID()}`;
let iconFlipperComponent: IconFlipper;
diff --git a/packages/bridge-ui/src/components/Transactions/InsufficientFunds.svelte b/packages/bridge-ui/src/components/Transactions/InsufficientFunds.svelte
index 8e78a5189b..afcd8c4f20 100644
--- a/packages/bridge-ui/src/components/Transactions/InsufficientFunds.svelte
+++ b/packages/bridge-ui/src/components/Transactions/InsufficientFunds.svelte
@@ -5,11 +5,10 @@
import { Icon } from '$components/Icon';
import { PUBLIC_GUIDE_URL } from '$env/static/public';
import { closeOnEscapeOrOutsideClick } from '$libs/customActions';
- import { uid } from '$libs/util/uid';
export let modalOpen = false;
- let dialogId = `dialog-${uid()}`;
+ let dialogId = `dialog-${crypto.randomUUID()}`;
function closeModal() {
modalOpen = false;
diff --git a/packages/bridge-ui/src/components/Transactions/MobileDetailsDialog.svelte b/packages/bridge-ui/src/components/Transactions/MobileDetailsDialog.svelte
index 6968d9431a..e07aaaadb0 100644
--- a/packages/bridge-ui/src/components/Transactions/MobileDetailsDialog.svelte
+++ b/packages/bridge-ui/src/components/Transactions/MobileDetailsDialog.svelte
@@ -13,7 +13,6 @@
import { getTokenAddresses } from '$libs/token/getTokenAddresses';
import { noop } from '$libs/util/noop';
import { shortenAddress } from '$libs/util/shortenAddress';
- import { uid } from '$libs/util/uid';
import { connectedSourceChain } from '$stores/network';
import ChainSymbolName from './ChainSymbolName.svelte';
@@ -34,7 +33,7 @@
const openToolTip = () => {
tooltipOpen = !tooltipOpen;
};
- let dialogId = `dialog-${uid()}`;
+ let dialogId = `dialog-${crypto.randomUUID()}`;
const handleStatusDialog = () => {
openStatusDialog = !openStatusDialog;
diff --git a/packages/bridge-ui/src/components/Transactions/Status/StatusInfoDialog.svelte b/packages/bridge-ui/src/components/Transactions/Status/StatusInfoDialog.svelte
index 3dc7f7245b..672480a605 100644
--- a/packages/bridge-ui/src/components/Transactions/Status/StatusInfoDialog.svelte
+++ b/packages/bridge-ui/src/components/Transactions/Status/StatusInfoDialog.svelte
@@ -3,13 +3,12 @@
import { CloseButton } from '$components/Button';
import { Icon } from '$components/Icon';
- import { uid } from '$libs/util/uid';
export let modalOpen = false;
export let noIcon = false;
- const dialogId = `dialog-${uid()}`;
+ const dialogId = `dialog-${crypto.randomUUID()}`;
const closeModal = () => (modalOpen = false);
diff --git a/packages/bridge-ui/src/i18n/en.json b/packages/bridge-ui/src/i18n/en.json
index 824bb73d6b..460f98ee46 100644
--- a/packages/bridge-ui/src/i18n/en.json
+++ b/packages/bridge-ui/src/i18n/en.json
@@ -250,6 +250,7 @@
"not_available_short": "N/A",
"ok": "Okay",
"recipient": "Recipient",
+ "reset_to_wallet": "Reset to current address",
"review": "Review",
"search_token": "Search token",
"see_results": "See results",
@@ -266,6 +267,16 @@
"custom_recipient": {
"placeholder": "Add custom recipient"
},
+ "destOwner": {
+ "alerts": {
+ "smartContract": "You cannot set the destination owner to a contract address"
+ },
+ "description": "You can set a custom address that should be able to claim the transaction on the destination chain, for example if the recipient is a smart contract that cannot manually claim.",
+ "placeholder": "add address that should be able to manually claim...",
+ "title": "Destination owner",
+ "tooltip": "Defaults to your address. You can specify a different address that should be able to claim this transaction.",
+ "tooltip_title": "What is Destination Owner?"
+ },
"faucet": {
"button": {
"checking": "Checking mintability",
diff --git a/packages/bridge-ui/src/libs/bridge/ERC1155Bridge.ts b/packages/bridge-ui/src/libs/bridge/ERC1155Bridge.ts
index bdc64eab28..94f9931e82 100644
--- a/packages/bridge-ui/src/libs/bridge/ERC1155Bridge.ts
+++ b/packages/bridge-ui/src/libs/bridge/ERC1155Bridge.ts
@@ -4,7 +4,7 @@ import { getContract, UserRejectedRequestError } from 'viem';
import { bridgeAbi, erc1155Abi, erc1155VaultAbi } from '$abi';
import { routingContractsMap } from '$bridgeConfig';
-import { gasLimitZero } from '$components/Bridge/state';
+import { destOwnerAddress, gasLimitZero } from '$components/Bridge/state';
import { gasLimitConfig } from '$config';
import {
ApproveError,
@@ -223,7 +223,7 @@ export class ERC1155Bridge extends Bridge {
const sendERC1155Args: NFTBridgeTransferOp = {
destChainId: BigInt(destChainId),
to,
- destOwner: to,
+ destOwner: get(destOwnerAddress) || to,
token,
gasLimit: Number(gasLimit),
fee,
diff --git a/packages/bridge-ui/src/libs/bridge/ERC20Bridge.ts b/packages/bridge-ui/src/libs/bridge/ERC20Bridge.ts
index f1c06c0324..e3023d9307 100644
--- a/packages/bridge-ui/src/libs/bridge/ERC20Bridge.ts
+++ b/packages/bridge-ui/src/libs/bridge/ERC20Bridge.ts
@@ -4,7 +4,7 @@ import { getContract, UserRejectedRequestError } from 'viem';
import { bridgeAbi, erc20Abi, erc20VaultAbi } from '$abi';
import { routingContractsMap } from '$bridgeConfig';
-import { gasLimitZero } from '$components/Bridge/state';
+import { destOwnerAddress, gasLimitZero } from '$components/Bridge/state';
import { gasLimitConfig } from '$config';
import {
ApproveError,
@@ -75,7 +75,7 @@ export class ERC20Bridge extends Bridge {
const sendERC20Args = {
destChainId: BigInt(destChainId),
- destOwner: to,
+ destOwner: get(destOwnerAddress) || to,
to,
token,
amount,
diff --git a/packages/bridge-ui/src/libs/bridge/ERC721Bridge.ts b/packages/bridge-ui/src/libs/bridge/ERC721Bridge.ts
index 294bdb6990..45c5f6968b 100644
--- a/packages/bridge-ui/src/libs/bridge/ERC721Bridge.ts
+++ b/packages/bridge-ui/src/libs/bridge/ERC721Bridge.ts
@@ -4,7 +4,7 @@ import { getContract, UserRejectedRequestError } from 'viem';
import { bridgeAbi, erc721Abi, erc721VaultAbi } from '$abi';
import { routingContractsMap } from '$bridgeConfig';
-import { gasLimitZero } from '$components/Bridge/state';
+import { destOwnerAddress, gasLimitZero } from '$components/Bridge/state';
import { gasLimitConfig } from '$config';
import {
ApproveError,
@@ -235,7 +235,7 @@ export class ERC721Bridge extends Bridge {
const sendERC721Args: NFTBridgeTransferOp = {
destChainId: BigInt(destChainId),
to,
- destOwner: to,
+ destOwner: get(destOwnerAddress) || to,
token,
gasLimit: Number(gasLimit),
fee,
diff --git a/packages/bridge-ui/src/libs/bridge/ETHBridge.ts b/packages/bridge-ui/src/libs/bridge/ETHBridge.ts
index 5cbae26530..b81911ec2c 100644
--- a/packages/bridge-ui/src/libs/bridge/ETHBridge.ts
+++ b/packages/bridge-ui/src/libs/bridge/ETHBridge.ts
@@ -3,7 +3,7 @@ import { get } from 'svelte/store';
import { getContract, UserRejectedRequestError } from 'viem';
import { bridgeAbi } from '$abi';
-import { gasLimitZero } from '$components/Bridge/state';
+import { destOwnerAddress, gasLimitZero } from '$components/Bridge/state';
import { BridgePausedError, SendMessageError } from '$libs/error';
import type { BridgeProver } from '$libs/proof';
import { isBridgePaused } from '$libs/util/checkForPausedContracts';
@@ -55,7 +55,7 @@ export class ETHBridge extends Bridge {
srcOwner: owner,
from: owner,
- destOwner: to,
+ destOwner: get(destOwnerAddress) || to,
srcChainId: BigInt(srcChainId),
destChainId: BigInt(destChainId),
diff --git a/packages/bridge-ui/src/libs/util/isSmartContractWallet.test.ts b/packages/bridge-ui/src/libs/util/isSmartContract.test.ts
similarity index 79%
rename from packages/bridge-ui/src/libs/util/isSmartContractWallet.test.ts
rename to packages/bridge-ui/src/libs/util/isSmartContract.test.ts
index ba9be467ff..64d9d99658 100644
--- a/packages/bridge-ui/src/libs/util/isSmartContractWallet.test.ts
+++ b/packages/bridge-ui/src/libs/util/isSmartContract.test.ts
@@ -4,7 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import { config } from '$libs/wagmi';
import { L1_CHAIN_ID } from '$mocks';
-import { isSmartContractWallet } from './isSmartContractWallet';
+import { isSmartContract } from './isSmartContract';
// Mock wagmi core
vi.mock('@wagmi/core');
@@ -13,7 +13,7 @@ vi.mock('$customToken');
vi.mock('$libs/token');
-describe('isSmartContractWallet', () => {
+describe('isSmartContract', () => {
const mockWalletAddress = '0x1234567890abcdef1234567890abcdef12345678';
const mockChainId = L1_CHAIN_ID;
const mockClient = {
@@ -30,7 +30,7 @@ describe('isSmartContractWallet', () => {
mockClient.getBytecode.mockResolvedValueOnce('0x6000600055');
// When
- const result = await isSmartContractWallet(mockWalletAddress, mockChainId);
+ const result = await isSmartContract(mockWalletAddress, mockChainId);
// Then
expect(result).toBe(true);
@@ -43,7 +43,7 @@ describe('isSmartContractWallet', () => {
mockClient.getBytecode.mockResolvedValueOnce('0x');
// When
- const result = await isSmartContractWallet(mockWalletAddress, mockChainId);
+ const result = await isSmartContract(mockWalletAddress, mockChainId);
// Then
expect(result).toBe(false);
@@ -56,6 +56,6 @@ describe('isSmartContractWallet', () => {
vi.mocked(getPublicClient).mockReturnValueOnce(null);
// When/Then
- await expect(isSmartContractWallet(mockWalletAddress, mockChainId)).rejects.toThrow('No public client found');
+ await expect(isSmartContract(mockWalletAddress, mockChainId)).rejects.toThrow('No public client found');
});
});
diff --git a/packages/bridge-ui/src/libs/util/isSmartContractWallet.ts b/packages/bridge-ui/src/libs/util/isSmartContract.ts
similarity index 70%
rename from packages/bridge-ui/src/libs/util/isSmartContractWallet.ts
rename to packages/bridge-ui/src/libs/util/isSmartContract.ts
index 53c49bf1e3..9bbc18e233 100644
--- a/packages/bridge-ui/src/libs/util/isSmartContractWallet.ts
+++ b/packages/bridge-ui/src/libs/util/isSmartContract.ts
@@ -5,9 +5,9 @@ import { config } from '$libs/wagmi';
import { getLogger } from './logger';
-const log = getLogger('util:isSmartContractWallet');
+const log = getLogger('util:isSmartContract');
-export const isSmartContractWallet = async (walletAddress: Address, chainId: number) => {
+export const isSmartContract = async (walletAddress: Address, chainId: number) => {
const publicClient = getPublicClient(config, { chainId });
if (!publicClient) throw new Error('No public client found');
@@ -18,6 +18,6 @@ export const isSmartContractWallet = async (walletAddress: Address, chainId: num
if (byteCode !== '0x' && byteCode !== undefined) {
isSmartContract = true;
}
- log('isSmartContractWallet', isSmartContract, walletAddress, chainId);
+ log('isSmartContract', isSmartContract, walletAddress, chainId);
return isSmartContract;
};
diff --git a/packages/bridge-ui/src/libs/util/uid.test.ts b/packages/bridge-ui/src/libs/util/uid.test.ts
deleted file mode 100644
index 44ee4aa327..0000000000
--- a/packages/bridge-ui/src/libs/util/uid.test.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { uid } from './uid';
-
-describe('uid', () => {
- it('should always return a unique id', () => {
- const generatedIds = new Set();
-
- // Is this unique enough? 😅
- for (let i = 0; i < 1000; i++) {
- generatedIds.add(uid());
- }
-
- expect(generatedIds.size).toBe(1000);
- });
-});
diff --git a/packages/bridge-ui/src/libs/util/uid.ts b/packages/bridge-ui/src/libs/util/uid.ts
deleted file mode 100644
index 62cb3175f1..0000000000
--- a/packages/bridge-ui/src/libs/util/uid.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function uid() {
- return Math.floor(Math.random() * Date.now()).toString(16);
-}
diff --git a/packages/bridge-ui/src/libs/wagmi/watcher.ts b/packages/bridge-ui/src/libs/wagmi/watcher.ts
index 3523b253dd..31fe27791c 100644
--- a/packages/bridge-ui/src/libs/wagmi/watcher.ts
+++ b/packages/bridge-ui/src/libs/wagmi/watcher.ts
@@ -3,13 +3,14 @@ import { watchAccount } from '@wagmi/core';
import { chains, isSupportedChain } from '$libs/chain';
import { refreshUserBalance } from '$libs/util/balance';
import { checkForPausedContracts } from '$libs/util/checkForPausedContracts';
-import { isSmartContractWallet } from '$libs/util/isSmartContractWallet';
+import { isSmartContract } from '$libs/util/isSmartContract';
import { getLogger } from '$libs/util/logger';
import { account, connectedSmartContractWallet } from '$stores/account';
import { switchChainModal } from '$stores/modal';
import { connectedSourceChain } from '$stores/network';
import { config } from './client';
+
const log = getLogger('wagmi:watcher');
let isWatching = false;
@@ -23,6 +24,7 @@ export async function startWatching() {
async onChange(data) {
await checkForPausedContracts();
log('Account changed', data);
+ account.set(data);
refreshUserBalance();
const { chainId, address } = data;
@@ -30,7 +32,7 @@ export async function startWatching() {
if (chainId && address) {
let smartWallet = false;
try {
- smartWallet = (await isSmartContractWallet(address, Number(chainId))) || false;
+ smartWallet = (await isSmartContract(address, Number(chainId))) || false;
} catch (error) {
console.error('Error checking for smart contract wallet', error);
} finally {
@@ -49,10 +51,8 @@ export async function startWatching() {
// the source chain.
const srcChain = chains.find((c) => c.id === Number(chainId));
if (srcChain) connectedSourceChain.set(srcChain);
-
refreshUserBalance();
}
- account.set(data);
},
});