address comments
This commit is contained in:
+1
-1
@@ -37,7 +37,7 @@
|
||||
"@cosmjs/proto-signing": "^0.31.0",
|
||||
"@cosmjs/stargate": "^0.31.0",
|
||||
"@cosmjs/tendermint-rpc": "^0.31.0",
|
||||
"@dydxprotocol/abacus": "^0.4.6",
|
||||
"@dydxprotocol/abacus": "^0.4.7",
|
||||
"@dydxprotocol/v4-client-js": "^0.32.0",
|
||||
"@dydxprotocol/v4-localization": "^0.0.25",
|
||||
"@ethersproject/providers": "^5.7.2",
|
||||
|
||||
Generated
+4
-4
@@ -27,8 +27,8 @@ dependencies:
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@dydxprotocol/abacus':
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6
|
||||
specifier: ^0.4.7
|
||||
version: 0.4.7
|
||||
'@dydxprotocol/v4-client-js':
|
||||
specifier: ^0.32.0
|
||||
version: 0.32.0
|
||||
@@ -1145,8 +1145,8 @@ packages:
|
||||
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
||||
dev: true
|
||||
|
||||
/@dydxprotocol/abacus@0.4.6:
|
||||
resolution: {integrity: sha512-nvF9B1JuWzsnrPtQ/mKo06XWuqFc9fy6TEFcFwlIGGbxKortod7fSDj9sEZGKGdRyIj5wvl7H/Rgh+dlywO+aQ==}
|
||||
/@dydxprotocol/abacus@0.4.7:
|
||||
resolution: {integrity: sha512-3c7Dx5H+KeXZYDpAOJs6fqxSNerKqNSD4tuMNn5F7RXAPWUOU8ADQHAFPnrP1PgTxPjfZBZQzLIziKpyXww4NQ==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/dydxjs@0.3.0:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const erc20 = [
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
@@ -219,4 +219,4 @@ export const erc20 = [
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
}
|
||||
] as const;
|
||||
]
|
||||
@@ -65,10 +65,14 @@ const useLocalNotificationsContext = () => {
|
||||
fromChainId,
|
||||
status: currentStatus,
|
||||
} of transferNotifications) {
|
||||
if (currentStatus && currentStatus?.squidTransactionStatus !== 'ongoing') continue;
|
||||
|
||||
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
|
||||
if (status) statuses[txHash] = status;
|
||||
try {
|
||||
if (currentStatus && currentStatus?.squidTransactionStatus !== 'ongoing') continue;
|
||||
|
||||
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
|
||||
if (status) statuses[txHash] = status;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return statuses;
|
||||
},
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
import { Squid } from '@0xsquid/sdk';
|
||||
|
||||
import { DydxV4Network, isDydxV4Network } from '@/constants/networks';
|
||||
import { CLIENT_NETWORK_CONFIGS, DydxV4Network, isDydxV4Network } from '@/constants/networks';
|
||||
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
|
||||
const SQUID_BASE_URL: Record<DydxV4Network, string | undefined> = {
|
||||
[DydxV4Network.V4Testnet2]: 'https://squid-api-git-feat-cosmos-maintestnet-0xsquid.vercel.app',
|
||||
[DydxV4Network.V4Staging]: undefined,
|
||||
[DydxV4Network.V4Local]: undefined,
|
||||
[DydxV4Network.V4Mainnet]: 'https://api.0xsquid.com',
|
||||
};
|
||||
export const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
||||
|
||||
const useSquidContext = () => {
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
@@ -27,7 +23,7 @@ const useSquidContext = () => {
|
||||
const squid = useMemo(
|
||||
() =>
|
||||
isDydxV4Network(selectedNetwork)
|
||||
? new Squid({ baseUrl: SQUID_BASE_URL[selectedNetwork as DydxV4Network] })
|
||||
? new Squid({ baseUrl: CLIENT_NETWORK_CONFIGS[selectedNetwork]?.endpoints['0xsquid'] })
|
||||
: undefined,
|
||||
[selectedNetwork]
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
useConnect as useConnectWagmi,
|
||||
useAccount as useAccountWagmi,
|
||||
useDisconnect as useDisconnectWagmi,
|
||||
usePublicClient as usePublicClientWagmi,
|
||||
useWalletClient as useWalletClientWagmi,
|
||||
} from 'wagmi';
|
||||
import {
|
||||
@@ -42,6 +43,7 @@ export const useWalletConnection = () => {
|
||||
defaultValue: undefined,
|
||||
});
|
||||
const { address: evmAddressWagmi, isConnected: isConnectedWagmi } = useAccountWagmi();
|
||||
const publicClientWagmi = usePublicClientWagmi();
|
||||
const { data: signerWagmi } = useWalletClientWagmi();
|
||||
const { disconnectAsync: disconnectWagmi } = useDisconnectWagmi();
|
||||
|
||||
@@ -214,7 +216,8 @@ export const useWalletConnection = () => {
|
||||
evmAddress,
|
||||
evmAddressWagmi,
|
||||
signerWagmi,
|
||||
|
||||
publicClientWagmi,
|
||||
|
||||
// Wallet connection (Cosmos)
|
||||
dydxAddress,
|
||||
dydxAddressGraz,
|
||||
|
||||
@@ -34,7 +34,7 @@ export const TransferStatusToast = ({
|
||||
const [secondsLeft, setSecondsLeft] = useState<number | undefined>();
|
||||
|
||||
const type = useMemo(
|
||||
() => (status?.toChain?.chainData.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
||||
() => (status?.toChain?.chainData?.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
||||
[status]
|
||||
);
|
||||
|
||||
|
||||
@@ -27,38 +27,17 @@ enum TransferStatusStep {
|
||||
export const TransferStatusSteps = ({ status }: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const type = useMemo(
|
||||
() => (status?.toChain?.chainData.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
||||
[status]
|
||||
);
|
||||
|
||||
const currentStep = useMemo(() => {
|
||||
const { currentStep, steps, type } = useMemo(() => {
|
||||
const routeStatus = status?.routeStatus;
|
||||
const fromChain = status?.fromChain?.chainData.chainId;
|
||||
const toChain = status?.toChain?.chainData.chainId;
|
||||
const fromChain = status?.fromChain?.chainData?.chainId;
|
||||
const toChain = status?.toChain?.chainData?.chainId;
|
||||
const type = toChain === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal';
|
||||
|
||||
if (!routeStatus?.length) return TransferStatusStep.FromChain;
|
||||
|
||||
const currentStatus = routeStatus[routeStatus?.length - 1];
|
||||
|
||||
if (currentStatus.chainId === toChain) {
|
||||
return currentStatus.status !== 'success'
|
||||
? TransferStatusStep.ToChain
|
||||
: TransferStatusStep.Complete;
|
||||
}
|
||||
|
||||
if (currentStatus.chainId === fromChain && currentStatus.status !== 'success') {
|
||||
return TransferStatusStep.FromChain;
|
||||
}
|
||||
|
||||
return TransferStatusStep.Bridge;
|
||||
}, [status]);
|
||||
|
||||
const steps = useMemo(
|
||||
() => [
|
||||
const steps = [
|
||||
{
|
||||
label: stringGetter({
|
||||
key: type === 'deposit' ? STRING_KEYS.INITIATED_DEPOSIT : STRING_KEYS.INITIATED_WITHDRAWAL,
|
||||
key:
|
||||
type === 'deposit' ? STRING_KEYS.INITIATED_DEPOSIT : STRING_KEYS.INITIATED_WITHDRAWAL,
|
||||
}),
|
||||
step: TransferStatusStep.FromChain,
|
||||
link: status?.fromChain?.transactionUrl,
|
||||
@@ -72,15 +51,35 @@ export const TransferStatusSteps = ({ status }: ElementProps) => {
|
||||
label: stringGetter({
|
||||
key: type === 'deposit' ? STRING_KEYS.DEPOSIT_TO_CHAIN : STRING_KEYS.WITHDRAW_TO_CHAIN,
|
||||
params: {
|
||||
CHAIN: status?.toChain?.chainData.chainName,
|
||||
}
|
||||
CHAIN: status?.toChain?.chainData?.chainName,
|
||||
},
|
||||
}),
|
||||
step: TransferStatusStep.ToChain,
|
||||
link: status?.toChain?.transactionUrl,
|
||||
},
|
||||
],
|
||||
[status]
|
||||
);
|
||||
];
|
||||
|
||||
const currentStatus = routeStatus[routeStatus?.length - 1];
|
||||
|
||||
let currentStep = TransferStatusStep.Bridge;
|
||||
|
||||
if (!routeStatus?.length) {
|
||||
currentStep = TransferStatusStep.FromChain;
|
||||
} else if (currentStatus.chainId === toChain) {
|
||||
currentStep =
|
||||
currentStatus.status !== 'success'
|
||||
? TransferStatusStep.ToChain
|
||||
: TransferStatusStep.Complete;
|
||||
} else if (currentStatus.chainId === fromChain && currentStatus.status !== 'success') {
|
||||
currentStep = TransferStatusStep.FromChain;
|
||||
}
|
||||
|
||||
return {
|
||||
currentStep,
|
||||
steps,
|
||||
type,
|
||||
};
|
||||
}, [status, stringGetter]);
|
||||
|
||||
if (!status) return <LoadingDots size={3} />;
|
||||
|
||||
@@ -108,9 +107,7 @@ export const TransferStatusSteps = ({ status }: ElementProps) => {
|
||||
</Styled.Label>
|
||||
</Link>
|
||||
) : (
|
||||
<Styled.Label highlighted={currentStep >= step.step}>
|
||||
{step.label}
|
||||
</Styled.Label>
|
||||
<Styled.Label highlighted={currentStep >= step.step}>{step.label}</Styled.Label>
|
||||
)}
|
||||
</Styled.row>
|
||||
</Styled.Step>
|
||||
|
||||
@@ -3,8 +3,8 @@ import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import { type NumberFormatValues } from 'react-number-format';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
import erc20 from '@/abi/erc20.json';
|
||||
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
@@ -14,6 +14,8 @@ import { NumberSign } from '@/constants/numbers';
|
||||
import { useAccounts, useDebounce, useStringGetter } from '@/hooks';
|
||||
import { useAccountBalance } from '@/hooks/useAccountBalance';
|
||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||
import { NATIVE_TOKEN_ADDRESS, useSquid } from '@/hooks/useSquid';
|
||||
import { useWalletConnection } from '@/hooks/useWalletConnection';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { formMixins } from '@/styles/formMixins';
|
||||
@@ -49,7 +51,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const { signerWagmi } = useAccounts();
|
||||
const { evmAddress, signerWagmi } = useAccounts();
|
||||
const { publicClientWagmi } = useWalletConnection();
|
||||
|
||||
const { addTransferNotification } = useLocalNotifications();
|
||||
|
||||
@@ -68,6 +71,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
[token, resources]
|
||||
);
|
||||
|
||||
const sourceChain = useMemo(
|
||||
() => (chainIdStr ? resources?.chainResources?.get(chainIdStr) : undefined),
|
||||
[chainId, resources]
|
||||
);
|
||||
|
||||
const [fromAmount, setFromAmount] = useState('');
|
||||
const [slippage, setSlippage] = useState(0.01); // 1% slippage
|
||||
const debouncedAmount = useDebounce<string>(fromAmount, 500);
|
||||
@@ -159,6 +167,36 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
}
|
||||
}, [balance, setFromAmount]);
|
||||
|
||||
const validateTokenApproval = useCallback(async () => {
|
||||
if (!signerWagmi || !publicClientWagmi) throw new Error('Missing signer');
|
||||
if (!sourceToken?.address) 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');
|
||||
if (sourceToken?.address === NATIVE_TOKEN_ADDRESS) return;
|
||||
|
||||
const allowance = await publicClientWagmi.readContract({
|
||||
address: sourceToken.address as `0x${string}`,
|
||||
abi: erc20,
|
||||
functionName: 'allowance',
|
||||
args: [evmAddress as `0x${string}`, requestPayload.targetAddress as `0x${string}`]
|
||||
});
|
||||
|
||||
const sourceAmountBN = BigInt(requestPayload.value)
|
||||
|
||||
if (sourceAmountBN > (allowance as bigint)) {
|
||||
const { request } = await publicClientWagmi.simulateContract({
|
||||
account: evmAddress,
|
||||
address: sourceToken.address as `0x${string}`,
|
||||
abi: erc20,
|
||||
functionName: 'approve',
|
||||
args: [requestPayload.targetAddress as `0x${string}`, sourceAmountBN],
|
||||
})
|
||||
|
||||
await signerWagmi.writeContract(request);
|
||||
}
|
||||
}, [signerWagmi, sourceToken, sourceChain, requestPayload, publicClientWagmi]);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
async (e: FormEvent) => {
|
||||
try {
|
||||
@@ -179,20 +217,23 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
validateTokenApproval();
|
||||
|
||||
let tx = {
|
||||
to: requestPayload.targetAddress as `0x${string}`,
|
||||
data: requestPayload.data as `0x${string}`,
|
||||
gasLimit: ethers.toBigInt(requestPayload.gasLimit),
|
||||
gasLimit: BigInt(requestPayload.gasLimit),
|
||||
value:
|
||||
requestPayload.routeType !== 'SEND' ? ethers.toBigInt(requestPayload.value) : undefined,
|
||||
requestPayload.routeType !== 'SEND' ? BigInt(requestPayload.value) : undefined,
|
||||
};
|
||||
const txHash = await signerWagmi.sendTransaction(tx);
|
||||
|
||||
onDeposit?.();
|
||||
|
||||
if (txHash) {
|
||||
addTransferNotification({
|
||||
txHash,
|
||||
txHash: txHash,
|
||||
toChainId: TESTNET_CHAIN_ID,
|
||||
fromChainId: chainIdStr || undefined,
|
||||
toAmount: summary?.usdcSize || undefined,
|
||||
@@ -202,6 +243,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
setFromAmount('');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setError(error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
|
||||
Reference in New Issue
Block a user