For testing/mocking purposes, I need to call a contract (A) from another contract (B) that just forwards the calls to (A).
The calls need to be forwarded, not delegated. And I don't want to rewrite every function of A in B, but instead use something generic.
My first approach was taking OpenZeppelin's (transparent) Proxy contract, @openzeppelin/contracts/proxy/Proxy.sol
and replace delegatecall
with call
.
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
// let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
let result := call(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
But it doesn't compiles, I get TypeError: Function "call" expects 7 arguments but got 6
Do you know the parameters of function call in assembly mode, or how can I implemented this forward non-transparent proxy?
call()
are described in Solidity Inline Assembly documentation pagecall()
documentation.// let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
bylet result := call(gas(), implementation, 0, 0, calldatasize(), 0, 0)
And it's working fine.callvalue()