@tokamak-zk-evm/synthesizer
Version:
Tokamak zk-EVM Synthesizer - Processes Ethereum transactions into wire maps for Tokamak zk-SNARK proof generation
208 lines (174 loc) • 7.62 kB
text/typescript
import { keccak256 } from 'ethereum-cryptography/keccak'
import { hexToBytes, Address, Account } from '@synthesizer-libs/util';
import { EVM } from '../../evm.js';
interface StorageItem {
astId: number;
contract: string;
label: string;
offset: number;
slot: string;
type: string;
}
interface StorageLayout {
storageLayout: {
storage: StorageItem[];
types: {
[key: string]: {
encoding: string;
label: string;
numberOfBytes: string;
key?: string;
value?: string;
};
};
};
}
const IMPLEMENTATION_SLOT = '0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3'
export const setupUSDCFromCalldata = async (
evm: EVM,
proxyAddr: Address,
implementationV1Addr: Address,
implementationV2Addr: Address,
proxyCode: Uint8Array,
v1Code: Uint8Array,
v2Code: Uint8Array,
proxyStorageLayout: StorageLayout,
v1StorageLayout: StorageLayout,
v2StorageLayout: StorageLayout,
calldata: string,
sender: Address,
) => {
console.log('=== Setting up USDC Environment ===');
console.log('Proxy address:', proxyAddr.toString());
console.log('Implementation V1 address:', implementationV1Addr.toString());
console.log('Implementation V2 address:', implementationV2Addr.toString());
// Setup all contract accounts
await evm.stateManager.putAccount(proxyAddr, new Account())
await evm.stateManager.putAccount(implementationV1Addr, new Account())
await evm.stateManager.putAccount(implementationV2Addr, new Account())
await evm.stateManager.putAccount(sender, new Account())
// Deploy all contract codes
await evm.stateManager.putCode(proxyAddr, proxyCode)
await evm.stateManager.putCode(implementationV1Addr, v1Code)
await evm.stateManager.putCode(implementationV2Addr, v2Code)
// Verify code deployment
const proxyDeployedCode = await evm.stateManager.getCode(proxyAddr)
const v1DeployedCode = await evm.stateManager.getCode(implementationV1Addr)
const v2DeployedCode = await evm.stateManager.getCode(implementationV2Addr)
// Setup delegation chain with verification
await evm.stateManager.putStorage(
proxyAddr,
hexToBytes(IMPLEMENTATION_SLOT),
hexToBytes('0x' + implementationV1Addr.toString().slice(2).padStart(64, '0'))
)
await evm.stateManager.putStorage(
implementationV1Addr,
hexToBytes(IMPLEMENTATION_SLOT),
hexToBytes('0x' + implementationV2Addr.toString().slice(2).padStart(64, '0'))
)
// Verify delegation chain
const proxyImpl = await evm.stateManager.getStorage(proxyAddr, hexToBytes(IMPLEMENTATION_SLOT))
const v1Impl = await evm.stateManager.getStorage(implementationV1Addr, hexToBytes(IMPLEMENTATION_SLOT))
console.log('Proxy implementation:', Buffer.from(proxyImpl).toString('hex'));
console.log('V1 implementation:', Buffer.from(v1Impl).toString('hex'));
// Helper function to find balance slot in storage layout
const findBalanceSlot = (layout: StorageLayout) => {
return layout.storageLayout.storage.find(
item => item.label === '_balances' || item.label === 'balances'
)?.slot
}
// Get balance slots from each layout
const proxyBalanceSlot = findBalanceSlot(proxyStorageLayout)
const v1BalanceSlot = findBalanceSlot(v1StorageLayout)
const v2BalanceSlot = findBalanceSlot(v2StorageLayout)
// Parse calldata
const params = calldata.slice(10)
const functionSig = calldata.slice(0, 10)
switch(functionSig) {
case '0xa9059cbb': { // transfer
const to = '0x' + params.slice(24, 64)
const amount = BigInt('0x' + params.slice(64))
console.log('=== Setup Debug Info ===')
console.log('Sender:', sender.toString())
console.log('To:', to)
console.log('Amount:', amount.toString())
// Setup recipient account
await evm.stateManager.putAccount(new Address(hexToBytes(to)), new Account())
// Setup balances in all contracts if needed
if (v2BalanceSlot) { // Use V2's layout as it's the final implementation
console.log('v2BalanceSlot:', v2BalanceSlot)
const balanceKey = keccak256(
hexToBytes(
'0x' + sender.toString().slice(2).padStart(64, '0') +
v2BalanceSlot.padStart(64, '0')
)
)
// Set initial balance for sender
const initialBalance = amount + BigInt(1000) // Some buffer
await evm.stateManager.putStorage(
proxyAddr, // Store in proxy's storage
balanceKey,
hexToBytes('0x' + initialBalance.toString(16).padStart(64, '0'))
)
const senderBalanceSlot = keccak256(
hexToBytes(
'0x' + sender.toString().slice(2).padStart(64, '0') +
v2BalanceSlot.padStart(64, '0'),
),
);
// 검증을 위해 저장된 값 확인
const storedBalance = await evm.stateManager.getStorage(proxyAddr, senderBalanceSlot);
console.log('Stored balance:', Buffer.from(storedBalance).toString('hex'));
}
break
}
case '0x095ea7b3': { // approve
const spender = '0x' + params.slice(24, 64)
const amount = BigInt('0x' + params.slice(64))
// Setup spender account
await evm.stateManager.putAccount(new Address(hexToBytes(spender)), new Account())
// Find allowance slots
const findAllowanceSlot = (layout: StorageLayout) => {
return layout.storageLayout.storage.find(
item => item.label === 'allowed'
)?.slot
}
const v2AllowanceSlot = findAllowanceSlot(v2StorageLayout)
if (v2AllowanceSlot) {
// Calculate storage slot for allowance
// allowances[owner][spender]
// console.log('v2AllowanceSlot:', v2AllowanceSlot)
const ownerKey = keccak256(
hexToBytes(
'0x' + sender.toString().slice(2).padStart(64, '0') +
v2AllowanceSlot.padStart(64, '0')
)
)
const spenderKey = keccak256(
hexToBytes(
'0x' + spender.slice(2).padStart(64, '0') +
ownerKey.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '').padStart(64, '0')
)
)
// Set initial allowance in proxy's storage
await evm.stateManager.putStorage(
proxyAddr, // Store in proxy's storage
spenderKey,
hexToBytes('0x' + amount.toString(16).padStart(64, '0')) //
)
console.log('Setup allowance mapping:', {
owner: sender.toString(),
spender: spender,
slot: v2AllowanceSlot,
storageKey: Buffer.from(spenderKey).toString('hex')
})
// Verify the allowance was set
const currentAllowance = await evm.stateManager.getStorage(proxyAddr, spenderKey)
console.log('Current allowance:', BigInt('0x' + Buffer.from(currentAllowance).toString('hex')).toString())
}
break
}
}
console.log('USDC Environment setup completed')
console.log('==================')
}