Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"lib/LayerZero-v2/lib/forge-std/src/Base.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
import {StdStorage} from "./StdStorage.sol";
import {Vm, VmSafe} from "./Vm.sol";
abstract contract CommonBase {
// Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
// console.sol and console2.sol work by executing a staticcall to this address.
address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67;
// Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.
address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
// Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38.
address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller"))));
// Address of the test contract, deployed by the DEFAULT_SENDER.
address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
// Deterministic deployment address of the Multicall3 contract.
address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;
// The order of the secp256k1 curve.
uint256 internal constant SECP256K1_ORDER =
115792089237316195423570985008687907852837564279074904382605163141518161494337;
uint256 internal constant UINT256_MAX =
115792089237316195423570985008687907853269984665640564039457584007913129639935;
Vm internal constant vm = Vm(VM_ADDRESS);
StdStorage internal stdstore;
}
abstract contract TestBase is CommonBase {}
abstract contract ScriptBase is CommonBase {
VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS);
}
"
},
"lib/LayerZero-v2/lib/forge-std/src/Script.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
// ???? ABOUT
// Forge Std's default Script.
// ???? MODULES
import {console} from "./console.sol";
import {console2} from "./console2.sol";
import {safeconsole} from "./safeconsole.sol";
import {StdChains} from "./StdChains.sol";
import {StdCheatsSafe} from "./StdCheats.sol";
import {stdJson} from "./StdJson.sol";
import {stdMath} from "./StdMath.sol";
import {StdStorage, stdStorageSafe} from "./StdStorage.sol";
import {StdStyle} from "./StdStyle.sol";
import {StdUtils} from "./StdUtils.sol";
import {VmSafe} from "./Vm.sol";
// ???? BOILERPLATE
import {ScriptBase} from "./Base.sol";
// ⭐️ SCRIPT
abstract contract Script is ScriptBase, StdChains, StdCheatsSafe, StdUtils {
// Note: IS_SCRIPT() must return true.
bool public IS_SCRIPT = true;
}
"
},
"lib/LayerZero-v2/lib/forge-std/src/StdChains.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
import {VmSafe} from "./Vm.sol";
/**
* StdChains provides information about EVM compatible chains that can be used in scripts/tests.
* For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are
* identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of
* the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the
* alias used in this contract, which can be found as the first argument to the
* `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function.
*
* There are two main ways to use this contract:
* 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or
* `setChain(string memory chainAlias, Chain memory chain)`
* 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`.
*
* The first time either of those are used, chains are initialized with the default set of RPC URLs.
* This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in
* `defaultRpcUrls`.
*
* The `setChain` function is straightforward, and it simply saves off the given chain data.
*
* The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say
* we want to retrieve the RPC URL for `mainnet`:
* - If you have specified data with `setChain`, it will return that.
* - If you have configured a mainnet RPC URL in `foundry.toml`, it will return the URL, provided it
* is valid (e.g. a URL is specified, or an environment variable is given and exists).
* - If neither of the above conditions is met, the default data is returned.
*
* Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults.
*/
abstract contract StdChains {
VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
bool private stdChainsInitialized;
struct ChainData {
string name;
uint256 chainId;
string rpcUrl;
}
struct Chain {
// The chain name.
string name;
// The chain's Chain ID.
uint256 chainId;
// The chain's alias. (i.e. what gets specified in `foundry.toml`).
string chainAlias;
// A default RPC endpoint for this chain.
// NOTE: This default RPC URL is included for convenience to facilitate quick tests and
// experimentation. Do not use this RPC URL for production test suites, CI, or other heavy
// usage as you will be throttled and this is a disservice to others who need this endpoint.
string rpcUrl;
}
// Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data.
mapping(string => Chain) private chains;
// Maps from the chain's alias to it's default RPC URL.
mapping(string => string) private defaultRpcUrls;
// Maps from a chain ID to it's alias.
mapping(uint256 => string) private idToAlias;
bool private fallbackToDefaultRpcUrls = true;
// The RPC URL will be fetched from config or defaultRpcUrls if possible.
function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) {
require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string.");
initializeStdChains();
chain = chains[chainAlias];
require(
chain.chainId != 0,
string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found."))
);
chain = getChainWithUpdatedRpcUrl(chainAlias, chain);
}
function getChain(uint256 chainId) internal virtual returns (Chain memory chain) {
require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0.");
initializeStdChains();
string memory chainAlias = idToAlias[chainId];
chain = chains[chainAlias];
require(
chain.chainId != 0,
string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found."))
);
chain = getChainWithUpdatedRpcUrl(chainAlias, chain);
}
// set chain info, with priority to argument's rpcUrl field.
function setChain(string memory chainAlias, ChainData memory chain) internal virtual {
require(
bytes(chainAlias).length != 0,
"StdChains setChain(string,ChainData): Chain alias cannot be the empty string."
);
require(chain.chainId != 0, "StdChains setChain(string,ChainData): Chain ID cannot be 0.");
initializeStdChains();
string memory foundAlias = idToAlias[chain.chainId];
require(
bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)),
string(
abi.encodePacked(
"StdChains setChain(string,ChainData): Chain ID ",
vm.toString(chain.chainId),
" already used by \"",
foundAlias,
"\"."
)
)
);
uint256 oldChainId = chains[chainAlias].chainId;
delete idToAlias[oldChainId];
chains[chainAlias] =
Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl});
idToAlias[chain.chainId] = chainAlias;
}
// set chain info, with priority to argument's rpcUrl field.
function setChain(string memory chainAlias, Chain memory chain) internal virtual {
setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl}));
}
function _toUpper(string memory str) private pure returns (string memory) {
bytes memory strb = bytes(str);
bytes memory copy = new bytes(strb.length);
for (uint256 i = 0; i < strb.length; i++) {
bytes1 b = strb[i];
if (b >= 0x61 && b <= 0x7A) {
copy[i] = bytes1(uint8(b) - 32);
} else {
copy[i] = b;
}
}
return string(copy);
}
// lookup rpcUrl, in descending order of priority:
// current -> config (foundry.toml) -> environment variable -> default
function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) private returns (Chain memory) {
if (bytes(chain.rpcUrl).length == 0) {
try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) {
chain.rpcUrl = configRpcUrl;
} catch (bytes memory err) {
string memory envName = string(abi.encodePacked(_toUpper(chainAlias), "_RPC_URL"));
if (fallbackToDefaultRpcUrls) {
chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]);
} else {
chain.rpcUrl = vm.envString(envName);
}
// Distinguish 'not found' from 'cannot read'
// The upstream error thrown by forge for failing cheats changed so we check both the old and new versions
bytes memory oldNotFoundError =
abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias)));
bytes memory newNotFoundError = abi.encodeWithSignature(
"CheatcodeError(string)", string(abi.encodePacked("invalid rpc url: ", chainAlias))
);
bytes32 errHash = keccak256(err);
if (
(errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError))
|| bytes(chain.rpcUrl).length == 0
) {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, err), mload(err))
}
}
}
}
return chain;
}
function setFallbackToDefaultRpcUrls(bool useDefault) internal {
fallbackToDefaultRpcUrls = useDefault;
}
function initializeStdChains() private {
if (stdChainsInitialized) return;
stdChainsInitialized = true;
// If adding an RPC here, make sure to test the default RPC URL in `testRpcs`
setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545"));
setChainWithDefaultRpcUrl(
"mainnet", ChainData("Mainnet", 1, "https://mainnet.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001")
);
setChainWithDefaultRpcUrl(
"goerli", ChainData("Goerli", 5, "https://goerli.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001")
);
setChainWithDefaultRpcUrl(
"sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001")
);
setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io"));
setChainWithDefaultRpcUrl("optimism_goerli", ChainData("Optimism Goerli", 420, "https://goerli.optimism.io"));
setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc"));
setChainWithDefaultRpcUrl(
"arbitrum_one_goerli", ChainData("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc")
);
setChainWithDefaultRpcUrl("arbitrum_nova", ChainData("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc"));
setChainWithDefaultRpcUrl("polygon", ChainData("Polygon", 137, "https://polygon-rpc.com"));
setChainWithDefaultRpcUrl(
"polygon_mumbai", ChainData("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com")
);
setChainWithDefaultRpcUrl("avalanche", ChainData("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc"));
setChainWithDefaultRpcUrl(
"avalanche_fuji", ChainData("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc")
);
setChainWithDefaultRpcUrl(
"bnb_smart_chain", ChainData("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org")
);
setChainWithDefaultRpcUrl(
"bnb_smart_chain_testnet",
ChainData("BNB Smart Chain Testnet", 97, "https://rpc.ankr.com/bsc_testnet_chapel")
);
setChainWithDefaultRpcUrl("gnosis_chain", ChainData("Gnosis Chain", 100, "https://rpc.gnosischain.com"));
setChainWithDefaultRpcUrl("moonbeam", ChainData("Moonbeam", 1284, "https://rpc.api.moonbeam.network"));
setChainWithDefaultRpcUrl(
"moonriver", ChainData("Moonriver", 1285, "https://rpc.api.moonriver.moonbeam.network")
);
setChainWithDefaultRpcUrl("moonbase", ChainData("Moonbase", 1287, "https://rpc.testnet.moonbeam.network"));
setChainWithDefaultRpcUrl("base_goerli", ChainData("Base Goerli", 84531, "https://goerli.base.org"));
setChainWithDefaultRpcUrl("base", ChainData("Base", 8453, "https://mainnet.base.org"));
}
// set chain info, with priority to chainAlias' rpc url in foundry.toml
function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private {
string memory rpcUrl = chain.rpcUrl;
defaultRpcUrls[chainAlias] = rpcUrl;
chain.rpcUrl = "";
setChain(chainAlias, chain);
chain.rpcUrl = rpcUrl; // restore argument
}
}
"
},
"lib/LayerZero-v2/lib/forge-std/src/StdCheats.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
pragma experimental ABIEncoderV2;
import {StdStorage, stdStorage} from "./StdStorage.sol";
import {console2} from "./console2.sol";
import {Vm} from "./Vm.sol";
abstract contract StdCheatsSafe {
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
uint256 private constant UINT256_MAX =
115792089237316195423570985008687907853269984665640564039457584007913129639935;
bool private gasMeteringOff;
// Data structures to parse Transaction objects from the broadcast artifact
// that conform to EIP1559. The Raw structs is what is parsed from the JSON
// and then converted to the one that is used by the user for better UX.
struct RawTx1559 {
string[] arguments;
address contractAddress;
string contractName;
// json value name = function
string functionSig;
bytes32 hash;
// json value name = tx
RawTx1559Detail txDetail;
// json value name = type
string opcode;
}
struct RawTx1559Detail {
AccessList[] accessList;
bytes data;
address from;
bytes gas;
bytes nonce;
address to;
bytes txType;
bytes value;
}
struct Tx1559 {
string[] arguments;
address contractAddress;
string contractName;
string functionSig;
bytes32 hash;
Tx1559Detail txDetail;
string opcode;
}
struct Tx1559Detail {
AccessList[] accessList;
bytes data;
address from;
uint256 gas;
uint256 nonce;
address to;
uint256 txType;
uint256 value;
}
// Data structures to parse Transaction objects from the broadcast artifact
// that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON
// and then converted to the one that is used by the user for better UX.
struct TxLegacy {
string[] arguments;
address contractAddress;
string contractName;
string functionSig;
string hash;
string opcode;
TxDetailLegacy transaction;
}
struct TxDetailLegacy {
AccessList[] accessList;
uint256 chainId;
bytes data;
address from;
uint256 gas;
uint256 gasPrice;
bytes32 hash;
uint256 nonce;
bytes1 opcode;
bytes32 r;
bytes32 s;
uint256 txType;
address to;
uint8 v;
uint256 value;
}
struct AccessList {
address accessAddress;
bytes32[] storageKeys;
}
// Data structures to parse Receipt objects from the broadcast artifact.
// The Raw structs is what is parsed from the JSON
// and then converted to the one that is used by the user for better UX.
struct RawReceipt {
bytes32 blockHash;
bytes blockNumber;
address contractAddress;
bytes cumulativeGasUsed;
bytes effectiveGasPrice;
address from;
bytes gasUsed;
RawReceiptLog[] logs;
bytes logsBloom;
bytes status;
address to;
bytes32 transactionHash;
bytes transactionIndex;
}
struct Receipt {
bytes32 blockHash;
uint256 blockNumber;
address contractAddress;
uint256 cumulativeGasUsed;
uint256 effectiveGasPrice;
address from;
uint256 gasUsed;
ReceiptLog[] logs;
bytes logsBloom;
uint256 status;
address to;
bytes32 transactionHash;
uint256 transactionIndex;
}
// Data structures to parse the entire broadcast artifact, assuming the
// transactions conform to EIP1559.
struct EIP1559ScriptArtifact {
string[] libraries;
string path;
string[] pending;
Receipt[] receipts;
uint256 timestamp;
Tx1559[] transactions;
TxReturn[] txReturns;
}
struct RawEIP1559ScriptArtifact {
string[] libraries;
string path;
string[] pending;
RawReceipt[] receipts;
TxReturn[] txReturns;
uint256 timestamp;
RawTx1559[] transactions;
}
struct RawReceiptLog {
// json value = address
address logAddress;
bytes32 blockHash;
bytes blockNumber;
bytes data;
bytes logIndex;
bool removed;
bytes32[] topics;
bytes32 transactionHash;
bytes transactionIndex;
bytes transactionLogIndex;
}
struct ReceiptLog {
// json value = address
address logAddress;
bytes32 blockHash;
uint256 blockNumber;
bytes data;
uint256 logIndex;
bytes32[] topics;
uint256 transactionIndex;
uint256 transactionLogIndex;
bool removed;
}
struct TxReturn {
string internalType;
string value;
}
struct Account {
address addr;
uint256 key;
}
enum AddressType {
Payable,
NonPayable,
ZeroAddress,
Precompile,
ForgeAddress
}
// Checks that `addr` is not blacklisted by token contracts that have a blacklist.
function assumeNotBlacklisted(address token, address addr) internal view virtual {
// Nothing to check if `token` is not a contract.
uint256 tokenCodeSize;
assembly {
tokenCodeSize := extcodesize(token)
}
require(tokenCodeSize > 0, "StdCheats assumeNotBlacklisted(address,address): Token address is not a contract.");
bool success;
bytes memory returnData;
// 4-byte selector for `isBlacklisted(address)`, used by USDC.
(success, returnData) = token.staticcall(abi.encodeWithSelector(0xfe575a87, addr));
vm.assume(!success || abi.decode(returnData, (bool)) == false);
// 4-byte selector for `isBlackListed(address)`, used by USDT.
(success, returnData) = token.staticcall(abi.encodeWithSelector(0xe47d6060, addr));
vm.assume(!success || abi.decode(returnData, (bool)) == false);
}
// Checks that `addr` is not blacklisted by token contracts that have a blacklist.
// This is identical to `assumeNotBlacklisted(address,address)` but with a different name, for
// backwards compatibility, since this name was used in the original PR which has already has
// a release. This function can be removed in a future release once we want a breaking change.
function assumeNoBlacklisted(address token, address addr) internal view virtual {
assumeNotBlacklisted(token, addr);
}
function assumeAddressIsNot(address addr, AddressType addressType) internal virtual {
if (addressType == AddressType.Payable) {
assumeNotPayable(addr);
} else if (addressType == AddressType.NonPayable) {
assumePayable(addr);
} else if (addressType == AddressType.ZeroAddress) {
assumeNotZeroAddress(addr);
} else if (addressType == AddressType.Precompile) {
assumeNotPrecompile(addr);
} else if (addressType == AddressType.ForgeAddress) {
assumeNotForgeAddress(addr);
}
}
function assumeAddressIsNot(address addr, AddressType addressType1, AddressType addressType2) internal virtual {
assumeAddressIsNot(addr, addressType1);
assumeAddressIsNot(addr, addressType2);
}
function assumeAddressIsNot(
address addr,
AddressType addressType1,
AddressType addressType2,
AddressType addressType3
) internal virtual {
assumeAddressIsNot(addr, addressType1);
assumeAddressIsNot(addr, addressType2);
assumeAddressIsNot(addr, addressType3);
}
function assumeAddressIsNot(
address addr,
AddressType addressType1,
AddressType addressType2,
AddressType addressType3,
AddressType addressType4
) internal virtual {
assumeAddressIsNot(addr, addressType1);
assumeAddressIsNot(addr, addressType2);
assumeAddressIsNot(addr, addressType3);
assumeAddressIsNot(addr, addressType4);
}
// This function checks whether an address, `addr`, is payable. It works by sending 1 wei to
// `addr` and checking the `success` return value.
// NOTE: This function may result in state changes depending on the fallback/receive logic
// implemented by `addr`, which should be taken into account when this function is used.
function _isPayable(address addr) private returns (bool) {
require(
addr.balance < UINT256_MAX,
"StdCheats _isPayable(address): Balance equals max uint256, so it cannot receive any more funds"
);
uint256 origBalanceTest = address(this).balance;
uint256 origBalanceAddr = address(addr).balance;
vm.deal(address(this), 1);
(bool success,) = payable(addr).call{value: 1}("");
// reset balances
vm.deal(address(this), origBalanceTest);
vm.deal(addr, origBalanceAddr);
return success;
}
// NOTE: This function may result in state changes depending on the fallback/receive logic
// implemented by `addr`, which should be taken into account when this function is used. See the
// `_isPayable` method for more information.
function assumePayable(address addr) internal virtual {
vm.assume(_isPayable(addr));
}
function assumeNotPayable(address addr) internal virtual {
vm.assume(!_isPayable(addr));
}
function assumeNotZeroAddress(address addr) internal pure virtual {
vm.assume(addr != address(0));
}
function assumeNotPrecompile(address addr) internal pure virtual {
assumeNotPrecompile(addr, _pureChainId());
}
function assumeNotPrecompile(address addr, uint256 chainId) internal pure virtual {
// Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific
// address), but the same rationale for excluding them applies so we include those too.
// These should be present on all EVM-compatible chains.
vm.assume(addr < address(0x1) || addr > address(0x9));
// forgefmt: disable-start
if (chainId == 10 || chainId == 420) {
// https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21
vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800));
} else if (chainId == 42161 || chainId == 421613) {
// https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains
vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068));
} else if (chainId == 43114 || chainId == 43113) {
// https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59
vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff));
vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF));
vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff));
}
// forgefmt: disable-end
}
function assumeNotForgeAddress(address addr) internal pure virtual {
// vm, console, and Create2Deployer addresses
vm.assume(
addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67
&& addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C
);
}
function readEIP1559ScriptArtifact(string memory path)
internal
view
virtual
returns (EIP1559ScriptArtifact memory)
{
string memory data = vm.readFile(path);
bytes memory parsedData = vm.parseJson(data);
RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact));
EIP1559ScriptArtifact memory artifact;
artifact.libraries = rawArtifact.libraries;
artifact.path = rawArtifact.path;
artifact.timestamp = rawArtifact.timestamp;
artifact.pending = rawArtifact.pending;
artifact.txReturns = rawArtifact.txReturns;
artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts);
artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions);
return artifact;
}
function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) {
Tx1559[] memory txs = new Tx1559[](rawTxs.length);
for (uint256 i; i < rawTxs.length; i++) {
txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);
}
return txs;
}
function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) {
Tx1559 memory transaction;
transaction.arguments = rawTx.arguments;
transaction.contractName = rawTx.contractName;
transaction.functionSig = rawTx.functionSig;
transaction.hash = rawTx.hash;
transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail);
transaction.opcode = rawTx.opcode;
return transaction;
}
function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)
internal
pure
virtual
returns (Tx1559Detail memory)
{
Tx1559Detail memory txDetail;
txDetail.data = rawDetail.data;
txDetail.from = rawDetail.from;
txDetail.to = rawDetail.to;
txDetail.nonce = _bytesToUint(rawDetail.nonce);
txDetail.txType = _bytesToUint(rawDetail.txType);
txDetail.value = _bytesToUint(rawDetail.value);
txDetail.gas = _bytesToUint(rawDetail.gas);
txDetail.accessList = rawDetail.accessList;
return txDetail;
}
function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) {
string memory deployData = vm.readFile(path);
bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions");
RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[]));
return rawToConvertedEIPTx1559s(rawTxs);
}
function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) {
string memory deployData = vm.readFile(path);
string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]"));
bytes memory parsedDeployData = vm.parseJson(deployData, key);
RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559));
return rawToConvertedEIPTx1559(rawTx);
}
// Analogous to readTransactions, but for receipts.
function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) {
string memory deployData = vm.readFile(path);
bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts");
RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[]));
return rawToConvertedReceipts(rawReceipts);
}
function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) {
string memory deployData = vm.readFile(path);
string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]"));
bytes memory parsedDeployData = vm.parseJson(deployData, key);
RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt));
return rawToConvertedReceipt(rawReceipt);
}
function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) {
Receipt[] memory receipts = new Receipt[](rawReceipts.length);
for (uint256 i; i < rawReceipts.length; i++) {
receipts[i] = rawToConvertedReceipt(rawReceipts[i]);
}
return receipts;
}
function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) {
Receipt memory receipt;
receipt.blockHash = rawReceipt.blockHash;
receipt.to = rawReceipt.to;
receipt.from = rawReceipt.from;
receipt.contractAddress = rawReceipt.contractAddress;
receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice);
receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed);
receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed);
receipt.status = _bytesToUint(rawReceipt.status);
receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex);
receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber);
receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs);
receipt.logsBloom = rawReceipt.logsBloom;
receipt.transactionHash = rawReceipt.transactionHash;
return receipt;
}
function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)
internal
pure
virtual
returns (ReceiptLog[] memory)
{
ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length);
for (uint256 i; i < rawLogs.length; i++) {
logs[i].logAddress = rawLogs[i].logAddress;
logs[i].blockHash = rawLogs[i].blockHash;
logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber);
logs[i].data = rawLogs[i].data;
logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex);
logs[i].topics = rawLogs[i].topics;
logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex);
logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex);
logs[i].removed = rawLogs[i].removed;
}
return logs;
}
// Deploy a contract by fetching the contract bytecode from
// the artifacts directory
// e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`
function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) {
bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
/// @solidity memory-safe-assembly
assembly {
addr := create(0, add(bytecode, 0x20), mload(bytecode))
}
require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed.");
}
function deployCode(string memory what) internal virtual returns (address addr) {
bytes memory bytecode = vm.getCode(what);
/// @solidity memory-safe-assembly
assembly {
addr := create(0, add(bytecode, 0x20), mload(bytecode))
}
require(addr != address(0), "StdCheats deployCode(string): Deployment failed.");
}
/// @dev deploy contract with value on construction
function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) {
bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
/// @solidity memory-safe-assembly
assembly {
addr := create(val, add(bytecode, 0x20), mload(bytecode))
}
require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed.");
}
function deployCode(string memory what, uint256 val) internal virtual returns (address addr) {
bytes memory bytecode = vm.getCode(what);
/// @solidity memory-safe-assembly
assembly {
addr := create(val, add(bytecode, 0x20), mload(bytecode))
}
require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed.");
}
// creates a labeled address and the corresponding private key
function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) {
privateKey = uint256(keccak256(abi.encodePacked(name)));
addr = vm.addr(privateKey);
vm.label(addr, name);
}
// creates a labeled address
function makeAddr(string memory name) internal virtual returns (address addr) {
(addr,) = makeAddrAndKey(name);
}
// Destroys an account immediately, sending the balance to beneficiary.
// Destroying means: balance will be zero, code will be empty, and nonce will be 0
// This is similar to selfdestruct but not identical: selfdestruct destroys code and nonce
// only after tx ends, this will run immediately.
function destroyAccount(address who, address beneficiary) internal virtual {
uint256 currBalance = who.balance;
vm.etch(who, abi.encode());
vm.deal(who, 0);
vm.resetNonce(who);
uint256 beneficiaryBalance = beneficiary.balance;
vm.deal(beneficiary, currBalance + beneficiaryBalance);
}
// creates a struct containing both a labeled address and the corresponding private key
function makeAccount(string memory name) internal virtual returns (Account memory account) {
(account.addr, account.key) = makeAddrAndKey(name);
}
function deriveRememberKey(string memory mnemonic, uint32 index)
internal
virtual
returns (address who, uint256 privateKey)
{
privateKey = vm.deriveKey(mnemonic, index);
who = vm.rememberKey(privateKey);
}
function _bytesToUint(bytes memory b) private pure returns (uint256) {
require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32.");
return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
}
function isFork() internal view virtual returns (bool status) {
try vm.activeFork() {
status = true;
} catch (bytes memory) {}
}
modifier skipWhenForking() {
if (!isFork()) {
_;
}
}
modifier skipWhenNotForking() {
if (isFork()) {
_;
}
}
modifier noGasMetering() {
vm.pauseGasMetering();
// To prevent turning gas monitoring back on with nested functions that use this modifier,
// we check if gasMetering started in the off position. If it did, we don't want to turn
// it back on until we exit the top level function that used the modifier
//
// i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well.
// funcA will have `gasStartedOff` as false, funcB will have it as true,
// so we only turn metering back on at the end of the funcA
bool gasStartedOff = gasMeteringOff;
gasMeteringOff = true;
_;
// if gas metering was on when this modifier was called, turn it back on at the end
if (!gasStartedOff) {
gasMeteringOff = false;
vm.resumeGasMetering();
}
}
// We use this complex approach of `_viewChainId` and `_pureChainId` to ensure there are no
// compiler warnings when accessing chain ID in any solidity version supported by forge-std. We
// can't simply access the chain ID in a normal view or pure function because the solc View Pure
// Checker changed `chainid` from pure to view in 0.8.0.
function _viewChainId() private view returns (uint256 chainId) {
// Assembly required since `block.chainid` was introduced in 0.8.0.
assembly {
chainId := chainid()
}
address(this); // Silence warnings in older Solc versions.
}
function _pureChainId() private pure returns (uint256 chainId) {
function() internal view returns (uint256) fnIn = _viewChainId;
function() internal pure returns (uint256) pureChainId;
assembly {
pureChainId := fnIn
}
chainId = pureChainId();
}
}
// Wrappers around cheatcodes to avoid footguns
abstract contract StdCheats is StdCheatsSafe {
using stdStorage for StdStorage;
StdStorage private stdstore;
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;
// Skip forward or rewind time by the specified number of seconds
function skip(uint256 time) internal virtual {
vm.warp(block.timestamp + time);
}
function rewind(uint256 time) internal virtual {
vm.warp(block.timestamp - time);
}
// Setup a prank from an address that has some ether
function hoax(address msgSender) internal virtual {
vm.deal(msgSender, 1 << 128);
vm.prank(msgSender);
}
function hoax(address msgSender, uint256 give) internal virtual {
vm.deal(msgSender, give);
vm.prank(msgSender);
}
function hoax(address msgSender, address origin) internal virtual {
vm.deal(msgSender, 1 << 128);
vm.prank(msgSender, origin);
}
function hoax(address msgSender, address origin, uint256 give) internal virtual {
vm.deal(msgSender, give);
vm.prank(msgSender, origin);
}
// Start perpetual prank from an address that has some ether
function startHoax(address msgSender) internal virtual {
vm.deal(msgSender, 1 << 128);
vm.startPrank(msgSender);
}
function startHoax(address msgSender, uint256 give) internal virtual {
vm.deal(msgSender, give);
vm.startPrank(msgSender);
}
// Start perpetual prank from an address that has some ether
// tx.origin is set to the origin parameter
function startHoax(address msgSender, address origin) internal virtual {
vm.deal(msgSender, 1 << 128);
vm.startPrank(msgSender, origin);
}
function startHoax(address msgSender, address origin, uint256 give) internal virtual {
vm.deal(msgSender, give);
vm.startPrank(msgSender, origin);
}
function changePrank(address msgSender) internal virtual {
console2_log_StdCheats("changePrank is deprecated. Please use vm.startPrank instead.");
vm.stopPrank();
vm.startPrank(msgSender);
}
function changePrank(address msgSender, address txOrigin) internal virtual {
vm.stopPrank();
vm.startPrank(msgSender, txOrigin);
}
// The same as Vm's `deal`
// Use the alternative signature for ERC20 tokens
function deal(address to, uint256 give) internal virtual {
vm.deal(to, give);
}
// Set the balance of an account for any ERC20 token
// Use the alternative signature to update `totalSupply`
function deal(address token, address to, uint256 give) internal virtual {
deal(token, to, give, false);
}
// Set the balance of an account for any ERC1155 token
// Use the alternative signature to update `totalSupply`
function dealERC1155(address token, address to, uint256 id, uint256 give) internal virtual {
dealERC1155(token, to, id, give, false);
}
function deal(address token, address to, uint256 give, bool adjust) internal virtual {
// get current balance
(, bytes memory balData) = token.staticcall(abi.encodeWithSelector(0x70a08231, to));
uint256 prevBal = abi.decode(balData, (uint256));
// update balance
stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give);
// update total supply
if (adjust) {
(, bytes memory totSupData) = token.staticcall(abi.encodeWithSelector(0x18160ddd));
uint256 totSup = abi.decode(totSupData, (uint256));
if (give < prevBal) {
totSup -= (prevBal - give);
} else {
totSup += (give - prevBal);
}
stdstore.target(token).sig(0x18160ddd).checked_write(totSup);
}
}
function dealERC1155(address token, address to, uint256 id, uint256 give, bool adjust) internal virtual {
// get current balance
(, bytes memory balData) = token.staticcall(abi.encodeWithSelector(0x00fdd58e, to, id));
uint256 prevBal = abi.decode(balData, (uint256));
// update balance
stdstore.target(token).sig(0x00fdd58e).with_key(to).with_key(id).checked_write(give);
// update total supply
if (adjust) {
(, bytes memory totSupData) = token.staticcall(abi.encodeWithSelector(0xbd85b039, id));
require(
totSupData.length != 0,
"StdCheats deal(address,address,uint,uint,bool): target contract is not ERC1155Supply."
);
uint256 totSup = abi.decode(totSupData, (uint256));
if (give < prevBal) {
totSup -= (prevBal - give);
} else {
totSup += (give - prevBal);
}
stdstore.target(token).sig(0xbd85b039).with_key(id).checked_write(totSup);
}
}
function dealERC721(address token, address to, uint256 id) internal virtual {
// check if token id is already minted and the actual owner.
(bool successMinted, bytes memory ownerData) = token.staticcall(abi.encodeWithSelector(0x6352211e, id));
require(successMinted, "StdCheats deal(address,address,uint,bool): id not minted.");
// get owner current balance
(, bytes memory fromBalData) =
token.staticcall(abi.encodeWithSelector(0x70a08231, abi.decode(ownerData, (address))));
uint256 fromPrevBal = abi.decode(fromBalData, (uint256));
// get new user current balance
(, bytes memory toBalData) = token.staticcall(abi.encodeWithSelector(0x70a08231, to));
uint256 toPrevBal = abi.decode(toBalData, (uint256));
// update balances
stdstore.target(token).sig(0x70a08231).with_key(abi.decode(ownerData, (address))).checked_write(--fromPrevBal);
stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(++toPrevBal);
// update owner
stdstore.target(token).sig(0x6352211e).with_key(id).checked_write(to);
}
function deployCodeTo(string memory what, address where) internal virtual {
deployCodeTo(what, "", 0, where);
}
function deployCodeTo(string memory what, bytes memory args, address where) internal virtual {
deployCodeTo(what, args, 0, where);
}
function deployCodeTo(string memory what, bytes memory args, uint256 value, address where) internal virtual {
bytes memory creationCode = vm.getCode(what);
vm.etch(where, abi.encodePacked(creationCode, args));
(bool success, bytes memory runtimeBytecode) = where.call{value: value}("");
require(success, "StdCheats deployCodeTo(string,bytes,uint256,address): Failed to create runtime bytecode.");
vm.etch(where, runtimeBytecode);
}
// Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere.
function console2_log_StdCheats(string memory p0) private view {
(bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0));
status;
}
}
"
},
"lib/LayerZero-v2/lib/forge-std/src/StdJson.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
pragma experimental ABIEncoderV2;
import {VmSafe} from "./Vm.sol";
// Helpers for parsing and writing JSON files
// To parse:
// ```
// using stdJson for string;
// string memory json = vm.readFile("some_peth");
// json.parseUint("<json_path>");
// ```
// To write:
// ```
// using stdJson for string;
// string memory json = "deploymentArtifact";
// Contract contract = new Contract();
// json.serialize("contractAddress", address(contract));
// json = json.serialize("deploymentTimes", uint(1));
// // store the stringified JSON to the 'json' variable we have been using as a key
// // as we won't need it any longer
// string memory json2 = "finalArtifact";
// string memory final = json2.serialize("depArtifact", json);
// final.write("<some_path>");
// ```
library stdJson {
VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) {
return vm.parseJson(json, key);
}
function readUint(string memory json, string memory key) internal pure returns (uint256) {
return vm.parseJsonUint(json, key);
}
function readUintArray(string memory json, string memory key) internal pure returns (uint256[] memory) {
return vm.parseJsonUintArray(json, key);
}
function readInt(string memory json, string memory key) internal pure returns (int256) {
return vm.parseJsonInt(json, key);
}
function readIntArray(string memory json, string memory key) internal pure returns (int256[] memory) {
return vm.parseJsonIntArray(json, key);
}
function readBytes32(string memory json, string memory key) internal pure returns (bytes32) {
return vm.parseJsonBytes32(json, key);
}
function readBytes32Array(string memory json, string memory key) internal pure returns (bytes32[] memory) {
return vm.parseJsonBytes32Array(json, key);
}
function readString(string memory json, string memory key) internal pure returns (string memory) {
return vm.parseJsonString(json, key);
}
function readStringArray(string memory json, string memory key) internal pure returns (string[] memory) {
return vm.parseJsonStringArray(json, key);
}
function readAddress(string memory json, string memory key) internal pure returns (address) {
return vm.parseJsonAddress(json, key);
}
function readAddressArray(string memory json, string memory key) internal pure returns (address[] memory) {
return vm.parseJsonAddressArray(json, key);
}
function readBool(string memory json, string memory key) internal pure returns (bool) {
return vm.parseJsonBool(json, key);
}
function readBoolArray(string memory json, string memory key) internal pure returns (bool[] memory) {
return vm.parseJsonBoolArray(json, key);
}
function readBytes(string memory json, string memory key) internal pure returns (bytes memory) {
return vm.parseJsonBytes(json, key);
}
function readBytesArray(string memory json, string memory key) internal pure returns (bytes[] memory) {
return vm.parseJsonBytesArray(json, key);
}
function serialize(string memory jsonKey, string memory rootObject) internal returns (string memory) {
return vm.serializeJson(jsonKey, rootObject);
}
function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) {
return vm.serializeBool(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, bool[] memory value)
internal
returns (string memory)
{
return vm.serializeBool(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) {
return vm.serializeUint(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, uint256[] memory value)
internal
returns (string memory)
{
return vm.serializeUint(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) {
return vm.serializeInt(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, int256[] memory value)
internal
returns (string memory)
{
return vm.serializeInt(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) {
return vm.serializeAddress(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, address[] memory value)
internal
returns (string memory)
{
return vm.serializeAddress(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) {
return vm.serializeBytes32(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, bytes32[] memory value)
internal
returns (string memory)
{
return vm.serializeBytes32(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) {
return vm.serializeBytes(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, bytes[] memory value)
internal
returns (string memory)
{
return vm.serializeBytes(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, string memory value)
internal
returns (string memory)
{
return vm.serializeString(jsonKey, key, value);
}
function serialize(string memory jsonKey, string memory key, string[] memory value)
internal
returns (string memory)
{
return vm.serializeString(jsonKey, key, value);
}
function write(string memory jsonKey, string memory path) internal {
vm.writeJson(jsonKey, path);
}
function write(string memory jsonKey, string memory path, string memory valueKey) internal {
vm.writeJson(jsonKey, path, valueKey);
}
}
"
},
"lib/LayerZero-v2/lib/forge-std/src/StdMath.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
library stdMath {
int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;
function abs(int256 a) internal pure returns (uint256) {
// Required or it will fail when `a = type(int256).min`
if (a == INT256_MIN) {
return 57896044618658097711785492504343953926634992332820282019728792003956564819968;
}
return uint256(a > 0 ? a : -a);
}
function delta(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}
function delta(int256 a, int256 b) internal pure returns (uint256) {
// a and b are of the same sign
// this works thanks to two's complement, the left-most bit is the sign bit
if ((a ^ b) > -1) {
return delta(abs(a), abs(b));
}
// a and b are of opposite signs
return abs(a) + abs(b);
}
function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 absDelta = delta(a, b);
return absDelta * 1e18 / b;
}
function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
uint256 absDelta = delta(a, b);
uint256 absB = abs(b);
return absDelta * 1e18 / absB;
}
}
"
},
"lib/LayerZero-v2/lib/forge-std/src/StdStorage.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
import {Vm} from "./Vm.sol";
struct StdStorage {
mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots;
mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds;
bytes32[] _keys;
bytes4 _sig;
uint256 _depth;
address _target;
bytes32 _set;
}
library stdStorageSafe {
event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot);
event WARNING_UninitedSlot(address who, uint256 slot);
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
function sigs(string memory sigStr) internal pure returns (bytes4) {
return bytes4(keccak256(bytes(sigStr)));
}
/// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against
// slot complexity:
// if flat, will be bytes32(uint256(uint));
// if map, will be keccak256(abi.encode(key, uint(slot)));
// if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));
// if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);
function find(StdStorage storage self) internal returns (uint256) {
address who = self._target;
bytes4 fsig = self._sig;
uint256 field_depth = self._depth;
bytes32[] memory ins = self._keys;
// calldata to test against
if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
}
bytes memory cald = abi.encodePacked(fsig, flatten(ins));
vm.record();
bytes32 fdat;
{
(, bytes memory rdat) = who.staticcall(cald);
fdat = bytesToBytes32(rdat, 32 * field_depth);
}
(bytes32[] memory reads,) = vm.accesses(address(who));
if (reads.length == 1) {
bytes32 curr = vm.load(who, reads[0]);
if (curr == bytes32(0)) {
emit WARNING_UninitedSlot(who, uint256(reads[0]));
}
if (fdat != curr) {
require(
false,
"stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported."
);
}
emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0]));
self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]);
self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
} else if (reads.length > 1) {
for (uint256 i = 0; i < reads.length; i++) {
bytes32 prev = vm.load(who, reads[i]);
if (prev == bytes32(0)) {
emit WARNING_UninitedSlot(who, uint256(reads[i]));
}
if (prev != fdat) {
continue;
}
bytes32 new_val = ~prev;
// store
vm.store(who, reads[i], new_val);
bool success;
{
bytes memory rdat;
(success, rdat) = who.staticcall(cald);
fdat = bytesToBytes32(rdat, 32 * field_depth);
}
if (success && fdat == new_val) {
// we found which of the slots is the actual one
emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i]));
self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]);
self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
vm.store(who, reads[i], prev);
break;
}
vm.store(who, reads[i], prev);
}
} else {
revert("stdStorage find(StdStorage): No storage use detected for target.");
}
require(
self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))],
"stdStorage find(StdStorage): Slot(s) not found."
);
delete self._target;
delete self._sig;
delete self._keys;
delete self._depth;
return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
}
function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
self._target = _target;
return self;
}
function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
self._sig = _sig;
return self;
}
function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
self._sig = sigs(_sig);
return self;
}
function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
self._keys.push(bytes32(uint256(uint160(who))));
return self;
}
function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
self._keys.push(bytes32(amt));
return self;
}
function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
self._keys.push(key);
return self;
}
function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
self._depth = _depth;
return self;
}
function read(StdStorage storage self) private returns (bytes memory) {
address t = self._target;
uint256 s = find(self);
return abi.encode(vm.load(t, bytes32(s)));
}
function read_bytes32(StdStorage storage self) internal returns (bytes32) {
return abi.decode(read(self), (bytes32));
}
function read_bool(StdStorage storage self) internal returns (bool) {
int256 v = read_int(self);
if (v == 0) return false;
if (v == 1) return true;
revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
}
function read_address(StdStorage storage self) internal returns (address) {
return abi.decode(read(self), (address));
}
function read_uint(StdStorage storage self) internal returns (uint256) {
return abi.decode(read(self), (uint256));
}
function read_int(StdStorage storage self) internal returns (int256) {
return abi.decode(read(self), (int256));
}
function parent(StdStorage storage self) internal returns (uint256, bytes32) {
address who = self._target;
uint256 field_depth = self._depth;
vm.startMappingRecording();
uint256 child = find(self) - field_depth;
(bool found, bytes32 key, bytes32 parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(child));
if (!found) {
revert(
"stdStorage read_bool(StdStorage): Cannot find parent. Make sure you give a slot and startMappingRecording() has been called."
);
}
return (uint256(parent_slot), key);
}
function root(StdStorage storage self) internal returns (uint256) {
address who = self._target;
uint256 field_depth = self._depth;
vm.startMappingRecording();
uint256 child = find(self) - field_depth;
bool found;
bytes32 root_slot;
bytes32 parent_slot;
(found,, parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(child));
if (!found) {
revert(
"stdStorage read_bool(StdStorage): Cannot find parent. Make sure you give a slot and startMappingRecording() has been called."
);
}
while (found) {
root_slot = parent_slot;
(found,, parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(root_slot));
}
return uint256(root_slot);
}
function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) {
bytes32 out;
uint256 max = b.length > 32 ? 32 : b.length;
for (uint256 i = 0; i < max; i++) {
out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function flatten(bytes32[] memory b) private pure returns (bytes memory) {
bytes memory result = new bytes(b.length * 32);
for (uint256 i = 0; i < b.length; i++) {
bytes32 k = b[i];
/// @solidity memory-safe-assembly
assembly {
mstore(add(result, add(32, mul(32, i))), k)
}
}
return result;
}
}
library stdStorage {
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
function sigs(string memory sigStr) internal pure returns (bytes4) {
return stdStorageSafe.sigs(sigStr);
}
function find(StdStorage storage self) internal returns (uint256) {
return stdStorageSafe.find(self);
}
function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
return stdStorageSafe.target(self, _target);
}
function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
return stdS
Submitted on: 2025-10-29 09:54:12
Comments
Log in to comment.
No comments yet.