-
Notifications
You must be signed in to change notification settings - Fork 32
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
feat(contracts-rfq): Multicall target abstraction [SLT-134] #3078
Conversation
function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external { | ||
for (uint256 i = 0; i < data.length; ++i) { | ||
// We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender` | ||
// calling the functions directly one by one, therefore doesn't add any security risks. | ||
// Note: msg.value is also preserved when doing a delegate call, but this function is not payable, | ||
// so it's always 0 and not a security risk. | ||
(bool success, bytes memory result) = address(this).delegatecall(data[i]); | ||
if (!success && !ignoreReverts) { | ||
_bubbleRevert(result); | ||
} | ||
} | ||
} |
Check notice
Code scanning / Slither
Calls inside a loop Low
function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external { | ||
for (uint256 i = 0; i < data.length; ++i) { | ||
// We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender` | ||
// calling the functions directly one by one, therefore doesn't add any security risks. | ||
// Note: msg.value is also preserved when doing a delegate call, but this function is not payable, | ||
// so it's always 0 and not a security risk. | ||
(bool success, bytes memory result) = address(this).delegatecall(data[i]); | ||
if (!success && !ignoreReverts) { | ||
_bubbleRevert(result); | ||
} | ||
} | ||
} |
Check warning
Code scanning / Slither
Low-level calls Warning
function multicallWithResults( | ||
bytes[] calldata data, | ||
bool ignoreReverts | ||
) | ||
external | ||
returns (Result[] memory results) | ||
{ | ||
results = new Result[](data.length); | ||
for (uint256 i = 0; i < data.length; ++i) { | ||
// We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender` | ||
// calling the functions directly one by one, therefore doesn't add any security risks. | ||
// Note: msg.value is also preserved when doing a delegate call, but this function is not payable, | ||
// so it's always 0 and not a security risk. | ||
(results[i].success, results[i].returnData) = address(this).delegatecall(data[i]); | ||
if (!results[i].success && !ignoreReverts) { | ||
_bubbleRevert(results[i].returnData); | ||
} | ||
} | ||
} |
Check notice
Code scanning / Slither
Calls inside a loop Low
function multicallWithResults( | ||
bytes[] calldata data, | ||
bool ignoreReverts | ||
) | ||
external | ||
returns (Result[] memory results) | ||
{ | ||
results = new Result[](data.length); | ||
for (uint256 i = 0; i < data.length; ++i) { | ||
// We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender` | ||
// calling the functions directly one by one, therefore doesn't add any security risks. | ||
// Note: msg.value is also preserved when doing a delegate call, but this function is not payable, | ||
// so it's always 0 and not a security risk. | ||
(results[i].success, results[i].returnData) = address(this).delegatecall(data[i]); | ||
if (!results[i].success && !ignoreReverts) { | ||
_bubbleRevert(results[i].returnData); | ||
} | ||
} | ||
} |
Check warning
Code scanning / Slither
Low-level calls Warning
function _bubbleRevert(bytes memory returnData) internal pure { | ||
// Look for revert reason and bubble it up if present | ||
if (returnData.length > 0) { | ||
// The easiest way to bubble the revert reason is using memory via assembly | ||
// solhint-disable-next-line no-inline-assembly | ||
assembly { | ||
let returndata_size := mload(returnData) | ||
revert(add(32, returnData), returndata_size) | ||
} | ||
} else { | ||
revert MulticallTarget__UndeterminedRevert(); | ||
} | ||
} |
Check warning
Code scanning / Slither
Assembly usage Warning
WalkthroughThe recent changes introduce a new interface and contract for handling multiple calls in Ethereum smart contracts, enhancing batch processing capabilities. The Changes
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #3078 +/- ##
===================================================
+ Coverage 23.09876% 25.87753% +2.77877%
===================================================
Files 193 178 -15
Lines 11624 10484 -1140
Branches 82 119 +37
===================================================
+ Hits 2685 2713 +28
+ Misses 8697 7532 -1165
+ Partials 242 239 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
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.
Actionable comments posted: 0
Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Files selected for processing (4)
- packages/contracts-rfq/contracts/interfaces/IMulticallTarget.sol (1 hunks)
- packages/contracts-rfq/contracts/utils/MulticallTarget.sol (1 hunks)
- packages/contracts-rfq/test/MulticallTarget.t.sol (1 hunks)
- packages/contracts-rfq/test/harnesses/MulticallTargetHarness.sol (1 hunks)
Additional context used
GitHub Check: Slither
packages/contracts-rfq/contracts/utils/MulticallTarget.sol
[notice] 19-30: Calls inside a loop
MulticallTarget.multicallNoResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#19-30) has external calls inside a loop: (success,result) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#25)
[warning] 19-30: Low-level calls
Low level call in MulticallTarget.multicallNoResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#19-30):
- (success,result) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#25)
[notice] 40-58: Calls inside a loop
MulticallTarget.multicallWithResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#40-58) has external calls inside a loop: (results[i].success,results[i].returnData) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#53)
[warning] 40-58: Low-level calls
Low level call in MulticallTarget.multicallWithResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#40-58):
- (results[i].success,results[i].returnData) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#53)
[warning] 63-75: Assembly usage
MulticallTarget._bubbleRevert(bytes) (contracts/utils/MulticallTarget.sol#63-75) uses assembly
- INLINE ASM (contracts/utils/MulticallTarget.sol#68-71)
Additional comments not posted (38)
packages/contracts-rfq/contracts/interfaces/IMulticallTarget.sol (4)
1-2
: LGTM!The SPDX license identifier and pragma directive are correctly specified.
6-10
: LGTM!The interface and struct are correctly defined.
12-12
: LGTM!The function
multicallNoResults
is correctly defined.
13-18
: LGTM!The function
multicallWithResults
is correctly defined.packages/contracts-rfq/test/harnesses/MulticallTargetHarness.sol (3)
1-2
: LGTM!The SPDX license identifier and pragma directive are correctly specified.
4-4
: LGTM!The import statement is correctly specified.
6-42
: LGTM!The contract and its functions are correctly defined.
packages/contracts-rfq/contracts/utils/MulticallTarget.sol (3)
1-2
: LGTM!The SPDX license identifier and pragma directive are correctly specified.
4-4
: LGTM!The import statement is correctly specified.
6-75
: LGTM!The contract and its functions are correctly defined.
Tools
GitHub Check: Slither
[notice] 19-30: Calls inside a loop
MulticallTarget.multicallNoResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#19-30) has external calls inside a loop: (success,result) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#25)
[warning] 19-30: Low-level calls
Low level call in MulticallTarget.multicallNoResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#19-30):
- (success,result) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#25)
[notice] 40-58: Calls inside a loop
MulticallTarget.multicallWithResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#40-58) has external calls inside a loop: (results[i].success,results[i].returnData) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#53)
[warning] 40-58: Low-level calls
Low level call in MulticallTarget.multicallWithResults(bytes[],bool) (contracts/utils/MulticallTarget.sol#40-58):
- (results[i].success,results[i].returnData) = address(this).delegatecall(data[i]) (contracts/utils/MulticallTarget.sol#53)
[warning] 63-75: Assembly usage
MulticallTarget._bubbleRevert(bytes) (contracts/utils/MulticallTarget.sol#63-75) uses assembly
- INLINE ASM (contracts/utils/MulticallTarget.sol#68-71)packages/contracts-rfq/test/MulticallTarget.t.sol (28)
1-2
: LGTM!The SPDX license identifier and pragma directive are correct.
4-7
: LGTM!The imports are necessary and correctly specified.
9-13
: LGTM!The contract declaration and state variables are necessary for the test setup.
15-19
: LGTM!The
setUp
function correctly initializes the test environment.
21-23
: LGTM!The
getEncodedStringRevertMessage
function correctly encodes the string revert message.
25-32
: LGTM!The
getMsgSenderData
function correctly encodes the function calls and returns them as an array.
34-41
: LGTM!The
getMsgSenderResults
function correctly creates and returns the array of results.
43-50
: LGTM!The
getNoRevertsData
function correctly encodes the function calls and returns them as an array.
52-59
: LGTM!The
getNoRevertsResults
function correctly creates and returns the array of results.
61-67
: LGTM!The
getCustomErrorRevertData
function correctly encodes the function calls and returns them as an array.
70-77
: LGTM!The
getCustomErrorRevertResults
function correctly creates and returns the array of results.
79-85
: LGTM!The
getStringRevertData
function correctly encodes the function calls and returns them as an array.
88-95
: LGTM!The
getStringRevertResults
function correctly creates and returns the array of results.
97-103
: LGTM!The
getUndeterminedRevertData
function correctly encodes the function calls and returns them as an array.
106-113
: LGTM!The
getUndeterminedRevertResults
function correctly creates and returns the array of results.
117-123
: LGTM!The
test_multicallNoResults_ignoreReverts_noReverts
function correctly tests themulticallNoResults
function.
125-132
: LGTM!The
test_multicallNoResults_ignoreReverts_withMsgSender
function correctly tests themulticallNoResults
function.
134-140
: LGTM!The
test_multicallNoResults_ignoreReverts_withCustomErrorRevert
function correctly tests themulticallNoResults
function.
142-148
: LGTM!The
test_multicallNoResults_ignoreReverts_withStringRevert
function correctly tests themulticallNoResults
function.
150-156
: LGTM!The
test_multicallNoResults_ignoreReverts_withUndeterminedRevert
function correctly tests themulticallNoResults
function.
158-164
: LGTM!The
test_multicallNoResults_dontIgnoreReverts_noReverts
function correctly tests themulticallNoResults
function.
166-173
: LGTM!The
test_multicallNoResults_dontIgnoreReverts_withMsgSender
function correctly tests themulticallNoResults
function.
175-179
: LGTM!The
test_multicallNoResults_dontIgnoreReverts_withCustomErrorRevert
function correctly tests themulticallNoResults
function.
181-186
: LGTM!The
test_multicallNoResults_dontIgnoreReverts_withStringRevert
function correctly tests themulticallNoResults
function.
188-192
: LGTM!The
test_multicallNoResults_dontIgnoreReverts_withUndeterminedRevert
function correctly tests themulticallNoResults
function.
196-203
: LGTM!The
test_multicallWithResults_ignoreReverts_noReverts
function correctly tests themulticallWithResults
function.
205-213
: LGTM!The
test_multicallWithResults_ignoreReverts_withMsgSender
function correctly tests themulticallWithResults
function.
215-222
: LGTM!The
test_multicallWithResults_ignoreReverts_withCustomErrorRevert
function correctly tests themulticallWithResults
function.
Description
Adds an abstract contract that is capable of receiving the multicall (batched calls) instructions from any account, including the EOAs (which don't have the built-in multicall feature on the vast majority of EVM chains).
The contract has two point of entries:
multicallNoResults
for doing batched calls when the returned value could be discarded. This is meant for EOAs to submit the transactions, as this saves gas and behaves identical tomulticallWithResults
outside of not forwarding the returned values from the calls.multicallWithResults
transaction doesn't have any additional benefit.multicallWithResults
for doing batched calls when the returned values are forwarded. This is meant for using viaeth_call
to effectively simulate the transaction execution without publishing and obtaining the results (this could also include the view functions). This could be also used by another contracts on-chain, if they care about getting the returned values and don't have an alternative way do do a batched call.Metadata
Completes SLT-134
Summary by CodeRabbit
New Features
Tests