Skip to main content

Try it Live

Run Authorization examples in the interactive playground

Processing

Process authorizations and extract delegation designations.

process

Process single authorization and return delegation designation.
Authorization.process.call(auth: Authorization.Item): Authorization.DelegationDesignation
Parameters:
  • auth: Authorization to process
Returns: DelegationDesignation containing:
  • authority: Address of signer (EOA granting permission)
  • delegatedAddress: Address of contract receiving delegation
Throws: ValidationError if authorization is invalid Process:
  1. Validates authorization structure
  2. Verifies signature and recovers authority
  3. Returns delegation designation

Usage

import { Authorization } from 'tevm';

const auth: Authorization.Item = {
  chainId: 1n,
  address: contractAddress,
  nonce: 0n,
  yParity: 0,
  r: 0x123...n,
  s: 0x456...n
};

try {
  const delegation = Authorization.process.call(auth);
  console.log(`Authority: ${delegation.authority}`);
  console.log(`Delegated to: ${delegation.delegatedAddress}`);
  console.log(`${delegation.authority}${delegation.delegatedAddress}`);
} catch (e) {
  console.error(`Processing failed: ${e}`);
}

DelegationDesignation

type DelegationDesignation = {
  authority: Address;         // Signer (EOA granting permission)
  delegatedAddress: Address;  // Contract receiving delegation
};
authority - The EOA that signed the authorization. This account’s code will be set to point to the delegated address. delegatedAddress - The contract address that authority is delegating to. The authority’s code will temporarily point to this address’s code.

Implementation

export function process(auth: BrandedAuthorization): DelegationDesignation {
  // Validate and recover authority
  const authority = verify(auth);

  return {
    authority,
    delegatedAddress: auth.address
  };
}

processAll

Process authorization list and return all delegation designations.
Authorization.processAll.call(authList: Authorization.Item[]): Authorization.DelegationDesignation[]
Parameters:
  • authList: Array of authorizations to process
Returns: Array of DelegationDesignations Note: Returns empty array for empty input

Usage

import { Authorization } from 'tevm';

const authList: Authorization.Item[] = [auth1, auth2, auth3];

const delegations = Authorization.processAll.call(authList);

console.log(`Processed ${delegations.length} authorizations:`);
delegations.forEach((d, i) => {
  console.log(`  ${i + 1}. ${d.authority}${d.delegatedAddress}`);
});

Empty List

const empty = Authorization.processAll.call([]);
console.log(empty.length); // 0

Error Handling

If any authorization is invalid, the entire operation fails:
try {
  const delegations = Authorization.processAll.call(authList);
  // All authorizations were valid
} catch (e) {
  // At least one authorization was invalid
  console.error(`Failed to process list: ${e}`);
}

Implementation

export function processAll(authList: BrandedAuthorization[]): DelegationDesignation[] {
  return authList.map(auth => process(auth));
}

Processing Patterns

Safe Processing

Process with error handling:
import { Authorization } from 'tevm';

interface ProcessResult {
  auth: Authorization.Item;
  delegation?: Authorization.DelegationDesignation;
  error?: string;
}

function safeProcess(auth: Authorization.Item): ProcessResult {
  try {
    const delegation = Authorization.process.call(auth);
    return { auth, delegation };
  } catch (e) {
    return {
      auth,
      error: e instanceof Error ? e.message : String(e)
    };
  }
}

const result = safeProcess(auth);
if (result.delegation) {
  console.log(`Success: ${result.delegation.authority}`);
} else {
  console.error(`Failed: ${result.error}`);
}

Batch Processing with Errors

Process all, collecting both successes and failures:
import { Authorization } from 'tevm';

function processAllSafe(authList: Authorization.Item[]): {
  delegations: Authorization.DelegationDesignation[];
  successes: Authorization.Item[];
  failures: Array<{ auth: Authorization.Item; error: string }>;
} {
  const delegations: Authorization.DelegationDesignation[] = [];
  const successes: Authorization.Item[] = [];
  const failures: Array<{ auth: Authorization.Item; error: string }> = [];

  for (const auth of authList) {
    try {
      const delegation = Authorization.process.call(auth);
      delegations.push(delegation);
      successes.push(auth);
    } catch (e) {
      failures.push({
        auth,
        error: e instanceof Error ? e.message : String(e)
      });
    }
  }

  return { delegations, successes, failures };
}

const result = processAllSafe(authList);
console.log(`Successes: ${result.successes.length}`);
console.log(`Failures: ${result.failures.length}`);

Pre-validation

Validate before processing for better error messages:
import { Authorization } from 'tevm';

function processWithValidation(auth: Authorization.Item): Authorization.DelegationDesignation {
  // Step 1: Type check
  if (!Authorization.isItem(auth)) {
    throw new Error('Not a valid authorization item');
  }

  // Step 2: Structure validation
  try {
    Authorization.validate.call(auth);
  } catch (e) {
    throw new Error(`Validation failed: ${e}`);
  }

  // Step 3: Process (includes signature verification)
  try {
    return Authorization.process.call(auth);
  } catch (e) {
    throw new Error(`Processing failed: ${e}`);
  }
}

Deduplication

Remove duplicate authorizations before processing:
import { Authorization } from 'tevm';

function deduplicateAuths(authList: Authorization.Item[]): Authorization.Item[] {
  const seen = new Set<string>();
  const unique: Authorization.Item[] = [];

  for (const auth of authList) {
    // Create unique key
    const key = `${auth.chainId}-${auth.address}-${auth.nonce}-${auth.r}-${auth.s}`;

    if (!seen.has(key)) {
      seen.add(key);
      unique.push(auth);
    }
  }

  return unique;
}

const deduplicated = deduplicateAuths(authList);
const delegations = Authorization.processAll.call(deduplicated);

Authority Grouping

Group delegations by authority:
import { Authorization, Address } from 'tevm';

function groupByAuthority(
  authList: Authorization.Item[]
): Map<string, Authorization.DelegationDesignation[]> {
  const delegations = Authorization.processAll.call(authList);
  const groups = new Map<string, Authorization.DelegationDesignation[]>();

  for (const delegation of delegations) {
    const key = Address.toHex(delegation.authority);
    const group = groups.get(key) || [];
    group.push(delegation);
    groups.set(key, group);
  }

  return groups;
}

const groups = groupByAuthority(authList);
for (const [authority, delegations] of groups) {
  console.log(`${authority} has ${delegations.length} delegations`);
}

EIP-7702 Transaction Processing

Authorization List in Transaction

EIP-7702 transactions include authorization list:
interface EIP7702Transaction {
  // Standard transaction fields
  chainId: bigint;
  nonce: bigint;
  gasPrice: bigint;
  gasLimit: bigint;
  to: Address | null;
  value: bigint;
  data: Uint8Array;

  // EIP-7702 specific
  authorizationList: Authorization.Item[];
}

Processing Flow

  1. Before Transaction Execution:
    // Process authorization list
    const delegations = Authorization.processAll.call(tx.authorizationList);
    
    // Apply delegations to accounts
    for (const delegation of delegations) {
      // Set authority's code to point to delegatedAddress
      setAccountCode(delegation.authority, delegation.delegatedAddress);
    }
    
  2. Execute Transaction:
    // Transaction executes with delegated code
    executeTx(tx);
    
  3. After Transaction:
    // Revert code delegations
    for (const delegation of delegations) {
      // Remove delegation
      clearAccountCode(delegation.authority);
    }
    

Gas Cost Calculation

Calculate gas before processing:
import { Authorization } from 'tevm';

async function processWithGasCheck(
  authList: Authorization.Item[],
  gasLimit: bigint
): Promise<Authorization.DelegationDesignation[]> {
  // Count empty accounts
  const emptyCount = await countEmptyAccounts(authList);

  // Calculate gas cost
  const gasCost = Authorization.calculateGasCost.call(authList, emptyCount);

  // Check against limit
  if (gasCost > gasLimit) {
    throw new Error(`Insufficient gas: need ${gasCost}, have ${gasLimit}`);
  }

  // Process authorizations
  return Authorization.processAll.call(authList);
}

Advanced Patterns

Delegation Cache

Cache processed delegations:
import { Authorization } from 'tevm';

class DelegationCache {
  private cache = new Map<string, Authorization.DelegationDesignation>();

  process(auth: Authorization.Item): Authorization.DelegationDesignation {
    // Create cache key
    const key = this.cacheKey(auth);

    // Check cache
    const cached = this.cache.get(key);
    if (cached) return cached;

    // Process and cache
    const delegation = Authorization.process.call(auth);
    this.cache.set(key, delegation);

    return delegation;
  }

  processAll(authList: Authorization.Item[]): Authorization.DelegationDesignation[] {
    return authList.map(auth => this.process(auth));
  }

  private cacheKey(auth: Authorization.Item): string {
    return `${auth.chainId}-${auth.address}-${auth.nonce}-${auth.r}-${auth.s}-${auth.yParity}`;
  }

  clear(): void {
    this.cache.clear();
  }
}

const cache = new DelegationCache();
const delegations = cache.processAll(authList);

Processing Pipeline

Create processing pipeline:
import { Authorization } from 'tevm';

interface Pipeline {
  filter?: (auth: Authorization.Item) => boolean;
  validate?: boolean;
  deduplicate?: boolean;
  maxCount?: number;
}

function processPipeline(
  authList: Authorization.Item[],
  options: Pipeline
): Authorization.DelegationDesignation[] {
  let auths = authList;

  // Filter
  if (options.filter) {
    auths = auths.filter(options.filter);
  }

  // Deduplicate
  if (options.deduplicate) {
    auths = deduplicateAuths(auths);
  }

  // Limit count
  if (options.maxCount !== undefined) {
    auths = auths.slice(0, options.maxCount);
  }

  // Validate
  if (options.validate) {
    for (const auth of auths) {
      Authorization.validate.call(auth);
    }
  }

  // Process
  return Authorization.processAll.call(auths);
}

const delegations = processPipeline(authList, {
  filter: (auth) => auth.chainId === 1n,
  deduplicate: true,
  maxCount: 10,
  validate: true
});

Authority Verification

Verify all authorities are expected:
import { Authorization, Address } from 'tevm';

function processWithAuthorityCheck(
  authList: Authorization.Item[],
  expectedAuthorities: Set<Address>
): Authorization.DelegationDesignation[] {
  const delegations = Authorization.processAll.call(authList);

  // Verify all authorities
  for (const delegation of delegations) {
    let found = false;
    for (const expected of expectedAuthorities) {
      if (Address.equals(delegation.authority, expected)) {
        found = true;
        break;
      }
    }

    if (!found) {
      throw new Error(`Unexpected authority: ${delegation.authority}`);
    }
  }

  return delegations;
}

const allowedAuthorities = new Set([eoa1, eoa2, eoa3]);
const delegations = processWithAuthorityCheck(authList, allowedAuthorities);

Performance

Operation Complexity

OperationTime ComplexityNotes
processO(1)Constant time per auth
processAllO(n)n = list length

Optimization

  1. Parallel Processing (if verification allows):
    // Process in parallel (note: may not preserve order)
    const delegations = await Promise.all(
      authList.map(auth =>
        Promise.resolve(Authorization.process.call(auth))
      )
    );
    
  2. Early Validation:
    // Validate all first to fail fast
    for (const auth of authList) {
      Authorization.validate.call(auth);
    }
    const delegations = Authorization.processAll.call(authList);
    
  3. Batch Size Limits:
    const MAX_BATCH = 100;
    if (authList.length > MAX_BATCH) {
      throw new Error(`Too many authorizations: ${authList.length}`);
    }
    

Testing

Test Processing

import { Authorization } from 'tevm';

// Create signed auth
const auth = Authorization.sign.call(unsigned, privateKey);

// Process
const delegation = Authorization.process.call(auth);

// Verify result
expect(delegation.authority).toBeDefined();
expect(delegation.delegatedAddress).toEqual(unsigned.address);

Test Batch Processing

import { Authorization } from 'tevm';

const authList = [auth1, auth2, auth3];
const delegations = Authorization.processAll.call(authList);

expect(delegations.length).toBe(3);
expect(delegations[0].authority).toBeDefined();
expect(delegations[1].authority).toBeDefined();
expect(delegations[2].authority).toBeDefined();

See Also