Compare commits
6 Commits
main
...
cex-withdr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
502fafd5de | ||
|
|
2eac714126 | ||
|
|
9e9bf8c5e0 | ||
|
|
8452537280 | ||
|
|
f397b91b9b | ||
|
|
756a346498 |
@ -40,9 +40,9 @@
|
|||||||
"@cosmjs/proto-signing": "^0.32.1",
|
"@cosmjs/proto-signing": "^0.32.1",
|
||||||
"@cosmjs/stargate": "^0.32.1",
|
"@cosmjs/stargate": "^0.32.1",
|
||||||
"@cosmjs/tendermint-rpc": "^0.32.1",
|
"@cosmjs/tendermint-rpc": "^0.32.1",
|
||||||
"@dydxprotocol/v4-abacus": "^1.4.5",
|
"@dydxprotocol/v4-abacus": "^1.4.6",
|
||||||
"@dydxprotocol/v4-client-js": "^1.0.20",
|
"@dydxprotocol/v4-client-js": "^1.0.20",
|
||||||
"@dydxprotocol/v4-localization": "^1.1.30",
|
"@dydxprotocol/v4-localization": "^1.1.31",
|
||||||
"@ethersproject/providers": "^5.7.2",
|
"@ethersproject/providers": "^5.7.2",
|
||||||
"@js-joda/core": "^5.5.3",
|
"@js-joda/core": "^5.5.3",
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
|
|||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@ -26,14 +26,14 @@ dependencies:
|
|||||||
specifier: ^0.32.1
|
specifier: ^0.32.1
|
||||||
version: 0.32.2
|
version: 0.32.2
|
||||||
'@dydxprotocol/v4-abacus':
|
'@dydxprotocol/v4-abacus':
|
||||||
specifier: ^1.4.5
|
specifier: ^1.4.6
|
||||||
version: 1.4.5
|
version: 1.4.6
|
||||||
'@dydxprotocol/v4-client-js':
|
'@dydxprotocol/v4-client-js':
|
||||||
specifier: ^1.0.20
|
specifier: ^1.0.20
|
||||||
version: 1.0.20
|
version: 1.0.20
|
||||||
'@dydxprotocol/v4-localization':
|
'@dydxprotocol/v4-localization':
|
||||||
specifier: ^1.1.30
|
specifier: ^1.1.31
|
||||||
version: 1.1.30
|
version: 1.1.31
|
||||||
'@ethersproject/providers':
|
'@ethersproject/providers':
|
||||||
specifier: ^5.7.2
|
specifier: ^5.7.2
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
@ -1286,8 +1286,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
|
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-abacus@1.4.5:
|
/@dydxprotocol/v4-abacus@1.4.6:
|
||||||
resolution: {integrity: sha512-LhJmpIaUkHCsSiHx+jdk+59euvGp2E+gGFelpfmOYpH1+enZgEXDQvWsgHSFEQxYP3mRiGG4uo+ZYNGdvffg7g==}
|
resolution: {integrity: sha512-qYq+4TizcMMxYVXckn0LCucWBe5N9ZNtD1XnowCAuBUUifHSgMGvao5OeZIKMgNM/udSKOXLss4zLy6dH/G2SA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-client-js@1.0.20:
|
/@dydxprotocol/v4-client-js@1.0.20:
|
||||||
@ -1319,8 +1319,8 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-localization@1.1.30:
|
/@dydxprotocol/v4-localization@1.1.31:
|
||||||
resolution: {integrity: sha512-TZfWWRSOxcjLHs972wlJVVHkE7+DVqAUnGZSs24HYHsPtUkPhZiNXMOA2Vk9YddQxumhM79xIRH0cmJSe5DDUg==}
|
resolution: {integrity: sha512-plJVIgFAKq9/hA/gk5GgKgCQFsH3pNtDWfG/yHLDXyiGX0M0mMEi1bTNVs4podFVoHJu1nSL9YPFlpJ00FteGw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-proto@4.0.0-dev.0:
|
/@dydxprotocol/v4-proto@4.0.0-dev.0:
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export const SearchSelectMenu = ({
|
|||||||
disabled,
|
disabled,
|
||||||
label,
|
label,
|
||||||
items,
|
items,
|
||||||
withSearch,
|
withSearch = true,
|
||||||
withReceiptItems,
|
withReceiptItems,
|
||||||
}: SearchSelectMenuProps) => {
|
}: SearchSelectMenuProps) => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
@ -77,6 +77,7 @@ export const SearchSelectMenu = ({
|
|||||||
withSearch={withSearch}
|
withSearch={withSearch}
|
||||||
onItemSelected={() => setOpen(false)}
|
onItemSelected={() => setOpen(false)}
|
||||||
withStickyLayout
|
withStickyLayout
|
||||||
|
$withSearch={withSearch}
|
||||||
/>
|
/>
|
||||||
</Styled.Popover>
|
</Styled.Popover>
|
||||||
</Styled.WithDetailsReceipt>
|
</Styled.WithDetailsReceipt>
|
||||||
@ -127,7 +128,7 @@ Styled.Popover = styled(Popover)`
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.ComboboxMenu = styled(ComboboxMenu)`
|
Styled.ComboboxMenu = styled(ComboboxMenu)<{ $withSearch?: boolean }>`
|
||||||
${layoutMixins.withInnerHorizontalBorders}
|
${layoutMixins.withInnerHorizontalBorders}
|
||||||
|
|
||||||
--comboboxMenu-backgroundColor: var(--color-layer-4);
|
--comboboxMenu-backgroundColor: var(--color-layer-4);
|
||||||
@ -140,7 +141,8 @@ Styled.ComboboxMenu = styled(ComboboxMenu)`
|
|||||||
--comboboxMenu-item-checked-textColor: var(--color-text-2);
|
--comboboxMenu-item-checked-textColor: var(--color-text-2);
|
||||||
--comboboxMenu-item-highlighted-textColor: var(--color-text-2);
|
--comboboxMenu-item-highlighted-textColor: var(--color-text-2);
|
||||||
|
|
||||||
--stickyArea1-topHeight: var(--form-input-height);
|
--stickyArea1-topHeight: ${({ $withSearch }) =>
|
||||||
|
!$withSearch ? '0' : 'var(--form-input-height)'};
|
||||||
|
|
||||||
input:focus-visible {
|
input:focus-visible {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { type ReactNode, useState } from 'react';
|
import { type ReactNode, useState, useEffect } from 'react';
|
||||||
|
|
||||||
import { ButtonAction, ButtonState } from '@/constants/buttons';
|
import { ButtonAction, ButtonState } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@ -8,6 +8,7 @@ import { Button, type ButtonStateConfig, type ButtonProps } from '@/components/B
|
|||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
timeoutInSeconds: number;
|
timeoutInSeconds: number;
|
||||||
|
onTimeOut?: () => void;
|
||||||
slotFinal?: ReactNode;
|
slotFinal?: ReactNode;
|
||||||
} & ButtonProps;
|
} & ButtonProps;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ export type TimeoutButtonProps = ElementProps;
|
|||||||
export const TimeoutButton = ({
|
export const TimeoutButton = ({
|
||||||
children,
|
children,
|
||||||
timeoutInSeconds,
|
timeoutInSeconds,
|
||||||
|
onTimeOut,
|
||||||
slotFinal,
|
slotFinal,
|
||||||
...otherProps
|
...otherProps
|
||||||
}: TimeoutButtonProps) => {
|
}: TimeoutButtonProps) => {
|
||||||
@ -25,6 +27,11 @@ export const TimeoutButton = ({
|
|||||||
|
|
||||||
const secondsLeft = Math.max(0, (timeoutDeadline - now) / 1000);
|
const secondsLeft = Math.max(0, (timeoutDeadline - now) / 1000);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (secondsLeft > 0) return;
|
||||||
|
onTimeOut?.();
|
||||||
|
}, [secondsLeft]);
|
||||||
|
|
||||||
if (slotFinal && secondsLeft <= 0) return slotFinal;
|
if (slotFinal && secondsLeft <= 0) return slotFinal;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -144,9 +144,17 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
|
|||||||
validatorUrl: string;
|
validatorUrl: string;
|
||||||
}
|
}
|
||||||
: T extends AnalyticsEvent.TransferDeposit
|
: T extends AnalyticsEvent.TransferDeposit
|
||||||
? {}
|
? {
|
||||||
|
chainId?: string;
|
||||||
|
tokenAddress?: string;
|
||||||
|
tokenSymbol?: string;
|
||||||
|
}
|
||||||
: T extends AnalyticsEvent.TransferWithdraw
|
: T extends AnalyticsEvent.TransferWithdraw
|
||||||
? {}
|
? {
|
||||||
|
chainId?: string;
|
||||||
|
tokenAddress?: string;
|
||||||
|
tokenSymbol?: string;
|
||||||
|
}
|
||||||
: // Trading
|
: // Trading
|
||||||
T extends AnalyticsEvent.TradeOrderTypeSelected
|
T extends AnalyticsEvent.TradeOrderTypeSelected
|
||||||
? {
|
? {
|
||||||
|
|||||||
@ -140,6 +140,7 @@ export type TransferNotifcation = {
|
|||||||
isCctp?: boolean;
|
isCctp?: boolean;
|
||||||
errorCount?: number;
|
errorCount?: number;
|
||||||
status?: StatusResponse;
|
status?: StatusResponse;
|
||||||
|
isExchange?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -82,24 +82,30 @@ const useLocalNotificationsContext = () => {
|
|||||||
isCctp,
|
isCctp,
|
||||||
errorCount,
|
errorCount,
|
||||||
status: currentStatus,
|
status: currentStatus,
|
||||||
|
isExchange,
|
||||||
} = transferNotification;
|
} = transferNotification;
|
||||||
|
|
||||||
// @ts-ignore status.errors is not in the type definition but can be returned
|
const hasErrors =
|
||||||
// also error can some time come back as an empty object so we need to ignore for that
|
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||||
const hasErrors = !!currentStatus?.errors ||
|
// also error can some time come back as an empty object so we need to ignore for that
|
||||||
(currentStatus?.error && Object.keys(currentStatus.error).length !== 0);
|
!!currentStatus?.errors ||
|
||||||
|
(currentStatus?.error && Object.keys(currentStatus.error).length !== 0);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
!isExchange &&
|
||||||
!hasErrors &&
|
!hasErrors &&
|
||||||
(!currentStatus?.squidTransactionStatus ||
|
(!currentStatus?.squidTransactionStatus ||
|
||||||
currentStatus?.squidTransactionStatus === 'ongoing')
|
currentStatus?.squidTransactionStatus === 'ongoing')
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const status = await fetchSquidStatus({
|
const status = await fetchSquidStatus(
|
||||||
transactionId: txHash,
|
{
|
||||||
toChainId,
|
transactionId: txHash,
|
||||||
fromChainId,
|
toChainId,
|
||||||
}, isCctp);
|
fromChainId,
|
||||||
|
},
|
||||||
|
isCctp
|
||||||
|
);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
transferNotification.status = status;
|
transferNotification.status = status;
|
||||||
|
|||||||
@ -179,8 +179,9 @@ export const notificationTypes: NotificationTypeConfig[] = [
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
for (const transfer of transferNotifications) {
|
for (const transfer of transferNotifications) {
|
||||||
const { fromChainId, status, txHash, toAmount, type } = transfer;
|
const { fromChainId, status, txHash, toAmount, type, isExchange } = transfer;
|
||||||
const isFinished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
|
const isFinished =
|
||||||
|
(Boolean(status) && status?.squidTransactionStatus !== 'ongoing') || isExchange;
|
||||||
const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />;
|
const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />;
|
||||||
|
|
||||||
const transferType =
|
const transferType =
|
||||||
|
|||||||
@ -25,3 +25,22 @@ export function convertBech32Address({
|
|||||||
}): string {
|
}): string {
|
||||||
return toBech32(bech32Prefix, fromHex(toHex(fromBech32(address).data)));
|
return toBech32(bech32Prefix, fromHex(toHex(fromBech32(address).data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a Cosmos address with a specific prefix.
|
||||||
|
* @param {string} address The Cosmos address to validate.
|
||||||
|
* @param {string} prefix The expected prefix for the address.
|
||||||
|
* @returns {boolean} True if the address is valid and matches the prefix, false otherwise.
|
||||||
|
*/
|
||||||
|
export function validateCosmosAddress(address: string, prefix: string) {
|
||||||
|
try {
|
||||||
|
// Decode the address to verify its structure and prefix
|
||||||
|
const { prefix: decodedPrefix } = fromBech32(address);
|
||||||
|
|
||||||
|
// Check if the decoded address has the expected prefix
|
||||||
|
return decodedPrefix === prefix;
|
||||||
|
} catch (error) {
|
||||||
|
// If decoding fails, the address is not valid
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -19,13 +19,17 @@ class TestFlags {
|
|||||||
return !!this.queryParams.displayinitializingmarkets;
|
return !!this.queryParams.displayinitializingmarkets;
|
||||||
}
|
}
|
||||||
|
|
||||||
get addressOverride():string {
|
get addressOverride(): string {
|
||||||
return this.queryParams.address;
|
return this.queryParams.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
get showTradingRewards() {
|
get showTradingRewards() {
|
||||||
return !!this.queryParams.tradingrewards;
|
return !!this.queryParams.tradingrewards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get showCexWithdrawal() {
|
||||||
|
return !!this.queryParams.cexwithdrawal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const testFlags = new TestFlags();
|
export const testFlags = new TestFlags();
|
||||||
|
|||||||
@ -13,8 +13,6 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { isMobile } = useBreakpoints();
|
const { isMobile } = useBreakpoints();
|
||||||
|
|
||||||
const closeDialog = () => setIsOpen?.(false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen
|
isOpen
|
||||||
@ -22,7 +20,7 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
title={stringGetter({ key: STRING_KEYS.DEPOSIT })}
|
title={stringGetter({ key: STRING_KEYS.DEPOSIT })}
|
||||||
placement={isMobile ? DialogPlacement.FullScreen : DialogPlacement.Default}
|
placement={isMobile ? DialogPlacement.FullScreen : DialogPlacement.Default}
|
||||||
>
|
>
|
||||||
<DepositDialogContent onDeposit={closeDialog} />
|
<DepositDialogContent />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
import { TransferInputField, TransferType } from '@/constants/abacus';
|
import { TransferInputField, TransferType } from '@/constants/abacus';
|
||||||
|
import { AnalyticsEvent } from '@/constants/analytics';
|
||||||
import { isMainnet } from '@/constants/networks';
|
import { isMainnet } from '@/constants/networks';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import { DepositForm } from '@/views/forms/AccountManagementForms/DepositForm';
|
|||||||
import { TestnetDepositForm } from '@/views/forms/AccountManagementForms/TestnetDepositForm';
|
import { TestnetDepositForm } from '@/views/forms/AccountManagementForms/TestnetDepositForm';
|
||||||
|
|
||||||
import abacusStateManager from '@/lib/abacus';
|
import abacusStateManager from '@/lib/abacus';
|
||||||
|
import { track } from '@/lib/analytics';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
onDeposit?: () => void;
|
onDeposit?: () => void;
|
||||||
@ -34,9 +36,19 @@ export const DepositDialogContent = ({ onDeposit }: ElementProps) => {
|
|||||||
return (
|
return (
|
||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
{isMainnet || !showFaucet ? (
|
{isMainnet || !showFaucet ? (
|
||||||
<DepositForm onDeposit={onDeposit} />
|
<DepositForm
|
||||||
|
onDeposit={(event) => {
|
||||||
|
track(AnalyticsEvent.TransferDeposit, event);
|
||||||
|
onDeposit?.();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<TestnetDepositForm onDeposit={onDeposit} />
|
<TestnetDepositForm
|
||||||
|
onDeposit={() => {
|
||||||
|
track(AnalyticsEvent.TransferFaucet);
|
||||||
|
onDeposit?.();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{!isMainnet && (
|
{!isMainnet && (
|
||||||
<Styled.TextToggle onClick={() => setShowFaucet(!showFaucet)}>
|
<Styled.TextToggle onClick={() => setShowFaucet(!showFaucet)}>
|
||||||
|
|||||||
@ -105,8 +105,8 @@ export const OnboardingDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
{isMainnet ? (
|
{isMainnet ? (
|
||||||
<DepositForm
|
<DepositForm
|
||||||
onDeposit={() => {
|
onDeposit={(event) => {
|
||||||
track(AnalyticsEvent.TransferDeposit);
|
track(AnalyticsEvent.TransferDeposit, event);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { Abi, parseUnits } from 'viem';
|
|||||||
import erc20 from '@/abi/erc20.json';
|
import erc20 from '@/abi/erc20.json';
|
||||||
import erc20_usdt from '@/abi/erc20_usdt.json';
|
import erc20_usdt from '@/abi/erc20_usdt.json';
|
||||||
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
||||||
|
import { AnalyticsEvent, AnalyticsEventData } from '@/constants/analytics';
|
||||||
import { AlertType } from '@/constants/alerts';
|
import { AlertType } from '@/constants/alerts';
|
||||||
import { ButtonSize } from '@/constants/buttons';
|
import { ButtonSize } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@ -48,7 +49,7 @@ import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
|
|||||||
import { NobleDeposit } from '../NobleDeposit';
|
import { NobleDeposit } from '../NobleDeposit';
|
||||||
|
|
||||||
type DepositFormProps = {
|
type DepositFormProps = {
|
||||||
onDeposit?: () => void;
|
onDeposit?: (event?: AnalyticsEventData<AnalyticsEvent.TransferDeposit>) => void;
|
||||||
onError?: () => void;
|
onError?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
if (error) onError?.();
|
if (error) onError?.();
|
||||||
}, [error]);
|
}, [error]);
|
||||||
|
|
||||||
const onSelectChain = useCallback((name: string, type: 'chain' | 'exchange') => {
|
const onSelectNetwork = useCallback((name: string, type: 'chain' | 'exchange') => {
|
||||||
if (name) {
|
if (name) {
|
||||||
abacusStateManager.clearTransferInputValues();
|
abacusStateManager.clearTransferInputValues();
|
||||||
setFromAmount('');
|
setFromAmount('');
|
||||||
@ -258,8 +259,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
};
|
};
|
||||||
const txHash = await signerWagmi.sendTransaction(tx);
|
const txHash = await signerWagmi.sendTransaction(tx);
|
||||||
|
|
||||||
onDeposit?.();
|
|
||||||
|
|
||||||
if (txHash) {
|
if (txHash) {
|
||||||
addTransferNotification({
|
addTransferNotification({
|
||||||
txHash: txHash,
|
txHash: txHash,
|
||||||
@ -271,6 +270,12 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
});
|
});
|
||||||
abacusStateManager.clearTransferInputValues();
|
abacusStateManager.clearTransferInputValues();
|
||||||
setFromAmount('');
|
setFromAmount('');
|
||||||
|
|
||||||
|
onDeposit?.({
|
||||||
|
chainId: chainIdStr || undefined,
|
||||||
|
tokenAddress: sourceToken?.address || undefined,
|
||||||
|
tokenSymbol: sourceToken?.symbol || undefined,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log('DepositForm/onSubmit', error);
|
log('DepositForm/onSubmit', error);
|
||||||
@ -279,7 +284,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[requestPayload, signerWagmi, chainId]
|
[requestPayload, signerWagmi, chainId, sourceToken, sourceChain]
|
||||||
);
|
);
|
||||||
|
|
||||||
const amountInputReceipt = [
|
const amountInputReceipt = [
|
||||||
@ -378,7 +383,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
<SourceSelectMenu
|
<SourceSelectMenu
|
||||||
selectedChain={chainIdStr || undefined}
|
selectedChain={chainIdStr || undefined}
|
||||||
selectedExchange={exchange || undefined}
|
selectedExchange={exchange || undefined}
|
||||||
onSelect={onSelectChain}
|
onSelect={onSelectNetwork}
|
||||||
/>
|
/>
|
||||||
{exchange && nobleAddress ? (
|
{exchange && nobleAddress ? (
|
||||||
<NobleDeposit />
|
<NobleDeposit />
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { popoverMixins } from '@/styles/popoverMixins';
|
|||||||
import { getTransferInputs } from '@/state/inputsSelectors';
|
import { getTransferInputs } from '@/state/inputsSelectors';
|
||||||
|
|
||||||
import { isTruthy } from '@/lib/isTruthy';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
|
import { testFlags } from '@/lib/testFlags';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
label?: string;
|
label?: string;
|
||||||
@ -62,11 +63,12 @@ export const SourceSelectMenu = ({
|
|||||||
return (
|
return (
|
||||||
<SearchSelectMenu
|
<SearchSelectMenu
|
||||||
items={[
|
items={[
|
||||||
exchangeItems.length > 0 && {
|
exchangeItems.length > 0 &&
|
||||||
group: 'exchanges',
|
(testFlags.showCexWithdrawal || type === TransferType.deposit) && {
|
||||||
groupLabel: stringGetter({ key: STRING_KEYS.EXCHANGES }),
|
group: 'exchanges',
|
||||||
items: exchangeItems,
|
groupLabel: stringGetter({ key: STRING_KEYS.EXCHANGES }),
|
||||||
},
|
items: exchangeItems,
|
||||||
|
},
|
||||||
chainItems.length > 0 && {
|
chainItems.length > 0 && {
|
||||||
group: 'chains',
|
group: 'chains',
|
||||||
groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }),
|
groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }),
|
||||||
|
|||||||
@ -17,9 +17,10 @@ import { getTransferInputs } from '@/state/inputsSelectors';
|
|||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
selectedToken?: TransferInputTokenResource;
|
selectedToken?: TransferInputTokenResource;
|
||||||
onSelectToken: (token: TransferInputTokenResource) => void;
|
onSelectToken: (token: TransferInputTokenResource) => void;
|
||||||
|
isExchange?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TokenSelectMenu = ({ selectedToken, onSelectToken }: ElementProps) => {
|
export const TokenSelectMenu = ({ selectedToken, onSelectToken, isExchange }: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { type, depositOptions, withdrawalOptions, resources } =
|
const { type, depositOptions, withdrawalOptions, resources } =
|
||||||
useSelector(getTransferInputs, shallowEqual) || {};
|
useSelector(getTransferInputs, shallowEqual) || {};
|
||||||
@ -47,19 +48,24 @@ export const TokenSelectMenu = ({ selectedToken, onSelectToken }: ElementProps)
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
label={stringGetter({ key: STRING_KEYS.ASSET })}
|
label={stringGetter({ key: STRING_KEYS.ASSET })}
|
||||||
withReceiptItems={[
|
withSearch={!isExchange}
|
||||||
{
|
withReceiptItems={
|
||||||
key: 'swap',
|
!isExchange
|
||||||
label: stringGetter({ key: STRING_KEYS.SWAP }),
|
? [
|
||||||
value: selectedToken && (
|
{
|
||||||
<>
|
key: 'swap',
|
||||||
<Tag>{type === TransferType.deposit ? selectedToken?.symbol : 'USDC'}</Tag>
|
label: stringGetter({ key: STRING_KEYS.SWAP }),
|
||||||
<DiffArrow />
|
value: selectedToken && (
|
||||||
<Tag>{type === TransferType.deposit ? 'USDC' : selectedToken?.symbol}</Tag>
|
<>
|
||||||
</>
|
<Tag>{type === TransferType.deposit ? selectedToken?.symbol : 'USDC'}</Tag>
|
||||||
),
|
<DiffArrow />
|
||||||
},
|
<Tag>{type === TransferType.deposit ? 'USDC' : selectedToken?.symbol}</Tag>
|
||||||
]}
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Styled.AssetRow>
|
<Styled.AssetRow>
|
||||||
{selectedToken ? (
|
{selectedToken ? (
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { isAddress } from 'viem';
|
|||||||
|
|
||||||
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
||||||
import { AlertType } from '@/constants/alerts';
|
import { AlertType } from '@/constants/alerts';
|
||||||
|
import { AnalyticsEvent } from '@/constants/analytics';
|
||||||
import { ButtonSize } from '@/constants/buttons';
|
import { ButtonSize } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { isMainnet } from '@/constants/networks';
|
import { isMainnet } from '@/constants/networks';
|
||||||
@ -55,6 +56,8 @@ import { getNobleChainId } from '@/lib/squid';
|
|||||||
|
|
||||||
import { TokenSelectMenu } from './TokenSelectMenu';
|
import { TokenSelectMenu } from './TokenSelectMenu';
|
||||||
import { WithdrawButtonAndReceipt } from './WithdrawForm/WithdrawButtonAndReceipt';
|
import { WithdrawButtonAndReceipt } from './WithdrawForm/WithdrawButtonAndReceipt';
|
||||||
|
import { validateCosmosAddress } from '@/lib/addressUtils';
|
||||||
|
import { track } from '@/lib/analytics';
|
||||||
|
|
||||||
export const WithdrawForm = () => {
|
export const WithdrawForm = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
@ -68,6 +71,7 @@ export const WithdrawForm = () => {
|
|||||||
const {
|
const {
|
||||||
requestPayload,
|
requestPayload,
|
||||||
token,
|
token,
|
||||||
|
exchange,
|
||||||
chain: chainIdStr,
|
chain: chainIdStr,
|
||||||
address: toAddress,
|
address: toAddress,
|
||||||
resources,
|
resources,
|
||||||
@ -179,18 +183,27 @@ export const WithdrawForm = () => {
|
|||||||
requestPayload.data,
|
requestPayload.data,
|
||||||
isCctp
|
isCctp
|
||||||
);
|
);
|
||||||
if (txHash) {
|
const nobleChainId = getNobleChainId();
|
||||||
|
const toChainId = Boolean(exchange) ? nobleChainId : chainIdStr || undefined;
|
||||||
|
if (txHash && toChainId) {
|
||||||
addTransferNotification({
|
addTransferNotification({
|
||||||
txHash: txHash,
|
txHash: txHash,
|
||||||
type: TransferNotificationTypes.Withdrawal,
|
type: TransferNotificationTypes.Withdrawal,
|
||||||
fromChainId: !isCctp ? selectedDydxChainId : getNobleChainId(),
|
fromChainId: !isCctp ? selectedDydxChainId : nobleChainId,
|
||||||
toChainId: chainIdStr || undefined,
|
toChainId,
|
||||||
toAmount: debouncedAmountBN.toNumber(),
|
toAmount: debouncedAmountBN.toNumber(),
|
||||||
triggeredAt: Date.now(),
|
triggeredAt: Date.now(),
|
||||||
isCctp,
|
isCctp,
|
||||||
|
isExchange: Boolean(exchange),
|
||||||
});
|
});
|
||||||
abacusStateManager.clearTransferInputValues();
|
abacusStateManager.clearTransferInputValues();
|
||||||
setWithdrawAmount('');
|
setWithdrawAmount('');
|
||||||
|
|
||||||
|
track(AnalyticsEvent.TransferWithdraw, {
|
||||||
|
chainId: toChainId,
|
||||||
|
tokenAddress: toToken?.address || undefined,
|
||||||
|
tokenSymbol: toToken?.symbol || undefined,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -213,7 +226,17 @@ export const WithdrawForm = () => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[requestPayload, debouncedAmountBN, chainIdStr, toAddress, screenAddresses, stringGetter]
|
[
|
||||||
|
requestPayload,
|
||||||
|
debouncedAmountBN,
|
||||||
|
chainIdStr,
|
||||||
|
toAddress,
|
||||||
|
selectedDydxChainId,
|
||||||
|
exchange,
|
||||||
|
toToken,
|
||||||
|
screenAddresses,
|
||||||
|
stringGetter,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onChangeAddress = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const onChangeAddress = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -246,13 +269,20 @@ export const WithdrawForm = () => {
|
|||||||
setWithdrawAmount(freeCollateralBN.toString());
|
setWithdrawAmount(freeCollateralBN.toString());
|
||||||
}, [freeCollateralBN, setWithdrawAmount]);
|
}, [freeCollateralBN, setWithdrawAmount]);
|
||||||
|
|
||||||
const onSelectChain = useCallback((chain: string) => {
|
const onSelectNetwork = useCallback((name: string, type: 'chain' | 'exchange') => {
|
||||||
if (chain) {
|
if (name) {
|
||||||
abacusStateManager.setTransferValue({
|
|
||||||
field: TransferInputField.chain,
|
|
||||||
value: chain,
|
|
||||||
});
|
|
||||||
setWithdrawAmount('');
|
setWithdrawAmount('');
|
||||||
|
if (type === 'chain') {
|
||||||
|
abacusStateManager.setTransferValue({
|
||||||
|
field: TransferInputField.chain,
|
||||||
|
value: name,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
abacusStateManager.setTransferValue({
|
||||||
|
field: TransferInputField.exchange,
|
||||||
|
value: name,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -313,7 +343,7 @@ export const WithdrawForm = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (debouncedAmountBN) {
|
if (debouncedAmountBN) {
|
||||||
if (!chainIdStr) {
|
if (!chainIdStr && !exchange) {
|
||||||
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_CHAIN });
|
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_CHAIN });
|
||||||
} else if (!toToken) {
|
} else if (!toToken) {
|
||||||
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ASSET });
|
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ASSET });
|
||||||
@ -360,14 +390,19 @@ export const WithdrawForm = () => {
|
|||||||
summary,
|
summary,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const isInvalidNobleAddress = Boolean(
|
||||||
|
exchange && toAddress && !validateCosmosAddress(toAddress, 'noble')
|
||||||
|
);
|
||||||
|
|
||||||
const isDisabled =
|
const isDisabled =
|
||||||
!!errorMessage ||
|
!!errorMessage ||
|
||||||
!toToken ||
|
!toToken ||
|
||||||
!chainIdStr ||
|
(!chainIdStr && !exchange) ||
|
||||||
!toAddress ||
|
!toAddress ||
|
||||||
debouncedAmountBN.isNaN() ||
|
debouncedAmountBN.isNaN() ||
|
||||||
debouncedAmountBN.isZero() ||
|
debouncedAmountBN.isZero() ||
|
||||||
isLoading;
|
isLoading ||
|
||||||
|
isInvalidNobleAddress;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.Form onSubmit={onSubmit}>
|
<Styled.Form onSubmit={onSubmit}>
|
||||||
@ -385,12 +420,21 @@ export const WithdrawForm = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SourceSelectMenu
|
<SourceSelectMenu
|
||||||
label={stringGetter({ key: STRING_KEYS.NETWORK })}
|
selectedExchange={exchange || undefined}
|
||||||
selectedChain={chainIdStr || undefined}
|
selectedChain={chainIdStr || undefined}
|
||||||
onSelect={onSelectChain}
|
onSelect={onSelectNetwork}
|
||||||
/>
|
/>
|
||||||
</Styled.DestinationRow>
|
</Styled.DestinationRow>
|
||||||
<TokenSelectMenu selectedToken={toToken || undefined} onSelectToken={onSelectToken} />
|
{isInvalidNobleAddress && (
|
||||||
|
<AlertMessage type={AlertType.Error}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.NOBLE_ADDRESS_VALIDATION })}
|
||||||
|
</AlertMessage>
|
||||||
|
)}
|
||||||
|
<TokenSelectMenu
|
||||||
|
selectedToken={toToken || undefined}
|
||||||
|
onSelectToken={onSelectToken}
|
||||||
|
isExchange={Boolean(exchange)}
|
||||||
|
/>
|
||||||
<Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}>
|
<Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}>
|
||||||
<FormInput
|
<FormInput
|
||||||
type={InputType.Number}
|
type={InputType.Number}
|
||||||
|
|||||||
@ -27,6 +27,8 @@ import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
|||||||
import { getSubaccount } from '@/state/accountSelectors';
|
import { getSubaccount } from '@/state/accountSelectors';
|
||||||
import { getTransferInputs } from '@/state/inputsSelectors';
|
import { getTransferInputs } from '@/state/inputsSelectors';
|
||||||
|
|
||||||
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
|
|
||||||
import { SlippageEditor } from '../SlippageEditor';
|
import { SlippageEditor } from '../SlippageEditor';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
@ -55,7 +57,7 @@ export const WithdrawButtonAndReceipt = ({
|
|||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
const { leverage } = useSelector(getSubaccount, shallowEqual) || {};
|
const { leverage } = useSelector(getSubaccount, shallowEqual) || {};
|
||||||
const { summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
|
const { summary, requestPayload, exchange } = useSelector(getTransferInputs, shallowEqual) || {};
|
||||||
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
||||||
const { usdcLabel } = useTokenConfigs();
|
const { usdcLabel } = useTokenConfigs();
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ export const WithdrawButtonAndReceipt = ({
|
|||||||
value: <Output type={OutputType.Fiat} value={totalFees} />,
|
value: <Output type={OutputType.Fiat} value={totalFees} />,
|
||||||
subitems: feeSubitems,
|
subitems: feeSubitems,
|
||||||
},
|
},
|
||||||
{
|
!exchange && {
|
||||||
key: 'exchange-rate',
|
key: 'exchange-rate',
|
||||||
label: <span>{stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })}</span>,
|
label: <span>{stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })}</span>,
|
||||||
value: withdrawToken && typeof summary?.exchangeRate === 'number' && (
|
value: withdrawToken && typeof summary?.exchangeRate === 'number' && (
|
||||||
@ -133,7 +135,9 @@ export const WithdrawButtonAndReceipt = ({
|
|||||||
{withdrawToken && <Tag>{withdrawToken?.symbol}</Tag>}
|
{withdrawToken && <Tag>{withdrawToken?.symbol}</Tag>}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
value: <Output type={OutputType.Asset} value={summary?.toAmount} fractionDigits={TOKEN_DECIMALS} />,
|
value: (
|
||||||
|
<Output type={OutputType.Asset} value={summary?.toAmount} fractionDigits={TOKEN_DECIMALS} />
|
||||||
|
),
|
||||||
subitems: [
|
subitems: [
|
||||||
{
|
{
|
||||||
key: 'minimum-amount-received',
|
key: 'minimum-amount-received',
|
||||||
@ -144,13 +148,17 @@ export const WithdrawButtonAndReceipt = ({
|
|||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
value: (
|
value: (
|
||||||
<Output type={OutputType.Asset} value={summary?.toAmountMin} fractionDigits={TOKEN_DECIMALS} />
|
<Output
|
||||||
|
type={OutputType.Asset}
|
||||||
|
value={summary?.toAmountMin}
|
||||||
|
fractionDigits={TOKEN_DECIMALS}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
tooltip: 'minimum-amount-received',
|
tooltip: 'minimum-amount-received',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
!exchange && {
|
||||||
key: 'slippage',
|
key: 'slippage',
|
||||||
label: <span>{stringGetter({ key: STRING_KEYS.MAX_SLIPPAGE })}</span>,
|
label: <span>{stringGetter({ key: STRING_KEYS.MAX_SLIPPAGE })}</span>,
|
||||||
value: (
|
value: (
|
||||||
@ -175,7 +183,7 @@ export const WithdrawButtonAndReceipt = ({
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
].filter(isTruthy);
|
||||||
|
|
||||||
const isFormValid = !isDisabled && !isEditingSlippage;
|
const isFormValid = !isDisabled && !isEditingSlippage;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||||
|
|
||||||
import { OpacityToken } from '@/constants/styles/base';
|
import { OpacityToken } from '@/constants/styles/base';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@ -10,7 +10,6 @@ import { useAccounts, useStringGetter } from '@/hooks';
|
|||||||
import { CopyButton } from '@/components/CopyButton';
|
import { CopyButton } from '@/components/CopyButton';
|
||||||
import { QrCode } from '@/components/QrCode';
|
import { QrCode } from '@/components/QrCode';
|
||||||
import { Checkbox } from '@/components/Checkbox';
|
import { Checkbox } from '@/components/Checkbox';
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
|
||||||
import { TimeoutButton } from '@/components/TimeoutButton';
|
import { TimeoutButton } from '@/components/TimeoutButton';
|
||||||
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
||||||
import { WithReceipt } from '@/components/WithReceipt';
|
import { WithReceipt } from '@/components/WithReceipt';
|
||||||
@ -19,6 +18,7 @@ import { generateFadedColorVariant } from '@/lib/styles';
|
|||||||
|
|
||||||
export const NobleDeposit = () => {
|
export const NobleDeposit = () => {
|
||||||
const [hasAcknowledged, setHasAcknowledged] = useState(false);
|
const [hasAcknowledged, setHasAcknowledged] = useState(false);
|
||||||
|
const [hasTimedout, setHasTimedout] = useState(false);
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { nobleAddress } = useAccounts();
|
const { nobleAddress } = useAccounts();
|
||||||
|
|
||||||
@ -30,23 +30,21 @@ export const NobleDeposit = () => {
|
|||||||
{
|
{
|
||||||
key: 'nobleAddress',
|
key: 'nobleAddress',
|
||||||
label: stringGetter({ key: STRING_KEYS.NOBLE_ADDRESS }),
|
label: stringGetter({ key: STRING_KEYS.NOBLE_ADDRESS }),
|
||||||
value: nobleAddress,
|
value:
|
||||||
|
hasAcknowledged && hasTimedout
|
||||||
|
? nobleAddress
|
||||||
|
: stringGetter({ key: STRING_KEYS.ACKNOWLEDGE_TO_REVEAL }),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Styled.QrCodeContainer>
|
<Styled.QrCode
|
||||||
<Styled.QrCode size={432} value={nobleAddress || ''} />
|
hasLogo
|
||||||
</Styled.QrCodeContainer>
|
size={432}
|
||||||
|
value={nobleAddress || ''}
|
||||||
|
blurred={!hasAcknowledged || !hasTimedout}
|
||||||
|
/>
|
||||||
</WithDetailsReceipt>
|
</WithDetailsReceipt>
|
||||||
|
|
||||||
<Styled.WaitingSpan>
|
|
||||||
<Styled.CautionIconContainer>
|
|
||||||
<Icon iconName={IconName.CautionCircleStroked} />
|
|
||||||
</Styled.CautionIconContainer>
|
|
||||||
|
|
||||||
<p>{stringGetter({ key: STRING_KEYS.NOBLE_WARNING })}</p>
|
|
||||||
</Styled.WaitingSpan>
|
|
||||||
|
|
||||||
<Styled.WithReceipt
|
<Styled.WithReceipt
|
||||||
slotReceipt={
|
slotReceipt={
|
||||||
<Styled.CheckboxContainer>
|
<Styled.CheckboxContainer>
|
||||||
@ -63,7 +61,12 @@ export const NobleDeposit = () => {
|
|||||||
>
|
>
|
||||||
<TimeoutButton
|
<TimeoutButton
|
||||||
timeoutInSeconds={8}
|
timeoutInSeconds={8}
|
||||||
slotFinal={<CopyButton state={{ isDisabled: !hasAcknowledged }} value={nobleAddress} />}
|
onTimeOut={() => setHasTimedout(true)}
|
||||||
|
slotFinal={
|
||||||
|
<CopyButton state={{ isDisabled: !hasAcknowledged }} value={nobleAddress}>
|
||||||
|
{!hasAcknowledged ? stringGetter({ key: STRING_KEYS.ACKNOWLEDGE_RISKS }) : undefined}
|
||||||
|
</CopyButton>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Styled.WithReceipt>
|
</Styled.WithReceipt>
|
||||||
</>
|
</>
|
||||||
@ -82,23 +85,14 @@ Styled.WithReceipt = styled(WithReceipt)`
|
|||||||
--withReceipt-backgroundColor: var(--color-layer-2);
|
--withReceipt-backgroundColor: var(--color-layer-2);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.QrCodeContainer = styled.div`
|
Styled.QrCode = styled(QrCode)<{ blurred: boolean }>`
|
||||||
display: flex;
|
border-radius: 0.5em;
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
padding: 0.5rem;
|
${({ blurred }) =>
|
||||||
|
blurred &&
|
||||||
background-color: var(--color-layer-2);
|
css`
|
||||||
border-radius: 0.5rem;
|
filter: blur(8px);
|
||||||
`;
|
`}
|
||||||
|
|
||||||
Styled.QrCode = styled(QrCode)`
|
|
||||||
max-height: 20rem;
|
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
max-height: 20rem;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.CheckboxContainer = styled.div`
|
Styled.CheckboxContainer = styled.div`
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export const TransferStatusNotification = ({
|
|||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
const [secondsLeft, setSecondsLeft] = useState<number>(0);
|
const [secondsLeft, setSecondsLeft] = useState<number>(0);
|
||||||
const { fromChainId, status, txHash, toAmount } = transfer;
|
const { fromChainId, status, txHash, toAmount, isExchange } = transfer;
|
||||||
|
|
||||||
// @ts-ignore status.errors is not in the type definition but can be returned
|
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||||
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
||||||
@ -54,6 +54,8 @@ export const TransferStatusNotification = ({
|
|||||||
|
|
||||||
useInterval({ callback: updateSecondsLeft });
|
useInterval({ callback: updateSecondsLeft });
|
||||||
|
|
||||||
|
const isComplete = status?.squidTransactionStatus === 'success' || isExchange;
|
||||||
|
|
||||||
const inProgressStatusString =
|
const inProgressStatusString =
|
||||||
type === TransferNotificationTypes.Deposit
|
type === TransferNotificationTypes.Deposit
|
||||||
? secondsLeft > 0
|
? secondsLeft > 0
|
||||||
@ -65,10 +67,10 @@ export const TransferStatusNotification = ({
|
|||||||
|
|
||||||
const statusString =
|
const statusString =
|
||||||
type === TransferNotificationTypes.Deposit
|
type === TransferNotificationTypes.Deposit
|
||||||
? status?.squidTransactionStatus === 'success'
|
? isComplete
|
||||||
? STRING_KEYS.DEPOSIT_COMPLETE
|
? STRING_KEYS.DEPOSIT_COMPLETE
|
||||||
: inProgressStatusString
|
: inProgressStatusString
|
||||||
: status?.squidTransactionStatus === 'success'
|
: isComplete
|
||||||
? STRING_KEYS.WITHDRAW_COMPLETE
|
? STRING_KEYS.WITHDRAW_COMPLETE
|
||||||
: inProgressStatusString;
|
: inProgressStatusString;
|
||||||
|
|
||||||
@ -108,12 +110,12 @@ export const TransferStatusNotification = ({
|
|||||||
slotIcon={isToast && slotIcon}
|
slotIcon={isToast && slotIcon}
|
||||||
slotTitle={slotTitle}
|
slotTitle={slotTitle}
|
||||||
slotCustomContent={
|
slotCustomContent={
|
||||||
!status ? (
|
!status && !isExchange ? (
|
||||||
<LoadingDots size={3} />
|
<LoadingDots size={3} />
|
||||||
) : (
|
) : (
|
||||||
<Styled.BridgingStatus>
|
<Styled.BridgingStatus>
|
||||||
{content}
|
{content}
|
||||||
{!isToast && status?.squidTransactionStatus !== 'success' && !hasError && (
|
{!isToast && !isComplete && !hasError && (
|
||||||
<Styled.TransferStatusSteps status={status} type={type} />
|
<Styled.TransferStatusSteps status={status} type={type} />
|
||||||
)}
|
)}
|
||||||
</Styled.BridgingStatus>
|
</Styled.BridgingStatus>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user