This repository has been archived by the owner on Nov 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
118 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ src/lib/abi/** | |
.nyc_output | ||
out/** | ||
lib/** | ||
src/mocks/MultiCallTest.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,117 @@ | ||
// Copyright 2024, Offchain Labs, Inc. | ||
// For license information, see https://github.com/nitro/blob/master/LICENSE | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
/* | ||
* this contract is the solidity equivalent of stylus multicall test contract | ||
* it should only be used for stylus tests, and it ignores good solidity good practices | ||
*/ | ||
|
||
contract MultiCallTest { | ||
event Called(address addr, uint8 count, bool success, bytes returnData); | ||
event Storage(bytes32 slot, bytes32 data, bool write); | ||
|
||
function getBE(bytes calldata data, uint8 numBytes) internal pure returns (uint256) { | ||
uint256 res = 0; | ||
for (uint8 i = 0; i < numBytes; i++) { | ||
res = res << 8; | ||
res = res | uint8(data[i]); | ||
} | ||
return res; | ||
} | ||
|
||
// solhint-disable no-complex-fallback | ||
// solhint-disable reason-string | ||
// solhint-disable avoid-low-level-calls | ||
// solhint-disable-next-line prettier/prettier | ||
fallback(bytes calldata input) external payable returns (bytes memory) { | ||
require(input.length > 0); | ||
uint8 count = uint8(input[0]); | ||
input = input[1:]; | ||
|
||
// combined output of all calls | ||
bytes memory output; | ||
|
||
for (uint8 i = 0; i < count; i++) { | ||
uint32 length = uint32(getBE(input, 4)); | ||
input = input[4:]; | ||
|
||
bytes calldata curr = input[:length]; | ||
input = input[length:]; | ||
|
||
uint8 kind = uint8(curr[0]); | ||
curr = curr[1:]; | ||
|
||
if (kind & 0xf0 == 0x0) { | ||
// call | ||
uint256 value; | ||
if (kind & 0x3 == 0) { | ||
value = getBE(curr, 32); | ||
curr = curr[32:]; | ||
} | ||
|
||
address addr = address(bytes20(curr[:20])); | ||
bytes calldata data = curr[20:]; | ||
bytes memory out; | ||
bool success; | ||
|
||
if (kind & 0x3 == 0) { | ||
(success, out) = addr.call{value: value}(data); | ||
} else if (kind & 0x3 == 1) { | ||
(success, out) = addr.delegatecall(data); | ||
} else if (kind & 0x3 == 2) { | ||
(success, out) = addr.staticcall(data); | ||
} else { | ||
revert("unknown call kind"); | ||
} | ||
if (!success) { | ||
if (kind & 0x4 == 0) { | ||
uint256 len = out.length; | ||
if (len > 0) { | ||
assembly { | ||
revert(add(out, 32), len) | ||
} | ||
} else { | ||
revert(); | ||
} | ||
} | ||
out = ""; | ||
} | ||
if (kind & 0x8 != 0) { | ||
emit Called(addr, count, success, out); | ||
} | ||
output = bytes.concat(output, out); | ||
} else if (kind & 0xf0 == 0x10) { | ||
// storage | ||
bytes32 slot = bytes32(curr[:32]); | ||
curr = curr[32:]; | ||
bytes32 data; | ||
bool write; | ||
if (kind & 0x3 == 0) { | ||
data = bytes32(curr[:32]); | ||
write = true; | ||
assembly { | ||
sstore(slot, data) | ||
} | ||
} else if (kind & 0x3 == 1){ | ||
write = false; | ||
assembly { | ||
data := sload(slot) | ||
} | ||
output = bytes.concat(output, data); | ||
} else { | ||
revert("unknown storage kind"); | ||
} | ||
if (kind & 0x8 != 0) { | ||
emit Storage(slot, data, write); | ||
} | ||
} else { | ||
revert("unknown command"); | ||
} | ||
} | ||
|
||
return output; | ||
} | ||
} |