Skip to content
This repository has been archived by the owner on Nov 26, 2024. It is now read-only.

Commit

Permalink
add multicalltest contract
Browse files Browse the repository at this point in the history
  • Loading branch information
tsahee committed Apr 24, 2024
1 parent e3725f7 commit 4130267
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ src/lib/abi/**
.nyc_output
out/**
lib/**
src/mocks/MultiCallTest.sol
117 changes: 117 additions & 0 deletions src/mocks/MultiCallTest.sol
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;
}
}

0 comments on commit 4130267

Please sign in to comment.