Documentation Index Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
Try it Live Run Authorization examples in the interactive playground
Gas Calculations
Calculate gas costs for EIP-7702 authorizations.
Overview
EIP-7702 authorization processing has two gas cost components:
Base cost per authorization: 12,500 gas
Empty account cost: 25,000 gas (if delegated address is empty)
Total cost: (authCount * 12500) + (emptyCount * 25000)
Constants
Authorization . PER_AUTH_BASE_COST = 12500 n ; // Base gas per authorization
Authorization . PER_EMPTY_ACCOUNT_COST = 25000 n ; // Gas for empty account
calculateGasCost
Calculate total gas cost for authorization list.
Authorization . calculateGasCost . call (
authList : Authorization . Item [],
emptyAccounts : number
): bigint
Parameters:
authList: Array of authorizations
emptyAccounts: Number of empty accounts being delegated to
Returns: Total gas cost as bigint
Formula: (authList.length * 12500) + (emptyAccounts * 25000)
Usage
import { Authorization } from 'tevm' ;
const authList : Authorization . Item [] = [ auth1 , auth2 , auth3 ];
const emptyAccountCount = 2 ;
const gas = Authorization . calculateGasCost . call ( authList , emptyAccountCount );
console . log ( `Total gas: ${ gas } ` );
// gas = (3 * 12500) + (2 * 25000) = 87500
Examples
All empty accounts:
const gas = Authorization . calculateGasCost . call ([ auth1 , auth2 ], 2 );
// (2 * 12500) + (2 * 25000) = 75000
No empty accounts:
const gas = Authorization . calculateGasCost . call ([ auth1 , auth2 ], 0 );
// (2 * 12500) + (0 * 25000) = 25000
Empty list:
const gas = Authorization . calculateGasCost . call ([], 0 );
// (0 * 12500) + (0 * 25000) = 0
Mixed:
const gas = Authorization . calculateGasCost . call ([ auth1 , auth2 , auth3 , auth4 ], 1 );
// (4 * 12500) + (1 * 25000) = 75000
getGasCost
Calculate gas cost for single authorization.
Authorization . getGasCost . call (
auth : Authorization . Item ,
isEmpty : boolean
): bigint
Parameters:
auth: Authorization to calculate cost for
isEmpty: Whether delegated address is empty
Returns: Gas cost as bigint
Formula:
If empty: 12500 + 25000 = 37500
If not empty: 12500
Usage
import { Authorization } from 'tevm' ;
const auth : Authorization . Item = { ... };
// Empty account
const gasIfEmpty = Authorization . getGasCost . call ( auth , true );
console . log ( `Gas (empty): ${ gasIfEmpty } ` );
// 37500
// Non-empty account
const gasIfNotEmpty = Authorization . getGasCost . call ( auth , false );
console . log ( `Gas (not empty): ${ gasIfNotEmpty } ` );
// 12500
Empty Account Detection
What is an Empty Account?
An account is considered empty if:
Balance = 0
Nonce = 0
Code length = 0
Storage is empty
Checking if Account is Empty
import { Authorization } from 'tevm' ;
async function isAccountEmpty ( address : Address ) : Promise < boolean > {
const balance = await getBalance ( address );
const nonce = await getNonce ( address );
const code = await getCode ( address );
return balance === 0 n && nonce === 0 n && code . length === 0 ;
}
// Use in gas calculation
const isEmpty = await isAccountEmpty ( auth . address );
const gas = Authorization . getGasCost . call ( auth , isEmpty );
Counting Empty Accounts
import { Authorization } from 'tevm' ;
async function countEmptyAccounts (
authList : Authorization . Item []
) : Promise < number > {
let count = 0 ;
for ( const auth of authList ) {
const isEmpty = await isAccountEmpty ( auth . address );
if ( isEmpty ) count ++ ;
}
return count ;
}
// Use in gas calculation
const emptyCount = await countEmptyAccounts ( authList );
const gas = Authorization . calculateGasCost . call ( authList , emptyCount );
Gas Estimation Patterns
Pre-transaction Estimation
Estimate gas before sending transaction:
import { Authorization } from 'tevm' ;
async function estimateAuthGas (
authList : Authorization . Item []
) : Promise < bigint > {
// Count empty accounts
const emptyCount = await countEmptyAccounts ( authList );
// Calculate authorization gas
const authGas = Authorization . calculateGasCost . call ( authList , emptyCount );
// Add execution gas (estimated separately)
const executionGas = 21000 n ; // Base transaction cost
const totalGas = authGas + executionGas ;
return totalGas ;
}
const gasEstimate = await estimateAuthGas ( authList );
console . log ( `Estimated gas: ${ gasEstimate } ` );
With Gas Limit
Check if within gas limit:
import { Authorization } from 'tevm' ;
async function validateGasLimit (
authList : Authorization . Item [],
gasLimit : bigint
) : Promise < void > {
const emptyCount = await countEmptyAccounts ( authList );
const authGas = Authorization . calculateGasCost . call ( authList , emptyCount );
if ( authGas > gasLimit ) {
throw new Error (
`Authorization gas ( ${ authGas } ) exceeds limit ( ${ gasLimit } )`
);
}
}
await validateGasLimit ( authList , 100000 n );
Per-Authorization Cost Breakdown
Calculate cost for each authorization:
import { Authorization } from 'tevm' ;
interface AuthGasCost {
auth : Authorization . Item ;
isEmpty : boolean ;
gas : bigint ;
}
async function calculateIndividualCosts (
authList : Authorization . Item []
) : Promise < AuthGasCost []> {
const costs : AuthGasCost [] = [];
for ( const auth of authList ) {
const isEmpty = await isAccountEmpty ( auth . address );
const gas = Authorization . getGasCost . call ( auth , isEmpty );
costs . push ({ auth , isEmpty , gas });
}
return costs ;
}
const costs = await calculateIndividualCosts ( authList );
costs . forEach (( c , i ) => {
console . log ( `Auth ${ i } : ${ c . gas } gas ( ${ c . isEmpty ? 'empty' : 'not empty' } )` );
});
Optimization Strategies
Minimize Empty Account Delegations
Empty accounts cost more gas. Prefer delegating to deployed contracts:
// More expensive: delegate to empty address
const expensiveAuth = {
chainId: 1 n ,
address: emptyAddress , // 37,500 gas
nonce: 0 n
};
// Cheaper: delegate to deployed contract
const cheaperAuth = {
chainId: 1 n ,
address: deployedContract , // 12,500 gas
nonce: 0 n
};
Batch Size Optimization
Larger batches have better gas efficiency per authorization:
import { Authorization } from 'tevm' ;
function calculateEfficiency (
authCount : number ,
emptyCount : number
) : number {
const totalGas = Authorization . calculateGasCost . call (
new Array ( authCount ). fill ( null ),
emptyCount
);
const gasPerAuth = Number ( totalGas ) / authCount ;
return gasPerAuth ;
}
// Examples
calculateEfficiency ( 1 , 0 ); // 12,500 gas/auth
calculateEfficiency ( 10 , 0 ); // 12,500 gas/auth (same)
calculateEfficiency ( 1 , 1 ); // 37,500 gas/auth
calculateEfficiency ( 10 , 5 ); // 25,000 gas/auth (better due to batching)
Deduplication
Remove duplicate delegations to save gas:
import { Authorization , Address } from 'tevm' ;
function deduplicateByAddress (
authList : Authorization . Item []
) : Authorization . Item [] {
const seen = new Set < string >();
const unique : Authorization . Item [] = [];
for ( const auth of authList ) {
const key = Address . toHex ( auth . address );
if ( ! seen . has ( key )) {
seen . add ( key );
unique . push ( auth );
}
}
return unique ;
}
const deduplicated = deduplicateByAddress ( authList );
const savedAuths = authList . length - deduplicated . length ;
const savedGas = BigInt ( savedAuths ) * Authorization . PER_AUTH_BASE_COST ;
console . log ( `Saved ${ savedGas } gas by removing ${ savedAuths } duplicates` );
Gas Cost Tables
Base Costs
Scenario Authorizations Empty Accounts Gas Cost Single (empty) 1 1 37,500 Single (not empty) 1 0 12,500 Batch of 5 (all empty) 5 5 187,500 Batch of 5 (none empty) 5 0 62,500 Batch of 10 (5 empty) 10 5 250,000
Cost per Authorization
Empty Accounts Gas per Auth All empty 37,500 None empty 12,500 50% empty 25,000 (average) 25% empty 18,750 (average)
Advanced Patterns
Dynamic Gas Pricing
Adjust authorization list based on gas price:
import { Authorization } from 'tevm' ;
async function optimizeAuthList (
authList : Authorization . Item [],
maxGas : bigint
) : Promise < Authorization . Item []> {
// Calculate costs
const costs = await calculateIndividualCosts ( authList );
// Sort by cost (cheapest first)
costs . sort (( a , b ) => Number ( a . gas - b . gas ));
// Include as many as possible within budget
const optimized : Authorization . Item [] = [];
let totalGas = 0 n ;
for ( const cost of costs ) {
if ( totalGas + cost . gas <= maxGas ) {
optimized . push ( cost . auth );
totalGas += cost . gas ;
}
}
return optimized ;
}
const optimized = await optimizeAuthList ( authList , 100000 n );
Gas Budget Allocation
Allocate gas budget across authorization types:
import { Authorization } from 'tevm' ;
interface GasBudget {
empty : bigint ;
nonEmpty : bigint ;
}
function allocateBudget ( totalGas : bigint ) : GasBudget {
// Reserve 60% for base costs, 40% for empty accounts
const baseGas = ( totalGas * 60 n ) / 100 n ;
const emptyGas = ( totalGas * 40 n ) / 100 n ;
return { empty: emptyGas , nonEmpty: baseGas };
}
function calculateMaxAuths ( budget : GasBudget ) : {
maxEmpty : number ;
maxNonEmpty : number ;
} {
const maxEmpty = Number ( budget . empty / Authorization . PER_EMPTY_ACCOUNT_COST );
const maxNonEmpty = Number ( budget . nonEmpty / Authorization . PER_AUTH_BASE_COST );
return { maxEmpty , maxNonEmpty };
}
const budget = allocateBudget ( 100000 n );
const max = calculateMaxAuths ( budget );
console . log ( `Can include up to ${ max . maxNonEmpty } non-empty or ${ max . maxEmpty } empty` );
Gas Monitoring
Track gas usage during processing:
import { Authorization } from 'tevm' ;
class GasMonitor {
private totalGas = 0 n ;
private authCount = 0 ;
private emptyCount = 0 ;
async addAuth ( auth : Authorization . Item ) : Promise < void > {
const isEmpty = await isAccountEmpty ( auth . address );
const gas = Authorization . getGasCost . call ( auth , isEmpty );
this . totalGas += gas ;
this . authCount ++ ;
if ( isEmpty ) this . emptyCount ++ ;
}
getStats () : {
totalGas : bigint ;
authCount : number ;
emptyCount : number ;
avgGasPerAuth : number ;
} {
return {
totalGas: this . totalGas ,
authCount: this . authCount ,
emptyCount: this . emptyCount ,
avgGasPerAuth: Number ( this . totalGas ) / this . authCount
};
}
reset () : void {
this . totalGas = 0 n ;
this . authCount = 0 ;
this . emptyCount = 0 ;
}
}
const monitor = new GasMonitor ();
for ( const auth of authList ) {
await monitor . addAuth ( auth );
}
console . log ( monitor . getStats ());
Testing
Test Gas Calculations
import { Authorization } from 'tevm' ;
// Empty list
expect ( Authorization . calculateGasCost . call ([], 0 )). toBe ( 0 n );
// Single non-empty
expect ( Authorization . getGasCost . call ( auth , false )). toBe ( 12500 n );
// Single empty
expect ( Authorization . getGasCost . call ( auth , true )). toBe ( 37500 n );
// Batch
const gas = Authorization . calculateGasCost . call ([ auth1 , auth2 , auth3 ], 2 );
expect ( gas ). toBe ( 87500 n ); // (3 * 12500) + (2 * 25000)
Gas calculation is O(1):
// Constant time calculation
const gas = Authorization . calculateGasCost . call ( authList , emptyCount );
// gas = authList.length * 12500 + emptyCount * 25000
See Also