-
Notifications
You must be signed in to change notification settings - Fork 156
Refactor MultisigScript #170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🟡 Heimdall Review Status
|
jackchuma
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we need to support combinations of call + delegate calls. We've never needed that before and it's unknown if we will in the future, however this adds ~300 lines of code to support this use case. It could end up being useful, so I'm ok with adding this as an option. Just pointing out that it still is inherently a confusing component that isn't super easy to work with
| /// @param calls The calls to get the call3 values for. | ||
| /// | ||
| /// @return The calls in the format expected by the `aggregateDelegateCalls` function. | ||
| function _toDelegateCall3s(Call[] memory calls) internal pure returns (CBMulticall.Call3[] memory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is unused in the script
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but I figured it might still be useful if a script needs to do it (unlikely but it might be the case that we want to build a call to a Multicall from within the script directly). I don't feel strongly here though and ok to remove.
| /// @param calls The calls to get the call3 values for. | ||
| /// | ||
| /// @return The calls in the format expected by the `aggregate3` function. | ||
| function _toCall3Values(Call[] memory calls) internal pure returns (CBMulticall.Call3Value[] memory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is unused in the script
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but I figured it might still be useful if a script needs to do it (unlikely but it might be the case that we want to build a call to a Multicall from within the script directly). I don't feel strongly here though and ok to remove.
| signatures // signatures | ||
| ) | ||
| ), | ||
| value: 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is value alwayas 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the value would/should already be on the safe
I agree that we don’t need to support combinations of call and delegatecall, although future use cases might eventually require it. The only reason it is currently supported is because the user can explicitly set the
It’s closer to ~150 additional lines. A good portion of that comes from adding proper NatSpec comments that weren’t present before. Still, I agree that handling the
I also agree that this component has always been somewhat confusing. I find this version easier to reason about, because the script only manipulates I feel like the assumptions are clearer and safer in this version. We always delegatecall into a multicall, approvals are always performed with regular calls, and we avoid using a multicall when there is only a single call to execute. |
|
|
||
| # See more config options https://github.com/foundry-rs/foundry/tree/master/config | ||
| [lint] | ||
| lint_on_build = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not overly opinionated on this but I'd prefer to leave the linter enabled. I've found it helpful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a temporary workaround for this issue foundry-rs/foundry#11668
| }); | ||
| } | ||
|
|
||
| return calls; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style guide returns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not too opinionated but I think implicit return makes sense here as we're building the array element by element (and the returned value is named)
This PR refactors the
MultisigScriptlogic to remove unnecessaryMulticallwrapping, provide more flexibility when building script calls, and use our customCBMulticallinstead of the canonical implementation.The
_buildCalls()method now returns an array ofCallstructs:Each call specifies its own execution mode (
CallorDelegateCall) via theoperationfield. The internal_buildCallsChecked()method validates these calls, preventing invalid combinations such as non-zerovaluefor delegate calls.The Safe-to-Safe approval chain has been simplified: approvals are now direct
approveHashcalls without any multicall wrapping.The only remaining multicall wrapping occurs when
_buildCalls()returns multiple calls. If there is exactly one call, it is executed directly. When multiple calls exist,_buildAggregatedScriptCall()groups and aggregates compatible calls. For example, the following calls returned by_buildCalls():[ Call(Call, ContractA, abi.encodeCall(a, ()), 0), Call(Call, ContractB, abi.encodeCall(b, ()), 0), Call(DelegateCall, OPCM, abi.encodeCall(upgrade, ()), 0), Call(Call, ContractC, abi.encodeCall(c, ()), 100), Call(Call, ContractD, abi.encodeCall(d, ()), 200) ]are aggregated into: