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.
Utilities for working with proxy patterns including ERC-1967 storage slots, ERC-1167 minimal proxies, and ERC-3448 MetaProxies.
Overview
Proxy patterns enable contract upgradeability by separating logic (implementation) from state (proxy). The proxy delegates calls to the implementation while maintaining its own storage.
Proxy Patterns:
ERC-1967 : Standard storage slots for proxy metadata (implementation, admin, beacon)
ERC-1167 : Minimal proxy clone (45 bytes runtime) for gas-efficient deployment
ERC-3448 : MetaProxy with embedded metadata for factory patterns
Quick Start
ERC-1967 Storage Slots
ERC-1167 Minimal Proxy
ERC-3448 MetaProxy
import * as Proxy from '@tevm/voltaire/Proxy' ;
import { eth_getStorageAt } from '@tevm/voltaire/rpc' ;
// Read implementation address from proxy
const implementation = await eth_getStorageAt (
proxyAddress ,
Proxy . IMPLEMENTATION_SLOT
);
// Read admin address
const admin = await eth_getStorageAt (
proxyAddress ,
Proxy . ADMIN_SLOT
);
console . log ( 'Implementation:' , implementation );
console . log ( 'Admin:' , admin );
import * as Proxy from '@tevm/voltaire/Proxy' ;
import { Address } from '@tevm/voltaire/Address' ;
// Generate minimal proxy bytecode
const implementation = Address . from ( '0x1234...' );
const proxyBytecode = Proxy . generateErc1167 ( implementation );
console . log ( 'Bytecode size:' , proxyBytecode . length ); // 55 bytes
console . log ( 'Runtime size:' , 45 ); // 45 bytes after deployment
// Parse deployed proxy
const code = await eth_getCode ( cloneAddress );
const parsed = Proxy . parseErc1167 ( code );
console . log ( 'Implementation:' , parsed . toHex ());
import * as Proxy from '@tevm/voltaire/Proxy' ;
import { Address } from '@tevm/voltaire/Address' ;
// Generate MetaProxy with metadata
const implementation = Address . from ( '0x1234...' );
const metadata = new TextEncoder (). encode ( JSON . stringify ({
creator: '0xabcd...' ,
salt: '0x1234...' ,
version: 1
}));
const metaProxyBytecode = Proxy . generateErc3448 (
implementation ,
metadata
);
// Parse deployed MetaProxy
const code = await eth_getCode ( metaProxyAddress );
const result = Proxy . parseErc3448 ( code );
console . log ( 'Implementation:' , result . implementation . toHex ());
console . log ( 'Metadata:' , new TextDecoder (). decode ( result . metadata ));
Proxy Patterns Comparison
Feature ERC-1967 ERC-1167 ERC-3448 Purpose Storage slots Minimal clone Clone + metadata Bytecode size Varies 55 bytes (creation) 55 + metadata + 32 Runtime size Varies 45 bytes 45 bytes (metadata not in runtime) Gas cost Standard Minimal Minimal + metadata Upgradeability Yes (UUPS/Transparent) No No Metadata No No Yes Use case Upgradeable proxies Gas-efficient clones Factory patterns
API Documentation
Constants ERC-1967 storage slot constants
generateErc1167 Generate minimal proxy bytecode
parseErc1167 Parse minimal proxy implementation
isErc1167 Check if bytecode is ERC-1167
generateErc3448 Generate MetaProxy with metadata
parseErc3448 Parse MetaProxy implementation and metadata
isErc3448 Check if bytecode is ERC-3448
Usage Patterns
UUPS Proxy Detection
import * as Proxy from '@tevm/voltaire/Proxy' ;
import { eth_getStorageAt } from '@tevm/voltaire/rpc' ;
async function detectUUPSProxy ( address : string ) {
// Check if ERC-1967 implementation slot is set
const implementation = await eth_getStorageAt (
address ,
Proxy . IMPLEMENTATION_SLOT
);
if ( implementation === '0x' + '00' . repeat ( 32 )) {
return null ; // Not a proxy
}
return {
type: 'UUPS' ,
implementation ,
slot: Proxy . IMPLEMENTATION_SLOT
};
}
Clone Factory
import * as Proxy from '@tevm/voltaire/Proxy' ;
import { Address } from '@tevm/voltaire/Address' ;
class CloneFactory {
implementation : Uint8Array ;
proxyBytecode : Uint8Array ;
constructor ( implementationAddress : string ) {
this . implementation = Address . from ( implementationAddress );
this . proxyBytecode = Proxy . generateErc1167 ( this . implementation );
}
async deployClone ( initData ?: Uint8Array ) {
// Deploy proxy
const address = await deploy ( this . proxyBytecode );
// Initialize if needed
if ( initData ) {
await call ( address , initData );
}
return address ;
}
isClone ( bytecode : Uint8Array ) : boolean {
if ( ! Proxy . isErc1167 ( bytecode )) {
return false ;
}
const impl = Proxy . parseErc1167 ( bytecode );
return impl . equals ( this . implementation );
}
}
import * as Proxy from '@tevm/voltaire/Proxy' ;
import { Address } from '@tevm/voltaire/Address' ;
import { keccak256 } from '@tevm/voltaire/crypto' ;
class MetaProxyFactory {
async deployWithMetadata (
implementation : string ,
creator : string ,
salt : string
) {
const metadata = new TextEncoder (). encode ( JSON . stringify ({
creator ,
salt ,
timestamp: Date . now (),
chainId: 1
}));
const bytecode = Proxy . generateErc3448 (
Address . from ( implementation ),
metadata
);
// Calculate deterministic address (CREATE2)
const address = Address . calculateCreate2Address (
Address . from ( this . factoryAddress ),
keccak256 ( new TextEncoder (). encode ( salt )),
bytecode
);
return { bytecode , address , metadata };
}
async readMetadata ( proxyAddress : string ) {
const code = await eth_getCode ( proxyAddress );
if ( ! Proxy . isErc3448 ( code )) {
throw new Error ( 'Not a MetaProxy' );
}
const { implementation , metadata } = Proxy . parseErc3448 ( code );
const metadataObj = JSON . parse (
new TextDecoder (). decode ( metadata )
);
return {
implementation: implementation . toHex (),
... metadataObj
};
}
}
Specification References
Storage - Namespaced storage for upgradeable contracts
Address - Address utilities including CREATE2
Bytecode - Bytecode analysis and manipulation