diff --git a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts index b64308ff34..4060920fef 100644 --- a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts +++ b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts @@ -170,6 +170,25 @@ export class CompilerImports extends Plugin { await this.call('solidityUnitTesting', 'createTestLibs') exist = await provider.exists(url) } + if (!exist && url === 'forge-std/Vm.sol') { + const content = `// SPDX-License-Identifier: MIT + pragma solidity >= 0.4.22 <0.9.0; + + library vm { + address constant VM_ADDRESS = address(0x000000000000000000636f6E736F6C652e6c6F68); + + function startPrank(address _sender) private view { + bytes memory payload = abi.encodeWithSignature("startPrank(address)", _sender); + uint256 payloadLength = payload.length; + address consoleAddress = VM_ADDRESS; + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + }` + await this.call('fileManager', 'writeFile', 'forge-std/Vm.sol', content) + } if (!exist && url.startsWith('browser/')) throw new Error(`not found ${url}`) if (!exist && url.startsWith('localhost/')) throw new Error(`not found ${url}`) if (exist) { diff --git a/libs/remix-simulator/src/VmProxy.ts b/libs/remix-simulator/src/VmProxy.ts index 26f71ca993..59820d7f3b 100644 --- a/libs/remix-simulator/src/VmProxy.ts +++ b/libs/remix-simulator/src/VmProxy.ts @@ -286,6 +286,26 @@ export class VmProxy { this.hhLogs[this.processingHash] = this.hhLogs[this.processingHash] ? this.hhLogs[this.processingHash] : [] this.hhLogs[this.processingHash].push(consoleArgs) } + // Track forge vm call + if (step.op === 'STATICCALL' && toHexPaddedString(step.stack[step.stack.length - 2]) === '0x000000000000000000000000000000000000000000636f6e736f6c652e6c6f68') { + const payloadStart = parseInt(toHexPaddedString(step.stack[step.stack.length - 3]), 16) + const memory = formatMemory(data.memory) + const memoryStr = memory.join('') + let payload = memoryStr.substring(payloadStart * 2, memoryStr.length) + const fnselectorStr = payload.substring(0, 8) + const fnselectorStrInHex = '0x' + fnselectorStr + const fnArgs = '(address)' + const iface = new ethers.utils.Interface([`function prank${fnArgs} view`]) + const functionDesc = iface.getFunction(`prank${fnArgs}`) + const sigHash = iface.getSighash(`prank${fnArgs}`) + if (fnArgs.includes('uint') && sigHash !== fnselectorStrInHex) { + payload = payload.replace(fnselectorStr, sigHash) + } else { + payload = '0x' + payload + } + let prankArgs = iface.decodeFunctionData(functionDesc, payload) + + } if (step.op === 'CREATE' || step.op === 'CALL') { if (step.op === 'CREATE') {