Skip to content

Commit

Permalink
NFT offers/mints gas estimation improvements (#5448)
Browse files Browse the repository at this point in the history
  • Loading branch information
benisgold authored Mar 21, 2024
1 parent 824c210 commit c5ce968
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 191 deletions.
9 changes: 5 additions & 4 deletions src/components/gas/GasSpeedButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const GasSpeedButton = ({
validateGasParams,
flashbotTransaction = false,
crossChainServiceTime,
loading = false,
}) => {
const { colors } = useTheme();
const { navigate, goBack } = useNavigation();
Expand Down Expand Up @@ -178,7 +179,7 @@ const GasSpeedButton = ({

const formatGasPrice = useCallback(
animatedValue => {
if (animatedValue === null || isNaN(animatedValue)) {
if (animatedValue === null || loading || isNaN(animatedValue)) {
return 0;
}
!gasPriceReady && setGasPriceReady(true);
Expand All @@ -199,7 +200,7 @@ const GasSpeedButton = ({
}`;
}
},
[gasPriceReady, isLegacyGasNetwork, nativeCurrencySymbol, nativeCurrency]
[loading, gasPriceReady, isLegacyGasNetwork, nativeCurrencySymbol, nativeCurrency]
);

const openCustomOptionsRef = useRef();
Expand Down Expand Up @@ -232,7 +233,7 @@ const GasSpeedButton = ({

const renderGasPriceText = useCallback(
animatedNumber => {
const priceText = animatedNumber === 0 ? lang.t('swap.loading') : animatedNumber;
const priceText = animatedNumber === 0 || loading ? lang.t('swap.loading') : animatedNumber;
return (
<Text
color={theme === 'dark' ? colors.whiteLabel : colors.alpha(colors.blueGreyDark, 0.8)}
Expand All @@ -244,7 +245,7 @@ const GasSpeedButton = ({
</Text>
);
},
[theme, colors]
[loading, theme, colors]
);

// I'M SHITTY CODE BUT GOT THINGS DONE REFACTOR ME ASAP
Expand Down
11 changes: 9 additions & 2 deletions src/graphql/queries/metadata.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,22 @@ fragment simulationError on TransactionError {
type
}

query simulateTransactions($chainId: Int!, $transactions: [Transaction!], $domain: String!) {
simulateTransactions(chainID: $chainId, transactions: $transactions, domain: $domain) {
query simulateTransactions($chainId: Int!, $transactions: [Transaction!], $domain: String, $currency: String) {
simulateTransactions(chainID: $chainId, transactions: $transactions, domain: $domain, currency: $currency) {
error {
...simulationError
}
scanning {
result
description
}
gas {
used
estimate
}
report {
url
}
simulation {
in {
...change
Expand Down
110 changes: 0 additions & 110 deletions src/handlers/nftOffers.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/references/ethereum-units.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@
"mether": 1000000000000000000000000,
"gether": 1000000000000000000000000000,
"tether": 1000000000000000000000000000000,
"mainnet_nft_offer_gas_fee_fallback": 600000,
"mainnet_nft_offer_gas_fee_fallback": 300000,
"l2_nft_offer_gas_fee_fallback": 2000000
}
118 changes: 68 additions & 50 deletions src/screens/NFTSingleOfferSheet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import { privateKeyToAccount } from 'viem/accounts';
import { createWalletClient, http } from 'viem';

import { RainbowError, logger } from '@/logger';
import { estimateNFTOfferGas } from '@/handlers/nftOffers';
import { useTheme } from '@/theme';
import { Network } from '@/helpers';
import { getNetworkObj } from '@/networks';
Expand All @@ -51,6 +50,9 @@ import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon';
import { addNewTransaction } from '@/state/pendingTransactions';
import { getUniqueId } from '@/utils/ethereumUtils';
import { getNextNonce } from '@/state/nonces';
import { metadataPOSTClient } from '@/graphql';
import { ethUnits } from '@/references';
import { Transaction } from '@/graphql/__generated__/metadataPOST';

const NFT_IMAGE_HEIGHT = 160;
const TWO_HOURS_MS = 2 * 60 * 60 * 1000;
Expand Down Expand Up @@ -99,6 +101,7 @@ export function NFTSingleOfferSheet() {
currency: nativeCurrency,
});

const [isGasReady, setIsGasReady] = useState<boolean>(false);
const [height, setHeight] = useState(0);
const [isAccepting, setIsAccepting] = useState(false);
const txsRef = useRef<string[]>([]);
Expand Down Expand Up @@ -176,68 +179,82 @@ export function NFTSingleOfferSheet() {
}, [offer.validUntil]);

const estimateGas = useCallback(() => {
const networkObj = getNetworkObj(network);
const signer = createWalletClient({
// @ts-ignore
account: accountAddress,
chain: networkObj,
transport: http(networkObj.rpc),
});
getClient()?.actions.acceptOffer({
items: [
{
token: `${offer.nft.contractAddress}:${offer.nft.tokenId}`,
quantity: 1,
},
],
options: feeParam
? {
feesOnTop: [feeParam],
}
: undefined,
chainId: networkObj.id,
precheck: true,
wallet: signer,
onProgress: async (steps: Execute['steps']) => {
let sale;
let approval;
steps.forEach(step =>
step.items?.forEach(async item => {
if (item.data?.data && item.data?.to && item.data?.from) {
if (step.id === 'sale') {
sale = {
to: item.data.to,
from: item.data.from,
data: item.data.data,
};
} else if (step.id === 'nft-approval') {
approval = {
try {
const networkObj = getNetworkObj(network);
const signer = createWalletClient({
// @ts-ignore
account: accountAddress,
chain: networkObj,
transport: http(networkObj.rpc),
});
getClient()?.actions.acceptOffer({
items: [
{
token: `${offer.nft.contractAddress}:${offer.nft.tokenId}`,
quantity: 1,
},
],
options: feeParam
? {
feesOnTop: [feeParam],
}
: undefined,
chainId: networkObj.id,
precheck: true,
wallet: signer,
onProgress: async (steps: Execute['steps']) => {
let reservoirEstimate = 0;
const txs: Transaction[] = [];
const fallbackEstimate =
offer.network === Network.mainnet ? ethUnits.mainnet_nft_offer_gas_fee_fallback : ethUnits.l2_nft_offer_gas_fee_fallback;
steps.forEach(step =>
step.items?.forEach(item => {
if (item?.data?.to && item?.data?.from && item?.data?.data) {
txs.push({
to: item.data.to,
from: item.data.from,
data: item.data.data,
};
value: item.data.value ?? '0x0',
});
}
}
})
);
const gas = await estimateNFTOfferGas(offer, approval, sale);
if (gas) {
updateTxFee(gas, null);
startPollingGasFees(network);
}
},
});
}, [accountAddress, feeParam, network, offer, startPollingGasFees, updateTxFee]);
// @ts-ignore missing from reservoir type
const txEstimate = item.gasEstimate;
if (typeof txEstimate === 'number') {
reservoirEstimate += txEstimate;
}
})
);
const txSimEstimate = parseInt(
(
await metadataPOSTClient.simulateTransactions({
chainId: networkObj.id,
transactions: txs,
})
)?.simulateTransactions?.[0]?.gas?.estimate ?? '0x0',
16
);
const estimate = txSimEstimate || reservoirEstimate || fallbackEstimate;
if (estimate) {
updateTxFee(estimate, null);
setIsGasReady(true);
}
},
});
} catch {
logger.error(new RainbowError('NFT Offer: Failed to estimate gas'));
}
}, [accountAddress, feeParam, network, offer, updateTxFee]);

// estimate gas
useEffect(() => {
if (!isReadOnlyWallet && !isExpired) {
startPollingGasFees(network);
estimateGas();
}
return () => {
stopPollingGasFees();
};
}, [estimateGas, isExpired, isReadOnlyWallet, stopPollingGasFees]);
}, [estimateGas, isExpired, isReadOnlyWallet, network, startPollingGasFees, stopPollingGasFees, updateTxFee]);

const acceptOffer = useCallback(async () => {
logger.info(`Initiating sale of NFT ${offer.nft.contractAddress}:${offer.nft.tokenId}`);
Expand Down Expand Up @@ -706,6 +723,7 @@ export function NFTSingleOfferSheet() {
asset={{
color: offer.nft.predominantColor || buttonColorFallback,
}}
loading={!isGasReady}
horizontalPadding={0}
currentNetwork={offer.network}
theme={theme.isDarkMode ? 'dark' : 'light'}
Expand Down
Loading

0 comments on commit c5ce968

Please sign in to comment.