How to properly calculate ContractCallTx fee?

Hey everybody! I would like to know how can I calculate a fee for a smart contract call. The goal is to multiply minimal fee to increase the speed of mining.

I’ve found this thread, and tried play around with TxBuilder.calculateMinFee("contractCallTx", {}), but without any success so far.

Thank you in advance.

1 Like

I am not sure if it is exposed in the SDK. Note that the miminum fee depends on a couple of different components, one of which is the size of the transaction itself. This means that if you compute the tx minimum fee and recreate the transaction with that new fee - the bytesize of the new transaction could as well be bigger than the previous one. This would mean something counterintuivite: adding more fee could require adding a bit more fee :smiley:

I think this is something @milenradkov.chain had faced already so I poke him.

Thank you Dimitar. I managed to reverse engineer SDK a little. Here’s the solution.

import {TX_TYPE} from "@aeternity/aepp-sdk/es/tx/builder/schema";
import {getFunctionACI} from "@aeternity/aepp-sdk/es/contract/aci/helpers";
import {transform, validateArguments} from "@aeternity/aepp-sdk/es/contract/aci/transformation";


  /**
   * @param method - Smart contract function name
   * @param params - Smart contract function arguments
   * @returns {Promise<void>}
   */
async function calculateContractCallFee(method, params) {
	const options = {
		...this.contract.options,
		...this.aeternity.Ae.defaults,
		callerId: this.publicKey,
		contractId: this.contractId
	};

	const ctVersion = this.aeternity.getVmVersion(
		TX_TYPE.contractCall,
		options
	);

	Object.assign(options, { abiVersion: ctVersion.abiVersion });

	const fnACI = getFunctionACI(this.contract.aci, method);

	const callData = await this.aeternity.contractEncodeCall(
		this.contract.source,
		method,
		await this.prepareArgsForEncode(fnACI, [params]),
		options
	);

	Object.assign(options, { callData });

	const { fee } = await this.aeternity.prepareTxParams(TX_TYPE.contractCall, {
		senderId: this.publicKey,
		...options
	});

	return fee;
}

// Copied from Aeternity JS SDK
async function prepareArgsForEncode(aci, params) {
	if (!aci || !aci.arguments) return params;
	// Validation
	if (aci.arguments.length > params.length) {
		throw new Error(
			`Function "${aci.name}" require ${
				aci.arguments.length
			} arguments of types [${aci.arguments.map(a =>
				JSON.stringify(a.type)
			)}] but get [${params.map(JSON.stringify)}]`
		);
	}

	validateArguments(aci, params);
	const bindings = aci.bindings;
	// Cast argument from JS to Sophia type
	return Promise.all(
		aci.arguments.map(async ({ type }, i) =>
			transform(type, params[i], {
				bindings
			})
		)
	);
}