Skip to content

Tokenization precompile gas: per-method base costs, the fixed buffers RequiredGas adds, executeMultiple and input-size costs, per-element constants.

The tokenization precompile charges a base cost per method plus a fixed buffer, computed in RequiredGas from the method ID and input size. This page lists the numbers from x/tokenization/precompile/precompile.go and gas.go.

go
// RequiredGas, simplified
baseGas := baseGasForMethod(methodID) // the per-method constant from the tables below
if isTransaction {
    return baseGas + 200_000
}
return baseGas + 50_000

The base is deducted before the precompile runs. The keeper's own work (state reads and writes, approval checks, events) then draws from the remaining gas of the call. The buffer exists so eth_estimateGas converges on a value that works.

Transaction Methods

MethodBase gasCharged up front
transferTokens30,000230,000
setIncomingApproval20,000220,000
setOutgoingApproval20,000220,000
createCollection50,000250,000
updateCollection40,000240,000
universalUpdateCollection50,000250,000
deleteCollection20,000220,000
createAddressLists30,000230,000
updateUserApprovals30,000230,000
deleteIncomingApproval15,000215,000
deleteOutgoingApproval15,000215,000
purgeApprovals25,000225,000
createDynamicStore20,000220,000
updateDynamicStore20,000220,000
deleteDynamicStore15,000215,000
setDynamicStoreValue15,000215,000
setValidTokenIds20,000220,000
setManager15,000215,000
setCollectionMetadata15,000215,000
setTokenMetadata20,000220,000
setCustomData15,000215,000
setStandards15,000215,000
setCollectionApprovals30,000230,000
setIsArchived15,000215,000
castVote15,000215,000

executeMultiple

text
base = 10,000
     + 1,000 * min(messageCount, 50)
     + 100 * floor(len(input) / 32)
charged = base + 200,000

The per-chunk term prices JSON parsing by input size, so a large batch cannot be under-charged. Each message's own keeper work still draws from the remaining gas.

Query Methods

MethodBase gasCharged up front
getCollection3,00053,000
getBalance3,00053,000
getBalanceAmount3,00053,000
getTotalSupply3,00053,000
getCollectionStats3,00053,000
getAddressList5,00055,000
getApprovalTracker5,00055,000
getChallengeTracker5,00055,000
getETHSignatureTracker5,00055,000
getDynamicStore5,00055,000
getDynamicStoreValue5,00055,000
getWrappableBalances5,00055,000
getAllReservedProtocolAddresses5,00055,000
getVote5,00055,000
getVotes5,00055,000
isAddressReservedProtocol2,00052,000
params2,00052,000

Utility Methods

Pure functions, no state access. They still receive the +50,000 query buffer in RequiredGas.

MethodBase gasExtra
convertEvmAddressToBech32500
convertBech32ToEvmAddress500
rangeContains200
rangesOverlap200
searchInRanges500+ 100 per 32-byte input chunk
getBalanceForIdAndTime500+ 100 per 32-byte input chunk
getReservedListId300

Per-Element Constants

gas.go defines calculators for size-proportional estimates. RequiredGas does not add these on top of the base today; the module's own gas metering covers the real per-element work. They are useful for off-chain estimation and may be applied in a future version.

ConstantGasUsed by
GasPerRecipient5,000CalculateTransferGas
GasPerTokenIdRange1,000CalculateTransferGas, CalculateApprovalGas
GasPerOwnershipTimeRange1,000CalculateTransferGas, CalculateApprovalGas
GasPerApprovalField500CalculateApprovalGas (per transfer time range)
GasPerQueryRange500CalculateQueryGas
GasPerInputChunk100executeMultiple, searchInRanges, getBalanceForIdAndTime
GasPerMessageInBatch1,000executeMultiple
go
// CalculateTransferGas
gas := GasTransferTokensBase
gas += len(toAddresses) * GasPerRecipient
gas += len(tokenIdsRanges) * GasPerTokenIdRange
gas += len(ownershipTimesRanges) * GasPerOwnershipTimeRange

Limits That Affect Gas

LimitValue
MaxMessagesPerBatch50
MaxQueryArraySize (token ID or ownership time ranges in a query)1,000
MaxRecipients, MaxTokenIdRanges, MaxOwnershipTimeRanges, MaxApprovalRanges100

Full list on Security.

Spending Less

  • Fewer recipients per transfer; merge adjacent token ID and ownership time ranges.
  • Use getBalanceAmount and getTotalSupply (direct uint256) instead of getBalance when you only need an amount.
  • Batch with executeMultiple instead of separate transactions; one buffer instead of N.
  • Use rangeContains and searchInRanges instead of hand-written range loops in Solidity.
  • Cache JSON strings you reuse across calls.
  • Simple operations are cheaper as native Cosmos messages than through the EVM. See Developer Guide.

Edit this page on GitHub