Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ten-rockets-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

Fix tx cost estimation for pay transaction modal
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { type UseMutationResult, useMutation } from "@tanstack/react-query";
import type { Chain } from "../../../../chains/types.js";
import { getGasPrice } from "../../../../gas/get-gas-price.js";
import type { BuyWithCryptoStatus } from "../../../../pay/buyWithCrypto/getStatus.js";
import type { BuyWithFiatStatus } from "../../../../pay/buyWithFiat/getStatus.js";
import type { FiatProvider } from "../../../../pay/utils/commonTypes.js";
import { estimateGasCost } from "../../../../transaction/actions/estimate-gas-cost.js";
import type { GaslessOptions } from "../../../../transaction/actions/gasless/types.js";
import { sendTransaction } from "../../../../transaction/actions/send-transaction.js";
import type { WaitForReceiptOptions } from "../../../../transaction/actions/wait-for-tx-receipt.js";
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
import { getTransactionGasCost } from "../../../../transaction/utils.js";
import { resolvePromisedValue } from "../../../../utils/promise/resolve-promised-value.js";
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
import { getTokenBalance } from "../../../../wallets/utils/getTokenBalance.js";
Expand Down Expand Up @@ -215,7 +214,7 @@
tokenAddress: _erc20Value.tokenAddress,
})
: undefined,
getTotalTxCostForBuy(tx, account.address),
getTransactionGasCost(tx, account.address),

Check warning on line 217 in packages/thirdweb/src/react/core/hooks/transaction/useSendTransaction.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/core/hooks/transaction/useSendTransaction.ts#L217

Added line #L217 was not covered by tests
]);

const gasSponsored = hasSponsoredTransactionsEnabled(wallet);
Expand Down Expand Up @@ -248,39 +247,3 @@
},
});
}

async function getTotalTxCostForBuy(tx: PreparedTransaction, from?: string) {
try {
const gasCost = await estimateGasCost({
transaction: tx,
from,
});

const bufferCost = gasCost.wei / 10n;

// Note: get tx.value AFTER estimateGasCost
const txValue = await resolvePromisedValue(tx.value);

// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
return gasCost.wei + bufferCost + (txValue || 0n);
} catch {
if (from) {
// try again without passing from
return await getTotalTxCostForBuy(tx);
}
// fallback if both fail, use the tx value + 2M * gas price
const value = await resolvePromisedValue(tx.value);

const gasPrice = await getGasPrice({
client: tx.client,
chain: tx.chain,
});

const buffer = 2_000_000n * gasPrice;

if (!value) {
return 0n + buffer;
}
return value + buffer;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { getChainMetadata } from "../../../../../../../chains/utils.js";
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
import { getContract } from "../../../../../../../contract/contract.js";
import { getCurrencyMetadata } from "../../../../../../../extensions/erc20/read/getCurrencyMetadata.js";
import { getGasPrice } from "../../../../../../../gas/get-gas-price.js";
import { encode } from "../../../../../../../transaction/actions/encode.js";
import { estimateGasCost } from "../../../../../../../transaction/actions/estimate-gas-cost.js";
import type { PreparedTransaction } from "../../../../../../../transaction/prepare-transaction.js";
import { getTransactionGasCost } from "../../../../../../../transaction/utils.js";
import type { Hex } from "../../../../../../../utils/encoding/hex.js";
import { resolvePromisedValue } from "../../../../../../../utils/promise/resolve-promised-value.js";
import type { Account } from "../../../../../../../wallets/interfaces/wallet.js";
Expand Down Expand Up @@ -138,30 +137,3 @@ export function useTransactionCostAndData(args: {
},
});
}

async function getTransactionGasCost(tx: PreparedTransaction, from?: string) {
try {
const gasCost = await estimateGasCost({
transaction: tx,
from,
});

const bufferCost = gasCost.wei / 10n;

// Note: get tx.value AFTER estimateGasCost
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
return gasCost.wei + bufferCost;
} catch {
if (from) {
// try again without passing from
return await getTransactionGasCost(tx);
}
// fallback if both fail, use the tx value + 2M * gas price
const gasPrice = await getGasPrice({
client: tx.client,
chain: tx.chain,
});

return 2_000_000n * gasPrice;
}
}
33 changes: 33 additions & 0 deletions packages/thirdweb/src/transaction/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { AbiFunction } from "abitype";
import { getGasPrice } from "../gas/get-gas-price.js";
import { estimateGasCost } from "./actions/estimate-gas-cost.js";
import type { PreparedTransaction } from "./prepare-transaction.js";

/**
* @internal
Expand All @@ -11,3 +14,33 @@
item.type === "function"
);
}

export async function getTransactionGasCost(
tx: PreparedTransaction,
from?: string,
) {
try {
const gasCost = await estimateGasCost({
transaction: tx,
from,
});

Check warning on line 26 in packages/thirdweb/src/transaction/utils.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/transaction/utils.ts#L18-L26

Added lines #L18 - L26 were not covered by tests

const bufferCost = gasCost.wei / 10n;

Check warning on line 28 in packages/thirdweb/src/transaction/utils.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/transaction/utils.ts#L28

Added line #L28 was not covered by tests

// Note: get tx.value AFTER estimateGasCost
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
return gasCost.wei + bufferCost;
} catch {
if (from) {

Check warning on line 34 in packages/thirdweb/src/transaction/utils.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/transaction/utils.ts#L32-L34

Added lines #L32 - L34 were not covered by tests
// try again without passing from
return await getTransactionGasCost(tx);
}

Check warning on line 37 in packages/thirdweb/src/transaction/utils.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/transaction/utils.ts#L36-L37

Added lines #L36 - L37 were not covered by tests
// fallback if both fail, use the tx value + 1M * gas price
const gasPrice = await getGasPrice({
client: tx.client,
chain: tx.chain,
});

Check warning on line 42 in packages/thirdweb/src/transaction/utils.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/transaction/utils.ts#L39-L42

Added lines #L39 - L42 were not covered by tests

return 1_000_000n * gasPrice;
}
}

Check warning on line 46 in packages/thirdweb/src/transaction/utils.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/transaction/utils.ts#L44-L46

Added lines #L44 - L46 were not covered by tests
Loading