diff --git a/package.json b/package.json index d2fef95..f39fffc 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@cosmjs/proto-signing": "^0.31.0", "@cosmjs/stargate": "^0.31.0", "@cosmjs/tendermint-rpc": "^0.31.0", - "@dydxprotocol/v4-abacus": "^1.0.19", + "@dydxprotocol/v4-abacus": "^1.0.24", "@dydxprotocol/v4-client-js": "^1.0.0", "@dydxprotocol/v4-localization": "^1.0.5", "@ethersproject/providers": "^5.7.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index acb4342..470293e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ dependencies: specifier: ^0.31.0 version: 0.31.0 '@dydxprotocol/v4-abacus': - specifier: ^1.0.19 - version: 1.0.19 + specifier: ^1.0.24 + version: 1.0.24 '@dydxprotocol/v4-client-js': specifier: ^1.0.0 version: 1.0.0 @@ -982,8 +982,8 @@ packages: resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==} dev: true - /@dydxprotocol/v4-abacus@1.0.19: - resolution: {integrity: sha512-XhvSHGr503gNwHWEiOYP7M2uYeLu+Qm4szpE5w5H6hWFCanSGz6zAsTbPuyPLtt7IE1gj5z8mlL9J3tw2AZROg==} + /@dydxprotocol/v4-abacus@1.0.24: + resolution: {integrity: sha512-wDGSjkrc3Se6Ev7UTjPgJV7PiyzZSz2mJwOTZikLwH7W3k1iPYGQmaCd7TudFk8h2aSdlEwNsQBCf0sLoyvHaQ==} dev: false /@dydxprotocol/v4-client-js@1.0.0: diff --git a/src/lib/abacus/rest.ts b/src/lib/abacus/rest.ts index 52e5ca4..12245f5 100644 --- a/src/lib/abacus/rest.ts +++ b/src/lib/abacus/rest.ts @@ -56,13 +56,8 @@ class AbacusRest implements AbacusRestProtocol { .then(async (response) => { const data = await response.text(); - if (response.ok) { - callback(data, response.status); - } else { - // response not OK, call callback with null data and the status, this includes 400/500 status codes - callback(null, response.status); - } - + callback(data, response.status); + try { lastSuccessfulRestRequestByOrigin[new URL(url).origin] = Date.now(); } catch {} diff --git a/src/views/forms/AccountManagementForms/DepositForm.tsx b/src/views/forms/AccountManagementForms/DepositForm.tsx index d7ce376..6797fcf 100644 --- a/src/views/forms/AccountManagementForms/DepositForm.tsx +++ b/src/views/forms/AccountManagementForms/DepositForm.tsx @@ -2,7 +2,7 @@ import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react import styled, { type AnyStyledComponent } from 'styled-components'; import { type NumberFormatValues } from 'react-number-format'; import { shallowEqual, useSelector } from 'react-redux'; -import { parseUnits } from 'viem' +import { parseUnits } from 'viem'; import erc20 from '@/abi/erc20.json'; import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus'; @@ -65,6 +65,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { chain: chainIdStr, resources, summary, + errors: routeErrors, + errorMessage: routeErrorMessage, } = useSelector(getTransferInputs, shallowEqual) || {}; const chainId = chainIdStr ? parseInt(chainIdStr) : undefined; @@ -97,7 +99,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { useEffect(() => { const hasInvalidInput = - debouncedAmountBN.isNaN() || debouncedAmountBN.lte(0) || debouncedAmountBN.gte(balanceBN); + debouncedAmountBN.isNaN() || debouncedAmountBN.lte(0) || debouncedAmountBN.gt(balanceBN); abacusStateManager.setTransferValue({ value: hasInvalidInput ? 0 : debouncedAmount, @@ -171,7 +173,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { const validateTokenApproval = useCallback(async () => { if (!signerWagmi || !publicClientWagmi) throw new Error('Missing signer'); - if (!sourceToken?.address || !sourceToken.decimals) throw new Error('Missing source token address'); + if (!sourceToken?.address || !sourceToken.decimals) + throw new Error('Missing source token address'); if (!sourceChain?.rpc) throw new Error('Missing source chain rpc'); if (!requestPayload?.targetAddress) throw new Error('Missing target address'); if (!requestPayload?.value) throw new Error('Missing transaction value'); @@ -181,11 +184,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { address: sourceToken.address as EvmAddress, abi: erc20, functionName: 'allowance', - args: [evmAddress as EvmAddress, requestPayload.targetAddress as EvmAddress] + args: [evmAddress as EvmAddress, requestPayload.targetAddress as EvmAddress], }); const sourceAmountBN = parseUnits(debouncedAmount, sourceToken.decimals); - + if (sourceAmountBN > (allowance as bigint)) { const { request } = await publicClientWagmi.simulateContract({ account: evmAddress, @@ -193,12 +196,12 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { abi: erc20, functionName: 'approve', args: [requestPayload.targetAddress as EvmAddress, sourceAmountBN], - }) + }); const approveTx = await signerWagmi.writeContract(request); await publicClientWagmi.waitForTransactionReceipt({ hash: approveTx, - }) + }); } }, [signerWagmi, sourceToken, sourceChain, requestPayload, publicClientWagmi]); @@ -228,8 +231,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { to: requestPayload.targetAddress as EvmAddress, data: requestPayload.data as EvmAddress, gasLimit: BigInt(requestPayload.gasLimit), - value: - requestPayload.routeType !== 'SEND' ? BigInt(requestPayload.value) : undefined, + value: requestPayload.routeType !== 'SEND' ? BigInt(requestPayload.value) : undefined, }; const txHash = await signerWagmi.sendTransaction(tx); @@ -287,6 +289,15 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { return parseWalletError({ error, stringGetter }).message; } + if (routeErrors) { + return routeErrorMessage + ? stringGetter({ + key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE, + params: { ERROR_MESSAGE: routeErrorMessage }, + }) + : stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG }); + } + if (fromAmount) { if (!chainId) { return stringGetter({ key: STRING_KEYS.MUST_SPECIFY_CHAIN }); @@ -300,7 +311,16 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { } return undefined; - }, [error, balance, chainId, fromAmount, sourceToken]); + }, [ + error, + routeErrors, + routeErrorMessage, + balance, + chainId, + fromAmount, + sourceToken, + stringGetter, + ]); const isDisabled = Boolean(errorMessage) || diff --git a/src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx b/src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx index 39baf6e..3be22f4 100644 --- a/src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx +++ b/src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx @@ -164,6 +164,7 @@ export const DepositButtonAndReceipt = ({ label: {stringGetter({ key: STRING_KEYS.SLIPPAGE })}, value: ( >; setSlippage: (slippage: number) => void; + disabled?: boolean; }; export type SlippageEditorProps = ElementProps; -export const SlippageEditor = ({ slippage, setIsEditing, setSlippage }: SlippageEditorProps) => { +export const SlippageEditor = ({ + disabled, + slippage, + setIsEditing, + setSlippage, +}: SlippageEditorProps) => { const percentSlippage = slippage * 100; const [slippageInputValue, setSlippageInputValue] = useState(percentSlippage.toString()); const [editorState, setEditorState] = useState(EditorState.Viewing); @@ -80,6 +86,10 @@ export const SlippageEditor = ({ slippage, setIsEditing, setSlippage }: Slippage } }; + if (disabled) { + return ; + } + return ( { const stringGetter = useStringGetter(); @@ -69,6 +69,8 @@ export const WithdrawForm = () => { chain: chainIdStr, address: toAddress, resources, + errors: routeErrors, + errorMessage: routeErrorMessage, } = useSelector(getTransferInputs, shallowEqual) || {}; const isValidAddress = toAddress && isAddress(toAddress); @@ -281,6 +283,15 @@ export const WithdrawForm = () => { }); } + if (routeErrors) { + return routeErrorMessage + ? stringGetter({ + key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE, + params: { ERROR_MESSAGE: routeErrorMessage }, + }) + : stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG }); + } + if (!toAddress) return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ADDRESS }); if (sanctionedAddresses.has(toAddress)) @@ -303,12 +314,15 @@ export const WithdrawForm = () => { return undefined; }, [ error, + routeErrors, + routeErrorMessage, freeCollateralBN, chainIdStr, debouncedAmountBN, toToken, toAddress, sanctionedAddresses, + stringGetter, ]); const isDisabled = diff --git a/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx b/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx index ab92414..20057ae 100644 --- a/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx +++ b/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx @@ -147,6 +147,7 @@ export const WithdrawButtonAndReceipt = ({ label: {stringGetter({ key: STRING_KEYS.SLIPPAGE })}, value: (