UNPKG

@tokamak-zk-evm/synthesizer

Version:

Tokamak zk-EVM Synthesizer - Processes Ethereum transactions into wire maps for Tokamak zk-SNARK proof generation

152 lines 7.16 kB
/** * The adapter provides an external interface that returns data structures directly in memory, * eliminating the need for file system operations. */ import { Address, hexToBytes } from '@synthesizer-libs/util'; import { finalize } from '../tokamak/core/finalize.js'; import { setupEVMFromCalldata } from '../tokamak/utils/erc20EvmSetup.js'; import { setupUSDCFromCalldata } from '../tokamak/utils/usdcEvmSetup.js'; import { createEVM } from '../constructors.js'; import { SUPPORTED_TOKENS, TON_STORAGE_LAYOUT, USDT_STORAGE_LAYOUT, USDC_PROXY_STORAGE_LAYOUT, USDC_STORAGE_LAYOUT_V1, USDC_STORAGE_LAYOUT_V2, TON_CONTRACT, USDT_CONTRACT, USDC_PROXY_CONTRACT, USDC_IMPLEMENTATION_V1, USDC_IMPLEMENTATION_V2, } from '../constants/index.js'; import { STORAGE_IN_PLACEMENT_INDEX, RETURN_PLACEMENT_INDEX, STORAGE_OUT_PLACEMENT_INDEX, } from '../tokamak/constant/constants.js'; const TOKEN_CONFIGS = { TON: { address: SUPPORTED_TOKENS.TON, bytecode: TON_CONTRACT.bytecode, storageLayout: TON_STORAGE_LAYOUT, setupFunction: setupEVMFromCalldata, }, USDT: { address: SUPPORTED_TOKENS.USDT, bytecode: USDT_CONTRACT.bytecode, storageLayout: USDT_STORAGE_LAYOUT, setupFunction: setupEVMFromCalldata, }, USDC: { address: SUPPORTED_TOKENS.USDC_PROXY, proxyAddress: SUPPORTED_TOKENS.USDC_PROXY, implementationV1Address: SUPPORTED_TOKENS.USDC_IMPLEMENTATION_V1, implementationV2Address: SUPPORTED_TOKENS.USDC_IMPLEMENTATION_V2, bytecode: USDC_PROXY_CONTRACT.bytecode, implementationV1Bytecode: USDC_IMPLEMENTATION_V1.bytecode, implementationV2Bytecode: USDC_IMPLEMENTATION_V2.bytecode, storageLayout: USDC_PROXY_STORAGE_LAYOUT, storageLayoutV1: USDC_STORAGE_LAYOUT_V1, storageLayoutV2: USDC_STORAGE_LAYOUT_V2, setupFunction: setupUSDCFromCalldata, }, }; export class SynthesizerAdapter { constructor() { // Initialize EVM in constructor this.evm = this.createFreshEVM(); } isSupportedToken(address) { return Object.values(SUPPORTED_TOKENS).includes(address.toLowerCase()); } isTON(address) { return address.toLowerCase() === SUPPORTED_TOKENS.TON.toLowerCase(); } getTokenConfig(address) { const config = Object.values(TOKEN_CONFIGS).find((config) => config.address.toLowerCase() === address.toLowerCase()); if (!config) { throw new Error(`Unsupported token address: ${address}. ` + `Supported tokens are: ${Object.values(TOKEN_CONFIGS) .map((c) => c.address) .join(', ')}`); } return config; } // 새로운 메소드 추가 isUnsupportedMethod(contractAddr, calldata) { if (this.isTON(contractAddr) && calldata.slice(0, 10).toLowerCase() === '0xcae9ca51') { return true; } return false; } get placementIndices() { return { storageIn: STORAGE_IN_PLACEMENT_INDEX, return: RETURN_PLACEMENT_INDEX, storageOut: STORAGE_OUT_PLACEMENT_INDEX, }; } async createFreshEVM() { const evm = await createEVM(); // Initialize placements inPts and outPts arrays if (evm.synthesizer) { evm.synthesizer.logPt = []; const returnPlacement = evm.synthesizer.placements.get(RETURN_PLACEMENT_INDEX); if (returnPlacement) { returnPlacement.inPts = []; returnPlacement.outPts = []; console.log('SynthesizerAdapter.parseTransaction: Cleared logPt and outPts arrays'); } // Initialize STORAGE_IN_PLACEMENT's inPts and outPts arrays const storageInPlacement = evm.synthesizer.placements.get(STORAGE_IN_PLACEMENT_INDEX); if (storageInPlacement) { storageInPlacement.inPts = []; storageInPlacement.outPts = []; console.log('SynthesizerAdapter.parseTransaction: Cleared STORAGE_IN_PLACEMENT arrays'); } // Initialize STORAGE_OUT_PLACEMENT's inPts and outPts arrays const storageOutPlacement = evm.synthesizer.placements.get(STORAGE_OUT_PLACEMENT_INDEX); if (storageOutPlacement) { storageOutPlacement.inPts = []; storageOutPlacement.outPts = []; console.log('SynthesizerAdapter.parseTransaction: Cleared STORAGE_OUT_PLACEMENT arrays'); } } return evm; } /** * Parses and processes an ERC20 transaction, returning all necessary data structures in memory. * @param {string} params.contractAddr - The ERC20 contract address * @param {string} params.calldata - The transaction calldata * @param {string} params.sender - The transaction sender address * @returns {Promise<{ * evm: EVM, * executionResult: ExecResult, * permutation: Permutation, * placementInstance: PlacementInstances * }>} Returns EVM instance, execution result, permutation and placementInstance */ async parseTransaction({ contractAddr, calldata, sender, }) { if (!this.isSupportedToken(contractAddr)) { throw new Error(`Unsupported token address: ${contractAddr}. Supported tokens are TON(Tokamak), USDT, and USDC.`); } if (this.isUnsupportedMethod(contractAddr, calldata)) { throw new Error(`Unsupported method for this token.`); } const config = this.getTokenConfig(contractAddr); // 생성자에서 초기화된 EVM 사용 const evm = await this.evm; const _contractAddr = new Address(hexToBytes(config.address)); const _sender = new Address(hexToBytes(sender)); const _contractCode = hexToBytes(config.bytecode); const _calldata = hexToBytes(calldata); if (config === TOKEN_CONFIGS.USDC) { await config.setupFunction(evm, _contractAddr, new Address(hexToBytes(config.implementationV1Address)), new Address(hexToBytes(config.implementationV2Address)), _contractCode, hexToBytes(config.implementationV1Bytecode), hexToBytes(config.implementationV2Bytecode), config.storageLayout, config.storageLayoutV1, config.storageLayoutV2, calldata, _sender); } else { await config.setupFunction(evm, _contractAddr, _contractCode, config.storageLayout, calldata, _sender); } const executionResult = await evm.runCode({ caller: _sender, to: _contractAddr, code: _contractCode, data: _calldata, }); // validate 옵션을 false로 설정하여 testInstances 함수를 건너뜁니다 const { permutation, placementInstance } = await finalize(executionResult.runState.synthesizer.placements, undefined, false, // validate를 false로 변경 false); return { evm, executionResult, permutation, placementInstance, }; } } //# sourceMappingURL=synthesizerAdapter.js.map