I would like to implement a process similar to what Nick Johnson wrote about some years ago.
https://weka.medium.com/dividend-bearing-tokens-on-ethereum-42d01c710657
I'm using 0.8.19 and changing the version is not feasible.
In earlier compilers, it was possible to wrap state-changing operations in a view function, e.g. by attaching a modifier. The state would not be updated in static calls, but the return values would reflect the result of the state changes that would have occurred. If the same code was executed in a transaction, then the changes would stick.
One could, for example, attend to housekeeping or garbage collection in modifiers applied to both view
and mutating functions, which was very useful for avoiding repetition. Having used it, I know it worked at that time.
Modern compilers are very strict about this, which means that concise code needs considerable duplication and decomposition in order that view functions and updating functions to reach the same conclusion (I realize it's possible).
staticcall
reverts if the target changes the state. We expect that to happen every time and it's okay if it's forgotten until next time. It will stick when there is a real transaction and someone pays the gas.
I've looked at https://github.com/gnosis/util-contracts.git, which looks promising. Either I can't get it to work or it has the same problem. Reverts if the target of the "simulation" modifies state. I haven't ruled out that the error is in my contract that tries to use it.
Is this even possible? I expect the EVM can do this unless a fork is explicitly blocking what used to work.
Pseudo:
pragma solidity 0.8.19;
...
function simulateUpdate() external view returns (uint256 nextUp) {
nextUp = externalContract.mutatingFunction();
}
- It's not feasible to change the contract we want to inspect on this "what if" basis.
- It's not feasible to drop
view
from the function that wants to look (too disruptive). - It's acceptable if the changes (if any) stick.
- It's acceptable if the changes (if any) revert.
In case it is illustrative, this compiles:
pragma solidity 0.4.17;
contract Target {
uint256 x;
function foo(uint256 y) external returns (uint256) {
x = x+y;
return x;
}
}
contract Simulate {
Target public target;
uint256 public foo; // because a modifier can't return a value
modifier getFoo (uint256 a) {
foo = target.foo(a);
_;
}
function Simulate() public {
target = new Target();
}
// mutating activities in the view function
function bar(uint256 y) external view getFoo(y) returns (uint256) {
return foo;
}
}
view
function so they don't have to make major changes. I'm finding there may not be any way around the rules but I don't want to rule it out without asking. Maybe a kind soul knows a magic trick?