feat(contracts): native ETH value support for ovmCALL#8
feat(contracts): native ETH value support for ovmCALL#8ben-chain wants to merge 14 commits intoregenesis/0.4.0from
Conversation
There was a problem hiding this comment.
I was able to import OVM_ETH here instead, but could not access OVM_ETH.balanceOf.selector for whatever reason...
There was a problem hiding this comment.
just noticed: this could be a staticcall
packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
Outdated
Show resolved
Hide resolved
packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
Outdated
Show resolved
Hide resolved
packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
Outdated
Show resolved
Hide resolved
packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
After talking this through with @maurelian this definitely needs to be fixed. We need to do some sort of enforcement of gasleft beforehand (perhaps line 1112 above becomes (success, returndata) = _contract.call{gas: min(_gasLimit, gasleft() - MIN_GAS_FOR_RETURN_VALUE_BACK) }(_data);
Otherwise, this code path here potentially allows a malicious contract to out-of-gas anyone who calls it with nonzero value, even if they only give the malicious contract a small portion of their own gas.
There was a problem hiding this comment.
In addition to ^^^ I'm going to give my understanding of the problem we're facing here and the proposed solution because I found it quite difficult to wrap my head around. This is based on conversation with @ben-chain (please correct me if you see any mistakes).
What we're trying to achieve here is to duplicate the behavior of EVM calls that come with attached value. Specifically, this behavior is as follows:
- If making a call with a value > 0 and the call fails, then the value IS NOT transferred to the recipient.
- If making a call with a value > 0 and the call succeeds, then the value IS transferred to the recipient.
- If making a call with a value > 0 and the user is unable to transfer funds (e.g., because they don't have enough balance OR because they don't have enough gas to execute the payment), then the value IS NOT transferred to the recipient AND the call fails with (success=false, returndata=0x). This IS how the EVM behaves. See geth: https://github.com/ethereum/go-ethereum/blob/2dee31930c9977af2a9fcb518fb9838aa609a7cf/core/vm/evm.go#L298
Case (2) is the straightforward happy path case.
Case (3) is also pretty easy to handle by checking for failure of the initial transfer.
Case (1) is slightly harder -- you want to revert the payment if the call fails. You can either do that by reverting the call frame in which the payment was transferred or by transferring the payment back to the original sender. Reverting the call frame here IS technically an option for cases where the transfer fails for some unexpected reason but we can avoid this because OVM_ETH is trusted. The only case we really need to be careful of is if we were to run out of gas when trying to transfer the ETH back. We could get around this by adding an extra call frame (expensive) or by making sure that the user always provides enough gas to execute both transfer steps when the value is greater than 0.
There was a problem hiding this comment.
on second thought: gonna leave these. Slightly more efficient and minimizes usage of an effectively deprecated code path
4572dfd to
ea5c006
Compare
There was a problem hiding this comment.
As discussed with @ben-chain, we can either attach the call value to the message context or pass it as a parameter to _callContract. Attaching the call value to the message context is probably best because it effectively is a message-specific parameter and it must be accessible for the sake of msg.value.
packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
In addition to ^^^ I'm going to give my understanding of the problem we're facing here and the proposed solution because I found it quite difficult to wrap my head around. This is based on conversation with @ben-chain (please correct me if you see any mistakes).
What we're trying to achieve here is to duplicate the behavior of EVM calls that come with attached value. Specifically, this behavior is as follows:
- If making a call with a value > 0 and the call fails, then the value IS NOT transferred to the recipient.
- If making a call with a value > 0 and the call succeeds, then the value IS transferred to the recipient.
- If making a call with a value > 0 and the user is unable to transfer funds (e.g., because they don't have enough balance OR because they don't have enough gas to execute the payment), then the value IS NOT transferred to the recipient AND the call fails with (success=false, returndata=0x). This IS how the EVM behaves. See geth: https://github.com/ethereum/go-ethereum/blob/2dee31930c9977af2a9fcb518fb9838aa609a7cf/core/vm/evm.go#L298
Case (2) is the straightforward happy path case.
Case (3) is also pretty easy to handle by checking for failure of the initial transfer.
Case (1) is slightly harder -- you want to revert the payment if the call fails. You can either do that by reverting the call frame in which the payment was transferred or by transferring the payment back to the original sender. Reverting the call frame here IS technically an option for cases where the transfer fails for some unexpected reason but we can avoid this because OVM_ETH is trusted. The only case we really need to be careful of is if we were to run out of gas when trying to transfer the ETH back. We could get around this by adding an extra call frame (expensive) or by making sure that the user always provides enough gas to execute both transfer steps when the value is greater than 0.
|
@smartcontracts that is a great writeup, right on the money. See here for proposed fix. |
34b479f to
7a59b2b
Compare
packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts
Outdated
Show resolved
Hide resolved
7a59b2b to
676ef59
Compare
* add ovmCALLVALUE context * add ovmBALANCE * test success and revert cases * test empty contract case * chore: lint
* fix ovmDELEGATECALL type, update tests * add ovmSELFBALANCE * fix ovmDELEGATECALL jumping to CALL * chore: lint
676ef59 to
f3d7b22
Compare
f3d7b22 to
2dc806f
Compare
Lots of good progress. Includes:
Still missing: