Skip to main content
Inco charges fees for certain operations to ensure the security and performance of the confidential computing infrastructure. This page explains how fees work and which operations require payment.

Fee Structure

Inco fees are paid in the native blockchain currency (ETH on Ethereum, etc.) and are required for operations that involve processing encrypted inputs from external sources.

Getting the Current Fee Amount

Use the inco.getFee() function to get the current fee amount:
uint256 fee = inco.getFee(); // 0.0001 ETH

Paying Fees

Fees can be paid in two ways: either by users including them in msg.value, or by having the contract pay from its own ETH balance.

Option 1: User Pays via msg.value

Fees must be paid via msg.value when calling functions that require them. The transaction will revert if insufficient fees are provided.
require(msg.value >= inco.getFee() * ciphertextCount, "Fee Not Paid");

Option 2: Contract Pays from Balance

Contracts can hold ETH in their balance to pay fees automatically, eliminating the need for users to include fees in msg.value.
contract MyContract {
    // Contract holds ETH to pay fees automatically

    function transfer(address to, bytes memory valueInput) external {
        // No payable modifier needed, no msg.value check required
        euint256 value = valueInput.newEuint256(msg.sender);
        // Contract's ETH balance is used to pay fees automatically
        // ... rest of function
    }

    // Function to top up contract's ETH balance
    function depositFees() external payable {
        // Allows anyone to add ETH to contract for fee payments
    }

    // Function to withdraw excess ETH
    function withdrawFees(uint256 amount) external onlyOwner {
        require(address(this).balance >= amount, "Insufficient balance");
        payable(owner()).transfer(amount);
    }
}
Benefits of contract-paid fees:
  • Better user experience - no need to calculate or send exact fees
  • Simpler function signatures - no payable modifier required
  • Automatic fee management by contract owner
Considerations:
  • Contract owner must ensure sufficient ETH balance
  • Monitor contract balance and top up as needed
  • Consider implementing balance thresholds and alerts

Operations That Require Fees

Encrypted Input Creation and Random Generation

The following operations create new encrypted handles from external ciphertexts or generate random values and require fees:
OperationFee RequiredDescription
e.newEuint256(bytes memory input)1 fee per callCreate a new euint256 from an encrypted input
e.newEbool(bytes memory input)1 fee per callCreate a new ebool from an encrypted input
e.newEaddress(bytes memory input)1 fee per callCreate a new eaddress from an encrypted input
e.rand()1 fee per callGenerate a random euint256 value
e.randBounded(uint256)1 fee per callGenerate a bounded random euint256 value
e.randBounded(euint256)1 fee per callGenerate a bounded random euint256 value
Example with user-paid fees:
function transfer(address to, bytes memory valueInput) external payable {
    // Each newEuint256 call requires 1 fee
    require(msg.value >= inco.getFee() * 1, "Fee Not Paid");
    euint256 value = valueInput.newEuint256(msg.sender);
    // ... rest of function
}
Example with contract-paid fees:
function transfer(address to, bytes memory valueInput) external {
    // No fee check needed - contract pays from its balance
    euint256 value = valueInput.newEuint256(msg.sender);
    // ... rest of function
}
Multiple encrypted inputs:
function multiInput(bytes memory input1, bytes memory input2) external payable {
    // Two newEuint256 calls require 2 fees (user pays)
    require(msg.value >= inco.getFee() * 2, "Fee Not Paid");
    euint256 value1 = input1.newEuint256(msg.sender);
    euint256 value2 = input2.newEuint256(msg.sender);
    // ... rest of function
}
Multiple encrypted inputs (contract pays):
function multiInput(bytes memory input1, bytes memory input2) external {
    // Contract automatically pays 2 fees from its balance
    euint256 value1 = input1.newEuint256(msg.sender);
    euint256 value2 = input2.newEuint256(msg.sender);
    // ... rest of function
}

Operations That Don’t Require Fees

All other Inco operations are free and don’t require any fee payment:

Math Operations

  • e.add, e.sub, e.mul, e.div, e.rem
  • e.and, e.or, e.xor, e.shr, e.shl, e.rotr, e.rotl

Comparison Operations

  • e.eq, e.ne, e.ge, e.gt, e.le, e.lt
  • e.min, e.max, e.not

Multiplexer Operations

  • e.select

Trivial Encryption (no external input)

  • e.asEuint256(uint256) - Convert known uint256 to euint256
  • e.asEbool(bool) - Convert known bool to ebool

Access Control

  • e.allow, e.allowThis, e.isAllowed

Fee Best Practices

For User-Paid Fees

Always Check Fees Before Operations

function _requireFee(uint256 ciphertextCount) internal view {
    require(msg.value >= inco.getFee() * ciphertextCount, "Insufficient fee");
}

Calculate Ciphertext Count Accurately

Count each newEuint256, newEbool or newEaddress call in your function to ensure you charge the correct total fee.

For Contract-Paid Fees

Monitor Contract Balance

function getContractFeeBalance() external view returns (uint256) {
    return address(this).balance;
}

function isBalanceSufficient(uint256 requiredFees) internal view returns (bool) {
    return address(this).balance >= requiredFees;
}

Implement Balance Management

function depositFees() external payable {
    // Allow topping up contract balance
}

function withdrawFees(uint256 amount) external onlyOwner {
    require(address(this).balance >= amount, "Insufficient balance");
    require(amount <= address(this).balance - minimumReserve, "Cannot withdraw below minimum reserve");
    payable(owner()).transfer(amount);
}

General Best Practices

Handle Fee Changes

Fees may change over time. Always use inco.getFee() rather than hardcoding fee amounts.

Test Fee Requirements

When testing contracts, ensure sufficient funds for both approaches:
// For user-paid fees in Foundry tests
vm.deal(user, inco.getFee() * 2); // User needs ETH for fees

// For contract-paid fees in Foundry tests
vm.deal(address(contract), inco.getFee() * 10); // Contract needs ETH balance

User-Paid Fee Errors

  • “Fee Not Paid”: Transaction reverted due to insufficient msg.value
  • Overpaying: While allowed, unnecessary ETH is consumed as gas
  • Fee changes: Contract fails if fees increase between deployment and usage

Contract-Paid Fee Errors

  • “Insufficient contract balance”: Contract doesn’t have enough ETH to pay fees
  • “Below minimum reserve”: Withdrawal attempts that would leave insufficient funds
  • “Contract balance depleted”: Functions fail when contract runs out of ETH during high usage
Important: Encrypted input operations (newEuint256, newEbool, newEaddress) require fees because they involve off-chain decryption and processing within Inco’s Trusted Execution Environment (TEE). All other operations are performed symbolically on-chain and are therefore free.