-
Notifications
You must be signed in to change notification settings - Fork 68
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
add support for prank(sender, origin) and startPrank(sender, origin) cheatcodes #336
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
f1e803b
WIP: beginning of startPrank(address sender, address origin)
karmacoma-eth 022e2df
add tests/test_prank.py
karmacoma-eth c1d5f9e
WIP: rework Prank class
karmacoma-eth 15ffcdb
add an origin field to Exec and wire pranks to it
karmacoma-eth 73f4478
finish wiring up new prank cheatcodes
karmacoma-eth d62c1eb
Merge branch 'main' into start-prank-origin
karmacoma-eth 1c3373b
simplify prank Target: recordCaller() -> reset()
karmacoma-eth 9939ca5
update tests/lib/multicaller to v1.3.2
karmacoma-eth 3ec4901
remove shallow from .gitmodules
karmacoma-eth 324f77d
delete multicaller
karmacoma-eth b6c1e48
replace multicaller submodule with a snapshot of the file we need
karmacoma-eth c051be4
update tests/lib/[email protected]
karmacoma-eth 8bb0d6f
test.yml: recursively checkout submodules
karmacoma-eth 707b9e1
test.yml: add --debug to halmos options
karmacoma-eth 656c359
test.yml: get back to a single pytest worker
karmacoma-eth de64d95
Revert "test.yml: recursively checkout submodules"
karmacoma-eth 09b6438
Merge branch 'main' into start-prank-origin
karmacoma-eth 1689032
add Prank test with nested contexts
karmacoma-eth 09b8066
add more Prank tests with nested contexts
karmacoma-eth df2c7a3
wire Prank inside CallContext rather than Exec
karmacoma-eth 1ea690c
add a startPrank in constructor test
karmacoma-eth c1c64e6
add test_prank_in_context
karmacoma-eth 17eba86
less convoluted code in prank/startPrank
karmacoma-eth 24f1493
Merge branch 'main' into start-prank-origin
karmacoma-eth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,15 @@ | ||
[submodule "tests/lib/forge-std"] | ||
path = tests/lib/forge-std | ||
url = https://github.com/foundry-rs/forge-std | ||
shallow = true | ||
[submodule "tests/lib/halmos-cheatcodes"] | ||
path = tests/lib/halmos-cheatcodes | ||
url = https://github.com/a16z/halmos-cheatcodes | ||
shallow = true | ||
[submodule "tests/lib/openzeppelin-contracts"] | ||
path = tests/lib/openzeppelin-contracts | ||
url = https://github.com/OpenZeppelin/openzeppelin-contracts | ||
shallow = true | ||
[submodule "tests/lib/solmate"] | ||
path = tests/lib/solmate | ||
url = https://github.com/transmissions11/solmate | ||
shallow = true | ||
[submodule "tests/lib/solady"] | ||
path = tests/lib/solady | ||
url = https://github.com/Vectorized/solady | ||
shallow = true | ||
[submodule "tests/lib/multicaller"] | ||
path = tests/lib/multicaller | ||
url = https://github.com/Vectorized/multicaller | ||
shallow = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
multicaller/=../../tests/lib/multicaller/src/ | ||
multicaller/=src/multicaller/ |
151 changes: 151 additions & 0 deletions
151
examples/simple/src/multicaller/MulticallerWithSender.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
/// from Vectorized/[email protected] | ||
|
||
/** | ||
* @title MulticallerWithSender | ||
* @author vectorized.eth | ||
* @notice Contract that allows for efficient aggregation of multiple calls | ||
* in a single transaction, while "forwarding" the `msg.sender`. | ||
*/ | ||
contract MulticallerWithSender { | ||
// ============================================================= | ||
// ERRORS | ||
// ============================================================= | ||
|
||
/** | ||
* @dev The lengths of the input arrays are not the same. | ||
*/ | ||
error ArrayLengthsMismatch(); | ||
|
||
/** | ||
* @dev This function does not support reentrancy. | ||
*/ | ||
error Reentrancy(); | ||
|
||
// ============================================================= | ||
// CONSTRUCTOR | ||
// ============================================================= | ||
|
||
constructor() payable { | ||
assembly { | ||
// Throughout this code, we will abuse returndatasize | ||
// in place of zero anywhere before a call to save a bit of gas. | ||
// We will use storage slot zero to store the caller at | ||
// bits [0..159] and reentrancy guard flag at bit 160. | ||
sstore(returndatasize(), shl(160, 1)) | ||
} | ||
} | ||
|
||
// ============================================================= | ||
// AGGREGATION OPERATIONS | ||
// ============================================================= | ||
|
||
/** | ||
* @dev Returns the address that called `aggregateWithSender` on this contract. | ||
* The value is always the zero address outside a transaction. | ||
*/ | ||
receive() external payable { | ||
assembly { | ||
mstore(returndatasize(), and(sub(shl(160, 1), 1), sload(returndatasize()))) | ||
return(returndatasize(), 0x20) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Aggregates multiple calls in a single transaction. | ||
* This method will set `sender` to the `msg.sender` temporarily | ||
* for the span of its execution. | ||
* This method does not support reentrancy. | ||
* @param targets An array of addresses to call. | ||
* @param data An array of calldata to forward to the targets. | ||
* @param values How much ETH to forward to each target. | ||
* @return An array of the returndata from each call. | ||
*/ | ||
function aggregateWithSender( | ||
address[] calldata targets, | ||
bytes[] calldata data, | ||
uint256[] calldata values | ||
) external payable returns (bytes[] memory) { | ||
assembly { | ||
if iszero(and(eq(targets.length, data.length), eq(data.length, values.length))) { | ||
// Store the function selector of `ArrayLengthsMismatch()`. | ||
mstore(returndatasize(), 0x3b800a46) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x04) | ||
} | ||
|
||
if iszero(and(sload(returndatasize()), shl(160, 1))) { | ||
// Store the function selector of `Reentrancy()`. | ||
mstore(returndatasize(), 0xab143c06) | ||
// Revert with (offset, size). | ||
revert(0x1c, 0x04) | ||
} | ||
|
||
mstore(returndatasize(), 0x20) // Store the memory offset of the `results`. | ||
mstore(0x20, data.length) // Store `data.length` into `results`. | ||
// Early return if no data. | ||
if iszero(data.length) { return(returndatasize(), 0x40) } | ||
|
||
// Set the sender slot temporarily for the span of this transaction. | ||
sstore(returndatasize(), caller()) | ||
|
||
let results := 0x40 | ||
// Left shift by 5 is equivalent to multiplying by 0x20. | ||
data.length := shl(5, data.length) | ||
// Copy the offsets from calldata into memory. | ||
calldatacopy(results, data.offset, data.length) | ||
// Offset into `results`. | ||
let resultsOffset := data.length | ||
// Pointer to the end of `results`. | ||
// Recycle `data.length` to avoid stack too deep. | ||
data.length := add(results, data.length) | ||
|
||
for {} 1 {} { | ||
// The offset of the current bytes in the calldata. | ||
let o := add(data.offset, mload(results)) | ||
let memPtr := add(resultsOffset, 0x40) | ||
// Copy the current bytes from calldata to the memory. | ||
calldatacopy( | ||
memPtr, | ||
add(o, 0x20), // The offset of the current bytes' bytes. | ||
calldataload(o) // The length of the current bytes. | ||
) | ||
if iszero( | ||
call( | ||
gas(), // Remaining gas. | ||
calldataload(targets.offset), // Address to call. | ||
calldataload(values.offset), // ETH to send. | ||
memPtr, // Start of input calldata in memory. | ||
calldataload(o), // Size of input calldata. | ||
0x00, // We will use returndatacopy instead. | ||
0x00 // We will use returndatacopy instead. | ||
) | ||
) { | ||
// Bubble up the revert if the call reverts. | ||
returndatacopy(0x00, 0x00, returndatasize()) | ||
revert(0x00, returndatasize()) | ||
} | ||
// Advance the `targets.offset`. | ||
targets.offset := add(targets.offset, 0x20) | ||
// Advance the `values.offset`. | ||
values.offset := add(values.offset, 0x20) | ||
// Append the current `resultsOffset` into `results`. | ||
mstore(results, resultsOffset) | ||
results := add(results, 0x20) | ||
// Append the returndatasize, and the returndata. | ||
mstore(memPtr, returndatasize()) | ||
returndatacopy(add(memPtr, 0x20), 0x00, returndatasize()) | ||
// Advance the `resultsOffset` by `returndatasize() + 0x20`, | ||
// rounded up to the next multiple of 0x20. | ||
resultsOffset := and(add(add(resultsOffset, returndatasize()), 0x3f), not(0x1f)) | ||
if iszero(lt(results, data.length)) { break } | ||
} | ||
// Restore the `sender` slot. | ||
sstore(0, shl(160, 1)) | ||
// Direct return. | ||
return(0x00, add(resultsOffset, 0x40)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
pytest -n 1
is what fixed CI, it seems that the issue was running multiple forge commands in parallel would result in race conditions trying to clone submodules or install solc