diff --git a/apps/remix-ide-e2e/src/tests/debugger.spec.ts b/apps/remix-ide-e2e/src/tests/debugger.spec.ts index ac2f1489fc..b43b94559b 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.spec.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.spec.ts @@ -323,7 +323,7 @@ const localVariable_step266_ABIEncoder = { // eslint-disable-line value: '0x0000000000000000000000000000000000000000000000000000000000000002' }, userData: { - error: '', + value: '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000015b38da6a701c568545dcfcb03fcb875f56beddc4', type: 'bytes' } } @@ -360,7 +360,7 @@ const localVariable_step717_ABIEncoder = { // eslint-disable-line value: '0x5b38da6a701c568545dcfcb03fcb875f56beddc45b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001' }, userData: { - error: '', + value: '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000015b38da6a701c568545dcfcb03fcb875f56beddc4', type: 'bytes' } } diff --git a/libs/remix-debug/src/Ethdebugger.ts b/libs/remix-debug/src/Ethdebugger.ts index 7f2ea7667a..3c492e1812 100644 --- a/libs/remix-debug/src/Ethdebugger.ts +++ b/libs/remix-debug/src/Ethdebugger.ts @@ -104,9 +104,10 @@ export class Ethdebugger { const stack = this.traceManager.getStackAt(step) const memory = this.traceManager.getMemoryAt(step) const address = this.traceManager.getCurrentCalledAddressAt(step) + const calldata = this.traceManager.getCallDataAt(step) try { const storageViewer = new StorageViewer({ stepIndex: step, tx: this.tx, address: address }, this.storageResolver, this.traceManager) - const locals = await localDecoder.solidityLocals(step, this.callTree, stack, memory, storageViewer, sourceLocation, null) + const locals = await localDecoder.solidityLocals(step, this.callTree, stack, memory, storageViewer, calldata, sourceLocation, null) if (locals['error']) { return callback(locals['error']) } diff --git a/libs/remix-debug/src/debugger/solidityLocals.ts b/libs/remix-debug/src/debugger/solidityLocals.ts index 64796a5f50..c7f25d01b8 100644 --- a/libs/remix-debug/src/debugger/solidityLocals.ts +++ b/libs/remix-debug/src/debugger/solidityLocals.ts @@ -62,6 +62,14 @@ export class DebuggerSolidityLocals { } catch (error) { next(error) } + }, + function getCallDataAt (stepIndex, next) { + try { + const calldata = self.traceManager.getCallDataAt(stepIndex) + next(null, calldata) + } catch (error) { + next(error) + } }], this.stepManager.currentStepIndex, (error, result) => { @@ -70,9 +78,10 @@ export class DebuggerSolidityLocals { } var stack = result[0].value var memory = result[1].value + var calldata = result[3].value try { var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: result[2].value }, this.storageResolver, this.traceManager) - solidityLocals(this.stepManager.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, sourceLocation, cursor).then((locals) => { + solidityLocals(this.stepManager.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, calldata, sourceLocation, cursor).then((locals) => { if (!cursor) { if (!locals['error']) { this.event.trigger('solidityLocals', [locals]) diff --git a/libs/remix-debug/src/solidity-decoder/internalCallTree.ts b/libs/remix-debug/src/solidity-decoder/internalCallTree.ts index acdeae4749..d84e023047 100644 --- a/libs/remix-debug/src/solidity-decoder/internalCallTree.ts +++ b/libs/remix-debug/src/solidity-decoder/internalCallTree.ts @@ -310,10 +310,10 @@ async function includeVariableDeclaration (tree, step, sourceLocation, scopeId, // } // input params if (inputs && inputs.parameters) { - functionDefinitionAndInputs.inputs = addParams(inputs, tree, scopeId, states, contractObj.name, previousSourceLocation, stack.length, inputs.parameters.length, -1) + functionDefinitionAndInputs.inputs = addParams(inputs, tree, scopeId, states, contractObj, previousSourceLocation, stack.length, inputs.parameters.length, -1) } // output params - if (outputs) addParams(outputs, tree, scopeId, states, contractObj.name, previousSourceLocation, stack.length, 0, 1) + if (outputs) addParams(outputs, tree, scopeId, states, contractObj, previousSourceLocation, stack.length, 0, 1) } } catch (error) { console.log(error) @@ -373,7 +373,8 @@ function extractFunctionDefinitions (ast, astWalker) { return ret } -function addParams (parameterList, tree, scopeId, states, contractName, sourceLocation, stackLength, stackPosition, dir) { +function addParams (parameterList, tree, scopeId, states, contractObj, sourceLocation, stackLength, stackPosition, dir) { + const contractName = contractObj.name const params = [] for (const inputParam in parameterList.parameters) { const param = parameterList.parameters[inputParam] @@ -386,7 +387,8 @@ function addParams (parameterList, tree, scopeId, states, contractName, sourceLo name: attributesName, type: parseType(param.typeDescriptions.typeString, states, contractName, location), stackDepth: stackDepth, - sourceLocation: sourceLocation + sourceLocation: sourceLocation, + abi: contractObj.contract.abi } params.push(attributesName) } diff --git a/libs/remix-debug/src/solidity-decoder/localDecoder.ts b/libs/remix-debug/src/solidity-decoder/localDecoder.ts index 89aba92a2a..9564efc93b 100644 --- a/libs/remix-debug/src/solidity-decoder/localDecoder.ts +++ b/libs/remix-debug/src/solidity-decoder/localDecoder.ts @@ -1,6 +1,6 @@ 'use strict' -export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storageResolver, currentSourceLocation, cursor) { +export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storageResolver, calldata, currentSourceLocation, cursor) { const scope = internalTreeCall.findScope(vmtraceIndex) if (!scope) { const error = { message: 'Can\'t display locals. reason: compilation result might not have been provided' } @@ -18,7 +18,7 @@ export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, mem anonymousIncr++ } try { - locals[name] = await variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver, cursor) + locals[name] = await variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver, calldata, cursor, variable) } catch (e) { console.log(e) locals[name] = '' diff --git a/libs/remix-debug/src/solidity-decoder/types/RefType.ts b/libs/remix-debug/src/solidity-decoder/types/RefType.ts index 97ce46a6a0..031d52f295 100644 --- a/libs/remix-debug/src/solidity-decoder/types/RefType.ts +++ b/libs/remix-debug/src/solidity-decoder/types/RefType.ts @@ -1,4 +1,5 @@ 'use strict' +import { ethers } from 'ethers' import { toBN } from './util' export class RefType { @@ -7,6 +8,7 @@ export class RefType { storageBytes typeName basicType + underlyingType constructor (storageSlots, storageBytes, typeName, location) { this.location = location @@ -33,7 +35,7 @@ export class RefType { * @param {Object} - storageResolver * @return {Object} decoded value */ - async decodeFromStack (stackDepth, stack, memory, storageResolver, cursor): Promise { + async decodeFromStack (stackDepth, stack, memory, storageResolver, calldata, cursor, variableDetails?): Promise { if (stack.length - 1 < stackDepth) { return { error: '', type: this.typeName } } @@ -49,6 +51,26 @@ export class RefType { } else if (this.isInMemory()) { offset = parseInt(offset, 16) return this.decodeFromMemoryInternal(offset, memory, cursor) + } else if (this.isInCallData()) { + calldata = calldata.length > 0 ? calldata[0] : '0x' + const ethersAbi = new ethers.utils.Interface(variableDetails.abi) + const fnSign = calldata.substr(0, 10) + const decodedData = ethersAbi.decodeFunctionData(ethersAbi.getFunction(fnSign), calldata) + let decodedValue = decodedData[variableDetails.name] + const isArray = Array.isArray(decodedValue) + if (isArray) { + decodedValue = decodedValue.map((el) => { + return { + value: el.toString(), + type: this.underlyingType.typeName + } + }) + } + return { + length: Array.isArray(decodedValue) ? '0x' + decodedValue.length.toString(16) : undefined, + value: decodedValue, + type: this.typeName + } } else { return { error: '', type: this.typeName } } @@ -84,4 +106,13 @@ export class RefType { isInMemory () { return this.location.indexOf('memory') === 0 } + + /** + * current type defined in storage + * + * @return {Bool} - return true if the type is defined in the storage + */ + isInCallData () { + return this.location.indexOf('calldata') === 0 + } } diff --git a/libs/remix-debug/src/solidity-decoder/types/StringType.ts b/libs/remix-debug/src/solidity-decoder/types/StringType.ts index 2c8f4cac60..8e31b3d17f 100644 --- a/libs/remix-debug/src/solidity-decoder/types/StringType.ts +++ b/libs/remix-debug/src/solidity-decoder/types/StringType.ts @@ -20,9 +20,9 @@ export class StringType extends DynamicByteArray { return format(decoded) } - async decodeFromStack (stackDepth, stack, memory) { + async decodeFromStack (stackDepth, stack, memory, calldata, variableDetails?) { try { - return await super.decodeFromStack(stackDepth, stack, memory, null, null) + return await super.decodeFromStack(stackDepth, stack, memory, null, calldata, variableDetails) } catch (e) { console.log(e) return '' diff --git a/libs/remix-debug/src/solidity-decoder/types/ValueType.ts b/libs/remix-debug/src/solidity-decoder/types/ValueType.ts index 61b4c65c54..63bd4ae0f0 100644 --- a/libs/remix-debug/src/solidity-decoder/types/ValueType.ts +++ b/libs/remix-debug/src/solidity-decoder/types/ValueType.ts @@ -43,7 +43,7 @@ export class ValueType { * @param {String} - memory * @return {Object} - decoded value */ - async decodeFromStack (stackDepth, stack, memory) { + async decodeFromStack (stackDepth, stack, memory, calldata, variableDetails?) { let value if (stackDepth >= stack.length) { value = this.decodeValue('') diff --git a/libs/remix-debug/test/decoder/localsTests/helper.ts b/libs/remix-debug/test/decoder/localsTests/helper.ts index 10537faee1..c041f4364a 100644 --- a/libs/remix-debug/test/decoder/localsTests/helper.ts +++ b/libs/remix-debug/test/decoder/localsTests/helper.ts @@ -22,13 +22,21 @@ export function decodeLocals (st, index, traceManager, callTree, verifier) { } catch (error) { callback(error) } + }, + function getCallDataAt (stepIndex, callback) { + try { + const result = traceManager.getCallDataAt(stepIndex) + callback(null, result) + } catch (error) { + callback(error) + } }], index, function (error, result) { if (error) { return st.fail(error) } - solidityLocals(index, callTree, result[0].value, result[1].value, {}, { start: 5000 }, null).then((locals) => { + solidityLocals(index, callTree, result[0].value, result[1].value, {}, result[2].value, { start: 5000 }, null).then((locals) => { verifier(locals) }) })