4

I am trying to calculate the cost of a transaction, post-hoc, from the response to calling the entrypoint. This is for the purposes of a testing tool I am building that I need accurate costs for.

As an example, I have the following information about the call I have just made from a call response:

res:  {
  operation_hash: 'op36m7td8UXUvCCUpZ72Xy3XLbU6pFf1VLF5y7cE6Rmb5qe7LNs',
  storage_size: 24698,
  consumed_gas: 15045.615,
  paid_storage_size_diff: 96,
  events: [],
}

I found a guide for calcuating cost from fees and burn. It includes this formula which seems fairly straightforward:

total_cost = burn + fees + amount of tez

burn = storage_difference * MINIMAL_FEE_PER_STORAGE_BYTE_MUTEZ

fees >= MINIMAL_FEE_MUTEZ +
        MINIMAL_FEE_PER_BYTE_MUTEZ * size +
        MINIMAL_FEE_PER_GAS_MUTEZ * gas

in practice:

fees in mutez >= 100 +
                 1 * size +
                 0.1 * gas

However, when I calculate the cost with the following formula:

function get_cost(
  storage_difference: number = res.paid_storage_size_diff,
  gas_use: number = res.consumed_gas,
  bytes_size: number = res.storage_size,
  ) : BigNumber {
    const fees = bytes_size + (gas_used*0.1)
    const burn = storage_difference*1000 
    return new BigNumber(fees + burn)
}

Plugging in the response output from above, I get a cost of 114292.6447 mutez (the decimal places are another issue, as I believe mutez should be an integer. I guess I'm just meant to round them?)

However, I know from looking at the actual delta that true cost of calling this entrypoint in mockup mode is only 26028 mutez.

Please help me to understand what is wrong with my approach, and how (if) I can calculate the cost from the information I have.

Help greatly appreciated


EDIT

Thanks to @Groxan I now have the following formula:

function get_cost(
  storage_difference: number = res.paid_storage_size_diff,
  gas_used: number = res.consumed_gas,
  bytes_size: number = res.storage_size,
  ) : BigNumber {
    const fees = 100 + bytes_size + (gas_used*0.1)
    const burn = storage_difference*250 
    return new BigNumber(fees + burn).integerValue(BigNumber.ROUND_UP)
}

This is much closer, but it is still giving me an answer that is a bit over twice the observable cost. This function predicts the cost should have been 50203 mutez. (vs the observed 26028)

Is there a different calculation or set of constants in use for the mockup mode?

Any ideas? Thanks all

3 Answers 3

2

You need to multiply paid_storage_size_diff by 250, instead of 1000, because according to the current procotol constants cost per byte is 0.000250 tez. Also, don't forget to add +100 in the fees calculation, according to the formula you mentioned above ;) And yes, mutez must be an integer, so just round it up.

3
  • Thanks this was a great help and I've made some changes accordingly (see my updated question). I'm still off the mark by a factor of 2 and a bit. Any thoughts?
    – Grum
    Mar 1 at 0:01
  • @Grum it seems you use storage_size as bytes_size, which is wrong, because bytes_size is a length of the forged operation bytes - bytes that you post to the /inject RPC endpoint
    – Groxan
    Mar 1 at 12:16
  • Thanks - this sounds like it will be the problem as I am using storage_size as bytes_size, but I admit I don't have enough context to understand what to do next - but this gives me a good clue to research from
    – Grum
    Mar 2 at 0:31
0

What bytes_size value are you using ? you don't show it in your example, that would help figuring it out. Note that it is the size of the transaction in bytes.

2
  • I am using storage_size from the response for the bytes_size. @Groxan has helpfully pointed out that this is wrong. Unfortunately I have poor fundamentals and do not understand what value I should be using instead (I do not understand @Groxan's comment about /inject etc at this point). Can I get the value I need from the response somehow?
    – Grum
    Mar 2 at 0:44
  • Code example below. Mar 2 at 15:25
0

Here is how to compute operation size (with Taquito):

import { LocalForger } from "@taquito/local-forging";
import { InMemorySigner } from '@taquito/signer'
import { OperationContents, OperationContentsTransaction, OpKind } from '@taquito/rpc';

async function compute_op_size() {
  const transaction: OperationContentsTransaction = {
    "kind": OpKind.TRANSACTION,
    "source": "tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb",
    "fee": "388",
    "counter": "72035",
    "gas_limit": "1304",
    "storage_limit": "0",
    "amount": "0",
    "destination": "KT1Vrag7PFbjAmbmCJ9sAzYKxYkzvsqrUNEv",
    "parameters": {
      "entrypoint": "default",
      "value": {
        "int": "4"
      }
    }
  };

  const local_forge = new LocalForger();
  const opContents: OperationContents[] = [transaction];

  const forge_param = {
    branch: "BLk3XprVitY86JimhijByZXcctLvsfkBmH16juNayRJbs3uHYbc",
    contents: opContents
  }

  const op_bytes: string = await local_forge.forge(forge_param);

  const signer = new InMemorySigner("edsk3QoqBuvdamxouPhin7swCvkQNgq4jP5KZPbwWNnwdZpSpJiEbq")
  const op_sign = await signer.sign(op_bytes)
  console.log(`opSize: ${op_sign.sbytes.length / 2}`)
}

compute_op_size()

It prints 157 when executed.

2
  • Thanks for this answer, but it seems that one of the inputs required to find the operation size in the example above is the transaction fee (In OperationContentsTransaction), which is the value I am trying to find. Also, I am trying to get the fee as part of testing, and I guess it is not possible to get a meaningful block hash in mockup mode (?)
    – Grum
    Apr 27 at 3:37
  • 1
    The point here is that 388 and BLk3XprVitY86JimhijByZXcctLvsfkBmH16juNayRJbs3uHYbc values are FAKE values just used to estimate the size in bytes of the transaction ... you can even keep theses values in your test if you want Apr 28 at 5:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.