Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discrepancy Between Estimated and Actual Fees for Storing Data in Smart Contract #53

Open
Nick-1979 opened this issue Feb 25, 2025 · 5 comments
Assignees

Comments

@Nick-1979
Copy link

The screenshots show the actual fee displayed on Subscan for storing data in a smart contract, which matches the exact amount deducted from the balance, as confirmed in Remix. However, as shown in the insights displayed in MetaMask, the estimated fee differs significantly from the actual fee.

We calculate the fee using the formula:

(gasConsumed.refTime + gasConsumed.proofSize) * gasPrice + storageDepositCharge

Image
@athei
Copy link
Member

athei commented Feb 25, 2025

You seem to be using some plugin from Polkagate. I have no idea how this is calculating the fee. But @pgherveou should have a look. He is back next week.

@Nick-1979
Copy link
Author

We are the PolkaGate team, currently working on adding Polkadot contract support to the existing PolkaGate Snap.
The formula used, as mentioned in the issue, is:

(gasConsumed.refTime + gasConsumed.proofSize) * gasPrice + storageDepositCharge

These values are retrieved from the call dry run.

@athei
Copy link
Member

athei commented Feb 25, 2025

You should not multiply the gasPrice with the weight. The gasPrice is there to help Metamask to calculate the fees from the one dimensional gas. It doesn't relate at all to the Weight.

Instead you should create a new extrinsic using the returned Weight and query its fee details using the transactionPayment runtime API.

However, you need to be aware that this is just an estimation and not binding. Only the gasLimit * gasPrice as inserted into the eth transaction is the authoritative limit. This dialogue could mislead user into believing that this is the actual limit they are setting.

@Nick-1979
Copy link
Author

Got it, thank you! Now, I’m using:

const trace = await api.call.reviveApi.call(...tx) as PalletRevivePrimitivesContractResultExecReturnValue;
const weightFee = await api.call.transactionPaymentApi.queryWeightToFee(trace.gasConsumed);

to get the fee based on the weight. Then, to find the estimated fee, I should:
• Add the deposit charge, if any.
• Subtract the refund, if applicable.

Is that correct?

@athei
Copy link
Member

athei commented Feb 26, 2025

This doesn't account for all the extrinc's fees. For example, the byte fee. You need to use:

const fee = await api.call.transactionPaymentApi.queryFeeDetails(<your encoded call extrinsic>);

Add the deposit charge, if any.

Yes

Subtract the refund, if applicable.

Do you mean Weight refund? If yes: No. gasConsumed is the gas that was consumed by the dry run. So it accounts for any refunds.

Or do you mean storage deposit refunds? Then yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants