Last active
February 3, 2023 14:02
-
-
Save skozin/60e6ec7e9c56f34a7410db1cd11ffa34 to your computer and use it in GitHub Desktop.
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
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.9; | |
interface IMultiLocate { | |
function a() external view returns (address); | |
function b() external view returns (address); | |
function c() external view returns (address); | |
function d() external view returns (address); | |
function e() external view returns (address); | |
function f() external view returns (address); | |
function locate(bytes calldata selectors) external view returns (address[] memory addresses); | |
} | |
contract MultiLocate is IMultiLocate { | |
address public immutable a = 0xaAaabbbBAAaABbbbAAAaBbbbaaaABbBbaAaaBbBb; | |
address public immutable b = 0x1111Eeee1111eeEe1111EEee1111EeeE1111eeee; | |
address public immutable c = 0x2222FFff2222FfFF2222fFFF2222fFFf2222FFfF; | |
address public immutable d = 0x3333aAAa3333aAaa3333AaAa3333AAAa3333aAAa; | |
address public immutable e = 0x4444BbBb4444bbbb4444bbbB4444BbBb4444bBbB; | |
address public immutable f = 0x5555cCCC5555CCCC5555Cccc5555CCcc5555ccCC; | |
function getSelectors() external pure returns (bytes memory) { | |
return abi.encodePacked( | |
IMultiLocate.a.selector, | |
IMultiLocate.b.selector, | |
IMultiLocate.c.selector, | |
IMultiLocate.d.selector, | |
IMultiLocate.e.selector, | |
IMultiLocate.f.selector | |
); | |
} | |
function locate(bytes calldata selectors) external view returns (address[] memory addresses) { | |
require(selectors.length % 4 == 0); | |
uint256 numAddresses = selectors.length / 4; | |
address self = address(this); | |
assembly { | |
// allocate addresses array and selector memory | |
addresses := mload(0x40) | |
mstore(addresses, numAddresses) | |
// store offset for the 4-byte selector value | |
let selOffset := add(add(addresses, mul(numAddresses, 32)), 32) | |
// update free memory pointer | |
mstore(0x40, add(selOffset, 4)) | |
// loop over selectors and call fns | |
let cdOffset := selectors.offset | |
let addrOffset := add(addresses, 32) | |
let postEndCdOffset := add(cdOffset, selectors.length) | |
for {} lt(cdOffset, postEndCdOffset) {} { | |
calldatacopy(selOffset, cdOffset, 4) | |
let result := staticcall(1000, self, selOffset, 4, addrOffset, 32) | |
cdOffset := add(cdOffset, 4) | |
addrOffset := add(addrOffset, 32) | |
} | |
} | |
} | |
function locate2() external view returns (address[] memory addresses) { | |
addresses = new address[](6); | |
addresses[0] = a; | |
addresses[1] = b; | |
addresses[2] = c; | |
addresses[3] = d; | |
addresses[4] = e; | |
addresses[5] = f; | |
} | |
} | |
contract Consumer { | |
event Addr(address a, address b, address c, address d, address e, address f); | |
IMultiLocate _locator; | |
constructor(address locator) { | |
_locator = IMultiLocate(locator); | |
} | |
function consume1() external { | |
address[] memory addr = _locator.locate(abi.encodePacked( | |
IMultiLocate.a.selector, | |
IMultiLocate.b.selector, | |
IMultiLocate.c.selector, | |
IMultiLocate.d.selector, | |
IMultiLocate.e.selector, | |
IMultiLocate.f.selector | |
)); | |
emit Addr(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
} | |
function _getLocator() internal view returns (IMultiLocate) { | |
return IMultiLocate(_locator); | |
} | |
function consume2() external { | |
// emulate the proxy loading impl on each call | |
emit Addr(_getLocator().a(), _getLocator().b(), _getLocator().c(), _getLocator().d(), _getLocator().e(), _getLocator().f()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment