add depositTo and withdrawTo functionality for smart contract wallets (#9)

* add depositTo and withdrawTo functionality for smart contract wallets

* tx list updates

* compliance check

* fix prettier

* fix prettier & address nits
This commit is contained in:
Lukas
2023-09-25 16:44:30 -04:00
committed by GitHub
parent 54be786ac7
commit 71b9ec3924
15 changed files with 311 additions and 74 deletions

View File

@@ -0,0 +1 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="white" xmlns="http://www.w3.org/2000/svg"><path d="M0.877075 7.49972C0.877075 3.84204 3.84222 0.876892 7.49991 0.876892C11.1576 0.876892 14.1227 3.84204 14.1227 7.49972C14.1227 11.1574 11.1576 14.1226 7.49991 14.1226C3.84222 14.1226 0.877075 11.1574 0.877075 7.49972ZM7.49991 1.82689C4.36689 1.82689 1.82708 4.36671 1.82708 7.49972C1.82708 10.6327 4.36689 13.1726 7.49991 13.1726C10.6329 13.1726 13.1727 10.6327 13.1727 7.49972C13.1727 4.36671 10.6329 1.82689 7.49991 1.82689ZM8.24993 10.5C8.24993 10.9142 7.91414 11.25 7.49993 11.25C7.08571 11.25 6.74993 10.9142 6.74993 10.5C6.74993 10.0858 7.08571 9.75 7.49993 9.75C7.91414 9.75 8.24993 10.0858 8.24993 10.5ZM6.05003 6.25C6.05003 5.57211 6.63511 4.925 7.50003 4.925C8.36496 4.925 8.95003 5.57211 8.95003 6.25C8.95003 6.74118 8.68002 6.99212 8.21447 7.27494C8.16251 7.30651 8.10258 7.34131 8.03847 7.37854L8.03841 7.37858C7.85521 7.48497 7.63788 7.61119 7.47449 7.73849C7.23214 7.92732 6.95003 8.23198 6.95003 8.7C6.95004 9.00376 7.19628 9.25 7.50004 9.25C7.8024 9.25 8.04778 9.00601 8.05002 8.70417L8.05056 8.7033C8.05924 8.6896 8.08493 8.65735 8.15058 8.6062C8.25207 8.52712 8.36508 8.46163 8.51567 8.37436L8.51571 8.37433C8.59422 8.32883 8.68296 8.27741 8.78559 8.21506C9.32004 7.89038 10.05 7.35382 10.05 6.25C10.05 4.92789 8.93511 3.825 7.50003 3.825C6.06496 3.825 4.95003 4.92789 4.95003 6.25C4.95003 6.55376 5.19628 6.8 5.50003 6.8C5.80379 6.8 6.05003 6.55376 6.05003 6.25Z" fill-rule="evenodd" clip-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,35 @@
import { Dispatch, SetStateAction } from 'react';
import Image from 'next/image';
type BridgeToInputProps = {
bridgeTo: string;
setBridgeTo: Dispatch<SetStateAction<string>>;
action: 'deposit' | 'withdraw';
};
export function BridgeToInput({ bridgeTo, setBridgeTo, action }: BridgeToInputProps) {
function handleChangeBridgeTo(e: { target: { value: SetStateAction<string> } }) {
setBridgeTo(e.target.value);
}
return (
<div className="flex flex-col p-6">
<div className="flex flex-row items-center space-x-2 mb-1">
<span className="font-sans text-sm font-medium text-white">{action === 'deposit' ? 'Deposit to' : 'Withdraw to'}</span>
<div className="has-tooltip">
<span className="tooltip -mt-10 ml-6 rounded-lg bg-cds-background-gray-90 p-2 text-black shadow-lg">
Only send funds on networks supported by your wallet provider if it is a smart contract
wallet or there may be permanent loss of funds.
</span>
<Image alt="tooltip" src="/icons/question-mark-circled.svg" width={16} height={16} />
</div>
</div>
<input
className="bg-transparent font-sans text-md text-white outline-none max-[640px]:grow sm:text-xl border border-cds-background-gray-60 p-4 rounded min-[640px]:w-96"
placeholder="Wallet address"
value={bridgeTo}
onChange={handleChangeBridgeTo}
/>
</div>
);
}

View File

@@ -1,6 +1,7 @@
import { useCallback, useMemo, useState } from 'react';
import { BridgeButton } from 'apps/bridge/src/components/BridgeButton/BridgeButton';
import { BridgeInput } from 'apps/bridge/src/components/BridgeInput/BridgeInput';
import { BridgeToInput } from 'apps/bridge/src/components/BridgeToInput/BridgeToInput';
import { ConnectWalletButton } from 'apps/bridge/src/components/ConnectWalletButton/ConnectWalletButton';
import { DepositModal } from 'apps/bridge/src/components/DepositModal/DepositModal';
import { FaqSidebar } from 'apps/bridge/src/components/Faq/FaqSidebar';
@@ -11,14 +12,18 @@ import { getAssetListForChainEnv } from 'apps/bridge/src/utils/assets/getAssetLi
import { useApproveContract } from 'apps/bridge/src/utils/hooks/useApproveContract';
import { useChainEnv } from 'apps/bridge/src/utils/hooks/useChainEnv';
import { useDisclosure } from 'apps/bridge/src/utils/hooks/useDisclosure';
import { useGetCode } from 'apps/bridge/src/utils/hooks/useGetCode';
import { useIsContractApproved } from 'apps/bridge/src/utils/hooks/useIsContractApproved';
import { useIsPermittedToBridge } from 'apps/bridge/src/utils/hooks/useIsPermittedToBridge';
import { useIsWalletConnected } from 'apps/bridge/src/utils/hooks/useIsWalletConnected';
import { usePrepareERC20Deposit } from 'apps/bridge/src/utils/hooks/usePrepareERC20Deposit';
import { usePrepareERC20DepositTo } from 'apps/bridge/src/utils/hooks/usePrepareERC20DepositTo';
import { usePrepareETHDeposit } from 'apps/bridge/src/utils/hooks/usePrepareETHDeposit';
import { utils } from 'ethers';
import { parseUnits } from 'ethers/lib/utils.js';
import getConfig from 'next/config';
import { useAccount, useBalance, useContractWrite } from 'wagmi';
import { useIsPermittedToBridgeTo } from 'apps/bridge/src/utils/hooks/useIsPermittedToBridgeTo';
const assetList = getAssetListForChainEnv();
@@ -29,6 +34,7 @@ export function DepositContainer() {
const [depositAmount, setDepositAmount] = useState('0');
const [L1ApproveTxHash, setL1ApproveTxHash] = useState<`0x${string}` | undefined>(undefined);
const [L1DepositTxHash, setL1DepositTxHash] = useState<`0x${string}` | undefined>(undefined);
const [depositTo, setDepositTo] = useState('');
const [isApprovalTx, setIsApprovalTx] = useState(false);
const isWalletConnected = useIsWalletConnected();
const [selectedAsset, setSelectedAsset] = useState<Asset>(assetList[0]);
@@ -36,6 +42,8 @@ export function DepositContainer() {
publicRuntimeConfig.assets.split(',').includes(asset.L1symbol.toLowerCase()),
);
const { address } = useAccount();
const codeAtAddress = useGetCode(address);
const isSmartContractWallet = !!codeAtAddress && codeAtAddress !== '0x';
const { data: L1Balance } = useBalance({
address,
@@ -79,11 +87,15 @@ export function DepositContainer() {
const chainEnv = useChainEnv();
const isMainnet = chainEnv === 'mainnet';
const includeTosVersionByte = isMainnet;
const isPermittedToBridge = useIsPermittedToBridge();
const isUserPermittedToBridge = useIsPermittedToBridge();
const isPermittedToBridgeTo = useIsPermittedToBridgeTo(depositTo as `0x${string}`);
const isPermittedToBridge = isSmartContractWallet
? isUserPermittedToBridge && isPermittedToBridgeTo
: isUserPermittedToBridge;
// deposit eth
const depositETHConfig = usePrepareETHDeposit({
userAddress: address,
userAddress: isSmartContractWallet ? (depositTo as `0x${string}`) : address,
depositAmount,
isPermittedToBridge,
includeTosVersionByte,
@@ -99,8 +111,17 @@ export function DepositContainer() {
isPermittedToBridge,
includeTosVersionByte,
});
const depositERC20ToConfig = usePrepareERC20DepositTo({
asset: selectedAsset,
to: depositTo as `0x${string}`,
depositAmount,
readApprovalResult,
isPermittedToBridge,
includeTosVersionByte,
});
const { writeAsync: depositERC20Write } = useContractWrite(depositERC20Config);
const { writeAsync: depositERC20ToWrite } = useContractWrite(depositERC20ToConfig);
const initiateApproval = useCallback(() => {
void (async () => {
@@ -118,7 +139,9 @@ export function DepositContainer() {
// next, call the transfer function
setIsApprovalTx(false);
const depositResult = await depositERC20Write?.();
const depositResult = await (isSmartContractWallet
? depositERC20ToWrite?.()
: depositERC20Write?.());
if (depositResult?.hash) {
const depositTxHash = depositResult.hash;
setL1DepositTxHash(depositTxHash);
@@ -128,7 +151,14 @@ export function DepositContainer() {
onCloseDepositModal();
}
})();
}, [approveWrite, depositERC20Write, onCloseDepositModal, onOpenDepositModal, setIsApprovalTx]);
}, [
approveWrite,
depositERC20ToWrite,
depositERC20Write,
isSmartContractWallet,
onCloseDepositModal,
onOpenDepositModal,
]);
const initiateDeposit = useCallback(() => {
void (async () => {
@@ -136,9 +166,13 @@ export function DepositContainer() {
try {
// Only bridge on mainnet if user has accepted ToS. Always allow bridging on testnet.
if (isPermittedToBridge) {
const depositResult = await (selectedAsset.L1contract
? depositERC20Write?.()
: depositETHWrite?.());
let depositMethod;
if (selectedAsset.L1contract) {
depositMethod = isSmartContractWallet ? depositERC20ToWrite : depositERC20Write;
} else {
depositMethod = depositETHWrite;
}
const depositResult = await depositMethod?.();
if (depositResult?.hash) {
const depositTxHash = depositResult.hash;
setL1DepositTxHash(depositTxHash);
@@ -155,25 +189,31 @@ export function DepositContainer() {
onOpenDepositModal,
isPermittedToBridge,
selectedAsset.L1contract,
isSmartContractWallet,
depositERC20ToWrite,
depositERC20Write,
depositETHWrite,
onCloseDepositModal,
]);
let button;
let depositDisabled;
if (!isWalletConnected) {
button = (
<ConnectWalletButton className="text-md flex w-full items-center justify-center rounded-md p-4 font-sans font-bold uppercase sm:w-auto" />
);
} else if (readApprovalResult || selectedAsset.L1symbol === 'ETH') {
depositDisabled =
parseFloat(depositAmount) <= 0 ||
parseFloat(depositAmount) >= parseFloat(L1Balance?.formatted ?? '0') ||
depositAmount === '' ||
(isSmartContractWallet && !utils.isAddress(depositTo ?? '')) ||
!isPermittedToBridge;
button = (
<BaseButton
onClick={initiateDeposit}
disabled={
parseFloat(depositAmount) <= 0 ||
parseFloat(depositAmount) >= parseFloat(L1Balance?.formatted ?? '0') ||
depositAmount === ''
}
disabled={depositDisabled}
toChainId={chainId}
className="text-md flex w-full items-center justify-center rounded-md p-4 font-sans font-bold uppercase sm:w-auto"
>
@@ -181,10 +221,13 @@ export function DepositContainer() {
</BaseButton>
);
} else {
depositDisabled =
(isSmartContractWallet && !utils.isAddress(depositTo ?? '')) || !isPermittedToBridge;
button = (
<BridgeButton
onClick={initiateApproval}
disabled={false}
disabled={depositDisabled}
className="text-md flex w-full items-center justify-center rounded-md p-4 font-sans font-bold uppercase sm:w-auto"
>
Approval
@@ -216,6 +259,10 @@ export function DepositContainer() {
{button}
</BridgeInput>
{isSmartContractWallet && (
<BridgeToInput bridgeTo={depositTo} setBridgeTo={setDepositTo} action="deposit" />
)}
<div className="border-t border-sidebar-border">
<TransactionSummary
header="TRANSACTION SUMMARY"
@@ -225,7 +272,7 @@ export function DepositContainer() {
chainId={publicRuntimeConfig.l1ChainID}
isDeposit
/>
<div className="w-full py-12 px-6 sm:hidden">{button}</div>
<div className="w-full px-6 py-12 sm:hidden">{button}</div>
</div>
</div>
<FaqSidebar />

View File

@@ -1,5 +1,6 @@
import { useCallback, useState } from 'react';
import { BridgeInput } from 'apps/bridge/src/components/BridgeInput/BridgeInput';
import { BridgeToInput } from 'apps/bridge/src/components/BridgeToInput/BridgeToInput';
import { ConnectWalletButton } from 'apps/bridge/src/components/ConnectWalletButton/ConnectWalletButton';
import { FaqSidebar } from 'apps/bridge/src/components/Faq/FaqSidebar';
import { BaseButton } from 'apps/bridge/src/components/SwitchNetworkButton/SwitchNetworkButton';
@@ -9,12 +10,16 @@ import { Asset } from 'apps/bridge/src/types/Asset';
import { getAssetListForChainEnv } from 'apps/bridge/src/utils/assets/getAssetListForChainEnv';
import { useChainEnv } from 'apps/bridge/src/utils/hooks/useChainEnv';
import { useDisclosure } from 'apps/bridge/src/utils/hooks/useDisclosure';
import { useGetCode } from 'apps/bridge/src/utils/hooks/useGetCode';
import { useIsPermittedToBridge } from 'apps/bridge/src/utils/hooks/useIsPermittedToBridge';
import { useIsWalletConnected } from 'apps/bridge/src/utils/hooks/useIsWalletConnected';
import { usePrepareERC20Withdrawal } from 'apps/bridge/src/utils/hooks/usePrepareERC20Withdrawal';
import { usePrepareERC20WithdrawalTo } from 'apps/bridge/src/utils/hooks/usePrepareERC20WithdrawalTo';
import { usePrepareETHWithdrawal } from 'apps/bridge/src/utils/hooks/usePrepareETHWithdrawal';
import { utils } from 'ethers';
import getConfig from 'next/config';
import { useAccount, useBalance, useContractWrite } from 'wagmi';
import { useIsPermittedToBridgeTo } from 'apps/bridge/src/utils/hooks/useIsPermittedToBridgeTo';
const assetList = getAssetListForChainEnv();
@@ -24,6 +29,7 @@ const chainId = parseInt(publicRuntimeConfig.l2ChainID);
export function WithdrawContainer() {
const [withdrawAmount, setWithdrawAmount] = useState('');
const [L2TxHash, setL2TxHash] = useState('');
const [withdrawTo, setWithdrawTo] = useState('');
const isWalletConnected = useIsWalletConnected();
const activeAssets = assetList.filter((asset) =>
publicRuntimeConfig.assets.split(',').includes(asset.L1symbol.toLowerCase()),
@@ -31,6 +37,9 @@ export function WithdrawContainer() {
const [selectedAsset, setSelectedAsset] = useState<Asset>(assetList[0]);
const { address } = useAccount();
const codeAtAddress = useGetCode(address);
const isSmartContractWallet = !!codeAtAddress && codeAtAddress !== '0x';
const { data: L2Balance } = useBalance({
address,
token: selectedAsset.L2contract,
@@ -40,7 +49,11 @@ export function WithdrawContainer() {
const chainEnv = useChainEnv();
const isMainnet = chainEnv === 'mainnet';
const includeTosVersionByte = isMainnet;
const isPermittedToBridge = useIsPermittedToBridge();
const isUserPermittedToBridge = useIsPermittedToBridge();
const isPermittedToBridgeTo = useIsPermittedToBridgeTo(withdrawTo as `0x${string}`);
const isPermittedToBridge = isSmartContractWallet
? isUserPermittedToBridge && isPermittedToBridgeTo
: isUserPermittedToBridge;
const erc20WithdrawalConfig = usePrepareERC20Withdrawal({
asset: selectedAsset,
@@ -48,10 +61,19 @@ export function WithdrawContainer() {
isPermittedToBridge,
includeTosVersionByte,
});
const erc20WithdrawalToConfig = usePrepareERC20WithdrawalTo({
asset: selectedAsset,
to: withdrawTo as `0x${string}`,
withdrawAmount,
isPermittedToBridge,
includeTosVersionByte,
});
const { writeAsync: withdrawERC20 } = useContractWrite(erc20WithdrawalConfig);
const { writeAsync: withdrawERC20To } = useContractWrite(erc20WithdrawalToConfig);
const withdrawConfig = usePrepareETHWithdrawal({
userAddress: address,
userAddress: isSmartContractWallet ? (withdrawTo as `0x${string}`) : address,
withdrawAmount,
isPermittedToBridge,
includeTosVersionByte,
@@ -75,9 +97,13 @@ export function WithdrawContainer() {
try {
// Only bridge on mainnet if user has accepted ToS. Always allow bridging on testnet.
if (isPermittedToBridge) {
const withdrawalResult = await (selectedAsset.L1contract
? withdrawERC20?.()
: withdraw?.());
let withdrawMethod;
if (selectedAsset.L1contract) {
withdrawMethod = isSmartContractWallet ? withdrawERC20To : withdrawERC20;
} else {
withdrawMethod = withdraw;
}
const withdrawalResult = await withdrawMethod?.();
if (withdrawalResult?.hash) {
const withdrawalTxHsh = withdrawalResult.hash;
setL2TxHash(withdrawalTxHsh);
@@ -94,25 +120,32 @@ export function WithdrawContainer() {
onOpenWithdrawModal,
isPermittedToBridge,
selectedAsset.L1contract,
isSmartContractWallet,
withdrawERC20To,
withdrawERC20,
withdraw,
onCloseWithdrawModal,
]);
let button;
let withdrawDisabled;
if (!isWalletConnected) {
button = (
<ConnectWalletButton className="text-md flex w-full items-center justify-center rounded-md p-4 font-sans font-bold uppercase sm:w-auto" />
);
} else {
withdrawDisabled =
parseFloat(withdrawAmount) <= 0 ||
parseFloat(withdrawAmount) >= parseFloat(L2Balance?.formatted ?? '0') ||
withdrawAmount === '' ||
(isSmartContractWallet && !utils.isAddress(withdrawTo ?? '')) ||
!isPermittedToBridge;
button = (
<BaseButton
onClick={initiateWithdrawal}
disabled={
parseFloat(withdrawAmount) <= 0 ||
parseFloat(withdrawAmount) >= parseFloat(L2Balance?.formatted ?? '0') ||
withdrawAmount === ''
}
disabled={withdrawDisabled}
toChainId={chainId}
className="text-md flex w-full items-center justify-center rounded-md p-4 font-sans font-bold uppercase sm:w-auto"
>
@@ -142,6 +175,11 @@ export function WithdrawContainer() {
>
{button}
</BridgeInput>
{isSmartContractWallet && (
<BridgeToInput bridgeTo={withdrawTo} setBridgeTo={setWithdrawTo} action="withdraw" />
)}
<div className="border-t border-sidebar-border">
<TransactionSummary
selectedAsset={selectedAsset}
@@ -151,7 +189,7 @@ export function WithdrawContainer() {
chainId={publicRuntimeConfig.l2ChainID}
isDeposit={false}
/>
<div className="w-full py-12 px-6 sm:hidden">{button}</div>
<div className="w-full px-6 py-12 sm:hidden">{button}</div>
</div>
</div>
<FaqSidebar />

View File

@@ -19,7 +19,7 @@ export const OFACContext = createContext<OFACContextType>({
isOFACAllowedLoading: false,
});
async function fetchIsAllowed(address?: `0x${string}`): Promise<{ result: boolean }> {
export async function fetchIsAllowed(address?: `0x${string}`): Promise<{ result: boolean }> {
if (!address) {
return { result: false };
}

View File

@@ -4,29 +4,19 @@ export function mergeAndSortTransactionsLists(
txList1: BridgeTransaction[],
txList2: BridgeTransaction[],
) {
const merged = [];
let index1 = 0;
let index2 = 0;
let current = 0;
while (current < txList1.length + txList2.length) {
const isTxList1Depleted = index1 >= txList1.length;
const isTxList2Depleted = index2 >= txList2.length;
if (
!isTxList1Depleted &&
(isTxList2Depleted ||
parseInt(txList1[index1].blockTimestamp) < parseInt(txList2[index2].blockTimestamp))
) {
merged[current] = txList1[index1];
index1 += 1;
} else {
merged[current] = txList2[index2];
index2 += 1;
return [...txList1, ...txList2].sort((a, b) => {
if (a.blockTimestamp && b.blockTimestamp) {
return parseInt(b.blockTimestamp) - parseInt(a.blockTimestamp);
}
current += 1;
}
if (a.blockTimestamp) {
return -1;
}
return merged.reverse();
if (b.blockTimestamp) {
return 1;
}
return 0;
});
}

View File

@@ -0,0 +1,19 @@
import { useEffect, useState } from 'react';
import { providers } from 'ethers';
import { useProvider } from 'wagmi';
export function useGetCode(address?: `0x${string}`) {
const provider = useProvider<providers.JsonRpcProvider>();
const [code, setCode] = useState<string | undefined>(undefined);
useEffect(() => {
if (address) {
void (async () => {
const codeAtAddress = await provider.getCode(address);
setCode(codeAtAddress);
})();
}
}, [address, provider]);
return code;
}

View File

@@ -0,0 +1,14 @@
import { fetchIsAllowed } from 'apps/bridge/src/contexts/OFACContext';
import { useQuery } from 'react-query';
export function useIsPermittedToBridgeTo(address?: `0x${string}`) {
const { data: isBridgeToAllowed, isLoading: isBridgeToAllowedLoading } = useQuery(
['isBridgeToAllowed', address],
async () => fetchIsAllowed(address),
{
select: (r) => r.result,
},
);
return !!isBridgeToAllowed && !isBridgeToAllowedLoading;
}

View File

@@ -0,0 +1,49 @@
import L1StandartBridge from 'apps/bridge/src/contract-abis/L1StandardBridge';
import { Asset } from 'apps/bridge/src/types/Asset';
import { BigNumber } from 'ethers';
import { parseUnits } from 'ethers/lib/utils.js';
import getConfig from 'next/config';
import { Address, usePrepareContractWrite } from 'wagmi';
const { publicRuntimeConfig } = getConfig();
type UsePrepareERC20DepositToProps = {
asset: Asset;
to: `0x${string}`;
depositAmount: string;
readApprovalResult?: boolean;
isPermittedToBridge: boolean;
includeTosVersionByte: boolean;
};
export function usePrepareERC20DepositTo({
asset,
to,
depositAmount,
isPermittedToBridge,
includeTosVersionByte,
}: UsePrepareERC20DepositToProps) {
const { config: depositConfig } = usePrepareContractWrite({
address:
isPermittedToBridge && depositAmount !== ''
? publicRuntimeConfig.l1BridgeProxyAddress
: undefined,
abi: L1StandartBridge,
functionName: 'depositERC20To',
chainId: parseInt(publicRuntimeConfig.l1ChainID),
args: [
asset.L1contract as Address,
asset.L2contract as Address,
to,
depositAmount !== ''
? parseUnits(depositAmount, asset.decimals)
: parseUnits('0', asset.decimals),
100000,
includeTosVersionByte ? publicRuntimeConfig.tosVersion : '0x',
],
cacheTime: 0,
staleTime: 1,
overrides: { gasLimit: BigNumber.from(300000) },
});
return depositConfig;
}

View File

@@ -0,0 +1,38 @@
import L2StandardBridge from '@eth-optimism/contracts-bedrock/artifacts/contracts/L2/L2StandardBridge.sol/L2StandardBridge.json';
import { Asset } from 'apps/bridge/src/types/Asset';
import { parseUnits } from 'ethers/lib/utils.js';
import getConfig from 'next/config';
import { Address, usePrepareContractWrite } from 'wagmi';
const { publicRuntimeConfig } = getConfig();
type UsePrepareERC20WithdrawalTo = {
asset: Asset;
to: `0x${string}`;
withdrawAmount: string;
isPermittedToBridge: boolean;
includeTosVersionByte: boolean;
};
export function usePrepareERC20WithdrawalTo({
asset,
to,
withdrawAmount,
isPermittedToBridge,
includeTosVersionByte,
}: UsePrepareERC20WithdrawalTo) {
const { config } = usePrepareContractWrite({
address: isPermittedToBridge ? publicRuntimeConfig.L2StandardBridge : undefined,
abi: L2StandardBridge.abi,
functionName: 'withdrawTo',
chainId: parseInt(publicRuntimeConfig.l2ChainID),
args: [
asset.L2contract as Address,
to,
parseUnits(withdrawAmount === '' ? '0' : withdrawAmount, asset.decimals),
100000,
includeTosVersionByte ? publicRuntimeConfig.tosVersion : '0x',
],
});
return config;
}

View File

@@ -39,24 +39,27 @@ export function explorerTxToBridgeDeposit(tx: BlockExplorerTransaction): BridgeT
};
}
const decodedWithdrawData = l1StandardBridgeInterface.decodeFunctionData(
const functionName = l1StandardBridgeInterface.getFunction(tx.input.slice(0, 10)).name;
const decodedDepositData = l1StandardBridgeInterface.decodeFunctionData(
tx.input.slice(0, 10),
tx.input,
);
const token = assetList.find(
(asset) =>
asset.L1chainId === parseInt(publicRuntimeConfig.l1ChainID) &&
asset.L1contract?.toLowerCase() === (decodedWithdrawData[0] as string).toLowerCase(),
asset.L1contract?.toLowerCase() === (decodedDepositData[0] as string).toLowerCase(),
) as Asset;
return {
type: 'Deposit',
from: tx.from,
to: tx.to,
assetSymbol: token.L1symbol ?? '',
amount: (decodedWithdrawData[2] as BigNumber).toString(),
amount: (
(functionName === 'depositERC20' ? decodedDepositData[2] : decodedDepositData[3]) as BigNumber
).toString(),
blockTimestamp: tx.timeStamp,
hash: tx.hash as `0x${string}`,
status: 'Complete',
priceApiId: token.apiId,
};
}
}

View File

@@ -38,6 +38,7 @@ export function explorerTxToBridgeWithdrawal(tx: BlockExplorerTransaction): Brid
};
}
const functionName = l2StandardBridgeInterface.getFunction(tx.input.slice(0, 10)).name;
const decodedWithdrawData = l2StandardBridgeInterface.decodeFunctionData(
tx.input.slice(0, 10),
tx.input,
@@ -52,9 +53,11 @@ export function explorerTxToBridgeWithdrawal(tx: BlockExplorerTransaction): Brid
from: tx.from,
to: tx.to,
assetSymbol: token.L2symbol ?? '',
amount: (decodedWithdrawData[1] as BigNumber).toString(),
amount: (
(functionName === 'withdraw' ? decodedWithdrawData[1] : decodedWithdrawData[2]) as BigNumber
).toString(),
blockTimestamp: tx.timeStamp,
hash: tx.hash as `0x${string}`,
priceApiId: token.apiId,
};
}
}

View File

@@ -32,7 +32,7 @@ export function isETHOrERC20Deposit(tx: BlockExplorerTransaction) {
// ERC-20 desposit
if (tx.to === ERC20_DEPOSIT_ADDRESS) {
const functionName = l1StandardBridgeInterface.getFunction(tx.input.slice(0, 10)).name;
if (functionName === 'depositERC20') {
if (functionName === 'depositERC20' || functionName === 'depositERC20To') {
return true;
}
}

View File

@@ -32,7 +32,7 @@ export function isETHOrERC20Withdrawal(tx: BlockExplorerTransaction) {
// ERC-20 Withdrawal
if (tx.to === ERC20_WITHDRAWAL_ADDRESS) {
const functionName = l2StandardBridgeInterface.getFunction(tx.input.slice(0, 10)).name;
if (functionName === 'withdraw') {
if (functionName === 'withdraw' || functionName === 'withdrawTo') {
return true;
}
}

View File

@@ -1,19 +1,19 @@
{
"arrowParens": "always",
"bracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 100,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false,
"overrides": [
module.exports = {
arrowParens: 'always',
bracketSameLine: false,
jsxSingleQuote: false,
printWidth: 100,
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'all',
useTabs: false,
overrides: [
{
"files": "*.json",
"options": {
"parser": "json-stringify"
}
}
]
}
files: '*.json',
options: {
parser: 'json-stringify',
},
},
],
};