// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;import {StdStorage} from"./StdStorage.sol";
import {Vm, VmSafe} from"./Vm.sol";
abstractcontractCommonBase{
// Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.addressinternalconstant VM_ADDRESS =address(uint160(uint256(keccak256("hevm cheat code"))));
// console.sol and console2.sol work by executing a staticcall to this address.addressinternalconstant CONSOLE =0x000000000000000000636F6e736F6c652e6c6f67;
// Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.addressinternalconstant CREATE2_FACTORY =0x4e59b44847b379578588920cA78FbF26c0B4956C;
// Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38.addressinternalconstant DEFAULT_SENDER =address(uint160(uint256(keccak256("foundry default caller"))));
// Address of the test contract, deployed by the DEFAULT_SENDER.addressinternalconstant DEFAULT_TEST_CONTRACT =0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
// Deterministic deployment address of the Multicall3 contract.addressinternalconstant MULTICALL3_ADDRESS =0xcA11bde05977b3631167028862bE2a173976CA11;
// The order of the secp256k1 curve.uint256internalconstant SECP256K1_ORDER =115792089237316195423570985008687907852837564279074904382605163141518161494337;
uint256internalconstant UINT256_MAX =115792089237316195423570985008687907853269984665640564039457584007913129639935;
Vm internalconstant vm = Vm(VM_ADDRESS);
StdStorage internal stdstore;
}
abstractcontractTestBaseisCommonBase{}
abstractcontractScriptBaseisCommonBase{
VmSafe internalconstant vmSafe = VmSafe(VM_ADDRESS);
}
Contract Source Code
File 2 of 29: Clock.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity >=0.8.19;import {ERC20} from"solmate/tokens/ERC20.sol";
import {IERC20} from"forge-std/interfaces/IERC20.sol";
import {Owned} from"solmate/auth/Owned.sol";
import {ClockStaking} from"./ClockStaking.sol";
import {IUniswapV2Factory} from"./interfaces/IUniswapV2Factory.sol";
import {IUniswapV2Router02} from"./interfaces/IUniswapV2Router02.sol";
contractClockClockisERC20, Owned{
uint256public TAX_AMOUNT =10;
uint256public TAX_POT_MAX =500_000e18;
uint256public MAX_TRANSFER_AMOUNT =1_000_000_000e18*2/10;
IUniswapV2Factory immutable uniswapFactory = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
IUniswapV2Router02 immutable uniswapRouter = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
//testnet//IUniswapV2Factory immutable uniswapFactory = IUniswapV2Factory(0x7E0987E5b3a30e3f2828572Bb659A548460a3003);//IUniswapV2Router02 immutable uniswapRouter = IUniswapV2Router02(0xC532a74256D3Db42D0Bf7a0400fEFDbad7694008);addressimmutable WETH =0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
//sepolia weth//address immutable WETH = 0xf531B8F309Be94191af87605CfBf600D71C2cFe0;addresspublic tokenPair;
addresspublic stakingContract;
addressinternal teamWallet;
boolpublic tradingPaused =false;
boolpublic whaleProtectionPeriod =false;
//@dev bool to control taxing during trasfers for dex swapsboolpublic isTaxOn =false;
errorTaxTooHigh();
errorWhaleProtectionActive();
eventTaxAmountChanged(uint256 newTaxAmount);
eventTradingPaused(bool, uint256block);
eventTax(addressindexed sender, uint256 taxAmount);
eventMaxPotChanged(uint256 newPotMax);
eventToggleTax(bool);
eventChangePayout(addressindexed newWallet);
modifieronlyStaking() virtual{
require(msg.sender== stakingContract, "UNAUTHORIZED");
_;
}
constructor(address _stakingContract, address _teamWallet) ERC20("Clock Clock", "CLOCK", 18) Owned(msg.sender) {
_mint(owner, 1_000_000_000e18);
stakingContract = _stakingContract;
teamWallet = _teamWallet;
tokenPair = uniswapFactory.createPair(address(this), WETH);
}
functioninitialize() externalonlyOwner{
IERC20(address(this)).approve(address(uniswapRouter), type(uint256).max);
isTaxOn =true;
whaleProtectionPeriod =true;
}
functionmint(address to, uint256 amount) externalonlyStaking{
_mint(to, amount);
}
functionburn(addressfrom, uint256 amount) externalonlyStaking{
_burn(from, amount);
}
functionpauseTrading(bool pause) externalonlyOwner{
tradingPaused = pause;
emit TradingPaused(pause, block.timestamp);
}
functionchangeTaxAmount(uint256 newTaxAmount) externalonlyOwner{
if (newTaxAmount >99) {
revert TaxTooHigh();
}
TAX_AMOUNT = newTaxAmount;
emit TaxAmountChanged(newTaxAmount);
}
functionchangeMaxPot(uint256 newPotMax) externalonlyOwner{
TAX_POT_MAX = newPotMax;
emit MaxPotChanged(newPotMax);
}
functiontoggleTax(bool value) externalonlyOwner{
isTaxOn = value;
emit ToggleTax(value);
}
functiontoggleWhaleProtection(bool value) externalonlyOwner{
whaleProtectionPeriod = value;
}
functionsetTeamWallet(address wallet) externalonlyOwner{
teamWallet = wallet;
emit ChangePayout(wallet);
}
//@dev in case something goes wrong and we end up with a different liquidity token address(this shouldn't happen but just in case)functionupdateTokenPair(address newTokenPair) externalonlyOwner{
tokenPair = newTokenPair;
}
functionupdateStakingContract(address newStakingContract) externalonlyOwner{
stakingContract = newStakingContract;
}
function_addTax(uint256 amount) internalviewreturns (uint256) {
return (amount * TAX_AMOUNT) /100;
}
function_swapAndPayOut() internal{
//avoids weird recursion loop
isTaxOn =false;
address[] memory path =newaddress[](2);
path[0] =address(this);
path[1] = WETH;
//we don't care about slippage here since there might be very low liquidity, and//we still want the sale to succeed no matter what
uniswapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
balanceOf[address(this)], 0, path, teamWallet, block.timestamp
);
//tax back on after swap
isTaxOn =true;
}
functiontransfer(address to, uint256 amount) publicvirtualoverridereturns (bool) {
if (whaleProtectionPeriod ==true&& amount >= MAX_TRANSFER_AMOUNT) {
revert WhaleProtectionActive();
}
if (balanceOf[address(this)] >= TAX_POT_MAX && isTaxOn) {
_swapAndPayOut();
}
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.if (msg.sender== owner ||msg.sender==address(this) ||msg.sender== stakingContract) {
unchecked {
balanceOf[to] += amount;
}
} else {
unchecked {
balanceOf[to] += amount - _addTax(amount);
balanceOf[address(this)] += _addTax(amount);
}
}
emit Transfer(msg.sender, to, amount - _addTax(amount));
emit Tax(msg.sender, _addTax(amount));
returntrue;
}
functiontransferFrom(addressfrom, address to, uint256 amount) publicvirtualoverridereturns (bool) {
if (whaleProtectionPeriod ==true&& amount >= MAX_TRANSFER_AMOUNT) {
revert WhaleProtectionActive();
}
if (balanceOf[address(this)] >= TAX_POT_MAX && isTaxOn) {
_swapAndPayOut();
}
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.if (allowed !=type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.if (from== owner ||from==address(this) ||from== stakingContract) {
unchecked {
balanceOf[to] += amount;
}
} else {
unchecked {
balanceOf[to] += amount - _addTax(amount);
balanceOf[address(this)] += _addTax(amount);
}
}
emit Transfer(from, to, amount - _addTax(amount));
emit Tax(from, _addTax(amount));
returntrue;
}
}
Contract Source Code
File 3 of 29: ClockStaking.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity >=0.8.19;import {ERC20} from"solmate/tokens/ERC20.sol";
import {Owned} from"solmate/auth/Owned.sol";
import {SafeTransferLib} from"solmate/utils/SafeTransferLib.sol";
import {ClockClock} from"./Clock.sol";
//TODO removeimport {Test, console2} from"forge-std/Test.sol";
contractClockStakingisOwned, Test{
usingSafeTransferLibforERC20;
structStakingBalance {
uint256 deposited;
uint256 stakeStart;
uint256 stakeEnd;
}
uint256immutable MULTIPLIER =10;
uint256immutable DENOMINATOR =10000;
ClockClock public clock;
mapping(address=> StakingBalance) public stakingBalances;
eventStaked(addressindexed staker, uint256 amount, uint256 timestamp);
eventUnstaked(addressindexed staker, uint256 timestamp);
eventClaim(addressindexed staker, uint256 amount, uint256 timestamp);
errorZeroAmount();
errorPeriodNotFinished();
errorPeriodStillActive();
errorPeriodAlreadyStarted();
constructor(ClockClock _clock) Owned(msg.sender) {
clock = _clock;
}
/*
* Stakes a users funds
* @param amount - the amount to be taken from the user, not including tax
* @dev the final amount staked is inclusive of the tax
*/functionstake(uint256 amount) external{
if (amount ==0) {
revert ZeroAmount();
}
if (stakingBalances[msg.sender].stakeEnd !=0) {
revert PeriodStillActive();
}
ERC20(address(clock)).safeTransferFrom(msg.sender, address(this), amount);
//account for tax
amount -= (amount * clock.TAX_AMOUNT()) /100;
stakingBalances[msg.sender].deposited += amount;
//redepositing more will reset your staking time, this is desired behavior
stakingBalances[msg.sender].stakeStart =block.timestamp;
stakingBalances[msg.sender].stakeEnd =0; //if they restake during a holding period, we reset their time to 0 //this shouldn't happen now that we're checking, but just in case, I'll leave itemit Staked(msg.sender, amount, block.timestamp);
}
/*
* Unstakes a users funds and begins the 3 day holding period
*/functionunstake() external{
StakingBalance storage user = stakingBalances[msg.sender];
if (user.stakeEnd !=0) {
revert PeriodAlreadyStarted();
}
user.stakeEnd =block.timestamp;
emit Unstaked(msg.sender, block.timestamp);
}
/*
* Claims a users funds after the 3 day holding period is over
* @dev a user must claim before being able to restake
*/functionclaim() externalreturns (uint256) {
StakingBalance storage user = stakingBalances[msg.sender];
if (block.timestamp< user.stakeEnd +72hours|| user.stakeEnd ==0) {
revert PeriodNotFinished();
}
uint256 amountToWithdraw = multiplyStakingBalance(msg.sender);
//burn the user's deposit since we are minting new coins
clock.burn(address(this), user.deposited);
user.deposited =0;
user.stakeStart =0;
user.stakeEnd =0;
//mint the entire amount on unstake
clock.mint(msg.sender, amountToWithdraw);
emit Claim(msg.sender, amountToWithdraw, block.timestamp);
return amountToWithdraw;
}
/*
* Claims a users funds after the 3 day holding period is over
* @param user the user to get the balance from
*/functionmultiplyStakingBalance(address user) publicviewreturns (uint256) {
uint256 end;
if (stakingBalances[user].stakeEnd ==0) {
end =block.timestamp;
} else {
end = stakingBalances[user].stakeEnd;
}
uint256 timeStaked = (end - stakingBalances[user].stakeStart);
uint256 startingBalance = stakingBalances[user].deposited;
uint256 daysStaked = timeStaked /1days;
uint256 hoursStaked = timeStaked /1hours;
uint256 amountPlusInterest;
if (daysStaked >0) {
uint256 bal = startingBalance;
uint256 leftoverHours = hoursStaked - (daysStaked *24);
uint256 hoursToPass;
//so basically, if we have 1 day -> we loop and then get the extra hours//on the extra loop//so we need daysStaked + 1for (uint256 i =0; i < daysStaked +1;) {
//if we are on our final loop iterationif (i == daysStaked) {
hoursToPass = leftoverHours;
} else {
hoursToPass =24;
}
amountPlusInterest = _getInterestHourly(bal, hoursToPass);
bal = amountPlusInterest;
unchecked {
i++;
}
}
} else {
amountPlusInterest = _getInterestHourly(startingBalance, hoursStaked);
}
return amountPlusInterest;
}
function_getInterestHourly(uint256 startingBalance, uint256 hoursStaked) internalpurereturns (uint256) {
uint256 mult = MULTIPLIER; //local copyuint256 hourlyInterest; //saves gasfor (uint256 i =0; i < hoursStaked;) {
hourlyInterest = (startingBalance * mult) / DENOMINATOR;
startingBalance += hourlyInterest;
mult +=10;
unchecked {
i++;
}
}
return startingBalance;
}
}
Contract Source Code
File 4 of 29: ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity >=0.8.0;/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation./// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.abstractcontractERC20{
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/eventTransfer(addressindexedfrom, addressindexed to, uint256 amount);
eventApproval(addressindexed owner, addressindexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/stringpublic name;
stringpublic symbol;
uint8publicimmutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/uint256public totalSupply;
mapping(address=>uint256) public balanceOf;
mapping(address=>mapping(address=>uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/uint256internalimmutable INITIAL_CHAIN_ID;
bytes32internalimmutable INITIAL_DOMAIN_SEPARATOR;
mapping(address=>uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/constructor(stringmemory _name,
stringmemory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID =block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/functionapprove(address spender, uint256 amount) publicvirtualreturns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
returntrue;
}
functiontransfer(address to, uint256 amount) publicvirtualreturns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
returntrue;
}
functiontransferFrom(addressfrom,
address to,
uint256 amount
) publicvirtualreturns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.if (allowed !=type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
returntrue;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/functionpermit(address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) publicvirtual{
require(deadline >=block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing// the owner's nonce which cannot realistically overflow.unchecked {
address recoveredAddress =ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress !=address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
functionDOMAIN_SEPARATOR() publicviewvirtualreturns (bytes32) {
returnblock.chainid== INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
functioncomputeDomainSeparator() internalviewvirtualreturns (bytes32) {
returnkeccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/function_mint(address to, uint256 amount) internalvirtual{
totalSupply += amount;
// Cannot overflow because the sum of all user// balances can't exceed the max uint256 value.unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function_burn(addressfrom, uint256 amount) internalvirtual{
balanceOf[from] -= amount;
// Cannot underflow because a user's balance// will never be larger than the total supply.unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
Contract Source Code
File 5 of 29: IERC20.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2;/// @dev Interface of the ERC20 standard as defined in the EIP./// @dev This includes the optional name, symbol, and decimals metadata.interfaceIERC20{
/// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`/// is the new allowance.eventApproval(addressindexed owner, addressindexed spender, uint256 value);
/// @notice Returns the amount of tokens in existence.functiontotalSupply() externalviewreturns (uint256);
/// @notice Returns the amount of tokens owned by `account`.functionbalanceOf(address account) externalviewreturns (uint256);
/// @notice Moves `amount` tokens from the caller's account to `to`.functiontransfer(address to, uint256 amount) externalreturns (bool);
/// @notice Returns the remaining number of tokens that `spender` is allowed/// to spend on behalf of `owner`functionallowance(address owner, address spender) externalviewreturns (uint256);
/// @notice Sets `amount` as the allowance of `spender` over the caller's tokens./// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729functionapprove(address spender, uint256 amount) externalreturns (bool);
/// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism./// `amount` is then deducted from the caller's allowance.functiontransferFrom(addressfrom, address to, uint256 amount) externalreturns (bool);
/// @notice Returns the name of the token.functionname() externalviewreturns (stringmemory);
/// @notice Returns the symbol of the token.functionsymbol() externalviewreturns (stringmemory);
/// @notice Returns the decimals places of the token.functiondecimals() externalviewreturns (uint8);
}
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity >=0.8.0;import {ERC20} from"../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values./// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer./// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.librarySafeTransferLib{
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/functionsafeTransferETH(address to, uint256 amount) internal{
bool success;
/// @solidity memory-safe-assemblyassembly {
// Transfer the ETH and store if it succeeded or not.
success :=call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/functionsafeTransferFrom(
ERC20 token,
addressfrom,
address to,
uint256 amount
) internal{
bool success;
/// @solidity memory-safe-assemblyassembly {
// Get a pointer to some free memory.let freeMemoryPointer :=mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success :=and(
// Set success to whether the call reverted, if not we check it either// returned exactly 1 (can't just be non-zero data), or had no return data.or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.// Counterintuitively, this call must be positioned second to the or() call in the// surrounding and() call or else returndatasize() will be zero during the computation.call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
functionsafeTransfer(
ERC20 token,
address to,
uint256 amount
) internal{
bool success;
/// @solidity memory-safe-assemblyassembly {
// Get a pointer to some free memory.let freeMemoryPointer :=mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success :=and(
// Set success to whether the call reverted, if not we check it either// returned exactly 1 (can't just be non-zero data), or had no return data.or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.// Counterintuitively, this call must be positioned second to the or() call in the// surrounding and() call or else returndatasize() will be zero during the computation.call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
functionsafeApprove(
ERC20 token,
address to,
uint256 amount
) internal{
bool success;
/// @solidity memory-safe-assemblyassembly {
// Get a pointer to some free memory.let freeMemoryPointer :=mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success :=and(
// Set success to whether the call reverted, if not we check it either// returned exactly 1 (can't just be non-zero data), or had no return data.or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.// Counterintuitively, this call must be positioned second to the or() call in the// surrounding and() call or else returndatasize() will be zero during the computation.call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
Contract Source Code
File 14 of 29: StdAssertions.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;import {DSTest} from"ds-test/test.sol";
import {stdMath} from"./StdMath.sol";
abstractcontractStdAssertionsisDSTest{
eventlog_array(uint256[] val);
eventlog_array(int256[] val);
eventlog_array(address[] val);
eventlog_named_array(string key, uint256[] val);
eventlog_named_array(string key, int256[] val);
eventlog_named_array(string key, address[] val);
functionfail(stringmemory err) internalvirtual{
emit log_named_string("Error", err);
fail();
}
functionassertFalse(bool data) internalvirtual{
assertTrue(!data);
}
functionassertFalse(bool data, stringmemory err) internalvirtual{
assertTrue(!data, err);
}
functionassertEq(bool a, bool b) internalvirtual{
if (a != b) {
emit log("Error: a == b not satisfied [bool]");
emit log_named_string(" Left", a ? "true" : "false");
emit log_named_string(" Right", b ? "true" : "false");
fail();
}
}
functionassertEq(bool a, bool b, stringmemory err) internalvirtual{
if (a != b) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
functionassertEq(bytesmemory a, bytesmemory b) internalvirtual{
assertEq0(a, b);
}
functionassertEq(bytesmemory a, bytesmemory b, stringmemory err) internalvirtual{
assertEq0(a, b, err);
}
functionassertEq(uint256[] memory a, uint256[] memory b) internalvirtual{
if (keccak256(abi.encode(a)) !=keccak256(abi.encode(b))) {
emit log("Error: a == b not satisfied [uint[]]");
emit log_named_array(" Left", a);
emit log_named_array(" Right", b);
fail();
}
}
functionassertEq(int256[] memory a, int256[] memory b) internalvirtual{
if (keccak256(abi.encode(a)) !=keccak256(abi.encode(b))) {
emit log("Error: a == b not satisfied [int[]]");
emit log_named_array(" Left", a);
emit log_named_array(" Right", b);
fail();
}
}
functionassertEq(address[] memory a, address[] memory b) internalvirtual{
if (keccak256(abi.encode(a)) !=keccak256(abi.encode(b))) {
emit log("Error: a == b not satisfied [address[]]");
emit log_named_array(" Left", a);
emit log_named_array(" Right", b);
fail();
}
}
functionassertEq(uint256[] memory a, uint256[] memory b, stringmemory err) internalvirtual{
if (keccak256(abi.encode(a)) !=keccak256(abi.encode(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
functionassertEq(int256[] memory a, int256[] memory b, stringmemory err) internalvirtual{
if (keccak256(abi.encode(a)) !=keccak256(abi.encode(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
functionassertEq(address[] memory a, address[] memory b, stringmemory err) internalvirtual{
if (keccak256(abi.encode(a)) !=keccak256(abi.encode(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
// Legacy helperfunctionassertEqUint(uint256 a, uint256 b) internalvirtual{
assertEq(uint256(a), uint256(b));
}
functionassertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_uint(" Left", a);
emit log_named_uint(" Right", b);
emit log_named_uint(" Max Delta", maxDelta);
emit log_named_uint(" Delta", delta);
fail();
}
}
functionassertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, stringmemory err) internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbs(a, b, maxDelta);
}
}
functionassertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_decimal_uint(" Left", a, decimals);
emit log_named_decimal_uint(" Right", b, decimals);
emit log_named_decimal_uint(" Max Delta", maxDelta, decimals);
emit log_named_decimal_uint(" Delta", delta, decimals);
fail();
}
}
functionassertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, stringmemory err)
internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbsDecimal(a, b, maxDelta, decimals);
}
}
functionassertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_int(" Left", a);
emit log_named_int(" Right", b);
emit log_named_uint(" Max Delta", maxDelta);
emit log_named_uint(" Delta", delta);
fail();
}
}
functionassertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, stringmemory err) internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbs(a, b, maxDelta);
}
}
functionassertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals) internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_decimal_int(" Left", a, decimals);
emit log_named_decimal_int(" Right", b, decimals);
emit log_named_decimal_uint(" Max Delta", maxDelta, decimals);
emit log_named_decimal_uint(" Delta", delta, decimals);
fail();
}
}
functionassertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, stringmemory err)
internalvirtual{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbsDecimal(a, b, maxDelta, decimals);
}
}
functionassertApproxEqRel(uint256 a,
uint256 b,
uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100%) internalvirtual{
if (b ==0) return assertEq(a, b); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_uint(" Left", a);
emit log_named_uint(" Right", b);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta *100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta *100, 18);
fail();
}
}
functionassertApproxEqRel(uint256 a,
uint256 b,
uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%stringmemory err
) internalvirtual{
if (b ==0) return assertEq(a, b, err); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRel(a, b, maxPercentDelta);
}
}
functionassertApproxEqRelDecimal(uint256 a,
uint256 b,
uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%uint256 decimals
) internalvirtual{
if (b ==0) return assertEq(a, b); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_decimal_uint(" Left", a, decimals);
emit log_named_decimal_uint(" Right", b, decimals);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta *100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta *100, 18);
fail();
}
}
functionassertApproxEqRelDecimal(uint256 a,
uint256 b,
uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%uint256 decimals,
stringmemory err
) internalvirtual{
if (b ==0) return assertEq(a, b, err); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals);
}
}
functionassertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internalvirtual{
if (b ==0) return assertEq(a, b); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_int(" Left", a);
emit log_named_int(" Right", b);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta *100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta *100, 18);
fail();
}
}
functionassertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, stringmemory err) internalvirtual{
if (b ==0) return assertEq(a, b, err); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRel(a, b, maxPercentDelta);
}
}
functionassertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals) internalvirtual{
if (b ==0) return assertEq(a, b); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_decimal_int(" Left", a, decimals);
emit log_named_decimal_int(" Right", b, decimals);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta *100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta *100, 18);
fail();
}
}
functionassertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, stringmemory err)
internalvirtual{
if (b ==0) return assertEq(a, b, err); // If the left is 0, right must be too.uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals);
}
}
functionassertEqCall(address target, bytesmemory callDataA, bytesmemory callDataB) internalvirtual{
assertEqCall(target, callDataA, target, callDataB, true);
}
functionassertEqCall(address targetA, bytesmemory callDataA, address targetB, bytesmemory callDataB)
internalvirtual{
assertEqCall(targetA, callDataA, targetB, callDataB, true);
}
functionassertEqCall(address target, bytesmemory callDataA, bytesmemory callDataB, bool strictRevertData)
internalvirtual{
assertEqCall(target, callDataA, target, callDataB, strictRevertData);
}
functionassertEqCall(address targetA,
bytesmemory callDataA,
address targetB,
bytesmemory callDataB,
bool strictRevertData
) internalvirtual{
(bool successA, bytesmemory returnDataA) =address(targetA).call(callDataA);
(bool successB, bytesmemory returnDataB) =address(targetB).call(callDataB);
if (successA && successB) {
assertEq(returnDataA, returnDataB, "Call return data does not match");
}
if (!successA &&!successB && strictRevertData) {
assertEq(returnDataA, returnDataB, "Call revert data does not match");
}
if (!successA && successB) {
emit log("Error: Calls were not equal");
emit log_named_bytes(" Left call revert data", returnDataA);
emit log_named_bytes(" Right call return data", returnDataB);
fail();
}
if (successA &&!successB) {
emit log("Error: Calls were not equal");
emit log_named_bytes(" Left call return data", returnDataA);
emit log_named_bytes(" Right call revert data", returnDataB);
fail();
}
}
}
Contract Source Code
File 15 of 29: StdChains.sol
// SPDX-License-Identifier: MITpragmasolidity >=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.
*/abstractcontractStdChains{
VmSafe privateconstant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
boolprivate stdChainsInitialized;
structChainData {
string name;
uint256 chainId;
string rpcUrl;
}
structChain {
// 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;
boolprivate fallbackToDefaultRpcUrls =true;
// The RPC URL will be fetched from config or defaultRpcUrls if possible.functiongetChain(stringmemory chainAlias) internalvirtualreturns (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);
}
functiongetChain(uint256 chainId) internalvirtualreturns (Chain memory chain) {
require(chainId !=0, "StdChains getChain(uint256): Chain ID cannot be 0.");
initializeStdChains();
stringmemory 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.functionsetChain(stringmemory chainAlias, ChainData memory chain) internalvirtual{
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();
stringmemory 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.functionsetChain(stringmemory chainAlias, Chain memory chain) internalvirtual{
setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl}));
}
function_toUpper(stringmemory str) privatepurereturns (stringmemory) {
bytesmemory strb =bytes(str);
bytesmemory copy =newbytes(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;
}
}
returnstring(copy);
}
// lookup rpcUrl, in descending order of priority:// current -> config (foundry.toml) -> environment variable -> defaultfunctiongetChainWithUpdatedRpcUrl(stringmemory chainAlias, Chain memory chain)
privateviewreturns (Chain memory)
{
if (bytes(chain.rpcUrl).length==0) {
try vm.rpcUrl(chainAlias) returns (stringmemory configRpcUrl) {
chain.rpcUrl = configRpcUrl;
} catch (bytesmemory err) {
stringmemory 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 versionsbytesmemory oldNotFoundError =abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias)));
bytesmemory 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-assemblyassembly {
revert(add(32, err), mload(err))
}
}
}
}
return chain;
}
functionsetFallbackToDefaultRpcUrls(bool useDefault) internal{
fallbackToDefaultRpcUrls = useDefault;
}
functioninitializeStdChains() 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.tomlfunctionsetChainWithDefaultRpcUrl(stringmemory chainAlias, ChainData memory chain) private{
stringmemory rpcUrl = chain.rpcUrl;
defaultRpcUrls[chainAlias] = rpcUrl;
chain.rpcUrl ="";
setChain(chainAlias, chain);
chain.rpcUrl = rpcUrl; // restore argument
}
}
Contract Source Code
File 16 of 29: StdCheats.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;pragmaexperimentalABIEncoderV2;import {StdStorage, stdStorage} from"./StdStorage.sol";
import {console2} from"./console2.sol";
import {Vm} from"./Vm.sol";
abstractcontractStdCheatsSafe{
Vm privateconstant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
uint256privateconstant UINT256_MAX =115792089237316195423570985008687907853269984665640564039457584007913129639935;
boolprivate 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.structRawTx1559 {
string[] arguments;
address contractAddress;
string contractName;
// json value name = functionstring functionSig;
bytes32 hash;
// json value name = tx
RawTx1559Detail txDetail;
// json value name = typestring opcode;
}
structRawTx1559Detail {
AccessList[] accessList;
bytes data;
addressfrom;
bytes gas;
bytes nonce;
address to;
bytes txType;
bytes value;
}
structTx1559 {
string[] arguments;
address contractAddress;
string contractName;
string functionSig;
bytes32 hash;
Tx1559Detail txDetail;
string opcode;
}
structTx1559Detail {
AccessList[] accessList;
bytes data;
addressfrom;
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.structTxLegacy {
string[] arguments;
address contractAddress;
string contractName;
string functionSig;
string hash;
string opcode;
TxDetailLegacy transaction;
}
structTxDetailLegacy {
AccessList[] accessList;
uint256 chainId;
bytes data;
addressfrom;
uint256 gas;
uint256 gasPrice;
bytes32 hash;
uint256 nonce;
bytes1 opcode;
bytes32 r;
bytes32 s;
uint256 txType;
address to;
uint8 v;
uint256 value;
}
structAccessList {
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.structRawReceipt {
bytes32 blockHash;
bytes blockNumber;
address contractAddress;
bytes cumulativeGasUsed;
bytes effectiveGasPrice;
addressfrom;
bytes gasUsed;
RawReceiptLog[] logs;
bytes logsBloom;
bytes status;
address to;
bytes32 transactionHash;
bytes transactionIndex;
}
structReceipt {
bytes32 blockHash;
uint256 blockNumber;
address contractAddress;
uint256 cumulativeGasUsed;
uint256 effectiveGasPrice;
addressfrom;
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.structEIP1559ScriptArtifact {
string[] libraries;
string path;
string[] pending;
Receipt[] receipts;
uint256 timestamp;
Tx1559[] transactions;
TxReturn[] txReturns;
}
structRawEIP1559ScriptArtifact {
string[] libraries;
string path;
string[] pending;
RawReceipt[] receipts;
TxReturn[] txReturns;
uint256 timestamp;
RawTx1559[] transactions;
}
structRawReceiptLog {
// json value = addressaddress logAddress;
bytes32 blockHash;
bytes blockNumber;
bytes data;
bytes logIndex;
bool removed;
bytes32[] topics;
bytes32 transactionHash;
bytes transactionIndex;
bytes transactionLogIndex;
}
structReceiptLog {
// json value = addressaddress logAddress;
bytes32 blockHash;
uint256 blockNumber;
bytes data;
uint256 logIndex;
bytes32[] topics;
uint256 transactionIndex;
uint256 transactionLogIndex;
bool removed;
}
structTxReturn {
string internalType;
string value;
}
structAccount {
address addr;
uint256 key;
}
enumAddressType {
Payable,
NonPayable,
ZeroAddress,
Precompile,
ForgeAddress
}
// Checks that `addr` is not blacklisted by token contracts that have a blacklist.functionassumeNotBlacklisted(address token, address addr) internalviewvirtual{
// 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;
bytesmemory 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.functionassumeNoBlacklisted(address token, address addr) internalviewvirtual{
assumeNotBlacklisted(token, addr);
}
functionassumeAddressIsNot(address addr, AddressType addressType) internalvirtual{
if (addressType == AddressType.Payable) {
assumeNotPayable(addr);
} elseif (addressType == AddressType.NonPayable) {
assumePayable(addr);
} elseif (addressType == AddressType.ZeroAddress) {
assumeNotZeroAddress(addr);
} elseif (addressType == AddressType.Precompile) {
assumeNotPrecompile(addr);
} elseif (addressType == AddressType.ForgeAddress) {
assumeNotForgeAddress(addr);
}
}
functionassumeAddressIsNot(address addr, AddressType addressType1, AddressType addressType2) internalvirtual{
assumeAddressIsNot(addr, addressType1);
assumeAddressIsNot(addr, addressType2);
}
functionassumeAddressIsNot(address addr,
AddressType addressType1,
AddressType addressType2,
AddressType addressType3
) internalvirtual{
assumeAddressIsNot(addr, addressType1);
assumeAddressIsNot(addr, addressType2);
assumeAddressIsNot(addr, addressType3);
}
functionassumeAddressIsNot(address addr,
AddressType addressType1,
AddressType addressType2,
AddressType addressType3,
AddressType addressType4
) internalvirtual{
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) privatereturns (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.functionassumePayable(address addr) internalvirtual{
vm.assume(_isPayable(addr));
}
functionassumeNotPayable(address addr) internalvirtual{
vm.assume(!_isPayable(addr));
}
functionassumeNotZeroAddress(address addr) internalpurevirtual{
vm.assume(addr !=address(0));
}
functionassumeNotPrecompile(address addr) internalpurevirtual{
assumeNotPrecompile(addr, _pureChainId());
}
functionassumeNotPrecompile(address addr, uint256 chainId) internalpurevirtual{
// 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-startif (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));
} elseif (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));
} elseif (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
}
functionassumeNotForgeAddress(address addr) internalpurevirtual{
// vm, console, and Create2Deployer addresses
vm.assume(
addr !=address(vm) && addr !=0x000000000000000000636F6e736F6c652e6c6f67&& addr !=0x4e59b44847b379578588920cA78FbF26c0B4956C
);
}
functionreadEIP1559ScriptArtifact(stringmemory path)
internalviewvirtualreturns (EIP1559ScriptArtifact memory)
{
stringmemory data = vm.readFile(path);
bytesmemory 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;
}
functionrawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internalpurevirtualreturns (Tx1559[] memory) {
Tx1559[] memory txs =new Tx1559[](rawTxs.length);
for (uint256 i; i < rawTxs.length; i++) {
txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);
}
return txs;
}
functionrawToConvertedEIPTx1559(RawTx1559 memory rawTx) internalpurevirtualreturns (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;
}
functionrawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)
internalpurevirtualreturns (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;
}
functionreadTx1559s(stringmemory path) internalviewvirtualreturns (Tx1559[] memory) {
stringmemory deployData = vm.readFile(path);
bytesmemory parsedDeployData = vm.parseJson(deployData, ".transactions");
RawTx1559[] memory rawTxs =abi.decode(parsedDeployData, (RawTx1559[]));
return rawToConvertedEIPTx1559s(rawTxs);
}
functionreadTx1559(stringmemory path, uint256 index) internalviewvirtualreturns (Tx1559 memory) {
stringmemory deployData = vm.readFile(path);
stringmemory key =string(abi.encodePacked(".transactions[", vm.toString(index), "]"));
bytesmemory parsedDeployData = vm.parseJson(deployData, key);
RawTx1559 memory rawTx =abi.decode(parsedDeployData, (RawTx1559));
return rawToConvertedEIPTx1559(rawTx);
}
// Analogous to readTransactions, but for receipts.functionreadReceipts(stringmemory path) internalviewvirtualreturns (Receipt[] memory) {
stringmemory deployData = vm.readFile(path);
bytesmemory parsedDeployData = vm.parseJson(deployData, ".receipts");
RawReceipt[] memory rawReceipts =abi.decode(parsedDeployData, (RawReceipt[]));
return rawToConvertedReceipts(rawReceipts);
}
functionreadReceipt(stringmemory path, uint256 index) internalviewvirtualreturns (Receipt memory) {
stringmemory deployData = vm.readFile(path);
stringmemory key =string(abi.encodePacked(".receipts[", vm.toString(index), "]"));
bytesmemory parsedDeployData = vm.parseJson(deployData, key);
RawReceipt memory rawReceipt =abi.decode(parsedDeployData, (RawReceipt));
return rawToConvertedReceipt(rawReceipt);
}
functionrawToConvertedReceipts(RawReceipt[] memory rawReceipts) internalpurevirtualreturns (Receipt[] memory) {
Receipt[] memory receipts =new Receipt[](rawReceipts.length);
for (uint256 i; i < rawReceipts.length; i++) {
receipts[i] = rawToConvertedReceipt(rawReceipts[i]);
}
return receipts;
}
functionrawToConvertedReceipt(RawReceipt memory rawReceipt) internalpurevirtualreturns (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;
}
functionrawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)
internalpurevirtualreturns (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))`functiondeployCode(stringmemory what, bytesmemory args) internalvirtualreturns (address addr) {
bytesmemory bytecode =abi.encodePacked(vm.getCode(what), args);
/// @solidity memory-safe-assemblyassembly {
addr :=create(0, add(bytecode, 0x20), mload(bytecode))
}
require(addr !=address(0), "StdCheats deployCode(string,bytes): Deployment failed.");
}
functiondeployCode(stringmemory what) internalvirtualreturns (address addr) {
bytesmemory bytecode = vm.getCode(what);
/// @solidity memory-safe-assemblyassembly {
addr :=create(0, add(bytecode, 0x20), mload(bytecode))
}
require(addr !=address(0), "StdCheats deployCode(string): Deployment failed.");
}
/// @dev deploy contract with value on constructionfunctiondeployCode(stringmemory what, bytesmemory args, uint256 val) internalvirtualreturns (address addr) {
bytesmemory bytecode =abi.encodePacked(vm.getCode(what), args);
/// @solidity memory-safe-assemblyassembly {
addr :=create(val, add(bytecode, 0x20), mload(bytecode))
}
require(addr !=address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed.");
}
functiondeployCode(stringmemory what, uint256 val) internalvirtualreturns (address addr) {
bytesmemory bytecode = vm.getCode(what);
/// @solidity memory-safe-assemblyassembly {
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 keyfunctionmakeAddrAndKey(stringmemory name) internalvirtualreturns (address addr, uint256 privateKey) {
privateKey =uint256(keccak256(abi.encodePacked(name)));
addr = vm.addr(privateKey);
vm.label(addr, name);
}
// creates a labeled addressfunctionmakeAddr(stringmemory name) internalvirtualreturns (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.functiondestroyAccount(address who, address beneficiary) internalvirtual{
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 keyfunctionmakeAccount(stringmemory name) internalvirtualreturns (Account memory account) {
(account.addr, account.key) = makeAddrAndKey(name);
}
functionderiveRememberKey(stringmemory mnemonic, uint32 index)
internalvirtualreturns (address who, uint256 privateKey)
{
privateKey = vm.deriveKey(mnemonic, index);
who = vm.rememberKey(privateKey);
}
function_bytesToUint(bytesmemory b) privatepurereturns (uint256) {
require(b.length<=32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32.");
returnabi.decode(abi.encodePacked(newbytes(32- b.length), b), (uint256));
}
functionisFork() internalviewvirtualreturns (bool status) {
try vm.activeFork() {
status =true;
} catch (bytesmemory) {}
}
modifierskipWhenForking() {
if (!isFork()) {
_;
}
}
modifierskipWhenNotForking() {
if (isFork()) {
_;
}
}
modifiernoGasMetering() {
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 funcAbool gasStartedOff = gasMeteringOff;
gasMeteringOff =true;
_;
// if gas metering was on when this modifier was called, turn it back on at the endif (!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() privateviewreturns (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() privatepurereturns (uint256 chainId) {
function() internalviewreturns (uint256) fnIn = _viewChainId;
function() internalpurereturns (uint256) pureChainId;
assembly {
pureChainId := fnIn
}
chainId = pureChainId();
}
}
// Wrappers around cheatcodes to avoid footgunsabstractcontractStdCheatsisStdCheatsSafe{
usingstdStorageforStdStorage;
StdStorage private stdstore;
Vm privateconstant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
addressprivateconstant CONSOLE2_ADDRESS =0x000000000000000000636F6e736F6c652e6c6f67;
// Skip forward or rewind time by the specified number of secondsfunctionskip(uint256 time) internalvirtual{
vm.warp(block.timestamp+ time);
}
functionrewind(uint256 time) internalvirtual{
vm.warp(block.timestamp- time);
}
// Setup a prank from an address that has some etherfunctionhoax(address msgSender) internalvirtual{
vm.deal(msgSender, 1<<128);
vm.prank(msgSender);
}
functionhoax(address msgSender, uint256 give) internalvirtual{
vm.deal(msgSender, give);
vm.prank(msgSender);
}
functionhoax(address msgSender, address origin) internalvirtual{
vm.deal(msgSender, 1<<128);
vm.prank(msgSender, origin);
}
functionhoax(address msgSender, address origin, uint256 give) internalvirtual{
vm.deal(msgSender, give);
vm.prank(msgSender, origin);
}
// Start perpetual prank from an address that has some etherfunctionstartHoax(address msgSender) internalvirtual{
vm.deal(msgSender, 1<<128);
vm.startPrank(msgSender);
}
functionstartHoax(address msgSender, uint256 give) internalvirtual{
vm.deal(msgSender, give);
vm.startPrank(msgSender);
}
// Start perpetual prank from an address that has some ether// tx.origin is set to the origin parameterfunctionstartHoax(address msgSender, address origin) internalvirtual{
vm.deal(msgSender, 1<<128);
vm.startPrank(msgSender, origin);
}
functionstartHoax(address msgSender, address origin, uint256 give) internalvirtual{
vm.deal(msgSender, give);
vm.startPrank(msgSender, origin);
}
functionchangePrank(address msgSender) internalvirtual{
console2_log_StdCheats("changePrank is deprecated. Please use vm.startPrank instead.");
vm.stopPrank();
vm.startPrank(msgSender);
}
functionchangePrank(address msgSender, address txOrigin) internalvirtual{
vm.stopPrank();
vm.startPrank(msgSender, txOrigin);
}
// The same as Vm's `deal`// Use the alternative signature for ERC20 tokensfunctiondeal(address to, uint256 give) internalvirtual{
vm.deal(to, give);
}
// Set the balance of an account for any ERC20 token// Use the alternative signature to update `totalSupply`functiondeal(address token, address to, uint256 give) internalvirtual{
deal(token, to, give, false);
}
// Set the balance of an account for any ERC1155 token// Use the alternative signature to update `totalSupply`functiondealERC1155(address token, address to, uint256 id, uint256 give) internalvirtual{
dealERC1155(token, to, id, give, false);
}
functiondeal(address token, address to, uint256 give, bool adjust) internalvirtual{
// get current balance
(, bytesmemory 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 supplyif (adjust) {
(, bytesmemory 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);
}
}
functiondealERC1155(address token, address to, uint256 id, uint256 give, bool adjust) internalvirtual{
// get current balance
(, bytesmemory 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 supplyif (adjust) {
(, bytesmemory 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);
}
}
functiondealERC721(address token, address to, uint256 id) internalvirtual{
// check if token id is already minted and the actual owner.
(bool successMinted, bytesmemory ownerData) = token.staticcall(abi.encodeWithSelector(0x6352211e, id));
require(successMinted, "StdCheats deal(address,address,uint,bool): id not minted.");
// get owner current balance
(, bytesmemory fromBalData) =
token.staticcall(abi.encodeWithSelector(0x70a08231, abi.decode(ownerData, (address))));
uint256 fromPrevBal =abi.decode(fromBalData, (uint256));
// get new user current balance
(, bytesmemory 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);
}
functiondeployCodeTo(stringmemory what, address where) internalvirtual{
deployCodeTo(what, "", 0, where);
}
functiondeployCodeTo(stringmemory what, bytesmemory args, address where) internalvirtual{
deployCodeTo(what, args, 0, where);
}
functiondeployCodeTo(stringmemory what, bytesmemory args, uint256 value, address where) internalvirtual{
bytesmemory creationCode = vm.getCode(what);
vm.etch(where, abi.encodePacked(creationCode, args));
(bool success, bytesmemory 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.functionconsole2_log_StdCheats(stringmemory p0) privateview{
(bool status,) =address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0));
status;
}
}
Contract Source Code
File 17 of 29: StdError.sol
// SPDX-License-Identifier: MIT// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Testpragmasolidity >=0.6.2 <0.9.0;librarystdError{
bytespublicconstant assertionError =abi.encodeWithSignature("Panic(uint256)", 0x01);
bytespublicconstant arithmeticError =abi.encodeWithSignature("Panic(uint256)", 0x11);
bytespublicconstant divisionError =abi.encodeWithSignature("Panic(uint256)", 0x12);
bytespublicconstant enumConversionError =abi.encodeWithSignature("Panic(uint256)", 0x21);
bytespublicconstant encodeStorageError =abi.encodeWithSignature("Panic(uint256)", 0x22);
bytespublicconstant popError =abi.encodeWithSignature("Panic(uint256)", 0x31);
bytespublicconstant indexOOBError =abi.encodeWithSignature("Panic(uint256)", 0x32);
bytespublicconstant memOverflowError =abi.encodeWithSignature("Panic(uint256)", 0x41);
bytespublicconstant zeroVarError =abi.encodeWithSignature("Panic(uint256)", 0x51);
}
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;librarystdMath{
int256privateconstant INT256_MIN =-57896044618658097711785492504343953926634992332820282019728792003956564819968;
functionabs(int256 a) internalpurereturns (uint256) {
// Required or it will fail when `a = type(int256).min`if (a == INT256_MIN) {
return57896044618658097711785492504343953926634992332820282019728792003956564819968;
}
returnuint256(a >0 ? a : -a);
}
functiondelta(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a - b : b - a;
}
functiondelta(int256 a, int256 b) internalpurereturns (uint256) {
// a and b are of the same sign// this works thanks to two's complement, the left-most bit is the sign bitif ((a ^ b) >-1) {
return delta(abs(a), abs(b));
}
// a and b are of opposite signsreturn abs(a) + abs(b);
}
functionpercentDelta(uint256 a, uint256 b) internalpurereturns (uint256) {
uint256 absDelta = delta(a, b);
return absDelta *1e18/ b;
}
functionpercentDelta(int256 a, int256 b) internalpurereturns (uint256) {
uint256 absDelta = delta(a, b);
uint256 absB = abs(b);
return absDelta *1e18/ absB;
}
}
Contract Source Code
File 21 of 29: StdStorage.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;import {Vm} from"./Vm.sol";
structStdStorage {
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;
}
librarystdStorageSafe{
eventSlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot);
eventWARNING_UninitedSlot(address who, uint256 slot);
Vm privateconstant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
functionsigs(stringmemory sigStr) internalpurereturns (bytes4) {
returnbytes4(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);functionfind(StdStorage storageself) internalreturns (uint256) {
address who =self._target;
bytes4 fsig =self._sig;
uint256 field_depth =self._depth;
bytes32[] memory ins =self._keys;
// calldata to test againstif (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
returnself.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
}
bytesmemory cald =abi.encodePacked(fsig, flatten(ins));
vm.record();
bytes32 fdat;
{
(, bytesmemory 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;
} elseif (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;
{
bytesmemory 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 oneemit 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."
);
deleteself._target;
deleteself._sig;
deleteself._keys;
deleteself._depth;
returnself.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
}
functiontarget(StdStorage storageself, address _target) internalreturns (StdStorage storage) {
self._target = _target;
returnself;
}
functionsig(StdStorage storageself, bytes4 _sig) internalreturns (StdStorage storage) {
self._sig = _sig;
returnself;
}
functionsig(StdStorage storageself, stringmemory _sig) internalreturns (StdStorage storage) {
self._sig = sigs(_sig);
returnself;
}
functionwith_key(StdStorage storageself, address who) internalreturns (StdStorage storage) {
self._keys.push(bytes32(uint256(uint160(who))));
returnself;
}
functionwith_key(StdStorage storageself, uint256 amt) internalreturns (StdStorage storage) {
self._keys.push(bytes32(amt));
returnself;
}
functionwith_key(StdStorage storageself, bytes32 key) internalreturns (StdStorage storage) {
self._keys.push(key);
returnself;
}
functiondepth(StdStorage storageself, uint256 _depth) internalreturns (StdStorage storage) {
self._depth = _depth;
returnself;
}
functionread(StdStorage storageself) privatereturns (bytesmemory) {
address t =self._target;
uint256 s = find(self);
returnabi.encode(vm.load(t, bytes32(s)));
}
functionread_bytes32(StdStorage storageself) internalreturns (bytes32) {
returnabi.decode(read(self), (bytes32));
}
functionread_bool(StdStorage storageself) internalreturns (bool) {
int256 v = read_int(self);
if (v ==0) returnfalse;
if (v ==1) returntrue;
revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
}
functionread_address(StdStorage storageself) internalreturns (address) {
returnabi.decode(read(self), (address));
}
functionread_uint(StdStorage storageself) internalreturns (uint256) {
returnabi.decode(read(self), (uint256));
}
functionread_int(StdStorage storageself) internalreturns (int256) {
returnabi.decode(read(self), (int256));
}
functionparent(StdStorage storageself) internalreturns (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);
}
functionroot(StdStorage storageself) internalreturns (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));
}
returnuint256(root_slot);
}
functionbytesToBytes32(bytesmemory b, uint256 offset) privatepurereturns (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;
}
functionflatten(bytes32[] memory b) privatepurereturns (bytesmemory) {
bytesmemory result =newbytes(b.length*32);
for (uint256 i =0; i < b.length; i++) {
bytes32 k = b[i];
/// @solidity memory-safe-assemblyassembly {
mstore(add(result, add(32, mul(32, i))), k)
}
}
return result;
}
}
librarystdStorage{
Vm privateconstant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
functionsigs(stringmemory sigStr) internalpurereturns (bytes4) {
return stdStorageSafe.sigs(sigStr);
}
functionfind(StdStorage storageself) internalreturns (uint256) {
return stdStorageSafe.find(self);
}
functiontarget(StdStorage storageself, address _target) internalreturns (StdStorage storage) {
return stdStorageSafe.target(self, _target);
}
functionsig(StdStorage storageself, bytes4 _sig) internalreturns (StdStorage storage) {
return stdStorageSafe.sig(self, _sig);
}
functionsig(StdStorage storageself, stringmemory _sig) internalreturns (StdStorage storage) {
return stdStorageSafe.sig(self, _sig);
}
functionwith_key(StdStorage storageself, address who) internalreturns (StdStorage storage) {
return stdStorageSafe.with_key(self, who);
}
functionwith_key(StdStorage storageself, uint256 amt) internalreturns (StdStorage storage) {
return stdStorageSafe.with_key(self, amt);
}
functionwith_key(StdStorage storageself, bytes32 key) internalreturns (StdStorage storage) {
return stdStorageSafe.with_key(self, key);
}
functiondepth(StdStorage storageself, uint256 _depth) internalreturns (StdStorage storage) {
return stdStorageSafe.depth(self, _depth);
}
functionchecked_write(StdStorage storageself, address who) internal{
checked_write(self, bytes32(uint256(uint160(who))));
}
functionchecked_write(StdStorage storageself, uint256 amt) internal{
checked_write(self, bytes32(amt));
}
functionchecked_write_int(StdStorage storageself, int256 val) internal{
checked_write(self, bytes32(uint256(val)));
}
functionchecked_write(StdStorage storageself, bool write) internal{
bytes32 t;
/// @solidity memory-safe-assemblyassembly {
t := write
}
checked_write(self, t);
}
functionchecked_write(StdStorage storageself, bytes32 set) internal{
address who =self._target;
bytes4 fsig =self._sig;
uint256 field_depth =self._depth;
bytes32[] memory ins =self._keys;
bytesmemory cald =abi.encodePacked(fsig, flatten(ins));
if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
find(self);
}
bytes32 slot =bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]);
bytes32 fdat;
{
(, bytesmemory rdat) = who.staticcall(cald);
fdat = bytesToBytes32(rdat, 32* field_depth);
}
bytes32 curr = vm.load(who, slot);
if (fdat != curr) {
require(
false,
"stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported."
);
}
vm.store(who, slot, set);
deleteself._target;
deleteself._sig;
deleteself._keys;
deleteself._depth;
}
functionread_bytes32(StdStorage storageself) internalreturns (bytes32) {
return stdStorageSafe.read_bytes32(self);
}
functionread_bool(StdStorage storageself) internalreturns (bool) {
return stdStorageSafe.read_bool(self);
}
functionread_address(StdStorage storageself) internalreturns (address) {
return stdStorageSafe.read_address(self);
}
functionread_uint(StdStorage storageself) internalreturns (uint256) {
return stdStorageSafe.read_uint(self);
}
functionread_int(StdStorage storageself) internalreturns (int256) {
return stdStorageSafe.read_int(self);
}
functionparent(StdStorage storageself) internalreturns (uint256, bytes32) {
return stdStorageSafe.parent(self);
}
functionroot(StdStorage storageself) internalreturns (uint256) {
return stdStorageSafe.root(self);
}
// Private function so needs to be copied overfunctionbytesToBytes32(bytesmemory b, uint256 offset) privatepurereturns (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;
}
// Private function so needs to be copied overfunctionflatten(bytes32[] memory b) privatepurereturns (bytesmemory) {
bytesmemory result =newbytes(b.length*32);
for (uint256 i =0; i < b.length; i++) {
bytes32 k = b[i];
/// @solidity memory-safe-assemblyassembly {
mstore(add(result, add(32, mul(32, i))), k)
}
}
return result;
}
}
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;pragmaexperimentalABIEncoderV2;import {IMulticall3} from"./interfaces/IMulticall3.sol";
import {MockERC20} from"./mocks/MockERC20.sol";
import {MockERC721} from"./mocks/MockERC721.sol";
import {VmSafe} from"./Vm.sol";
abstractcontractStdUtils{
/*//////////////////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/
IMulticall3 privateconstant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11);
VmSafe privateconstant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
addressprivateconstant CONSOLE2_ADDRESS =0x000000000000000000636F6e736F6c652e6c6f67;
uint256privateconstant INT256_MIN_ABS =57896044618658097711785492504343953926634992332820282019728792003956564819968;
uint256privateconstant SECP256K1_ORDER =115792089237316195423570985008687907852837564279074904382605163141518161494337;
uint256privateconstant UINT256_MAX =115792089237316195423570985008687907853269984665640564039457584007913129639935;
// Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.addressprivateconstant CREATE2_FACTORY =0x4e59b44847b379578588920cA78FbF26c0B4956C;
/*//////////////////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/function_bound(uint256 x, uint256 min, uint256 max) internalpurevirtualreturns (uint256 result) {
require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min.");
// If x is between min and max, return x directly. This is to ensure that dictionary values// do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188if (x >= min && x <= max) return x;
uint256 size = max - min +1;
// If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side.// This helps ensure coverage of the min/max values.if (x <=3&& size > x) return min + x;
if (x >= UINT256_MAX -3&& size > UINT256_MAX - x) return max - (UINT256_MAX - x);
// Otherwise, wrap x into the range [min, max], i.e. the range is inclusive.if (x > max) {
uint256 diff = x - max;
uint256 rem = diff % size;
if (rem ==0) return max;
result = min + rem -1;
} elseif (x < min) {
uint256 diff = min - x;
uint256 rem = diff % size;
if (rem ==0) return min;
result = max - rem +1;
}
}
functionbound(uint256 x, uint256 min, uint256 max) internalpurevirtualreturns (uint256 result) {
result = _bound(x, min, max);
console2_log_StdUtils("Bound Result", result);
}
function_bound(int256 x, int256 min, int256 max) internalpurevirtualreturns (int256 result) {
require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min.");
// Shifting all int256 values to uint256 to use _bound function. The range of two types are:// int256 : -(2**255) ~ (2**255 - 1)// uint256: 0 ~ (2**256 - 1)// So, add 2**255, INT256_MIN_ABS to the integer values.//// If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow.// So, use `~uint256(x) + 1` instead.uint256 _x = x <0 ? (INT256_MIN_ABS -~uint256(x) -1) : (uint256(x) + INT256_MIN_ABS);
uint256 _min = min <0 ? (INT256_MIN_ABS -~uint256(min) -1) : (uint256(min) + INT256_MIN_ABS);
uint256 _max = max <0 ? (INT256_MIN_ABS -~uint256(max) -1) : (uint256(max) + INT256_MIN_ABS);
uint256 y = _bound(_x, _min, _max);
// To move it back to int256 value, subtract INT256_MIN_ABS at here.
result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) +1) : int256(y - INT256_MIN_ABS);
}
functionbound(int256 x, int256 min, int256 max) internalpurevirtualreturns (int256 result) {
result = _bound(x, min, max);
console2_log_StdUtils("Bound result", vm.toString(result));
}
functionboundPrivateKey(uint256 privateKey) internalpurevirtualreturns (uint256 result) {
result = _bound(privateKey, 1, SECP256K1_ORDER -1);
}
functionbytesToUint(bytesmemory b) internalpurevirtualreturns (uint256) {
require(b.length<=32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32.");
returnabi.decode(abi.encodePacked(newbytes(32- b.length), b), (uint256));
}
/// @dev Compute the address a contract will be deployed at for a given deployer address and nonce/// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol)functioncomputeCreateAddress(address deployer, uint256 nonce) internalpurevirtualreturns (address) {
console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead.");
return vm.computeCreateAddress(deployer, nonce);
}
functioncomputeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer)
internalpurevirtualreturns (address)
{
console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead.");
return vm.computeCreate2Address(salt, initcodeHash, deployer);
}
/// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployerfunctioncomputeCreate2Address(bytes32 salt, bytes32 initCodeHash) internalpurereturns (address) {
console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead.");
return vm.computeCreate2Address(salt, initCodeHash);
}
/// @dev returns an initialized mock ERC20 contractfunctiondeployMockERC20(stringmemory name, stringmemory symbol, uint8 decimals)
internalreturns (MockERC20 mock)
{
mock =new MockERC20();
mock.initialize(name, symbol, decimals);
}
/// @dev returns an initialized mock ERC721 contractfunctiondeployMockERC721(stringmemory name, stringmemory symbol) internalreturns (MockERC721 mock) {
mock =new MockERC721();
mock.initialize(name, symbol);
}
/// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments/// @param creationCode the creation code of a contract C, as returned by type(C).creationCodefunctionhashInitCode(bytesmemory creationCode) internalpurereturns (bytes32) {
return hashInitCode(creationCode, "");
}
/// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2/// @param creationCode the creation code of a contract C, as returned by type(C).creationCode/// @param args the ABI-encoded arguments to the constructor of CfunctionhashInitCode(bytesmemory creationCode, bytesmemory args) internalpurereturns (bytes32) {
returnkeccak256(abi.encodePacked(creationCode, args));
}
// Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses.functiongetTokenBalances(address token, address[] memory addresses)
internalvirtualreturns (uint256[] memory balances)
{
uint256 tokenCodeSize;
assembly {
tokenCodeSize :=extcodesize(token)
}
require(tokenCodeSize >0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract.");
// ABI encode the aggregate call to Multicall3.uint256 length = addresses.length;
IMulticall3.Call[] memory calls =new IMulticall3.Call[](length);
for (uint256 i =0; i < length; ++i) {
// 0x70a08231 = bytes4("balanceOf(address)"))
calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))});
}
// Make the aggregate call.
(, bytes[] memory returnData) = multicall.aggregate(calls);
// ABI decode the return data and return the balances.
balances =newuint256[](length);
for (uint256 i =0; i < length; ++i) {
balances[i] =abi.decode(returnData[i], (uint256));
}
}
/*//////////////////////////////////////////////////////////////////////////
PRIVATE FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/functionaddressFromLast20Bytes(bytes32 bytesValue) privatepurereturns (address) {
returnaddress(uint160(uint256(bytesValue)));
}
// This section is used to prevent the compilation of console, which shortens the compilation time when console is// not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid// any breaking changes to function signatures.function_castLogPayloadViewToPure(function(bytesmemory) internalview fnIn)
internalpurereturns (function(bytesmemory) internalpure fnOut)
{
assembly {
fnOut := fnIn
}
}
function_sendLogPayload(bytesmemory payload) internalpure{
_castLogPayloadViewToPure(_sendLogPayloadView)(payload);
}
function_sendLogPayloadView(bytesmemory payload) privateview{
uint256 payloadLength = payload.length;
address consoleAddress = CONSOLE2_ADDRESS;
/// @solidity memory-safe-assemblyassembly {
let payloadStart :=add(payload, 32)
let r :=staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
}
}
functionconsole2_log_StdUtils(stringmemory p0) privatepure{
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
functionconsole2_log_StdUtils(stringmemory p0, uint256 p1) privatepure{
_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
}
functionconsole2_log_StdUtils(stringmemory p0, stringmemory p1) privatepure{
_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
}
}
// Automatically @generated by scripts/vm.py. Do not modify manually.// SPDX-License-Identifier: MIT OR Apache-2.0pragmasolidity >=0.6.2 <0.9.0;pragmaexperimentalABIEncoderV2;/// The `VmSafe` interface does not allow manipulation of the EVM state or other actions that may/// result in Script simulations differing from on-chain execution. It is recommended to only use/// these cheats in scripts.interfaceVmSafe{
/// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.enumCallerMode {
// No caller modification is currently active.
None,
// A one time broadcast triggered by a `vm.broadcast()` call is currently active.
Broadcast,
// A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active.
RecurrentBroadcast,
// A one time prank triggered by a `vm.prank()` call is currently active.
Prank,
// A recurrent prank triggered by a `vm.startPrank()` call is currently active.
RecurrentPrank
}
/// The kind of account access that occurred.enumAccountAccessKind {
// The account was called.
Call,
// The account was called via delegatecall.
DelegateCall,
// The account was called via callcode.
CallCode,
// The account was called via staticcall.
StaticCall,
// The account was created.
Create,
// The account was selfdestructed.
SelfDestruct,
// Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess).
Resume,
// The account's balance was read.
Balance,
// The account's codesize was read.
Extcodesize,
// The account's codehash was read.
Extcodehash,
// The account's code was copied.
Extcodecopy
}
/// An Ethereum log. Returned by `getRecordedLogs`.structLog {
// The topics of the log, including the signature, if any.bytes32[] topics;
// The raw data of the log.bytes data;
// The address of the log's emitter.address emitter;
}
/// An RPC URL and its alias. Returned by `rpcUrlStructs`.structRpc {
// The alias of the RPC URL.string key;
// The RPC URL.string url;
}
/// An RPC log object. Returned by `eth_getLogs`.structEthGetLogs {
// The address of the log's emitter.address emitter;
// The topics of the log, including the signature, if any.bytes32[] topics;
// The raw data of the log.bytes data;
// The block hash.bytes32 blockHash;
// The block number.uint64 blockNumber;
// The transaction hash.bytes32 transactionHash;
// The transaction index in the block.uint64 transactionIndex;
// The log index.uint256 logIndex;
// Whether the log was removed.bool removed;
}
/// A single entry in a directory listing. Returned by `readDir`.structDirEntry {
// The error message, if any.string errorMessage;
// The path of the entry.string path;
// The depth of the entry.uint64 depth;
// Whether the entry is a directory.bool isDir;
// Whether the entry is a symlink.bool isSymlink;
}
/// Metadata information about a file./// This structure is returned from the `fsMetadata` function and represents known/// metadata about a file such as its permissions, size, modification/// times, etc.structFsMetadata {
// True if this metadata is for a directory.bool isDir;
// True if this metadata is for a symlink.bool isSymlink;
// The size of the file, in bytes, this metadata is for.uint256 length;
// True if this metadata is for a readonly (unwritable) file.bool readOnly;
// The last modification time listed in this metadata.uint256 modified;
// The last access time of this metadata.uint256 accessed;
// The creation time listed in this metadata.uint256 created;
}
/// A wallet with a public and private key.structWallet {
// The wallet's address.address addr;
// The wallet's public key `X`.uint256 publicKeyX;
// The wallet's public key `Y`.uint256 publicKeyY;
// The wallet's private key.uint256 privateKey;
}
/// The result of a `tryFfi` call.structFfiResult {
// The exit code of the call.int32 exitCode;
// The optionally hex-decoded `stdout` data.bytes stdout;
// The `stderr` data.bytes stderr;
}
/// Information on the chain and fork.structChainInfo {
// The fork identifier. Set to zero if no fork is active.uint256 forkId;
// The chain ID of the current fork.uint256 chainId;
}
/// The result of a `stopAndReturnStateDiff` call.structAccountAccess {
// The chain and fork the access occurred.
ChainInfo chainInfo;
// The kind of account access that determines what the account is.// If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee.// If kind is Create, then the account is the newly created account.// If kind is SelfDestruct, then the account is the selfdestruct recipient.// If kind is a Resume, then account represents a account context that has resumed.
AccountAccessKind kind;
// The account that was accessed.// It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT.address account;
// What accessed the account.address accessor;
// If the account was initialized or empty prior to the access.// An account is considered initialized if it has code, a// non-zero nonce, or a non-zero balance.bool initialized;
// The previous balance of the accessed account.uint256 oldBalance;
// The potential new balance of the accessed account.// That is, all balance changes are recorded here, even if reverts occurred.uint256 newBalance;
// Code of the account deployed by CREATE.bytes deployedCode;
// Value passed along with the account accessuint256 value;
// Input data provided to the CREATE or CALLbytes data;
// If this access reverted in either the current or parent context.bool reverted;
// An ordered list of storage accesses made during an account access operation.
StorageAccess[] storageAccesses;
}
/// The storage accessed during an `AccountAccess`.structStorageAccess {
// The account whose storage was accessed.address account;
// The slot that was accessed.bytes32 slot;
// If the access was a write.bool isWrite;
// The previous value of the slot.bytes32 previousValue;
// The new value of the slot.bytes32 newValue;
// If the access was reverted.bool reverted;
}
// ======== Environment ========/// Gets the environment variable `name` and parses it as `address`./// Reverts if the variable was not found or could not be parsed.functionenvAddress(stringcalldata name) externalviewreturns (address value);
/// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvAddress(stringcalldata name, stringcalldata delim) externalviewreturns (address[] memory value);
/// Gets the environment variable `name` and parses it as `bool`./// Reverts if the variable was not found or could not be parsed.functionenvBool(stringcalldata name) externalviewreturns (bool value);
/// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvBool(stringcalldata name, stringcalldata delim) externalviewreturns (bool[] memory value);
/// Gets the environment variable `name` and parses it as `bytes32`./// Reverts if the variable was not found or could not be parsed.functionenvBytes32(stringcalldata name) externalviewreturns (bytes32 value);
/// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvBytes32(stringcalldata name, stringcalldata delim) externalviewreturns (bytes32[] memory value);
/// Gets the environment variable `name` and parses it as `bytes`./// Reverts if the variable was not found or could not be parsed.functionenvBytes(stringcalldata name) externalviewreturns (bytesmemory value);
/// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvBytes(stringcalldata name, stringcalldata delim) externalviewreturns (bytes[] memory value);
/// Gets the environment variable `name` and parses it as `int256`./// Reverts if the variable was not found or could not be parsed.functionenvInt(stringcalldata name) externalviewreturns (int256 value);
/// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvInt(stringcalldata name, stringcalldata delim) externalviewreturns (int256[] memory value);
/// Gets the environment variable `name` and parses it as `bool`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, bool defaultValue) externalviewreturns (bool value);
/// Gets the environment variable `name` and parses it as `uint256`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, uint256 defaultValue) externalviewreturns (uint256 value);
/// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, address[] calldata defaultValue)
externalviewreturns (address[] memory value);
/// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, bytes32[] calldata defaultValue)
externalviewreturns (bytes32[] memory value);
/// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, string[] calldata defaultValue)
externalviewreturns (string[] memory value);
/// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, bytes[] calldata defaultValue)
externalviewreturns (bytes[] memory value);
/// Gets the environment variable `name` and parses it as `int256`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, int256 defaultValue) externalviewreturns (int256 value);
/// Gets the environment variable `name` and parses it as `address`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, address defaultValue) externalviewreturns (address value);
/// Gets the environment variable `name` and parses it as `bytes32`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, bytes32 defaultValue) externalviewreturns (bytes32 value);
/// Gets the environment variable `name` and parses it as `string`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata defaultValue) externalviewreturns (stringmemory value);
/// Gets the environment variable `name` and parses it as `bytes`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, bytescalldata defaultValue) externalviewreturns (bytesmemory value);
/// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, bool[] calldata defaultValue)
externalviewreturns (bool[] memory value);
/// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, uint256[] calldata defaultValue)
externalviewreturns (uint256[] memory value);
/// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`./// Reverts if the variable could not be parsed./// Returns `defaultValue` if the variable was not found.functionenvOr(stringcalldata name, stringcalldata delim, int256[] calldata defaultValue)
externalviewreturns (int256[] memory value);
/// Gets the environment variable `name` and parses it as `string`./// Reverts if the variable was not found or could not be parsed.functionenvString(stringcalldata name) externalviewreturns (stringmemory value);
/// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvString(stringcalldata name, stringcalldata delim) externalviewreturns (string[] memory value);
/// Gets the environment variable `name` and parses it as `uint256`./// Reverts if the variable was not found or could not be parsed.functionenvUint(stringcalldata name) externalviewreturns (uint256 value);
/// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`./// Reverts if the variable was not found or could not be parsed.functionenvUint(stringcalldata name, stringcalldata delim) externalviewreturns (uint256[] memory value);
/// Sets environment variables.functionsetEnv(stringcalldata name, stringcalldata value) external;
// ======== EVM ========/// Gets all accessed reads and write slot from a `vm.record` session, for a given address.functionaccesses(address target) externalreturns (bytes32[] memory readSlots, bytes32[] memory writeSlots);
/// Gets the address for a given private key.functionaddr(uint256 privateKey) externalpurereturns (address keyAddr);
/// Gets all the logs according to specified filter.functioneth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics)
externalreturns (EthGetLogs[] memory logs);
/// Gets the current `block.number`./// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction,/// and as a result will get optimized out by the compiler./// See https://github.com/foundry-rs/foundry/issues/6180functiongetBlockNumber() externalviewreturns (uint256 height);
/// Gets the current `block.timestamp`./// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction,/// and as a result will get optimized out by the compiler./// See https://github.com/foundry-rs/foundry/issues/6180functiongetBlockTimestamp() externalviewreturns (uint256 timestamp);
/// Gets the map key and parent of a mapping at a given slot, for a given address.functiongetMappingKeyAndParentOf(address target, bytes32 elementSlot)
externalreturns (bool found, bytes32 key, bytes32 parent);
/// Gets the number of elements in the mapping at the given slot, for a given address.functiongetMappingLength(address target, bytes32 mappingSlot) externalreturns (uint256 length);
/// Gets the elements at index idx of the mapping at the given slot, for a given address. The/// index must be less than the length of the mapping (i.e. the number of keys in the mapping).functiongetMappingSlotAt(address target, bytes32 mappingSlot, uint256 idx) externalreturns (bytes32 value);
/// Gets the nonce of an account.functiongetNonce(address account) externalviewreturns (uint64 nonce);
/// Gets all the recorded logs.functiongetRecordedLogs() externalreturns (Log[] memory logs);
/// Loads a storage slot from an address.functionload(address target, bytes32 slot) externalviewreturns (bytes32 data);
/// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused.functionpauseGasMetering() external;
/// Records all storage reads and writes.functionrecord() external;
/// Record all the transaction logs.functionrecordLogs() external;
/// Resumes gas metering (i.e. gas usage is counted again). Noop if already on.functionresumeGasMetering() external;
/// Performs an Ethereum JSON-RPC request to the current fork URL.functionrpc(stringcalldata method, stringcalldata params) externalreturns (bytesmemory data);
/// Signs `digest` with `privateKey` using the secp256r1 curve.functionsignP256(uint256 privateKey, bytes32 digest) externalpurereturns (bytes32 r, bytes32 s);
/// Signs `digest` with `privateKey` using the secp256k1 curve.functionsign(uint256 privateKey, bytes32 digest) externalpurereturns (uint8 v, bytes32 r, bytes32 s);
/// Starts recording all map SSTOREs for later retrieval.functionstartMappingRecording() external;
/// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order,/// along with the context of the callsfunctionstartStateDiffRecording() external;
/// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session.functionstopAndReturnStateDiff() externalreturns (AccountAccess[] memory accountAccesses);
/// Stops recording all map SSTOREs for later retrieval and clears the recorded data.functionstopMappingRecording() external;
// ======== Filesystem ========/// Closes file for reading, resetting the offset and allowing to read it from beginning with readLine./// `path` is relative to the project root.functioncloseFile(stringcalldata path) external;
/// Copies the contents of one file to another. This function will **overwrite** the contents of `to`./// On success, the total number of bytes copied is returned and it is equal to the length of the `to` file as reported by `metadata`./// Both `from` and `to` are relative to the project root.functioncopyFile(stringcalldatafrom, stringcalldata to) externalreturns (uint64 copied);
/// Creates a new, empty directory at the provided path./// This cheatcode will revert in the following situations, but is not limited to just these cases:/// - User lacks permissions to modify `path`./// - A parent of the given path doesn't exist and `recursive` is false./// - `path` already exists and `recursive` is false./// `path` is relative to the project root.functioncreateDir(stringcalldata path, bool recursive) external;
/// Returns true if the given path points to an existing entity, else returns false.functionexists(stringcalldata path) externalreturns (bool result);
/// Performs a foreign function call via the terminal.functionffi(string[] calldata commandInput) externalreturns (bytesmemory result);
/// Given a path, query the file system to get information about a file, directory, etc.functionfsMetadata(stringcalldata path) externalviewreturns (FsMetadata memory metadata);
/// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file.functiongetCode(stringcalldata artifactPath) externalviewreturns (bytesmemory creationBytecode);
/// Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file.functiongetDeployedCode(stringcalldata artifactPath) externalviewreturns (bytesmemory runtimeBytecode);
/// Returns true if the path exists on disk and is pointing at a directory, else returns false.functionisDir(stringcalldata path) externalreturns (bool result);
/// Returns true if the path exists on disk and is pointing at a regular file, else returns false.functionisFile(stringcalldata path) externalreturns (bool result);
/// Get the path of the current project root.functionprojectRoot() externalviewreturns (stringmemory path);
/// Reads the directory at the given path recursively, up to `maxDepth`./// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned./// Follows symbolic links if `followLinks` is true.functionreadDir(stringcalldata path) externalviewreturns (DirEntry[] memory entries);
/// See `readDir(string)`.functionreadDir(stringcalldata path, uint64 maxDepth) externalviewreturns (DirEntry[] memory entries);
/// See `readDir(string)`.functionreadDir(stringcalldata path, uint64 maxDepth, bool followLinks)
externalviewreturns (DirEntry[] memory entries);
/// Reads the entire content of file to string. `path` is relative to the project root.functionreadFile(stringcalldata path) externalviewreturns (stringmemory data);
/// Reads the entire content of file as binary. `path` is relative to the project root.functionreadFileBinary(stringcalldata path) externalviewreturns (bytesmemory data);
/// Reads next line of file to string.functionreadLine(stringcalldata path) externalviewreturns (stringmemory line);
/// Reads a symbolic link, returning the path that the link points to./// This cheatcode will revert in the following situations, but is not limited to just these cases:/// - `path` is not a symbolic link./// - `path` does not exist.functionreadLink(stringcalldata linkPath) externalviewreturns (stringmemory targetPath);
/// Removes a directory at the provided path./// This cheatcode will revert in the following situations, but is not limited to just these cases:/// - `path` doesn't exist./// - `path` isn't a directory./// - User lacks permissions to modify `path`./// - The directory is not empty and `recursive` is false./// `path` is relative to the project root.functionremoveDir(stringcalldata path, bool recursive) external;
/// Removes a file from the filesystem./// This cheatcode will revert in the following situations, but is not limited to just these cases:/// - `path` points to a directory./// - The file doesn't exist./// - The user lacks permissions to remove the file./// `path` is relative to the project root.functionremoveFile(stringcalldata path) external;
/// Performs a foreign function call via terminal and returns the exit code, stdout, and stderr.functiontryFfi(string[] calldata commandInput) externalreturns (FfiResult memory result);
/// Returns the time since unix epoch in milliseconds.functionunixTime() externalreturns (uint256 milliseconds);
/// Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does./// `path` is relative to the project root.functionwriteFile(stringcalldata path, stringcalldata data) external;
/// Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does./// `path` is relative to the project root.functionwriteFileBinary(stringcalldata path, bytescalldata data) external;
/// Writes line to file, creating a file if it does not exist./// `path` is relative to the project root.functionwriteLine(stringcalldata path, stringcalldata data) external;
// ======== JSON ========/// Checks if `key` exists in a JSON object.functionkeyExists(stringcalldata json, stringcalldata key) externalviewreturns (bool);
/// Parses a string of JSON data at `key` and coerces it to `address`.functionparseJsonAddress(stringcalldata json, stringcalldata key) externalpurereturns (address);
/// Parses a string of JSON data at `key` and coerces it to `address[]`.functionparseJsonAddressArray(stringcalldata json, stringcalldata key)
externalpurereturns (address[] memory);
/// Parses a string of JSON data at `key` and coerces it to `bool`.functionparseJsonBool(stringcalldata json, stringcalldata key) externalpurereturns (bool);
/// Parses a string of JSON data at `key` and coerces it to `bool[]`.functionparseJsonBoolArray(stringcalldata json, stringcalldata key) externalpurereturns (bool[] memory);
/// Parses a string of JSON data at `key` and coerces it to `bytes`.functionparseJsonBytes(stringcalldata json, stringcalldata key) externalpurereturns (bytesmemory);
/// Parses a string of JSON data at `key` and coerces it to `bytes32`.functionparseJsonBytes32(stringcalldata json, stringcalldata key) externalpurereturns (bytes32);
/// Parses a string of JSON data at `key` and coerces it to `bytes32[]`.functionparseJsonBytes32Array(stringcalldata json, stringcalldata key)
externalpurereturns (bytes32[] memory);
/// Parses a string of JSON data at `key` and coerces it to `bytes[]`.functionparseJsonBytesArray(stringcalldata json, stringcalldata key) externalpurereturns (bytes[] memory);
/// Parses a string of JSON data at `key` and coerces it to `int256`.functionparseJsonInt(stringcalldata json, stringcalldata key) externalpurereturns (int256);
/// Parses a string of JSON data at `key` and coerces it to `int256[]`.functionparseJsonIntArray(stringcalldata json, stringcalldata key) externalpurereturns (int256[] memory);
/// Returns an array of all the keys in a JSON object.functionparseJsonKeys(stringcalldata json, stringcalldata key) externalpurereturns (string[] memory keys);
/// Parses a string of JSON data at `key` and coerces it to `string`.functionparseJsonString(stringcalldata json, stringcalldata key) externalpurereturns (stringmemory);
/// Parses a string of JSON data at `key` and coerces it to `string[]`.functionparseJsonStringArray(stringcalldata json, stringcalldata key) externalpurereturns (string[] memory);
/// Parses a string of JSON data at `key` and coerces it to `uint256`.functionparseJsonUint(stringcalldata json, stringcalldata key) externalpurereturns (uint256);
/// Parses a string of JSON data at `key` and coerces it to `uint256[]`.functionparseJsonUintArray(stringcalldata json, stringcalldata key) externalpurereturns (uint256[] memory);
/// ABI-encodes a JSON object.functionparseJson(stringcalldata json) externalpurereturns (bytesmemory abiEncodedData);
/// ABI-encodes a JSON object at `key`.functionparseJson(stringcalldata json, stringcalldata key) externalpurereturns (bytesmemory abiEncodedData);
/// See `serializeJson`.functionserializeAddress(stringcalldata objectKey, stringcalldata valueKey, address value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeAddress(stringcalldata objectKey, stringcalldata valueKey, address[] calldata values)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeBool(stringcalldata objectKey, stringcalldata valueKey, bool value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeBool(stringcalldata objectKey, stringcalldata valueKey, bool[] calldata values)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeBytes32(stringcalldata objectKey, stringcalldata valueKey, bytes32 value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeBytes32(stringcalldata objectKey, stringcalldata valueKey, bytes32[] calldata values)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeBytes(stringcalldata objectKey, stringcalldata valueKey, bytescalldata value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeBytes(stringcalldata objectKey, stringcalldata valueKey, bytes[] calldata values)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeInt(stringcalldata objectKey, stringcalldata valueKey, int256 value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeInt(stringcalldata objectKey, stringcalldata valueKey, int256[] calldata values)
externalreturns (stringmemory json);
/// Serializes a key and value to a JSON object stored in-memory that can be later written to a file./// Returns the stringified version of the specific JSON file up to that moment.functionserializeJson(stringcalldata objectKey, stringcalldata value) externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeString(stringcalldata objectKey, stringcalldata valueKey, stringcalldata value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeString(stringcalldata objectKey, stringcalldata valueKey, string[] calldata values)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeUint(stringcalldata objectKey, stringcalldata valueKey, uint256 value)
externalreturns (stringmemory json);
/// See `serializeJson`.functionserializeUint(stringcalldata objectKey, stringcalldata valueKey, uint256[] calldata values)
externalreturns (stringmemory json);
/// Write a serialized JSON object to a file. If the file exists, it will be overwritten.functionwriteJson(stringcalldata json, stringcalldata path) external;
/// Write a serialized JSON object to an **existing** JSON file, replacing a value with key = <value_key.>/// This is useful to replace a specific value of a JSON file, without having to parse the entire thing.functionwriteJson(stringcalldata json, stringcalldata path, stringcalldata valueKey) external;
// ======== Scripting ========/// Using the address that calls the test contract, has the next call (at this call depth only)/// create a transaction that can later be signed and sent onchain.functionbroadcast() external;
/// Has the next call (at this call depth only) create a transaction with the address provided/// as the sender that can later be signed and sent onchain.functionbroadcast(address signer) external;
/// Has the next call (at this call depth only) create a transaction with the private key/// provided as the sender that can later be signed and sent onchain.functionbroadcast(uint256 privateKey) external;
/// Using the address that calls the test contract, has all subsequent calls/// (at this call depth only) create transactions that can later be signed and sent onchain.functionstartBroadcast() external;
/// Has all subsequent calls (at this call depth only) create transactions with the address/// provided that can later be signed and sent onchain.functionstartBroadcast(address signer) external;
/// Has all subsequent calls (at this call depth only) create transactions with the private key/// provided that can later be signed and sent onchain.functionstartBroadcast(uint256 privateKey) external;
/// Stops collecting onchain transactions.functionstopBroadcast() external;
// ======== String ========/// Parses the given `string` into an `address`.functionparseAddress(stringcalldata stringifiedValue) externalpurereturns (address parsedValue);
/// Parses the given `string` into a `bool`.functionparseBool(stringcalldata stringifiedValue) externalpurereturns (bool parsedValue);
/// Parses the given `string` into `bytes`.functionparseBytes(stringcalldata stringifiedValue) externalpurereturns (bytesmemory parsedValue);
/// Parses the given `string` into a `bytes32`.functionparseBytes32(stringcalldata stringifiedValue) externalpurereturns (bytes32 parsedValue);
/// Parses the given `string` into a `int256`.functionparseInt(stringcalldata stringifiedValue) externalpurereturns (int256 parsedValue);
/// Parses the given `string` into a `uint256`.functionparseUint(stringcalldata stringifiedValue) externalpurereturns (uint256 parsedValue);
/// Converts the given value to a `string`.functiontoString(address value) externalpurereturns (stringmemory stringifiedValue);
/// Converts the given value to a `string`.functiontoString(bytescalldata value) externalpurereturns (stringmemory stringifiedValue);
/// Converts the given value to a `string`.functiontoString(bytes32 value) externalpurereturns (stringmemory stringifiedValue);
/// Converts the given value to a `string`.functiontoString(bool value) externalpurereturns (stringmemory stringifiedValue);
/// Converts the given value to a `string`.functiontoString(uint256 value) externalpurereturns (stringmemory stringifiedValue);
/// Converts the given value to a `string`.functiontoString(int256 value) externalpurereturns (stringmemory stringifiedValue);
// ======== Testing ========/// If the condition is false, discard this run's fuzz inputs and generate new ones.functionassume(bool condition) externalpure;
/// Writes a breakpoint to jump to in the debugger.functionbreakpoint(stringcalldata char) external;
/// Writes a conditional breakpoint to jump to in the debugger.functionbreakpoint(stringcalldata char, bool value) external;
/// Returns the RPC url for the given alias.functionrpcUrl(stringcalldata rpcAlias) externalviewreturns (stringmemory json);
/// Returns all rpc urls and their aliases as structs.functionrpcUrlStructs() externalviewreturns (Rpc[] memory urls);
/// Returns all rpc urls and their aliases `[alias, url][]`.functionrpcUrls() externalviewreturns (string[2][] memory urls);
/// Suspends execution of the main thread for `duration` milliseconds.functionsleep(uint256 duration) external;
// ======== Utilities ========/// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer.functioncomputeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer)
externalpurereturns (address);
/// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer.functioncomputeCreate2Address(bytes32 salt, bytes32 initCodeHash) externalpurereturns (address);
/// Compute the address a contract will be deployed at for a given deployer address and nonce.functioncomputeCreateAddress(address deployer, uint256 nonce) externalpurereturns (address);
/// Derives a private key from the name, labels the account with that name, and returns the wallet.functioncreateWallet(stringcalldata walletLabel) externalreturns (Wallet memory wallet);
/// Generates a wallet from the private key and returns the wallet.functioncreateWallet(uint256 privateKey) externalreturns (Wallet memory wallet);
/// Generates a wallet from the private key, labels the account with that name, and returns the wallet.functioncreateWallet(uint256 privateKey, stringcalldata walletLabel) externalreturns (Wallet memory wallet);
/// Derive a private key from a provided mnenomic string (or mnenomic file path)/// at the derivation path `m/44'/60'/0'/0/{index}`.functionderiveKey(stringcalldata mnemonic, uint32 index) externalpurereturns (uint256 privateKey);
/// Derive a private key from a provided mnenomic string (or mnenomic file path)/// at `{derivationPath}{index}`.functionderiveKey(stringcalldata mnemonic, stringcalldata derivationPath, uint32 index)
externalpurereturns (uint256 privateKey);
/// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language/// at the derivation path `m/44'/60'/0'/0/{index}`.functionderiveKey(stringcalldata mnemonic, uint32 index, stringcalldata language)
externalpurereturns (uint256 privateKey);
/// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language/// at `{derivationPath}{index}`.functionderiveKey(stringcalldata mnemonic, stringcalldata derivationPath, uint32 index, stringcalldata language)
externalpurereturns (uint256 privateKey);
/// Gets the label for the specified address.functiongetLabel(address account) externalviewreturns (stringmemory currentLabel);
/// Get a `Wallet`'s nonce.functiongetNonce(Wallet calldata wallet) externalreturns (uint64 nonce);
/// Labels an address in call traces.functionlabel(address account, stringcalldata newLabel) external;
/// Adds a private key to the local forge wallet and returns the address.functionrememberKey(uint256 privateKey) externalreturns (address keyAddr);
/// Signs data with a `Wallet`.functionsign(Wallet calldata wallet, bytes32 digest) externalreturns (uint8 v, bytes32 r, bytes32 s);
/// Encodes a `bytes` value to a base64url string.functiontoBase64URL(bytescalldata data) externalpurereturns (stringmemory);
/// Encodes a `string` value to a base64url string.functiontoBase64URL(stringcalldata data) externalpurereturns (stringmemory);
/// Encodes a `bytes` value to a base64 string.functiontoBase64(bytescalldata data) externalpurereturns (stringmemory);
/// Encodes a `string` value to a base64 string.functiontoBase64(stringcalldata data) externalpurereturns (stringmemory);
}
/// The `Vm` interface does allow manipulation of the EVM state. These are all intended to be used/// in tests, but it is not recommended to use these cheats in scripts.interfaceVmisVmSafe{
// ======== EVM ========/// Returns the identifier of the currently active fork. Reverts if no fork is currently active.functionactiveFork() externalviewreturns (uint256 forkId);
/// In forking mode, explicitly grant the given address cheatcode access.functionallowCheatcodes(address account) external;
/// Sets `block.chainid`.functionchainId(uint256 newChainId) external;
/// Clears all mocked calls.functionclearMockedCalls() external;
/// Sets `block.coinbase`.functioncoinbase(address newCoinbase) external;
/// Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork.functioncreateFork(stringcalldata urlOrAlias) externalreturns (uint256 forkId);
/// Creates a new fork with the given endpoint and block and returns the identifier of the fork.functioncreateFork(stringcalldata urlOrAlias, uint256 blockNumber) externalreturns (uint256 forkId);
/// Creates a new fork with the given endpoint and at the block the given transaction was mined in,/// replays all transaction mined in the block before the transaction, and returns the identifier of the fork.functioncreateFork(stringcalldata urlOrAlias, bytes32 txHash) externalreturns (uint256 forkId);
/// Creates and also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork.functioncreateSelectFork(stringcalldata urlOrAlias) externalreturns (uint256 forkId);
/// Creates and also selects a new fork with the given endpoint and block and returns the identifier of the fork.functioncreateSelectFork(stringcalldata urlOrAlias, uint256 blockNumber) externalreturns (uint256 forkId);
/// Creates and also selects new fork with the given endpoint and at the block the given transaction was mined in,/// replays all transaction mined in the block before the transaction, returns the identifier of the fork.functioncreateSelectFork(stringcalldata urlOrAlias, bytes32 txHash) externalreturns (uint256 forkId);
/// Sets an address' balance.functiondeal(address account, uint256 newBalance) external;
/// Removes the snapshot with the given ID created by `snapshot`./// Takes the snapshot ID to delete./// Returns `true` if the snapshot was successfully deleted./// Returns `false` if the snapshot does not exist.functiondeleteSnapshot(uint256 snapshotId) externalreturns (bool success);
/// Removes _all_ snapshots previously created by `snapshot`.functiondeleteSnapshots() external;
/// Sets `block.difficulty`./// Not available on EVM versions from Paris onwards. Use `prevrandao` instead./// Reverts if used on unsupported EVM versions.functiondifficulty(uint256 newDifficulty) external;
/// Dump a genesis JSON file's `allocs` to disk.functiondumpState(stringcalldata pathToStateJson) external;
/// Sets an address' code.functionetch(address target, bytescalldata newRuntimeBytecode) external;
/// Sets `block.basefee`.functionfee(uint256 newBasefee) external;
/// Returns true if the account is marked as persistent.functionisPersistent(address account) externalviewreturns (bool persistent);
/// Load a genesis JSON file's `allocs` into the in-memory revm state.functionloadAllocs(stringcalldata pathToAllocsJson) external;
/// Marks that the account(s) should use persistent storage across fork swaps in a multifork setup/// Meaning, changes made to the state of this account will be kept when switching forks.functionmakePersistent(address account) external;
/// See `makePersistent(address)`.functionmakePersistent(address account0, address account1) external;
/// See `makePersistent(address)`.functionmakePersistent(address account0, address account1, address account2) external;
/// See `makePersistent(address)`.functionmakePersistent(address[] calldata accounts) external;
/// Reverts a call to an address with specified revert data.functionmockCallRevert(address callee, bytescalldata data, bytescalldata revertData) external;
/// Reverts a call to an address with a specific `msg.value`, with specified revert data.functionmockCallRevert(address callee, uint256 msgValue, bytescalldata data, bytescalldata revertData)
external;
/// Mocks a call to an address, returning specified data./// Calldata can either be strict or a partial match, e.g. if you only/// pass a Solidity selector to the expected calldata, then the entire Solidity/// function will be mocked.functionmockCall(address callee, bytescalldata data, bytescalldata returnData) external;
/// Mocks a call to an address with a specific `msg.value`, returning specified data./// Calldata match takes precedence over `msg.value` in case of ambiguity.functionmockCall(address callee, uint256 msgValue, bytescalldata data, bytescalldata returnData) external;
/// Sets the *next* call's `msg.sender` to be the input address.functionprank(address msgSender) external;
/// Sets the *next* call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.functionprank(address msgSender, address txOrigin) external;
/// Sets `block.prevrandao`./// Not available on EVM versions before Paris. Use `difficulty` instead./// If used on unsupported EVM versions it will revert.functionprevrandao(bytes32 newPrevrandao) external;
/// Reads the current `msg.sender` and `tx.origin` from state and reports if there is any active caller modification.functionreadCallers() externalreturns (CallerMode callerMode, address msgSender, address txOrigin);
/// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts.functionresetNonce(address account) external;
/// Revert the state of the EVM to a previous snapshot/// Takes the snapshot ID to revert to./// Returns `true` if the snapshot was successfully reverted./// Returns `false` if the snapshot does not exist./// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteSnapshot`.functionrevertTo(uint256 snapshotId) externalreturns (bool success);
/// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots/// Takes the snapshot ID to revert to./// Returns `true` if the snapshot was successfully reverted and deleted./// Returns `false` if the snapshot does not exist.functionrevertToAndDelete(uint256 snapshotId) externalreturns (bool success);
/// Revokes persistent status from the address, previously added via `makePersistent`.functionrevokePersistent(address account) external;
/// See `revokePersistent(address)`.functionrevokePersistent(address[] calldata accounts) external;
/// Sets `block.height`.functionroll(uint256 newHeight) external;
/// Updates the currently active fork to given block number/// This is similar to `roll` but for the currently active fork.functionrollFork(uint256 blockNumber) external;
/// Updates the currently active fork to given transaction. This will `rollFork` with the number/// of the block the transaction was mined in and replays all transaction mined before it in the block.functionrollFork(bytes32 txHash) external;
/// Updates the given fork to given block number.functionrollFork(uint256 forkId, uint256 blockNumber) external;
/// Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block.functionrollFork(uint256 forkId, bytes32 txHash) external;
/// Takes a fork identifier created by `createFork` and sets the corresponding forked state as active.functionselectFork(uint256 forkId) external;
/// Sets the nonce of an account. Must be higher than the current nonce of the account.functionsetNonce(address account, uint64 newNonce) external;
/// Sets the nonce of an account to an arbitrary value.functionsetNonceUnsafe(address account, uint64 newNonce) external;
/// Snapshot the current state of the evm./// Returns the ID of the snapshot that was created./// To revert a snapshot use `revertTo`.functionsnapshot() externalreturns (uint256 snapshotId);
/// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called.functionstartPrank(address msgSender) external;
/// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.functionstartPrank(address msgSender, address txOrigin) external;
/// Resets subsequent calls' `msg.sender` to be `address(this)`.functionstopPrank() external;
/// Stores a value to an address' storage slot.functionstore(address target, bytes32 slot, bytes32 value) external;
/// Fetches the given transaction from the active fork and executes it on the current state.functiontransact(bytes32 txHash) external;
/// Fetches the given transaction from the given fork and executes it on the current state.functiontransact(uint256 forkId, bytes32 txHash) external;
/// Sets `tx.gasprice`.functiontxGasPrice(uint256 newGasPrice) external;
/// Sets `block.timestamp`.functionwarp(uint256 newTimestamp) external;
// ======== Testing ========/// Expect a call to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.functionexpectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytescalldata data) external;
/// Expect given number of calls to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.functionexpectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytescalldata data, uint64 count)
external;
/// Expects a call to an address with the specified calldata./// Calldata can either be a strict or a partial match.functionexpectCall(address callee, bytescalldata data) external;
/// Expects given number of calls to an address with the specified calldata.functionexpectCall(address callee, bytescalldata data, uint64 count) external;
/// Expects a call to an address with the specified `msg.value` and calldata.functionexpectCall(address callee, uint256 msgValue, bytescalldata data) external;
/// Expects given number of calls to an address with the specified `msg.value` and calldata.functionexpectCall(address callee, uint256 msgValue, bytescalldata data, uint64 count) external;
/// Expect a call to an address with the specified `msg.value`, gas, and calldata.functionexpectCall(address callee, uint256 msgValue, uint64 gas, bytescalldata data) external;
/// Expects given number of calls to an address with the specified `msg.value`, gas, and calldata.functionexpectCall(address callee, uint256 msgValue, uint64 gas, bytescalldata data, uint64 count) external;
/// Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.)./// Call this function, then emit an event, then call a function. Internally after the call, we check if/// logs were emitted in the expected order with the expected topics and data (as specified by the booleans).functionexpectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;
/// Same as the previous method, but also checks supplied address against emitting contract.functionexpectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter)
external;
/// Prepare an expected log with all topic and data checks enabled./// Call this function, then emit an event, then call a function. Internally after the call, we check if/// logs were emitted in the expected order with the expected topics and data.functionexpectEmit() external;
/// Same as the previous method, but also checks supplied address against emitting contract.functionexpectEmit(address emitter) external;
/// Expects an error on next call with any revert data.functionexpectRevert() external;
/// Expects an error on next call that starts with the revert data.functionexpectRevert(bytes4 revertData) external;
/// Expects an error on next call that exactly matches the revert data.functionexpectRevert(bytescalldata revertData) external;
/// Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the current subcontext. If any other/// memory is written to, the test will fail. Can be called multiple times to add more ranges to the set.functionexpectSafeMemory(uint64 min, uint64 max) external;
/// Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the next created subcontext./// If any other memory is written to, the test will fail. Can be called multiple times to add more ranges/// to the set.functionexpectSafeMemoryCall(uint64 min, uint64 max) external;
/// Marks a test as skipped. Must be called at the top of the test.functionskip(bool skipTest) external;
}
// SPDX-License-Identifier: GPL-3.0-or-later// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License// along with this program. If not, see <http://www.gnu.org/licenses/>.pragmasolidity >=0.5.0;contractDSTest{
eventlog (string);
eventlogs (bytes);
eventlog_address (address);
eventlog_bytes32 (bytes32);
eventlog_int (int);
eventlog_uint (uint);
eventlog_bytes (bytes);
eventlog_string (string);
eventlog_named_address (string key, address val);
eventlog_named_bytes32 (string key, bytes32 val);
eventlog_named_decimal_int (string key, int val, uint decimals);
eventlog_named_decimal_uint (string key, uint val, uint decimals);
eventlog_named_int (string key, int val);
eventlog_named_uint (string key, uint val);
eventlog_named_bytes (string key, bytes val);
eventlog_named_string (string key, string val);
boolpublic IS_TEST =true;
boolprivate _failed;
addressconstant HEVM_ADDRESS =address(bytes20(uint160(uint256(keccak256('hevm cheat code')))));
modifiermayRevert() { _; }
modifiertestopts(stringmemory) { _; }
functionfailed() publicreturns (bool) {
if (_failed) {
return _failed;
} else {
bool globalFailed =false;
if (hasHEVMContext()) {
(, bytesmemory retdata) = HEVM_ADDRESS.call(
abi.encodePacked(
bytes4(keccak256("load(address,bytes32)")),
abi.encode(HEVM_ADDRESS, bytes32("failed"))
)
);
globalFailed =abi.decode(retdata, (bool));
}
return globalFailed;
}
}
functionfail() internal{
if (hasHEVMContext()) {
(bool status, ) = HEVM_ADDRESS.call(
abi.encodePacked(
bytes4(keccak256("store(address,bytes32,bytes32)")),
abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01)))
)
);
status; // Silence compiler warnings
}
_failed =true;
}
functionhasHEVMContext() internalviewreturns (bool) {
uint256 hevmCodeSize =0;
assembly {
hevmCodeSize :=extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)
}
return hevmCodeSize >0;
}
modifierlogs_gas() {
uint startGas =gasleft();
_;
uint endGas =gasleft();
emit log_named_uint("gas", startGas - endGas);
}
functionassertTrue(bool condition) internal{
if (!condition) {
emit log("Error: Assertion Failed");
fail();
}
}
functionassertTrue(bool condition, stringmemory err) internal{
if (!condition) {
emit log_named_string("Error", err);
assertTrue(condition);
}
}
functionassertEq(address a, address b) internal{
if (a != b) {
emit log("Error: a == b not satisfied [address]");
emit log_named_address(" Expected", b);
emit log_named_address(" Actual", a);
fail();
}
}
functionassertEq(address a, address b, stringmemory err) internal{
if (a != b) {
emit log_named_string ("Error", err);
assertEq(a, b);
}
}
functionassertEq(bytes32 a, bytes32 b) internal{
if (a != b) {
emit log("Error: a == b not satisfied [bytes32]");
emit log_named_bytes32(" Expected", b);
emit log_named_bytes32(" Actual", a);
fail();
}
}
functionassertEq(bytes32 a, bytes32 b, stringmemory err) internal{
if (a != b) {
emit log_named_string ("Error", err);
assertEq(a, b);
}
}
functionassertEq32(bytes32 a, bytes32 b) internal{
assertEq(a, b);
}
functionassertEq32(bytes32 a, bytes32 b, stringmemory err) internal{
assertEq(a, b, err);
}
functionassertEq(int a, int b) internal{
if (a != b) {
emit log("Error: a == b not satisfied [int]");
emit log_named_int(" Expected", b);
emit log_named_int(" Actual", a);
fail();
}
}
functionassertEq(int a, int b, stringmemory err) internal{
if (a != b) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
functionassertEq(uint a, uint b) internal{
if (a != b) {
emit log("Error: a == b not satisfied [uint]");
emit log_named_uint(" Expected", b);
emit log_named_uint(" Actual", a);
fail();
}
}
functionassertEq(uint a, uint b, stringmemory err) internal{
if (a != b) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
functionassertEqDecimal(int a, int b, uint decimals) internal{
if (a != b) {
emit log("Error: a == b not satisfied [decimal int]");
emit log_named_decimal_int(" Expected", b, decimals);
emit log_named_decimal_int(" Actual", a, decimals);
fail();
}
}
functionassertEqDecimal(int a, int b, uint decimals, stringmemory err) internal{
if (a != b) {
emit log_named_string("Error", err);
assertEqDecimal(a, b, decimals);
}
}
functionassertEqDecimal(uint a, uint b, uint decimals) internal{
if (a != b) {
emit log("Error: a == b not satisfied [decimal uint]");
emit log_named_decimal_uint(" Expected", b, decimals);
emit log_named_decimal_uint(" Actual", a, decimals);
fail();
}
}
functionassertEqDecimal(uint a, uint b, uint decimals, stringmemory err) internal{
if (a != b) {
emit log_named_string("Error", err);
assertEqDecimal(a, b, decimals);
}
}
functionassertGt(uint a, uint b) internal{
if (a <= b) {
emit log("Error: a > b not satisfied [uint]");
emit log_named_uint(" Value a", a);
emit log_named_uint(" Value b", b);
fail();
}
}
functionassertGt(uint a, uint b, stringmemory err) internal{
if (a <= b) {
emit log_named_string("Error", err);
assertGt(a, b);
}
}
functionassertGt(int a, int b) internal{
if (a <= b) {
emit log("Error: a > b not satisfied [int]");
emit log_named_int(" Value a", a);
emit log_named_int(" Value b", b);
fail();
}
}
functionassertGt(int a, int b, stringmemory err) internal{
if (a <= b) {
emit log_named_string("Error", err);
assertGt(a, b);
}
}
functionassertGtDecimal(int a, int b, uint decimals) internal{
if (a <= b) {
emit log("Error: a > b not satisfied [decimal int]");
emit log_named_decimal_int(" Value a", a, decimals);
emit log_named_decimal_int(" Value b", b, decimals);
fail();
}
}
functionassertGtDecimal(int a, int b, uint decimals, stringmemory err) internal{
if (a <= b) {
emit log_named_string("Error", err);
assertGtDecimal(a, b, decimals);
}
}
functionassertGtDecimal(uint a, uint b, uint decimals) internal{
if (a <= b) {
emit log("Error: a > b not satisfied [decimal uint]");
emit log_named_decimal_uint(" Value a", a, decimals);
emit log_named_decimal_uint(" Value b", b, decimals);
fail();
}
}
functionassertGtDecimal(uint a, uint b, uint decimals, stringmemory err) internal{
if (a <= b) {
emit log_named_string("Error", err);
assertGtDecimal(a, b, decimals);
}
}
functionassertGe(uint a, uint b) internal{
if (a < b) {
emit log("Error: a >= b not satisfied [uint]");
emit log_named_uint(" Value a", a);
emit log_named_uint(" Value b", b);
fail();
}
}
functionassertGe(uint a, uint b, stringmemory err) internal{
if (a < b) {
emit log_named_string("Error", err);
assertGe(a, b);
}
}
functionassertGe(int a, int b) internal{
if (a < b) {
emit log("Error: a >= b not satisfied [int]");
emit log_named_int(" Value a", a);
emit log_named_int(" Value b", b);
fail();
}
}
functionassertGe(int a, int b, stringmemory err) internal{
if (a < b) {
emit log_named_string("Error", err);
assertGe(a, b);
}
}
functionassertGeDecimal(int a, int b, uint decimals) internal{
if (a < b) {
emit log("Error: a >= b not satisfied [decimal int]");
emit log_named_decimal_int(" Value a", a, decimals);
emit log_named_decimal_int(" Value b", b, decimals);
fail();
}
}
functionassertGeDecimal(int a, int b, uint decimals, stringmemory err) internal{
if (a < b) {
emit log_named_string("Error", err);
assertGeDecimal(a, b, decimals);
}
}
functionassertGeDecimal(uint a, uint b, uint decimals) internal{
if (a < b) {
emit log("Error: a >= b not satisfied [decimal uint]");
emit log_named_decimal_uint(" Value a", a, decimals);
emit log_named_decimal_uint(" Value b", b, decimals);
fail();
}
}
functionassertGeDecimal(uint a, uint b, uint decimals, stringmemory err) internal{
if (a < b) {
emit log_named_string("Error", err);
assertGeDecimal(a, b, decimals);
}
}
functionassertLt(uint a, uint b) internal{
if (a >= b) {
emit log("Error: a < b not satisfied [uint]");
emit log_named_uint(" Value a", a);
emit log_named_uint(" Value b", b);
fail();
}
}
functionassertLt(uint a, uint b, stringmemory err) internal{
if (a >= b) {
emit log_named_string("Error", err);
assertLt(a, b);
}
}
functionassertLt(int a, int b) internal{
if (a >= b) {
emit log("Error: a < b not satisfied [int]");
emit log_named_int(" Value a", a);
emit log_named_int(" Value b", b);
fail();
}
}
functionassertLt(int a, int b, stringmemory err) internal{
if (a >= b) {
emit log_named_string("Error", err);
assertLt(a, b);
}
}
functionassertLtDecimal(int a, int b, uint decimals) internal{
if (a >= b) {
emit log("Error: a < b not satisfied [decimal int]");
emit log_named_decimal_int(" Value a", a, decimals);
emit log_named_decimal_int(" Value b", b, decimals);
fail();
}
}
functionassertLtDecimal(int a, int b, uint decimals, stringmemory err) internal{
if (a >= b) {
emit log_named_string("Error", err);
assertLtDecimal(a, b, decimals);
}
}
functionassertLtDecimal(uint a, uint b, uint decimals) internal{
if (a >= b) {
emit log("Error: a < b not satisfied [decimal uint]");
emit log_named_decimal_uint(" Value a", a, decimals);
emit log_named_decimal_uint(" Value b", b, decimals);
fail();
}
}
functionassertLtDecimal(uint a, uint b, uint decimals, stringmemory err) internal{
if (a >= b) {
emit log_named_string("Error", err);
assertLtDecimal(a, b, decimals);
}
}
functionassertLe(uint a, uint b) internal{
if (a > b) {
emit log("Error: a <= b not satisfied [uint]");
emit log_named_uint(" Value a", a);
emit log_named_uint(" Value b", b);
fail();
}
}
functionassertLe(uint a, uint b, stringmemory err) internal{
if (a > b) {
emit log_named_string("Error", err);
assertLe(a, b);
}
}
functionassertLe(int a, int b) internal{
if (a > b) {
emit log("Error: a <= b not satisfied [int]");
emit log_named_int(" Value a", a);
emit log_named_int(" Value b", b);
fail();
}
}
functionassertLe(int a, int b, stringmemory err) internal{
if (a > b) {
emit log_named_string("Error", err);
assertLe(a, b);
}
}
functionassertLeDecimal(int a, int b, uint decimals) internal{
if (a > b) {
emit log("Error: a <= b not satisfied [decimal int]");
emit log_named_decimal_int(" Value a", a, decimals);
emit log_named_decimal_int(" Value b", b, decimals);
fail();
}
}
functionassertLeDecimal(int a, int b, uint decimals, stringmemory err) internal{
if (a > b) {
emit log_named_string("Error", err);
assertLeDecimal(a, b, decimals);
}
}
functionassertLeDecimal(uint a, uint b, uint decimals) internal{
if (a > b) {
emit log("Error: a <= b not satisfied [decimal uint]");
emit log_named_decimal_uint(" Value a", a, decimals);
emit log_named_decimal_uint(" Value b", b, decimals);
fail();
}
}
functionassertLeDecimal(uint a, uint b, uint decimals, stringmemory err) internal{
if (a > b) {
emit log_named_string("Error", err);
assertGeDecimal(a, b, decimals);
}
}
functionassertEq(stringmemory a, stringmemory b) internal{
if (keccak256(abi.encodePacked(a)) !=keccak256(abi.encodePacked(b))) {
emit log("Error: a == b not satisfied [string]");
emit log_named_string(" Expected", b);
emit log_named_string(" Actual", a);
fail();
}
}
functionassertEq(stringmemory a, stringmemory b, stringmemory err) internal{
if (keccak256(abi.encodePacked(a)) !=keccak256(abi.encodePacked(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
functioncheckEq0(bytesmemory a, bytesmemory b) internalpurereturns (bool ok) {
ok =true;
if (a.length== b.length) {
for (uint i =0; i < a.length; i++) {
if (a[i] != b[i]) {
ok =false;
}
}
} else {
ok =false;
}
}
functionassertEq0(bytesmemory a, bytesmemory b) internal{
if (!checkEq0(a, b)) {
emit log("Error: a == b not satisfied [bytes]");
emit log_named_bytes(" Expected", b);
emit log_named_bytes(" Actual", a);
fail();
}
}
functionassertEq0(bytesmemory a, bytesmemory b, stringmemory err) internal{
if (!checkEq0(a, b)) {
emit log_named_string("Error", err);
assertEq0(a, b);
}
}
}