// 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 45: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)pragmasolidity ^0.8.20;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
function_contextSuffixLength() internalviewvirtualreturns (uint256) {
return0;
}
}
Contract Source Code
File 3 of 45: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)pragmasolidity ^0.8.20;import {IERC165} from"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualreturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 4 of 45: ERC20.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)pragmasolidity ^0.8.20;import {IERC20} from"./IERC20.sol";
import {IERC20Metadata} from"./extensions/IERC20Metadata.sol";
import {Context} from"../../utils/Context.sol";
import {IERC20Errors} from"../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/abstractcontractERC20isContext, IERC20, IERC20Metadata, IERC20Errors{
mapping(address account =>uint256) private _balances;
mapping(address account =>mapping(address spender =>uint256)) private _allowances;
uint256private _totalSupply;
stringprivate _name;
stringprivate _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/functionname() publicviewvirtualreturns (stringmemory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/functionsymbol() publicviewvirtualreturns (stringmemory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/functiondecimals() publicviewvirtualreturns (uint8) {
return18;
}
/**
* @dev See {IERC20-totalSupply}.
*/functiontotalSupply() publicviewvirtualreturns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/functionbalanceOf(address account) publicviewvirtualreturns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/functiontransfer(address to, uint256 value) publicvirtualreturns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
returntrue;
}
/**
* @dev See {IERC20-allowance}.
*/functionallowance(address owner, address spender) publicviewvirtualreturns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/functionapprove(address spender, uint256 value) publicvirtualreturns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
returntrue;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/functiontransferFrom(addressfrom, address to, uint256 value) publicvirtualreturns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
returntrue;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/function_transfer(addressfrom, address to, uint256 value) internal{
if (from==address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to ==address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/function_update(addressfrom, address to, uint256 value) internalvirtual{
if (from==address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to ==address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/function_mint(address account, uint256 value) internal{
if (account ==address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/function_burn(address account, uint256 value) internal{
if (account ==address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/function_approve(address owner, address spender, uint256 value) internal{
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/function_approve(address owner, address spender, uint256 value, bool emitEvent) internalvirtual{
if (owner ==address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender ==address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/function_spendAllowance(address owner, address spender, uint256 value) internalvirtual{
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance !=type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
Contract Source Code
File 5 of 45: ERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)pragmasolidity ^0.8.20;import {IERC721} from"./IERC721.sol";
import {IERC721Receiver} from"./IERC721Receiver.sol";
import {IERC721Metadata} from"./extensions/IERC721Metadata.sol";
import {Context} from"../../utils/Context.sol";
import {Strings} from"../../utils/Strings.sol";
import {IERC165, ERC165} from"../../utils/introspection/ERC165.sol";
import {IERC721Errors} from"../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/abstractcontractERC721isContext, ERC165, IERC721, IERC721Metadata, IERC721Errors{
usingStringsforuint256;
// Token namestringprivate _name;
// Token symbolstringprivate _symbol;
mapping(uint256 tokenId =>address) private _owners;
mapping(address owner =>uint256) private _balances;
mapping(uint256 tokenId =>address) private _tokenApprovals;
mapping(address owner =>mapping(address operator =>bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewvirtualreturns (uint256) {
if (owner ==address(0)) {
revert ERC721InvalidOwner(address(0));
}
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId) publicviewvirtualreturns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualreturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualreturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualreturns (stringmemory) {
_requireOwned(tokenId);
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length>0 ? string.concat(baseURI, tokenId.toString()) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicvirtual{
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId) publicviewvirtualreturns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtual{
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator) publicviewvirtualreturns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom, address to, uint256 tokenId) publicvirtual{
if (to ==address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner !=from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId) public{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId, bytesmemory data) publicvirtual{
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/function_ownerOf(uint256 tokenId) internalviewvirtualreturns (address) {
return _owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/function_getApproved(uint256 tokenId) internalviewvirtualreturns (address) {
return _tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/function_isAuthorized(address owner, address spender, uint256 tokenId) internalviewvirtualreturns (bool) {
return
spender !=address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/function_checkAuthorized(address owner, address spender, uint256 tokenId) internalviewvirtual{
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner ==address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/function_increaseBalance(address account, uint128 value) internalvirtual{
unchecked {
_balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/function_update(address to, uint256 tokenId, address auth) internalvirtualreturns (address) {
addressfrom= _ownerOf(tokenId);
// Perform (optional) operator checkif (auth !=address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the updateif (from!=address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
_balances[from] -=1;
}
}
if (to !=address(0)) {
unchecked {
_balances[to] +=1;
}
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
returnfrom;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/function_mint(address to, uint256 tokenId) internal{
if (to ==address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner !=address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeMint(address to, uint256 tokenId) internal{
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/function_safeMint(address to, uint256 tokenId, bytesmemory data) internalvirtual{
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId) internal{
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner ==address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom, address to, uint256 tokenId) internal{
if (to ==address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner ==address(0)) {
revert ERC721NonexistentToken(tokenId);
} elseif (previousOwner !=from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeTransfer(addressfrom, address to, uint256 tokenId) internal{
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/function_safeTransfer(addressfrom, address to, uint256 tokenId, bytesmemory data) internalvirtual{
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/function_approve(address to, uint256 tokenId, address auth) internal{
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/function_approve(address to, uint256 tokenId, address auth, bool emitEvent) internalvirtual{
// Avoid reading the owner unless necessaryif (emitEvent || auth !=address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approveif (auth !=address(0) && owner != auth &&!isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
_tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/function_setApprovalForAll(address owner, address operator, bool approved) internalvirtual{
if (operator ==address(0)) {
revert ERC721InvalidOperator(operator);
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/function_requireOwned(uint256 tokenId) internalviewreturns (address) {
address owner = _ownerOf(tokenId);
if (owner ==address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
*/function_checkOnERC721Received(addressfrom, address to, uint256 tokenId, bytesmemory data) private{
if (to.code.length>0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytesmemory reason) {
if (reason.length==0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assemblyassembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}
Contract Source Code
File 6 of 45: ERC721Burnable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Burnable.sol)pragmasolidity ^0.8.20;import {ERC721} from"../ERC721.sol";
import {Context} from"../../../utils/Context.sol";
/**
* @title ERC721 Burnable Token
* @dev ERC721 Token that can be burned (destroyed).
*/abstractcontractERC721BurnableisContext, ERC721{
/**
* @dev Burns `tokenId`. See {ERC721-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/functionburn(uint256 tokenId) publicvirtual{
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
_update(address(0), tokenId, _msgSender());
}
}
Contract Source Code
File 7 of 45: ERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)pragmasolidity ^0.8.20;import {ERC721} from"../ERC721.sol";
import {IERC721Enumerable} from"./IERC721Enumerable.sol";
import {IERC165} from"../../../utils/introspection/ERC165.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
* of all the token ids in the contract as well as all token ids owned by each account.
*
* CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
* interfere with enumerability and should not be used together with `ERC721Enumerable`.
*/abstractcontractERC721EnumerableisERC721, IERC721Enumerable{
mapping(address owner =>mapping(uint256 index =>uint256)) private _ownedTokens;
mapping(uint256 tokenId =>uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 tokenId =>uint256) private _allTokensIndex;
/**
* @dev An `owner`'s token query was out of bounds for `index`.
*
* NOTE: The owner being `address(0)` indicates a global out of bounds index.
*/errorERC721OutOfBoundsIndex(address owner, uint256 index);
/**
* @dev Batch mint is not allowed.
*/errorERC721EnumerableForbiddenBatchMint();
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(IERC165, ERC721) returns (bool) {
return interfaceId ==type(IERC721Enumerable).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) publicviewvirtualreturns (uint256) {
if (index >= balanceOf(owner)) {
revert ERC721OutOfBoundsIndex(owner, index);
}
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/functiontotalSupply() publicviewvirtualreturns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/functiontokenByIndex(uint256 index) publicviewvirtualreturns (uint256) {
if (index >= totalSupply()) {
revert ERC721OutOfBoundsIndex(address(0), index);
}
return _allTokens[index];
}
/**
* @dev See {ERC721-_update}.
*/function_update(address to, uint256 tokenId, address auth) internalvirtualoverridereturns (address) {
address previousOwner =super._update(to, tokenId, auth);
if (previousOwner ==address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} elseif (previousOwner != to) {
_removeTokenFromOwnerEnumeration(previousOwner, tokenId);
}
if (to ==address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} elseif (previousOwner != to) {
_addTokenToOwnerEnumeration(to, tokenId);
}
return previousOwner;
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/function_addTokenToOwnerEnumeration(address to, uint256 tokenId) private{
uint256 length = balanceOf(to) -1;
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/function_addTokenToAllTokensEnumeration(uint256 tokenId) private{
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/function_removeTokenFromOwnerEnumeration(addressfrom, uint256 tokenId) private{
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and// then delete the last slot (swap and pop).uint256 lastTokenIndex = balanceOf(from);
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessaryif (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the arraydelete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/function_removeTokenFromAllTokensEnumeration(uint256 tokenId) private{
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and// then delete the last slot (swap and pop).uint256 lastTokenIndex = _allTokens.length-1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding// an 'if' statement (like in _removeTokenFromOwnerEnumeration)uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index// This also deletes the contents at the last position of the arraydelete _allTokensIndex[tokenId];
_allTokens.pop();
}
/**
* See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
*/function_increaseBalance(address account, uint128 amount) internalvirtualoverride{
if (amount >0) {
revert ERC721EnumerableForbiddenBatchMint();
}
super._increaseBalance(account, amount);
}
}
Contract Source Code
File 8 of 45: ERC721URIStorage.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol)pragmasolidity ^0.8.20;import {ERC721} from"../ERC721.sol";
import {Strings} from"../../../utils/Strings.sol";
import {IERC4906} from"../../../interfaces/IERC4906.sol";
import {IERC165} from"../../../interfaces/IERC165.sol";
/**
* @dev ERC721 token with storage based token URI management.
*/abstractcontractERC721URIStorageisIERC4906, ERC721{
usingStringsforuint256;
// Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only// defines events and does not include any external function.bytes4privateconstant ERC4906_INTERFACE_ID =bytes4(0x49064906);
// Optional mapping for token URIsmapping(uint256 tokenId =>string) private _tokenURIs;
/**
* @dev See {IERC165-supportsInterface}
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC721, IERC165) returns (bool) {
return interfaceId == ERC4906_INTERFACE_ID ||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
_requireOwned(tokenId);
stringmemory _tokenURI = _tokenURIs[tokenId];
stringmemory base = _baseURI();
// If there is no base URI, return the token URI.if (bytes(base).length==0) {
return _tokenURI;
}
// If both are set, concatenate the baseURI and tokenURI (via string.concat).if (bytes(_tokenURI).length>0) {
returnstring.concat(base, _tokenURI);
}
returnsuper.tokenURI(tokenId);
}
/**
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Emits {MetadataUpdate}.
*/function_setTokenURI(uint256 tokenId, stringmemory _tokenURI) internalvirtual{
_tokenURIs[tokenId] = _tokenURI;
emit MetadataUpdate(tokenId);
}
}
Contract Source Code
File 9 of 45: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)pragmasolidity ^0.8.20;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 10 of 45: IERC20.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)pragmasolidity ^0.8.20;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransfer(address to, uint256 value) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/functionapprove(address spender, uint256 value) externalreturns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom, address to, uint256 value) externalreturns (bool);
}
Contract Source Code
File 11 of 45: IERC20Metadata.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)pragmasolidity ^0.8.20;import {IERC20} from"../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/interfaceIERC20MetadataisIERC20{
/**
* @dev Returns the name of the token.
*/functionname() externalviewreturns (stringmemory);
/**
* @dev Returns the symbol of the token.
*/functionsymbol() externalviewreturns (stringmemory);
/**
* @dev Returns the decimals places of the token.
*/functiondecimals() externalviewreturns (uint8);
}
Contract Source Code
File 12 of 45: IERC4906.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol)pragmasolidity ^0.8.20;import {IERC165} from"./IERC165.sol";
import {IERC721} from"./IERC721.sol";
/// @title EIP-721 Metadata Update ExtensioninterfaceIERC4906isIERC165, IERC721{
/// @dev This event emits when the metadata of a token is changed./// So that the third-party platforms such as NFT market could/// timely update the images and related attributes of the NFT.eventMetadataUpdate(uint256 _tokenId);
/// @dev This event emits when the metadata of a range of tokens is changed./// So that the third-party platforms such as NFT market could/// timely update the images and related attributes of the NFTs.eventBatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
Contract Source Code
File 13 of 45: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.20;import {IERC165} from"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId, bytescalldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
Contract Source Code
File 14 of 45: IERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)pragmasolidity ^0.8.20;import {IERC721} from"../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/interfaceIERC721EnumerableisIERC721{
/**
* @dev Returns the total amount of tokens stored by the contract.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/functiontokenByIndex(uint256 index) externalviewreturns (uint256);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.20;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.23;import {ERC721} from"@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721Enumerable} from"@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import {ERC721URIStorage} from"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import {ERC721Burnable} from"@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import {Pausable} from"@openzeppelin/contracts/utils/Pausable.sol";
import {ReentrancyGuard} from"@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Ownable} from"@openzeppelin/contracts/access/Ownable.sol";
import {Strings} from"@openzeppelin/contracts/utils/Strings.sol";
import {ERC20} from"@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Math} from"@openzeppelin/contracts/utils/math/Math.sol";
import {console2} from"forge-std/Test.sol";
import {IL2VENFT} from"./interfaces/IL2VENFT.sol";
import {IL2VENFTPhase1} from"./interfaces/IL2VENFTPhase1.sol";
contractL2VENFTPublicisERC721,
ERC721Enumerable,
ERC721URIStorage,
Pausable,
Ownable,
ReentrancyGuard,
ERC721Burnable{
/// ===== 1. Propery Variables =====uint256private _tokenIdCounter;
uint256publicconstant MAX_SUPPLY =10_000;
uint256publicconstant MAX_PERMITTED =5;
ERC20 publicimmutable L2VE;
uint256public startAt;
uint256public totalSupplyPhase1;
uint256public totalBurned;
stringpublic baseURI;
addresspublic l2veNftPhase1;
mapping(address wallet =>uint256 numOfTokens) public tokens;
mapping(address wallet =>bool isBlacklisted) public blacklist;
modifierwhenStarted() {
if (startAt ==0) revert IL2VENFT.L2VENFT__Not_Initialized();
_;
}
/// ===== 2. Lifecycle Methods =====constructor(address _l2ve, address _l2veNft) ERC721("L2VE NFT PUBLIC", "L2VEP") Ownable(msg.sender) {
L2VE = ERC20(_l2ve);
baseURI ="ipfs://QmfQVrmH3MwGtbUXUbinphpFBmqKcXGAsb1P2eMCK48xW1/";
l2veNftPhase1 = _l2veNft;
uint256 supply = overallSupply();
totalSupplyPhase1 = supply;
_tokenIdCounter = supply +1; // Starts where past contract stopped
pause(); // Initialize it as pausedemit IL2VENFT.Created(MAX_SUPPLY);
}
/// ===== 3. Pauseable Functions =====/**
* @dev Pauses all token transfers.
* Can only be called by the contract owner.
*/functionpause() publiconlyOwner{
_pause();
}
/**
* @dev Unpauses token transfers.
* Can only be called by the contract owner.
*/functionunpause() publiconlyOwner{
_unpause();
}
/**
* @dev Adds an address to the blacklist, preventing them from minting NFTs.
* Can only be called by the contract owner.
* @param wallet The address to blacklist.
*/functionaddToBlackList(address wallet) externalonlyOwnernonReentrant{
blacklist[wallet] =true;
emit IL2VENFT.WalletBlacklisted(wallet);
}
/**
* @dev Removes an address from the blacklist, allowing them to mint NFTs again.
* Can only be called by the contract owner.
* @param wallet The address to remove from the blacklist.
*/functionremoveFromBlacklist(address wallet) externalonlyOwnernonReentrant{
blacklist[wallet] =false;
emit IL2VENFT.WalletRemovedFromBlacklist(wallet);
}
/**
* @dev Initializes the contract with timestamps for round endings.
* Can only be called by the contract owner.
*/functioninitialize(uint256 _startAt) externalonlyOwnernonReentrant{
if (startAt >0) revert IL2VENFT.L2VENFT__Already_Initialized();
if (_startAt ==0) revert IL2VENFT.L2VENFT__Cannot_Be_Zero();
startAt = _startAt;
unpause();
}
/// ===== 4. Minting Functions =====/**
* @dev Mints a new NFT token to the specified address.
* - Checks if minting is paused (requires `whenNotPaused` modifier).
* - Prevents reentrancy attacks (requires `nonReentrant` modifier).
* - Mints the specified number of tokens and emits a Minted event.
*
* Reverts with specific error messages in cases of:
* - User already minted in the current round.
* - User attempting to mint in round two without having minted in round one.
* - Exceeding the maximum supply.
*
* @param to The address to which the minted NFT will be assigned.
*/functionmint(address to) externalwhenNotPausedwhenStarted{
if (blacklist[to]) revert IL2VENFT.L2VENFT__Wallet_Blacklisted();
if (tokens[to] == MAX_PERMITTED) revert IL2VENFT.L2VENFT__Minted_Max_Permitted();
if (overallSupply() + MAX_PERMITTED > MAX_SUPPLY) {
revert IL2VENFT.L2VENFT__Reached_Max_Supply();
}
for (uint256 i =0; i < MAX_PERMITTED; i++) {
_mint(to);
}
}
/**
* @dev Mints a specified number of NFTs for the team wallet.
* Can only be called by the contract owner.
*
* @param to The address to mint tokens to (usually the team wallet).
* @param numOfTokens The number of NFTs to mint.
*
* Emits no event.
*/functionmintForTeam(address to, uint256 numOfTokens) externalonlyOwnerwhenStarted{
if (numOfTokens ==0) revert IL2VENFT.L2VENFT__Cannot_Mint_Zero_Tokens();
if (numOfTokens >10) revert IL2VENFT.L2VENFT__Reached_Max_For_Tx();
if (overallSupply() + numOfTokens > MAX_SUPPLY) revert IL2VENFT.L2VENFT__Reached_Max_Supply();
for (uint256 i =0; i < numOfTokens; i++) {
_mint(to);
}
}
/**
* @dev Internal function to mint a new token and assign it to the specified address.
* Increments the token ID counter and sets the token URI.
* Emits a Minted event on successful minting.
* @param to The address to which the minted token will be assigned.
*/function_mint(address to) privatenonReentrant{
uint256 tokenId = _tokenIdCounter;
_tokenIdCounter++;
tokens[to]++; // increase wallet mints counterstringmemory tokenUri = _generateTokenURI(tokenId);
_safeMint(to, tokenId);
_setTokenURI(tokenId, tokenUri);
emit IL2VENFT.Minted(to, tokenId, tokenUri);
}
/// ===== 5. Other Functions =====/**
* @dev Updates the base URI for the token metadata.
* Can only be called by the contract owner.
* @param _newBaseURI The new base URI for the token metadata.
*/functionupdatedBaseURI(stringmemory _newBaseURI) externalonlyOwnernonReentrant{
baseURI = _newBaseURI;
emit IL2VENFT.UpdatedBaseURI(owner(), _newBaseURI);
}
/**
* @dev Burns a range of tokens starting from a specified tokenId.
* Can only be called by the contract owner.
* @param to The wallet to mint tokens
*/functionburnTokensBatched(address to) externalonlyOwnernonReentrant{
uint256 startId = _tokenIdCounter;
uint256 batchSize =250;
// Calculate tokens to burn (capped by remaining supply)uint256 tokensToBurn = Math.min(batchSize, MAX_SUPPLY - overallSupply());
for (uint256 i =0; i < tokensToBurn; i++) {
uint256 tokenId = _tokenIdCounter;
stringmemory tokenUri = _generateTokenURI(tokenId);
_safeMint(to, tokenId);
_setTokenURI(tokenId, tokenUri);
_burn(startId + i);
_tokenIdCounter++;
totalBurned +=1;
}
emit IL2VENFT.TokensBurned(to, startId, startId + tokensToBurn -1);
}
/// INTERNAL FUNCTIONS/**
* @dev Internal function to generate the token URI based on the token ID.
* @param tokenId The ID of the token.
* @return The generated token URI.
*/function_generateTokenURI(uint256 tokenId) internalpurereturns (stringmemory) {
stringmemory tokenIdStr = Strings.toString(tokenId);
stringmemory tokenUri =string(abi.encodePacked(tokenIdStr, ".json"));
return tokenUri;
}
/// ===== 6. Overrinding Functions/**
* @dev Returns the base URI for the token metadata.
* @return The base URI.
*/function_baseURI() internalviewoverridereturns (stringmemory) {
return baseURI;
}
function_increaseBalance(address account, uint128 amount) internalvirtualoverride(ERC721, ERC721Enumerable) {}
function_update(address to, uint256 tokenId, address auth)
internalvirtualoverride(ERC721, ERC721Enumerable)
returns (address)
{
returnsuper._update(to, tokenId, auth); // Call the parent implementation if needed
}
/// PUBLIC FUNCTIONS/**
* @dev Returns the token URI for a given token ID.
* Overrides the inherited tokenURI function.
* @param tokenId The ID of the token.
* @return The token URI.
*/functiontokenURI(uint256 tokenId) publicviewoverride(ERC721, ERC721URIStorage) returns (stringmemory) {
returnsuper.tokenURI(tokenId);
}
/**
* @dev Checks if a given contract interface is supported.
* Overrides the inherited supportsInterface function.
* @param interfaceId The interface ID to check.
* @return A boolean indicating whether the interface is supported.
*/functionsupportsInterface(bytes4 interfaceId)
publicviewoverride(ERC721, ERC721Enumerable, ERC721URIStorage)
returns (bool)
{
returnsuper.supportsInterface(interfaceId);
}
functionoverallSupply() publicviewreturns (uint256) {
return totalSupply() + IL2VENFTPhase1(l2veNftPhase1).totalSupply();
}
}
Contract Source Code
File 21 of 45: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)pragmasolidity ^0.8.20;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
/**
* @dev Muldiv operation overflow.
*/errorMathOverflowedMulDiv();
enumRounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/functiontryAdd(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/functiontrySub(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/functiontryMul(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the// benefit is lost if 'b' is also tested.// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522if (a ==0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/functiontryDiv(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b ==0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/functiontryMod(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b ==0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b) / 2 can overflow.return (a & b) + (a ^ b) /2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
if (b ==0) {
// Guarantee the same behavior as in a regular Solidity division.return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.return a ==0 ? 0 : (a -1) / b +1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/functionmulDiv(uint256 x, uint256 y, uint256 denominator) internalpurereturns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256// variables such that product = prod1 * 2^256 + prod0.uint256 prod0 = x * y; // Least significant 256 bits of the productuint256 prod1; // Most significant 256 bits of the productassembly {
let mm :=mulmod(x, y, not(0))
prod1 :=sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.if (prod1 ==0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.// The surrounding unchecked block does not change this fact.// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////// 512 by 256 division.///////////////////////////////////////////////// Make division exact by subtracting the remainder from [prod1 prod0].uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder :=mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 :=sub(prod1, gt(remainder, prod0))
prod0 :=sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.uint256 twos = denominator & (0- denominator);
assembly {
// Divide denominator by twos.
denominator :=div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 :=div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos :=add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for// four bits. That is, denominator * inv = 1 mod 2^4.uint256 inverse = (3* denominator) ^2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also// works in modular arithmetic, doubling the correct bits in each step.
inverse *=2- denominator * inverse; // inverse mod 2^8
inverse *=2- denominator * inverse; // inverse mod 2^16
inverse *=2- denominator * inverse; // inverse mod 2^32
inverse *=2- denominator * inverse; // inverse mod 2^64
inverse *=2- denominator * inverse; // inverse mod 2^128
inverse *=2- denominator * inverse; // inverse mod 2^256// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/functionmulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internalpurereturns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) &&mulmod(x, y, denominator) >0) {
result +=1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.//// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.//// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`//// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.uint256 result =1<< (log2(a) >>1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision// into the expected uint128 result.unchecked {
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/functionlog2(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=128;
}
if (value >>64>0) {
value >>=64;
result +=64;
}
if (value >>32>0) {
value >>=32;
result +=32;
}
if (value >>16>0) {
value >>=16;
result +=16;
}
if (value >>8>0) {
value >>=8;
result +=8;
}
if (value >>4>0) {
value >>=4;
result +=4;
}
if (value >>2>0) {
value >>=2;
result +=2;
}
if (value >>1>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result =log2(value);
return result + (unsignedRoundsUp(rounding) &&1<< result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/functionlog10(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >=10**64) {
value /=10**64;
result +=64;
}
if (value >=10**32) {
value /=10**32;
result +=32;
}
if (value >=10**16) {
value /=10**16;
result +=16;
}
if (value >=10**8) {
value /=10**8;
result +=8;
}
if (value >=10**4) {
value /=10**4;
result +=4;
}
if (value >=10**2) {
value /=10**2;
result +=2;
}
if (value >=10**1) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) &&10** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/functionlog256(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=16;
}
if (value >>64>0) {
value >>=64;
result +=8;
}
if (value >>32>0) {
value >>=32;
result +=4;
}
if (value >>16>0) {
value >>=16;
result +=2;
}
if (value >>8>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) &&1<< (result <<3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/functionunsignedRoundsUp(Rounding rounding) internalpurereturns (bool) {
returnuint8(rounding) %2==1;
}
}
Contract Source Code
File 22 of 45: MockERC20.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;/// @notice This is a mock contract of the ERC20 standard for testing purposes only, it SHOULD NOT be used in production./// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC20.solcontractMockERC20{
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/eventTransfer(addressindexedfrom, addressindexed to, uint256 amount);
eventApproval(addressindexed owner, addressindexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/stringpublic name;
stringpublic symbol;
uint8public decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/uint256public totalSupply;
mapping(address=>uint256) public balanceOf;
mapping(address=>mapping(address=>uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/uint256internal INITIAL_CHAIN_ID;
bytes32internal INITIAL_DOMAIN_SEPARATOR;
mapping(address=>uint256) public nonces;
/*//////////////////////////////////////////////////////////////
INITIALIZE
//////////////////////////////////////////////////////////////*//// @dev A bool to track whether the contract has been initialized.boolprivate initialized;
/// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and/// syntaxes, we add an initialization function that can be called only once.functioninitialize(stringmemory _name, stringmemory _symbol, uint8 _decimals) public{
require(!initialized, "ALREADY_INITIALIZED");
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = _pureChainId();
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
initialized =true;
}
/*//////////////////////////////////////////////////////////////
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] = _sub(balanceOf[msg.sender], amount);
balanceOf[to] = _add(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 !=~uint256(0)) allowance[from][msg.sender] = _sub(allowed, amount);
balanceOf[from] = _sub(balanceOf[from], amount);
balanceOf[to] = _add(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");
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) {
return _pureChainId() == 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"),
_pureChainId(),
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/function_mint(address to, uint256 amount) internalvirtual{
totalSupply = _add(totalSupply, amount);
balanceOf[to] = _add(balanceOf[to], amount);
emit Transfer(address(0), to, amount);
}
function_burn(addressfrom, uint256 amount) internalvirtual{
balanceOf[from] = _sub(balanceOf[from], amount);
totalSupply = _sub(totalSupply, amount);
emit Transfer(from, address(0), amount);
}
/*//////////////////////////////////////////////////////////////
INTERNAL SAFE MATH LOGIC
//////////////////////////////////////////////////////////////*/function_add(uint256 a, uint256 b) internalpurereturns (uint256) {
uint256 c = a + b;
require(c >= a, "ERC20: addition overflow");
return c;
}
function_sub(uint256 a, uint256 b) internalpurereturns (uint256) {
require(a >= b, "ERC20: subtraction underflow");
return a - b;
}
/*//////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////*/// 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();
}
}
Contract Source Code
File 23 of 45: MockERC721.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.9.0;/// @notice This is a mock contract of the ERC721 standard for testing purposes only, it SHOULD NOT be used in production./// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC721.solcontractMockERC721{
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed id);
eventApproval(addressindexed owner, addressindexed spender, uint256indexed id);
eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE/LOGIC
//////////////////////////////////////////////////////////////*/stringpublic name;
stringpublic symbol;
functiontokenURI(uint256 id) publicviewvirtualreturns (stringmemory) {}
/*//////////////////////////////////////////////////////////////
ERC721 BALANCE/OWNER STORAGE
//////////////////////////////////////////////////////////////*/mapping(uint256=>address) internal _ownerOf;
mapping(address=>uint256) internal _balanceOf;
functionownerOf(uint256 id) publicviewvirtualreturns (address owner) {
require((owner = _ownerOf[id]) !=address(0), "NOT_MINTED");
}
functionbalanceOf(address owner) publicviewvirtualreturns (uint256) {
require(owner !=address(0), "ZERO_ADDRESS");
return _balanceOf[owner];
}
/*//////////////////////////////////////////////////////////////
ERC721 APPROVAL STORAGE
//////////////////////////////////////////////////////////////*/mapping(uint256=>address) public getApproved;
mapping(address=>mapping(address=>bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
INITIALIZE
//////////////////////////////////////////////////////////////*//// @dev A bool to track whether the contract has been initialized.boolprivate initialized;
/// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and/// syntaxes, we add an initialization function that can be called only once.functioninitialize(stringmemory _name, stringmemory _symbol) public{
require(!initialized, "ALREADY_INITIALIZED");
name = _name;
symbol = _symbol;
initialized =true;
}
/*//////////////////////////////////////////////////////////////
ERC721 LOGIC
//////////////////////////////////////////////////////////////*/functionapprove(address spender, uint256 id) publicvirtual{
address owner = _ownerOf[id];
require(msg.sender== owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
functionsetApprovalForAll(address operator, bool approved) publicvirtual{
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
functiontransferFrom(addressfrom, address to, uint256 id) publicvirtual{
require(from== _ownerOf[id], "WRONG_FROM");
require(to !=address(0), "INVALID_RECIPIENT");
require(
msg.sender==from|| isApprovedForAll[from][msg.sender] ||msg.sender== getApproved[id], "NOT_AUTHORIZED"
);
// Underflow of the sender's balance is impossible because we check for// ownership above and the recipient's balance can't realistically overflow.
_balanceOf[from]--;
_balanceOf[to]++;
_ownerOf[id] = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
functionsafeTransferFrom(addressfrom, address to, uint256 id) publicvirtual{
transferFrom(from, to, id);
require(
!_isContract(to)
|| IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "")
== IERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
functionsafeTransferFrom(addressfrom, address to, uint256 id, bytesmemory data) publicvirtual{
transferFrom(from, to, id);
require(
!_isContract(to)
|| IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data)
== IERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/functionsupportsInterface(bytes4 interfaceId) publicpurevirtualreturns (bool) {
return interfaceId ==0x01ffc9a7// ERC165 Interface ID for ERC165|| interfaceId ==0x80ac58cd// ERC165 Interface ID for ERC721|| interfaceId ==0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/function_mint(address to, uint256 id) internalvirtual{
require(to !=address(0), "INVALID_RECIPIENT");
require(_ownerOf[id] ==address(0), "ALREADY_MINTED");
// Counter overflow is incredibly unrealistic.
_balanceOf[to]++;
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function_burn(uint256 id) internalvirtual{
address owner = _ownerOf[id];
require(owner !=address(0), "NOT_MINTED");
_balanceOf[owner]--;
delete _ownerOf[id];
delete getApproved[id];
emit Transfer(owner, address(0), id);
}
/*//////////////////////////////////////////////////////////////
INTERNAL SAFE MINT LOGIC
//////////////////////////////////////////////////////////////*/function_safeMint(address to, uint256 id) internalvirtual{
_mint(to, id);
require(
!_isContract(to)
|| IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "")
== IERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function_safeMint(address to, uint256 id, bytesmemory data) internalvirtual{
_mint(to, id);
require(
!_isContract(to)
|| IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data)
== IERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
/*//////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////*/function_isContract(address _addr) privateviewreturns (bool) {
uint256 codeLength;
// Assembly required for versions < 0.8.0 to check extcodesize.assembly {
codeLength :=extcodesize(_addr)
}
return codeLength >0;
}
}
interfaceIERC721TokenReceiver{
functiononERC721Received(address, address, uint256, bytescalldata) externalreturns (bytes4);
}
Contract Source Code
File 24 of 45: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)pragmasolidity ^0.8.20;import {Context} from"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/errorOwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/errorOwnableInvalidOwner(address owner);
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/constructor(address initialOwner) {
if (initialOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
if (newOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 25 of 45: Pausable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)pragmasolidity ^0.8.20;import {Context} from"../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/abstractcontractPausableisContext{
boolprivate _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/eventPaused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/eventUnpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/errorEnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/errorExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/constructor() {
_paused =false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/modifierwhenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/modifierwhenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/functionpaused() publicviewvirtualreturns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/function_requireNotPaused() internalviewvirtual{
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/function_requirePaused() internalviewvirtual{
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/function_pause() internalvirtualwhenNotPaused{
_paused =true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/function_unpause() internalvirtualwhenPaused{
_paused =false;
emit Unpaused(_msgSender());
}
}
Contract Source Code
File 26 of 45: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)pragmasolidity ^0.8.20;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant NOT_ENTERED =1;
uint256privateconstant ENTERED =2;
uint256private _status;
/**
* @dev Unauthorized reentrant call.
*/errorReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be NOT_ENTEREDif (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/function_reentrancyGuardEntered() internalviewreturns (bool) {
return _status == ENTERED;
}
}
Contract Source Code
File 27 of 45: SignedMath.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)pragmasolidity ^0.8.20;/**
* @dev Standard signed math utilities missing in the Solidity language.
*/librarySignedMath{
/**
* @dev Returns the largest of two signed numbers.
*/functionmax(int256 a, int256 b) internalpurereturns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/functionmin(int256 a, int256 b) internalpurereturns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/functionaverage(int256 a, int256 b) internalpurereturns (int256) {
// Formula from the book "Hacker's Delight"int256 x = (a & b) + ((a ^ b) >>1);
return x + (int256(uint256(x) >>255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/functionabs(int256 n) internalpurereturns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`returnuint256(n >=0 ? n : -n);
}
}
}
Contract Source Code
File 28 of 45: 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 29 of 45: 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 30 of 45: 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 31 of 45: 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 35 of 45: 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));
}
}
Contract Source Code
File 38 of 45: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)pragmasolidity ^0.8.20;import {Math} from"./math/Math.sol";
import {SignedMath} from"./math/SignedMath.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant HEX_DIGITS ="0123456789abcdef";
uint8privateconstant ADDRESS_LENGTH =20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/errorStringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /=10;
if (value ==0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/functiontoStringSigned(int256 value) internalpurereturns (stringmemory) {
returnstring.concat(value <0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
uint256 localValue = value;
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = HEX_DIGITS[localValue &0xf];
localValue >>=4;
}
if (localValue !=0) {
revert StringsInsufficientHexLength(value, length);
}
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/functionequal(stringmemory a, stringmemory b) internalpurereturns (bool) {
returnbytes(a).length==bytes(b).length&&keccak256(bytes(a)) ==keccak256(bytes(b));
}
}
// 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: MIT// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)pragmasolidity ^0.8.20;/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/interfaceIERC20Errors{
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/errorERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/errorERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/errorERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/errorERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/errorERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/errorERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/interfaceIERC721Errors{
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/errorERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/errorERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/errorERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/errorERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/errorERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/errorERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/errorERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/errorERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/interfaceIERC1155Errors{
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/errorERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/errorERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/errorERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/errorERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/errorERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/errorERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/errorERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
// 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() internalvirtual{
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(" Left", a);
emit log_named_address(" Right", b);
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(" Left", a);
emit log_named_bytes32(" Right", b);
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(" Left", a);
emit log_named_int(" Right", b);
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(" Left", a);
emit log_named_uint(" Right", b);
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(" Left", a, decimals);
emit log_named_decimal_int(" Right", b, 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(" Left", a, decimals);
emit log_named_decimal_uint(" Right", b, 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);
}
}
functionassertNotEq(address a, address b) internal{
if (a == b) {
emit log("Error: a != b not satisfied [address]");
emit log_named_address(" Left", a);
emit log_named_address(" Right", b);
fail();
}
}
functionassertNotEq(address a, address b, stringmemory err) internal{
if (a == b) {
emit log_named_string ("Error", err);
assertNotEq(a, b);
}
}
functionassertNotEq(bytes32 a, bytes32 b) internal{
if (a == b) {
emit log("Error: a != b not satisfied [bytes32]");
emit log_named_bytes32(" Left", a);
emit log_named_bytes32(" Right", b);
fail();
}
}
functionassertNotEq(bytes32 a, bytes32 b, stringmemory err) internal{
if (a == b) {
emit log_named_string ("Error", err);
assertNotEq(a, b);
}
}
functionassertNotEq32(bytes32 a, bytes32 b) internal{
assertNotEq(a, b);
}
functionassertNotEq32(bytes32 a, bytes32 b, stringmemory err) internal{
assertNotEq(a, b, err);
}
functionassertNotEq(int a, int b) internal{
if (a == b) {
emit log("Error: a != b not satisfied [int]");
emit log_named_int(" Left", a);
emit log_named_int(" Right", b);
fail();
}
}
functionassertNotEq(int a, int b, stringmemory err) internal{
if (a == b) {
emit log_named_string("Error", err);
assertNotEq(a, b);
}
}
functionassertNotEq(uint a, uint b) internal{
if (a == b) {
emit log("Error: a != b not satisfied [uint]");
emit log_named_uint(" Left", a);
emit log_named_uint(" Right", b);
fail();
}
}
functionassertNotEq(uint a, uint b, stringmemory err) internal{
if (a == b) {
emit log_named_string("Error", err);
assertNotEq(a, b);
}
}
functionassertNotEqDecimal(int a, int b, uint decimals) internal{
if (a == b) {
emit log("Error: a != b not satisfied [decimal int]");
emit log_named_decimal_int(" Left", a, decimals);
emit log_named_decimal_int(" Right", b, decimals);
fail();
}
}
functionassertNotEqDecimal(int a, int b, uint decimals, stringmemory err) internal{
if (a == b) {
emit log_named_string("Error", err);
assertNotEqDecimal(a, b, decimals);
}
}
functionassertNotEqDecimal(uint a, uint b, uint decimals) internal{
if (a == b) {
emit log("Error: a != b not satisfied [decimal uint]");
emit log_named_decimal_uint(" Left", a, decimals);
emit log_named_decimal_uint(" Right", b, decimals);
fail();
}
}
functionassertNotEqDecimal(uint a, uint b, uint decimals, stringmemory err) internal{
if (a == b) {
emit log_named_string("Error", err);
assertNotEqDecimal(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);
assertLeDecimal(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(" Left", a);
emit log_named_string(" Right", b);
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);
}
}
functionassertNotEq(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(" Left", a);
emit log_named_string(" Right", b);
fail();
}
}
functionassertNotEq(stringmemory a, stringmemory b, stringmemory err) internal{
if (keccak256(abi.encodePacked(a)) ==keccak256(abi.encodePacked(b))) {
emit log_named_string("Error", err);
assertNotEq(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(" Left", a);
emit log_named_bytes(" Right", b);
fail();
}
}
functionassertEq0(bytesmemory a, bytesmemory b, stringmemory err) internal{
if (!checkEq0(a, b)) {
emit log_named_string("Error", err);
assertEq0(a, b);
}
}
functionassertNotEq0(bytesmemory a, bytesmemory b) internal{
if (checkEq0(a, b)) {
emit log("Error: a != b not satisfied [bytes]");
emit log_named_bytes(" Left", a);
emit log_named_bytes(" Right", b);
fail();
}
}
functionassertNotEq0(bytesmemory a, bytesmemory b, stringmemory err) internal{
if (checkEq0(a, b)) {
emit log_named_string("Error", err);
assertNotEq0(a, b);
}
}
}