Skip to content

Commit

Permalink
Fix withdraw (#88)
Browse files Browse the repository at this point in the history
* Erc7412 support for withdraw.
- It isn't required for sUSD but is for other collateral

* Avoid tx under prices issues on base-goerli

* Deps

* Done use hasTrustedForwarder to detect if network have erc7412
  • Loading branch information
0xjocke authored Oct 18, 2023
1 parent 5804b4e commit 5a1d534
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 28 deletions.
1 change: 1 addition & 0 deletions liquidity/components/WithdrawModal/WithdrawModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export function WithdrawModal({
const { exec: execWithdraw } = useWithdraw({
accountId: params.accountId,
collateralTypeAddress: accountCollateral?.tokenAddress,
accountCollateral,
});
const queryClient = useQueryClient();

Expand Down
4 changes: 3 additions & 1 deletion liquidity/lib/feeSuggestion/feeSuggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ export const feeSuggestion = async (
provider: ethers.providers.JsonRpcProvider,
fromBlock = 'latest'
) => {
if (provider.network.chainId === 13370) {
// If local or base-goerli, use defaults
// Base goerli sometimes doesn't have enough tx we can use to estimate the priority fee, when this happens the tx will get "tx underprices"
if (provider.network.chainId === 13370 || provider.network.chainId === 84531) {
return defaultForLocalProvider();
}
const feeHistory = await provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useOracleManagerProxy } from '@snx-v3/useOracleManagerProxy';
import { z } from 'zod';
import { notNil } from '@snx-v3/tsHelpers';
import { CoreProxyType, useCoreProxy } from '@snx-v3/useCoreProxy';
import { useNetwork } from '@snx-v3/useBlockchain';
import { networksWithERC7412, useNetwork } from '@snx-v3/useBlockchain';
import { ZodBigNumber } from '@snx-v3/zod';
import { wei } from '@synthetixio/wei';

Expand Down Expand Up @@ -56,8 +56,8 @@ export const useAllCollateralPriceIds = () => {
if (!CoreProxy || !Multicall3 || !OracleProxy) {
throw Error('useAllCollateralPriceIds should not be enabled ');
}
const hasTrustedForwarder = 'getTrustedForwarder' in CoreProxy.functions;
if (!hasTrustedForwarder) return [];

if (!networksWithERC7412[network.name]) return [];
const configs = await loadConfigs({ CoreProxy });
const oracleNodeIds = configs.map((x) => x.oracleNodeId);
const calls = oracleNodeIds.map((oracleNodeId) => ({
Expand Down
3 changes: 3 additions & 0 deletions liquidity/lib/useBlockchain/useBlockchain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export const NETWORKS: Record<string, Network> = {
isTestnet: true,
},
};
export const networksWithERC7412: Record<string, boolean | undefined> = {
'base-goerli': true,
};

const DEFAULT_NETWORK_NAME = window.localStorage.getItem('DEFAULT_NETWORK') || 'optimism-mainnet';
export const DEFAULT_NETWORK =
Expand Down
3 changes: 3 additions & 0 deletions liquidity/lib/useWithdraw/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
"main": "index.ts",
"version": "0.0.1",
"dependencies": {
"@snx-v3/fetchPythPrices": "workspace:*",
"@snx-v3/txnReducer": "workspace:*",
"@snx-v3/useAccountCollateral": "workspace:*",
"@snx-v3/useAllCollateralPriceIds": "workspace:*",
"@snx-v3/useBlockchain": "workspace:*",
"@snx-v3/useCoreProxy": "workspace:*",
"@snx-v3/useGasOptions": "workspace:*",
"@snx-v3/useGasPrice": "workspace:*",
"@snx-v3/useGasSpeed": "workspace:*",
"@snx-v3/withERC7412": "workspace:*",
"@tanstack/react-query": "^4.35.7",
"ethers": "^5.7.2",
"react": "^18.2.0"
Expand Down
53 changes: 35 additions & 18 deletions liquidity/lib/useWithdraw/useWithdraw.tsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,83 @@
import { useReducer } from 'react';
import { useCoreProxy } from '@snx-v3/useCoreProxy';
import { useMutation } from '@tanstack/react-query';
import { useProvider, useSigner } from '@snx-v3/useBlockchain';
import { useNetwork, useProvider, useSigner } from '@snx-v3/useBlockchain';
import { initialState, reducer } from '@snx-v3/txnReducer';
import { BigNumber } from 'ethers';
import { useAccountSpecificCollateral } from '@snx-v3/useAccountCollateral';
import { formatGasPriceForTransaction } from '@snx-v3/useGasOptions';
import { getGasPrice } from '@snx-v3/useGasPrice';
import { useGasSpeed } from '@snx-v3/useGasSpeed';
import { AccountCollateralWithSymbol } from '@snx-v3/useAccountCollateral';
import { useAllCollateralPriceIds } from '@snx-v3/useAllCollateralPriceIds';
import { fetchPriceUpdates, priceUpdatesToPopulatedTx } from '@snx-v3/fetchPythPrices';
import { withERC7412 } from '@snx-v3/withERC7412';

export const useWithdraw = ({
accountId,
collateralTypeAddress,
accountCollateral,
}: {
accountId?: string;
collateralTypeAddress?: string;
accountCollateral: AccountCollateralWithSymbol;
}) => {
const { data: accountCollateral } = useAccountSpecificCollateral(
accountId,
collateralTypeAddress
);

const [txnState, dispatch] = useReducer(reducer, initialState);
const { data: CoreProxy } = useCoreProxy();
const { data: collateralPriceIds } = useAllCollateralPriceIds();
const network = useNetwork();

const { gasSpeed } = useGasSpeed();
const signer = useSigner();
const provider = useProvider();

const mutation = useMutation({
mutationFn: async () => {
if (!signer) return;
if (!(CoreProxy && collateralTypeAddress && accountCollateral?.availableCollateral)) return;
if (
!(
CoreProxy &&
collateralTypeAddress &&
accountCollateral?.availableCollateral &&
collateralPriceIds
)
)
return;
if (accountCollateral?.availableCollateral.eq(0)) return;
const walletAddress = await signer.getAddress();

try {
dispatch({ type: 'prompting' });

const gasPricesPromised = getGasPrice({ provider });
const gasLimitPromised = CoreProxy.estimateGas.withdraw(

const populatedTxnPromised = CoreProxy.populateTransaction.withdraw(
BigNumber.from(accountId),
collateralTypeAddress,
accountCollateral?.availableCollateral.toBN()
);
const populatedTxnPromised = CoreProxy.populateTransaction.withdraw(
BigNumber.from(accountId),
collateralTypeAddress,
accountCollateral?.availableCollateral.toBN(),
{ gasLimit: gasLimitPromised }

const collateralPriceCallsPromise = fetchPriceUpdates(
collateralPriceIds,
network.isTestnet
).then((signedData) =>
priceUpdatesToPopulatedTx(walletAddress, collateralPriceIds, signedData)
);
const [gasPrices, gasLimit, populatedTxn] = await Promise.all([
const [gasPrices, populatedTxn, collateralPriceCalls] = await Promise.all([
gasPricesPromised,
gasLimitPromised,
populatedTxnPromised,
collateralPriceCallsPromise,
]);
const allCalls = collateralPriceCalls.concat(populatedTxn);

const erc7412Tx = await withERC7412(provider, allCalls, 'useWithdraw');

const gasOptionsForTransaction = formatGasPriceForTransaction({
gasLimit,
gasLimit: erc7412Tx.gasLimit,
gasPrices,
gasSpeed,
});

const txn = await signer.sendTransaction({ ...populatedTxn, ...gasOptionsForTransaction });
const txn = await signer.sendTransaction({ ...erc7412Tx, ...gasOptionsForTransaction });
dispatch({ type: 'pending', payload: { txnHash: txn.hash } });

await txn.wait();
Expand Down
8 changes: 2 additions & 6 deletions liquidity/lib/withERC7412/withERC7412.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { EvmPriceServiceConnection } from '@pythnetwork/pyth-evm-js';
import { z } from 'zod';
import { ZodBigNumber } from '@snx-v3/zod';
import { offchainMainnetEndpoint, offchainTestnetEndpoint } from '@snx-v3/constants';
import { NETWORKS } from '@snx-v3/useBlockchain';
import { NETWORKS, networksWithERC7412 } from '@snx-v3/useBlockchain';
import type { Modify } from '@snx-v3/tsHelpers';
import { importMulticall3 } from '@snx-v3/useMulticall3';
import { withMemoryCache } from './withMemoryCache';
Expand Down Expand Up @@ -167,10 +167,6 @@ const getDefaultFromAddress = (chainName: keyof typeof NETWORKS) => {
}
};

const networkWithERC7412: Record<string, boolean | undefined> = {
'base-goerli': true,
};

/**
* If a tx requires ERC7412 pattern, wrap your tx with this function.
*/
Expand Down Expand Up @@ -201,7 +197,7 @@ export const withERC7412 = async (
// If from is set to the default address (wETH) we can assume it's a read rather than a write
const isRead = from === getDefaultFromAddress(networkName);
const isTestnet = network?.isTestnet || false;
const networkHaveERC7412 = networkWithERC7412[networkName] || false;
const networkHaveERC7412 = networksWithERC7412[networkName] || false;
const useCoreProxy = !networkHaveERC7412 && !isRead;

const { address: multicallAddress, abi: multiCallAbi } = useCoreProxy
Expand Down
3 changes: 3 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6194,13 +6194,16 @@ __metadata:
version: 0.0.0-use.local
resolution: "@snx-v3/useWithdraw@workspace:liquidity/lib/useWithdraw"
dependencies:
"@snx-v3/fetchPythPrices": "workspace:*"
"@snx-v3/txnReducer": "workspace:*"
"@snx-v3/useAccountCollateral": "workspace:*"
"@snx-v3/useAllCollateralPriceIds": "workspace:*"
"@snx-v3/useBlockchain": "workspace:*"
"@snx-v3/useCoreProxy": "workspace:*"
"@snx-v3/useGasOptions": "workspace:*"
"@snx-v3/useGasPrice": "workspace:*"
"@snx-v3/useGasSpeed": "workspace:*"
"@snx-v3/withERC7412": "workspace:*"
"@tanstack/react-query": ^4.35.7
ethers: ^5.7.2
react: ^18.2.0
Expand Down

0 comments on commit 5a1d534

Please sign in to comment.