More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 44,739 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint Reward | 50655225 | 2 secs ago | IN | 0 ETH | 0.00001814 | ||||
Mint Reward | 50655204 | 24 secs ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50655154 | 1 min ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50655136 | 1 min ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50655068 | 2 mins ago | IN | 0 ETH | 0.00000999 | ||||
Mint Reward | 50655055 | 2 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50655045 | 3 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50655034 | 3 mins ago | IN | 0 ETH | 0.00000999 | ||||
Mint Reward | 50655018 | 3 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654915 | 5 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654896 | 5 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654890 | 5 mins ago | IN | 0 ETH | 0.00001018 | ||||
Mint Reward | 50654889 | 5 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654883 | 6 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654874 | 6 mins ago | IN | 0 ETH | 0.00001805 | ||||
Mint Reward | 50654839 | 6 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654836 | 6 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654834 | 6 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654797 | 7 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654771 | 7 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654770 | 7 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654743 | 8 mins ago | IN | 0 ETH | 0.00001008 | ||||
Mint Reward | 50654731 | 8 mins ago | IN | 0 ETH | 0.00001805 | ||||
Mint Reward | 50654725 | 8 mins ago | IN | 0 ETH | 0.00000999 | ||||
Mint Reward | 50654721 | 8 mins ago | IN | 0 ETH | 0.00000999 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
44627456 | 77 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
Rewards
Compiler Version
v0.8.23+commit.f704f362
ZkSolc Version
v1.4.1
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {NODL} from "./NODL.sol"; import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol"; import {EIP712} from "openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol"; import {SignatureChecker} from "openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol"; import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol"; /** * @title Nodle DePIN Rewards * @dev This contract allows an authorized oracle to issue off-chain signed rewards to recipients. * This contract must have the MINTER_ROLE in the NODL token contract. */ contract Rewards is AccessControl, EIP712 { using Math for uint256; /** * @dev The signing domain used for generating signatures. */ string public constant SIGNING_DOMAIN = "rewards.depin.nodle"; /** * @dev The version of the signature scheme used. */ string public constant SIGNATURE_VERSION = "1"; /** * @dev The hash of the reward type structure. * It is calculated using the keccak256 hash function. * The structure consists of the recipient's address, the amount of the reward, and the sequence number for that recipient. */ bytes32 public constant REWARD_TYPE_HASH = keccak256("Reward(address recipient,uint256 amount,uint256 sequence)"); /** * @dev The hash of the batch reward type. * It is calculated by taking the keccak256 hash of the string representation of the batch reward type. * The batch reward type consists of the recipients, amounts, and sequence of that batch. */ bytes32 public constant BATCH_REWARD_TYPE_HASH = keccak256("BatchReward(bytes32 recipientsHash,bytes32 amountsHash,uint256 sequence)"); /** * @dev The maximum period for reward quota renewal. This is to prevent overflows while avoiding the ongoing overhead of safe math operations. */ uint256 public constant MAX_PERIOD = 30 days; /** * @dev The maximum value for basis points values. */ uint16 public constant BASIS_POINTS_DIVISOR = 10000; /** * @dev Struct on which basis an individual reward must be issued. */ struct Reward { address recipient; uint256 amount; uint256 sequence; } /** * @dev Represents a batch reward distribution. * Each batch reward consists of an array of recipients, an array of corresponding amounts, * and a sequence number to avoid replay attacks. */ struct BatchReward { address[] recipients; uint256[] amounts; uint256 sequence; } /** * @dev Reference to the NODL token contract. */ NODL public immutable nodl; /** * @dev Address of the authorized oracle. */ address public immutable authorizedOracle; /** * @dev Reward quota renewal period. */ uint256 public period; /** * @dev Maximum amount of rewards that can be distributed in a period. */ uint256 public quota; /** * @dev Timestamp indicating when the reward quota is due to be renewed. */ uint256 public quotaRenewalTimestamp; /** * @dev Amount of rewards claimed in the current period. */ uint256 public claimed; /** * @dev Mapping to store reward sequences for each recipient to prevent replay attacks. */ mapping(address => uint256) public sequences; /** * @dev The sequence number of the batch reward. */ uint256 public batchSequence; /** * @dev Represents the latest batch reward digest. */ bytes32 public latestBatchRewardDigest; /** * @notice The fraction of the batch reward that the submitter will receive. */ uint16 public batchSubmitterRewardBasisPoints; /** * @dev Error when the reward quota is exceeded. */ error QuotaExceeded(); /** * @dev Error indicating the reward renewal period is set to zero which is not acceptable. */ error ZeroPeriod(); /** * @dev Error indicating that scheduling the reward quota renewal has failed most likely due to the period being too long. */ error TooLongPeriod(); /** * @dev Error when the reward is not from the authorized oracle. */ error UnauthorizedOracle(); /** * @dev Error when the recipient's reward sequence does not match. */ error InvalidRecipientSequence(); /** * @dev Error thrown when an invalid batch sequence is encountered. */ error InvalidBatchSequence(); /** * @dev Throws an error if the batch structure is invalid. * The recipient and amounts arrays must have the same length. */ error InvalidBatchStructure(); /** * @dev Error thrown when the value is out of range. For example for basis point values they should be less than BASIS_POINTS_DIVISOR. */ error OutOfRangeValue(); /** * @dev Event emitted when the reward quota is set. */ event QuotaSet(uint256 quota); /** * @dev Event emitted when the reward period is set. */ event PeriodSet(uint256 period); /** * @dev Event emitted when the submitter's reward basis point is set. */ event BatchSubmitterRewardSet(uint16 bp); /** * @dev Event emitted when a reward is minted. */ event Minted(address indexed recipient, uint256 amount, uint256 totalRewardsClaimed); /** * @dev Emitted when a batch reward is minted. * @param batchSum The sum of rewards in the batch. * @param totalRewardsClaimed The total number of rewards claimed so far. */ event BatchMinted(uint256 batchSum, uint256 totalRewardsClaimed, bytes32 digest); /** * @dev Initializes the contract with the specified parameters. * @param token Address of the NODL token contract. * @param initialQuota Initial reward quota. * @param initialPeriod Initial reward period. * @param oracleAddress Address of the authorized oracle. * @param rewardBasisPoints The fraction of the reward to be given to the batch submitter. * @param admin Address of the admin who can change parameters like quota, period and submitter's reward fraction. */ constructor( NODL token, uint256 initialQuota, uint256 initialPeriod, address oracleAddress, uint16 rewardBasisPoints, address admin ) EIP712(SIGNING_DOMAIN, SIGNATURE_VERSION) { _mustBeWithinPeriodRange(initialPeriod); _mustBeLessThanBasisPointsDivisor(rewardBasisPoints); _grantRole(DEFAULT_ADMIN_ROLE, admin); nodl = token; quota = initialQuota; period = initialPeriod; quotaRenewalTimestamp = block.timestamp + period; authorizedOracle = oracleAddress; batchSubmitterRewardBasisPoints = rewardBasisPoints; } /** * @dev Sets the reward quota. Only accounts with the DEFAULT_ADMIN_ROLE can call this function. * @param newQuota The new reward quota. */ function setQuota(uint256 newQuota) external { _checkRole(DEFAULT_ADMIN_ROLE); quota = newQuota; emit QuotaSet(newQuota); } /** * @dev Sets the reward period. Only accounts with the DEFAULT_ADMIN_ROLE can call this function. * @param newPeriod The new reward period. */ function setPeriod(uint256 newPeriod) external { _checkRole(DEFAULT_ADMIN_ROLE); _mustBeWithinPeriodRange(newPeriod); period = newPeriod; emit PeriodSet(newPeriod); } /** * @dev Mints rewards to the recipient if the signature is valid and quota is not exceeded. * @param reward The reward details. * @param signature The signature from the authorized oracle. */ function mintReward(Reward memory reward, bytes memory signature) external { _mustBeExpectedSequence(reward.recipient, reward.sequence); _mustBeFromAuthorizedOracle(digestReward(reward), signature); _checkedResetClaimed(); _checkedUpdateClaimed(reward.amount); // Safe to increment the sequence after checking this is the expected number (no overflow for the age of universe even with 1000 reward claims per second) sequences[reward.recipient] = reward.sequence + 1; nodl.mint(reward.recipient, reward.amount); emit Minted(reward.recipient, reward.amount, claimed); } /** * @dev Mints batch rewards to multiple recipients. * @param batch The BatchReward struct containing the recipients and amounts of rewards to be minted. * @param signature The signature to verify the authenticity of the batch reward. */ function mintBatchReward(BatchReward memory batch, bytes memory signature) external { _mustBeValidBatchStructure(batch); _mustBeExpectedBatchSequence(batch.sequence); bytes32 digest = digestBatchReward(batch); _mustBeFromAuthorizedOracle(digest, signature); _checkedResetClaimed(); uint256 batchSum = _batchSum(batch); uint256 submitterRewardAmount = (batchSum * batchSubmitterRewardBasisPoints) / BASIS_POINTS_DIVISOR; _checkedUpdateClaimed(batchSum + submitterRewardAmount); // Safe to increment the sequence after checking this is the expected number (no overflow for the age of universe even with 1000 reward claims per second) batchSequence = batch.sequence + 1; latestBatchRewardDigest = digest; for (uint256 i = 0; i < batch.recipients.length; i++) { nodl.mint(batch.recipients[i], batch.amounts[i]); } nodl.mint(msg.sender, submitterRewardAmount); emit BatchMinted(batchSum, claimed, digest); } /** * @dev Sets the fraction of the batch reward that the submitter will receive. * @param newBasisPoints The new basis points value. */ function setBatchSubmitterRewardBasisPoints(uint16 newBasisPoints) external { _checkRole(DEFAULT_ADMIN_ROLE); _mustBeLessThanBasisPointsDivisor(newBasisPoints); batchSubmitterRewardBasisPoints = newBasisPoints; emit BatchSubmitterRewardSet(newBasisPoints); } /** * @notice This function resets the rewards claimed to 0 and updates the quota renewal timestamp based on the reward period. * @notice The following operations are safe based on the constructor's requirements for longer than the age of the universe. */ function _checkedResetClaimed() internal { if (block.timestamp >= quotaRenewalTimestamp) { claimed = 0; // The following operations are safe based on the constructor's requirements for longer than the age of universe :) uint256 timeAhead = block.timestamp - quotaRenewalTimestamp; quotaRenewalTimestamp = block.timestamp + period - (timeAhead % period); } } /** * @dev Internal function to update the rewards claimed by a given amount. * @param amount The amount of rewards to be added. * @notice This function is used to update the rewards claimed by a user. It checks if the new rewards claimed * exceeds the reward quota and reverts the transaction if it does. Otherwise, it updates the rewards claimed * by adding the specified amount. */ function _checkedUpdateClaimed(uint256 amount) internal { (bool success, uint256 newClaimed) = claimed.tryAdd(amount); if (!success || newClaimed > quota) { revert QuotaExceeded(); } claimed = newClaimed; } /** * @dev Internal check to ensure the basis points value is less than the divisor. * @param basisPoints The basis points value to be checked. */ function _mustBeLessThanBasisPointsDivisor(uint16 basisPoints) internal pure { if (basisPoints > BASIS_POINTS_DIVISOR) { revert OutOfRangeValue(); } } /** * @dev Internal check to ensure the `sequence` value is expected for `recipient`. * @param recipient The address of the recipient to check. * @param sequence The sequence value. */ function _mustBeExpectedSequence(address recipient, uint256 sequence) internal view { if (sequences[recipient] != sequence) { revert InvalidRecipientSequence(); } } /** * @dev Internal checks to ensure the given sequence is expected for the batch. * @param sequence The sequence to be checked. */ function _mustBeExpectedBatchSequence(uint256 sequence) internal view { if (batchSequence != sequence) { revert InvalidBatchSequence(); } } /** * @dev Internal check to ensure the given batch reward structure is valid, meaning same number of recipients and amounts. * @param batch The batch reward structure to be validated. */ function _mustBeValidBatchStructure(BatchReward memory batch) internal pure { if (batch.recipients.length != batch.amounts.length) { revert InvalidBatchStructure(); } } /** * @dev Checks if the provided signature is valid for the given hash and authorized oracle address. * @param hash The hash to be verified. * @param signature The signature to be checked. * @dev Throws an `UnauthorizedOracle` exception if the signature is not valid. */ function _mustBeFromAuthorizedOracle(bytes32 hash, bytes memory signature) internal view { if (!SignatureChecker.isValidSignatureNow(authorizedOracle, hash, signature)) { revert UnauthorizedOracle(); } } /** * @dev Calculates the sum of amounts in a BatchReward struct. * @param batch The BatchReward struct containing the amounts to be summed. * @return The sum of all amounts in the batch. */ function _batchSum(BatchReward memory batch) internal pure returns (uint256) { uint256 sum = 0; for (uint256 i = 0; i < batch.amounts.length; i++) { sum += batch.amounts[i]; } return sum; } /** * @dev Internal function to ensure the period is within the acceptable range. * @param newPeriod The new period to be checked. */ function _mustBeWithinPeriodRange(uint256 newPeriod) internal { // This is to avoid the ongoing overhead of safe math operations if (newPeriod == 0) { revert ZeroPeriod(); } // This is to prevent overflows while avoiding the ongoing overhead of safe math operations if (newPeriod > MAX_PERIOD) { revert TooLongPeriod(); } } /** * @dev Helper function to get the digest of the typed data to be signed. * @param reward detailing recipient, amount, and sequence. * @return The hash of the typed data. */ function digestReward(Reward memory reward) public view returns (bytes32) { return _hashTypedDataV4(keccak256(abi.encode(REWARD_TYPE_HASH, reward.recipient, reward.amount, reward.sequence))); } /** * @dev Calculates the digest of a BatchReward struct. * @param batch The BatchReward struct containing the recipients, amounts, and sequence. * @return The digest of the BatchReward struct. */ function digestBatchReward(BatchReward memory batch) public view returns (bytes32) { bytes32 recipientsHash = keccak256(abi.encodePacked(batch.recipients)); bytes32 amountsHash = keccak256(abi.encodePacked(batch.amounts)); return _hashTypedDataV4(keccak256(abi.encode(BATCH_REWARD_TYPE_HASH, recipientsHash, amountsHash, batch.sequence))); } /** * @dev Returns the latest batch details. * @return The next batch sequence and the latest digest of a successfully submitted batch which must have been for batchSequence - 1. */ function latestBatchDetails() external view returns (uint256, bytes32) { return (batchSequence, latestBatchRewardDigest); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @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. */ error ERC20InsufficientBalance(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. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(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. */ error ERC20InsufficientAllowance(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. */ error ERC20InvalidApprover(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. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @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. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(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. */ error ERC721IncorrectOwner(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. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(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. */ error ERC721InsufficientApproval(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. */ error ERC721InvalidApprover(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. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @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. */ error ERC1155InsufficientBalance(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. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(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. */ error ERC1155MissingApprovalForAll(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. */ error ERC1155InvalidApprover(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. */ error ERC1155InvalidOperator(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 */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; import {IERC721} from "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, 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. event MetadataUpdate(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. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^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. */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _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(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { 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}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (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`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (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. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @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`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @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(address from, 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(address from, address to, uint256 value) internal virtual { 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) internal virtual { 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) internal virtual { 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); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys a `value` amount of tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 value) public virtual { _burn(_msgSender(), value); } /** * @dev Destroys a `value` amount of tokens from `account`, deducting from * the caller's allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `value`. */ function burnFrom(address account, uint256 value) public virtual { _spendAllowance(account, _msgSender(), value); _burn(account, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed 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. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (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. */ function transfer(address to, uint256 value) external returns (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. */ function allowance(address owner, address spender) external view returns (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. */ function approve(address spender, uint256 value) external returns (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. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol) pragma solidity ^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}. */ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { using Strings for uint256; // Token name string private _name; // Token symbol string private _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(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual returns (uint256) { if (owner == address(0)) { revert ERC721InvalidOwner(address(0)); } return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual returns (address) { return _requireOwned(tokenId); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual returns (string memory) { _requireOwned(tokenId); string memory baseURI = _baseURI(); return bytes(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() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual { _approve(to, tokenId, _msgSender()); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual returns (address) { _requireOwned(tokenId); return _getApproved(tokenId); } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual { 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}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { 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) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. */ function _getApproved(uint256 tokenId) internal view virtual returns (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) internal view virtual returns (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) internal view virtual { 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) internal virtual { 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) internal virtual returns (address) { address from = _ownerOf(tokenId); // Perform (optional) operator check if (auth != address(0)) { _checkAuthorized(from, auth, tokenId); } // Execute the update if (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); return from; } /** * @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, bytes memory data) internal virtual { _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(address from, 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); } else if (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(address from, 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(address from, address to, uint256 tokenId, bytes memory data) internal virtual { _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) internal virtual { // Avoid reading the owner unless necessary if (emitEvent || auth != address(0)) { address owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve if (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) internal virtual { 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) internal view returns (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(address from, address to, uint256 tokenId, bytes memory 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 (bytes memory reason) { if (reason.length == 0) { revert ERC721InvalidReceiver(to); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol) pragma solidity ^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. */ abstract contract ERC721URIStorage is IERC4906, ERC721 { using Strings for uint256; // 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. bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906); // Optional mapping for token URIs mapping(uint256 tokenId => string) private _tokenURIs; /** * @dev See {IERC165-supportsInterface} */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireOwned(tokenId); string memory _tokenURI = _tokenURIs[tokenId]; string memory 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) { return string.concat(base, _tokenURI); } return super.tokenURI(tokenId); } /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * * Emits {MetadataUpdate}. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { _tokenURIs[tokenId] = _tokenURI; emit MetadataUpdate(tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (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. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata 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. */ function safeTransferFrom(address from, 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. */ function transferFrom(address from, 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. */ function approve(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. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @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`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^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. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "./MessageHashUtils.sol"; import {ShortStrings, ShortString} from "../ShortStrings.sol"; import {IERC5267} from "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * @custom:oz-upgrades-unsafe-allow state-variable-immutable */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {IERC-5267}. */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: By default this function reads _name which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Name() internal view returns (string memory) { return _name.toStringWithFallback(_nameFallback); } /** * @dev The version parameter for the EIP712 domain. * * NOTE: By default this function reads _version which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Version() internal view returns (string memory) { return _version.toStringWithFallback(_versionFallback); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.20; import {ECDSA} from "./ECDSA.sol"; import {IERC1271} from "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Safe Wallet (previously Gnosis Safe). */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature); return (error == ECDSA.RecoverError.NoError && recovered == signer) || isValidERC1271SignatureNow(signer, hash, signature); } /** * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated * against the signer smart contract using ERC1271. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidERC1271SignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeCall(IERC1271.isValidSignature, (hash, signature)) ); return (success && result.length >= 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^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}. */ interface IERC165 { /** * @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. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { 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. */ function tryAdd(uint256 a, uint256 b) internal pure returns (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. */ function trySub(uint256 a, uint256 b) internal pure returns (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. */ function tryMul(uint256 a, uint256 b) internal pure returns (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/522 if (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. */ function tryDiv(uint256 a, uint256 b) internal pure returns (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. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (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. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (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. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (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 product uint256 prod1; // Most significant 256 bits of the product assembly { 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. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (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). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // 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. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (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. */ function log2(uint256 value) internal pure returns (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. */ function log2(uint256 value, Rounding rounding) internal pure returns (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. */ function log10(uint256 value) internal pure returns (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. */ function log10(uint256 value, Rounding rounding) internal pure returns (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. */ function log256(uint256 value) internal pure returns (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. */ function log256(uint256 value, Rounding rounding) internal pure returns (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. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (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. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) pragma solidity ^0.8.20; import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using * {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { 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. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(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); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {NODL} from "../NODL.sol"; /// @title BridgeBase /// @notice Abstract contract for bridging free or vested tokens with the help of oracles. /// @dev This contract provides basic functionalities for voting on proposals /// to bridge tokens and ensuring certain constraints such as voting thresholds and delays. abstract contract BridgeBase { /// @notice Token contract address for the NODL token. NODL public immutable nodl; /// @notice Mapping to track whether an address is an oracle. mapping(address => bool) public isOracle; /// @notice Minimum number of votes needed to execute a proposal. uint8 public threshold; /// @notice Number of blocks to delay before a proposal can be executed after reaching the voting threshold. uint256 public delay; /// @notice Maximum number of oracles allowed. uint8 public constant MAX_ORACLES = 10; /// @notice Mapping of proposals to oracles votes on them. mapping(bytes32 => mapping(address => bool)) public voted; /// @notice Emitted when the first vote a proposal has been cast. event VoteStarted(bytes32 indexed proposal, address oracle, address indexed user, uint256 amount); /// @notice Emitted when an oracle votes on a proposal which is already created. event Voted(bytes32 indexed proposal, address oracle); /// @notice Error to indicate an oracle has already voted on a proposal. error AlreadyVoted(bytes32 proposal, address oracle); /// @notice Error to indicate a proposal has already been executed. error AlreadyExecuted(bytes32 proposal); /// @notice Error to indicate parameters of a proposal have been changed after initiation. error ParametersChanged(bytes32 proposal); /// @notice Error to indicate an address is not recognized as an oracle. error NotAnOracle(address user); /// @notice Error to indicate it's too soon to execute a proposal. /// Please note `withdraw` here refers to a function for free tokens where they are minted for the user. /// We have kept the name for API compatibility. error NotYetWithdrawable(bytes32 proposal); /// @notice Error to indicate insufficient votes to execute a proposal. error NotEnoughVotes(bytes32 proposal); /// @notice Error to indicate that the number of oracles exceeds the allowed maximum. error MaxOraclesExceeded(); /// @notice Error to indicate that the number of oracles is less than the minimum required. error NotEnoughOracles(); /// @notice Error to indicate an invalid value for the minimum votes. error InvalidZeroForMinVotes(); /// @notice Initializes the contract with specified parameters. /// @param bridgeOracles Array of oracle accounts. /// @param token Contract address of the NODL token. /// @param minVotes Minimum required votes to consider a proposal valid. /// @param minDelay Blocks to wait before a passed proposal can be executed. constructor(address[] memory bridgeOracles, NODL token, uint8 minVotes, uint256 minDelay) { _mustNotBeZeroMinVotes(minVotes); _mustHaveEnoughOracles(bridgeOracles.length, minVotes); _mustNotExceedMaxOracles(bridgeOracles.length); for (uint256 i = 0; i < bridgeOracles.length; i++) { isOracle[bridgeOracles[i]] = true; } nodl = token; threshold = minVotes; delay = minDelay; } /// @notice Creates a new vote on a proposal. /// @dev Sets initial values and emits a VoteStarted event. /// @param proposal The hash identifier of the proposal. /// @param oracle The oracle address initiating the vote. /// @param user The user address associated with the vote. /// @param amount The amount of tokens being bridged. function _createVote(bytes32 proposal, address oracle, address user, uint256 amount) internal virtual { _processVote(proposal, oracle); emit VoteStarted(proposal, oracle, user, amount); } /// @notice Records a vote for a proposal by an oracle. /// @param proposal The hash identifier of the proposal. /// @param oracle The oracle casting the vote. function _recordVote(bytes32 proposal, address oracle) internal virtual { _mustNotHaveVotedYet(proposal, oracle); _processVote(proposal, oracle); emit Voted(proposal, oracle); } /// @notice Processes a vote for a proposal. function _processVote(bytes32 proposal, address oracle) internal virtual { voted[proposal][oracle] = true; _incTotalVotes(proposal); _updateLastVote(proposal, block.number); } /// @notice Executes a proposal after all conditions are met. /// @param proposal The hash identifier of the proposal. function _execute(bytes32 proposal) internal { _mustNotHaveExecutedYet(proposal); _mustHaveEnoughVotes(proposal); _mustBePastSafetyDelay(proposal); _flagAsExecuted(proposal); } /** * @dev Updates the last vote value for a given proposal. * @param proposal The identifier of the proposal. * @param value The new value for the last vote. */ function _updateLastVote(bytes32 proposal, uint256 value) internal virtual; /** * @dev Increments the total votes count for a given proposal. * @param proposal The identifier of the proposal. */ function _incTotalVotes(bytes32 proposal) internal virtual; /** * @dev Flags a proposal as executed. * @param proposal The identifier of the proposal. */ function _flagAsExecuted(bytes32 proposal) internal virtual; /** * @dev Retrieves the last vote value for a given proposal. * @param proposal The identifier of the proposal. * @return The last vote value. */ function _lastVote(bytes32 proposal) internal view virtual returns (uint256); /** * @dev Retrieves the total votes count for a given proposal. * @param proposal The identifier of the proposal. * @return The total votes count. */ function _totalVotes(bytes32 proposal) internal view virtual returns (uint8); /** * @dev Checks if a proposal has been executed. * @param proposal The identifier of the proposal. * @return A boolean indicating if the proposal has been executed. */ function _executed(bytes32 proposal) internal view virtual returns (bool); function _mustNotHaveExecutedYet(bytes32 proposal) internal view { if (_executed(proposal)) { revert AlreadyExecuted(proposal); } } function _mustBePastSafetyDelay(bytes32 proposal) internal view { if (block.number - _lastVote(proposal) < delay) { revert NotYetWithdrawable(proposal); } } function _mustHaveEnoughVotes(bytes32 proposal) internal view { if (_totalVotes(proposal) < threshold) { revert NotEnoughVotes(proposal); } } function _mustHaveEnoughOracles(uint256 length, uint256 minOracles) internal pure { if (length < minOracles) { revert NotEnoughOracles(); } } function _mustBeAnOracle(address maybeOracle) internal view { if (!isOracle[maybeOracle]) { revert NotAnOracle(maybeOracle); } } function _mustNotExceedMaxOracles(uint256 length) internal pure { if (length > MAX_ORACLES) { revert MaxOraclesExceeded(); } } function _mustNotBeZeroMinVotes(uint8 value) internal pure { if (value == 0) { revert InvalidZeroForMinVotes(); } } function _mustNotHaveVotedYet(bytes32 proposal, address oracle) internal view { if (voted[proposal][oracle]) { revert AlreadyVoted(proposal, oracle); } } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {Grants} from "../Grants.sol"; import {NODL} from "../NODL.sol"; import {BridgeBase} from "./BridgeBase.sol"; contract GrantsMigration is BridgeBase { /// @notice Maximum number of vesting schedules allowed per proposal. The 100 limit is coming from the Eden parachain. uint8 public constant MAX_SCHEDULES = 100; /// @dev Represents the vesting details of a proposal. struct Proposal { address target; // Address of the grant recipient. uint256 amount; // Total amount of tokens to be vested. Grants.VestingSchedule[] schedules; // Array of vesting schedules. } /// @dev Tracks voting and execution status of a proposal. struct ProposalStatus { uint256 lastVote; // Timestamp of the last vote. uint8 totalVotes; // Total number of votes cast. bool executed; // Whether the proposal has been executed. } // State variables Grants public immutable grants; // Grants contract. mapping(bytes32 => Proposal) public proposals; // Proposals identified by a hash. mapping(bytes32 => ProposalStatus) public proposalStatus; // Status of each proposal. // Events event Granted(bytes32 indexed proposal, address indexed user, uint256 amount, uint256 numOfSchedules); /** * @notice Error to indicate that the schedule array is empty. */ error EmptySchedules(); /** * @notice Error to indicate that the schedule array is too large. */ error TooManySchedules(); /** * @notice Error to indicate that the schedules do not add up to the total amount. */ error AmountMismatch(); /** * @param bridgeOracles Array of addresses authorized to initiate and vote on proposals. * @param token Address of the NODL token used for grants. * @param _grants Address of the Grants contract managing vesting schedules. * @param minVotes Minimum number of votes required to execute a proposal. * @param minDelay Minimum delay before a proposal can be executed. */ constructor(address[] memory bridgeOracles, NODL token, Grants _grants, uint8 minVotes, uint256 minDelay) BridgeBase(bridgeOracles, token, minVotes, minDelay) { grants = _grants; } /** * @notice Bridges a proposal for grant distribution across chains or domains. * @param paraTxHash Hash of the cross-chain transaction or parameter. * @param user Recipient of the grant. * @param amount Total token amount for the grant. * @param schedules Array of VestingSchedule, detailing the vesting mechanics. */ function bridge(bytes32 paraTxHash, address user, uint256 amount, Grants.VestingSchedule[] memory schedules) external { _mustBeAnOracle(msg.sender); _mustNotHaveExecutedYet(paraTxHash); if (_proposalExists(paraTxHash)) { _mustNotHaveVotedYet(paraTxHash, msg.sender); _mustNotBeChangingParameters(paraTxHash, user, amount, schedules); _recordVote(paraTxHash, msg.sender); } else { _createProposal(paraTxHash, msg.sender, user, amount, schedules); } } /** * @notice Executes the grant proposal, transferring vested tokens according to the schedules. * @param paraTxHash Hash of the proposal to be executed. */ function grant(bytes32 paraTxHash) external { _execute(paraTxHash); Proposal storage p = proposals[paraTxHash]; nodl.mint(address(this), proposals[paraTxHash].amount); nodl.approve(address(grants), proposals[paraTxHash].amount); for (uint256 i = 0; i < p.schedules.length; i++) { grants.addVestingSchedule( p.target, p.schedules[i].start, p.schedules[i].period, p.schedules[i].periodCount, p.schedules[i].perPeriodAmount, p.schedules[i].cancelAuthority ); } emit Granted(paraTxHash, p.target, p.amount, p.schedules.length); } // Internal helper functions below function _mustNotBeChangingParameters( bytes32 proposal, address user, uint256 amount, Grants.VestingSchedule[] memory schedules ) internal view { Proposal storage storedProposal = proposals[proposal]; if (storedProposal.amount != amount || storedProposal.target != user) { revert ParametersChanged(proposal); } uint256 len = storedProposal.schedules.length; if (len != schedules.length) { revert ParametersChanged(proposal); } for (uint256 i = 0; i < len; i++) { if ( storedProposal.schedules[i].start != schedules[i].start || storedProposal.schedules[i].period != schedules[i].period || storedProposal.schedules[i].periodCount != schedules[i].periodCount || storedProposal.schedules[i].perPeriodAmount != schedules[i].perPeriodAmount || storedProposal.schedules[i].cancelAuthority != schedules[i].cancelAuthority ) { revert ParametersChanged(proposal); } } } function _createProposal( bytes32 proposal, address oracle, address user, uint256 amount, Grants.VestingSchedule[] memory schedules ) internal { if (schedules.length == 0) { revert EmptySchedules(); } if (schedules.length > MAX_SCHEDULES) { revert TooManySchedules(); } uint256 totalAmount = 0; for (uint256 i = 0; i < schedules.length; i++) { grants.validateVestingSchedule( user, schedules[i].period, schedules[i].periodCount, schedules[i].perPeriodAmount ); totalAmount += schedules[i].perPeriodAmount * schedules[i].periodCount; } if (totalAmount != amount) { revert AmountMismatch(); } proposals[proposal] = Proposal({target: user, amount: amount, schedules: schedules}); super._createVote(proposal, oracle, user, amount); } function _proposalExists(bytes32 proposal) internal view returns (bool) { return proposalStatus[proposal].totalVotes > 0; } function _flagAsExecuted(bytes32 proposal) internal override { proposalStatus[proposal].executed = true; } function _incTotalVotes(bytes32 proposal) internal override { proposalStatus[proposal].totalVotes++; } function _updateLastVote(bytes32 proposal, uint256 value) internal override { proposalStatus[proposal].lastVote = value; } function _totalVotes(bytes32 proposal) internal view override returns (uint8) { return proposalStatus[proposal].totalVotes; } function _lastVote(bytes32 proposal) internal view override returns (uint256) { return proposalStatus[proposal].lastVote; } function _executed(bytes32 proposal) internal view override returns (bool) { return proposalStatus[proposal].executed; } }
// SPDX-License-Identifier: BSD-3-Clause-Clear /* * NOTE: For anyone considering reusing this contract, we recommend reading through the * matter-labs audit results carefully before proceeding. The Nodle team will not address * this issue because we may not use this contract in the near future. * * NFT Minting Can Be Blocked * Severity: Medium * Status: Reported * * Users cannot mint NFTs once the `individualHolders` variable exceeds the `maxHolders` * value, which is enforced by _mustAlreadyBeHolderOrEnoughHoldersRemaining. To mint a * level-1 NFT, users will need to bridge a relatively small amount of NODL tokens compared * to other levels. Given that the `individualHolders` variable is shared among all NFT * levels, malicious actors could exploit this by bridging small amounts of NODL tokens to * multiple addresses until reaching the `maxHolders` limit and minting level-1 NFTs for * them. As a result, it will disrupt the minting process for legitimate users. * * Recommendation: * We recommend revising the NFT minting process to allow unlimited NFT minting for lower * levels. */ pragma solidity 0.8.23; import {ERC721} from "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol"; import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; import {NODLMigration} from "./NODLMigration.sol"; contract MigrationNFT is ERC721 { uint256 public nextTokenId; uint256 public immutable maxHolders; NODLMigration public immutable migration; uint256[] public levels; string[] public levelToTokenURI; error InvalidZeroHolders(); error InvalidZeroLevels(); /** * @notice Mapping of token IDs to the levels they represent denominated from 1 (0 means token does not exists) */ mapping(uint256 => uint256) public tokenIdToNextLevel; /** * @notice Mapping of holders to the highest level they reached (denominated from 1) */ mapping(address => uint256) public holderToNextLevel; uint256 public individualHolders; mapping(bytes32 => bool) public claimed; error UnsortedLevelsList(); error UnequalLengths(); error TooManyHolders(); error AlreadyClaimed(); error NoLevelUp(); error ProposalDoesNotExist(); error NotExecuted(); error SoulBoundIsNotTransferrable(); /** * @notice Construct a new MigrationNFT contract * @param _migration the NODLMigration contract to bridge tokens * @param _maxHolders the maximum number of holders for the NFTs * @param _levels an array representing the different reward levels expressed in * the amount of tokens needed to get the NFT * @param _levelToTokenURI an array of URIs to the metadata of the NFTs */ constructor( NODLMigration _migration, uint256 _maxHolders, uint256[] memory _levels, string[] memory _levelToTokenURI ) ERC721("OG ZK NODL", "OG_ZK_NODL") { if (_maxHolders == 0) { revert InvalidZeroHolders(); } if (_levels.length == 0) { revert InvalidZeroLevels(); } if (_levels.length != _levelToTokenURI.length) { revert UnequalLengths(); } for (uint256 i = 1; i < _levels.length; i++) { if (_levels[i] <= _levels[i - 1]) { revert UnsortedLevelsList(); } } migration = _migration; maxHolders = _maxHolders; levels = _levels; levelToTokenURI = _levelToTokenURI; } /** * @notice Return the URI of the proper metadata for the given token ID * @param tokenId the token ID to mint */ function tokenURI(uint256 tokenId) public view virtual override(ERC721) returns (string memory) { _requireOwned(tokenId); // this will also mean that tokenIdToNextLevel is at least 1 uint256 level = tokenIdToNextLevel[tokenId]; return levelToTokenURI[level - 1]; } /** * @notice Mint a new NFT for the given user * @param txHash the transaction hash to bridge */ function safeMint(bytes32 txHash) public { _mustNotHaveBeenClaimed(txHash); (address target, uint256 amount,,, bool executed) = migration.proposals(txHash); _mustBeAnExistingProposal(target); _mustBeExecuted(executed); bool alreadyHolder = _mustAlreadyBeHolderOrEnoughHoldersRemaining(target); (uint256[] memory levelsToMint, uint256 nbLevelsToMint) = _computeLevelUps(target, amount); claimed[txHash] = true; if (!alreadyHolder) { individualHolders++; } for (uint256 i = 0; i < nbLevelsToMint; i++) { uint256 tokenId = nextTokenId++; tokenIdToNextLevel[tokenId] = levelsToMint[i] + 1; holderToNextLevel[target] = levelsToMint[i] + 1; _safeMint(target, tokenId); } } function _computeLevelUps(address target, uint256 amount) internal view returns (uint256[] memory levelsToMint, uint256 nbLevelsToMint) { levelsToMint = new uint256[](levels.length); nbLevelsToMint = 0; // We effectively iterate over all the levels the `target` has YET // to qualify for. This expressively skips levels the `target` has // already qualified for. uint256 nextLevel = holderToNextLevel[target]; for (uint256 i = nextLevel; i < levels.length; i++) { if (amount >= levels[i]) { levelsToMint[i - nextLevel] = i; nbLevelsToMint++; } } if (nbLevelsToMint == 0) { revert NoLevelUp(); } } function _mustNotHaveBeenClaimed(bytes32 txHash) internal view { if (claimed[txHash]) { revert AlreadyClaimed(); } } function _mustBeAnExistingProposal(address target) internal pure { // the relayers skip any transfers to the 0 address if (target == address(0)) { revert ProposalDoesNotExist(); } } function _mustBeExecuted(bool executed) internal pure { if (!executed) { revert NotExecuted(); } } function _mustAlreadyBeHolderOrEnoughHoldersRemaining(address target) internal view returns (bool alreadyHolder) { alreadyHolder = balanceOf(target) > 0; if (!alreadyHolder && individualHolders == maxHolders) { revert TooManyHolders(); } } function _update(address to, uint256 tokenId, address auth) internal override(ERC721) returns (address) { address from = _ownerOf(tokenId); if (from != address(0) && to != address(0)) { // only burn or mint is allowed for a SoulBound token revert SoulBoundIsNotTransferrable(); } return super._update(to, tokenId, auth); } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {NODL} from "../NODL.sol"; import {BridgeBase} from "./BridgeBase.sol"; /// @title NODLMigration /// @notice This contract is used to help migrating the NODL assets from the Nodle Parachain /// to the ZkSync contracts. contract NODLMigration is BridgeBase { struct Proposal { address target; uint256 amount; uint256 lastVote; uint8 totalVotes; bool executed; } // We track votes in a separate mapping to avoid having to write helper functions to // expose the votes for each proposal. mapping(bytes32 => Proposal) public proposals; event Withdrawn(bytes32 indexed proposal, address indexed user, uint256 amount); constructor(address[] memory bridgeOracles, NODL token, uint8 minVotes, uint256 minDelay) BridgeBase(bridgeOracles, token, minVotes, minDelay) {} /// @notice Bridge some tokens from the Nodle Parachain to the ZkSync contracts. This /// tracks "votes" from each oracle and unlocks execution after a withdrawal delay. /// @param paraTxHash The transaction hash on the Parachain for this transfer. /// @param user The user address. /// @param amount The amount of NODL tokens that the user has burnt on the Parachain. function bridge(bytes32 paraTxHash, address user, uint256 amount) external { _mustBeAnOracle(msg.sender); _mustNotHaveExecutedYet(paraTxHash); if (_proposalExists(paraTxHash)) { _mustNotHaveVotedYet(paraTxHash, msg.sender); _mustNotBeChangingParameters(paraTxHash, user, amount); _recordVote(paraTxHash, msg.sender); } else { _createVote(paraTxHash, msg.sender, user, amount); } } /// @notice Withdraw the NODL tokens from the contract to the user's address if the /// proposal has enough votes and has passed the safety delay. /// @param paraTxHash The transaction hash on the Parachain for this transfer. function withdraw(bytes32 paraTxHash) external { _execute(paraTxHash); _withdraw(paraTxHash, proposals[paraTxHash].target, proposals[paraTxHash].amount); } function _mustNotBeChangingParameters(bytes32 proposal, address user, uint256 amount) internal view { if (proposals[proposal].amount != amount || proposals[proposal].target != user) { revert ParametersChanged(proposal); } } function _proposalExists(bytes32 proposal) internal view returns (bool) { return proposals[proposal].totalVotes > 0 && proposals[proposal].amount > 0; } function _createVote(bytes32 proposal, address oracle, address user, uint256 amount) internal override { proposals[proposal].target = user; proposals[proposal].amount = amount; super._createVote(proposal, oracle, user, amount); } function _withdraw(bytes32 proposal, address user, uint256 amount) internal { nodl.mint(user, amount); emit Withdrawn(proposal, user, amount); } function _flagAsExecuted(bytes32 proposal) internal override { proposals[proposal].executed = true; } function _incTotalVotes(bytes32 proposal) internal override { proposals[proposal].totalVotes++; } function _updateLastVote(bytes32 proposal, uint256 value) internal override { proposals[proposal].lastVote = value; } function _totalVotes(bytes32 proposal) internal view override returns (uint8) { return proposals[proposal].totalVotes; } function _lastVote(bytes32 proposal) internal view override returns (uint256) { return proposals[proposal].lastVote; } function _executed(bytes32 proposal) internal view override returns (bool) { return proposals[proposal].executed; } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {ERC721} from "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol"; import {ERC721URIStorage} from "openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import {WhitelistPaymaster} from "../paymasters/WhitelistPaymaster.sol"; /// @notice a simple NFT contract for contentsign data where each nft is mapped to a one-time /// configurable URL. This is used for every variant of ContentSign with associated hooks. abstract contract BaseContentSign is ERC721, ERC721URIStorage { uint256 public nextTokenId; error UserIsNotWhitelisted(address user); constructor(string memory name, string memory symbol) ERC721(name, symbol) {} function safeMint(address to, string memory uri) public { _mustBeWhitelisted(); uint256 tokenId = nextTokenId++; _safeMint(to, tokenId); _setTokenURI(tokenId, uri); } function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); } function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721URIStorage) returns (bool) { return ERC721.supportsInterface(interfaceId) || ERC721URIStorage.supportsInterface(interfaceId); } function _mustBeWhitelisted() internal view { if (!_userIsWhitelisted(msg.sender)) { revert UserIsNotWhitelisted(msg.sender); } } function _userIsWhitelisted(address user) internal view virtual returns (bool); }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {BaseContentSign} from "./BaseContentSign.sol"; import {WhitelistPaymaster} from "../paymasters/WhitelistPaymaster.sol"; /// @notice the content sign contract variant for Click. Only users whitelisted on the paymaster can mint tokens contract ClickContentSign is BaseContentSign { WhitelistPaymaster public whitelistPaymaster; constructor(string memory name, string memory symbol, WhitelistPaymaster whitelist) BaseContentSign(name, symbol) { whitelistPaymaster = whitelist; } function _userIsWhitelisted(address user) internal view override returns (bool) { return whitelistPaymaster.isWhitelistedUser(user); } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {BaseContentSign} from "./BaseContentSign.sol"; import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol"; /// @notice the content sign contract variant for enterprises. Only users whitelisted on this contract can mint contract EnterpriseContentSign is BaseContentSign, AccessControl { bytes32 public constant WHITELISTED_ROLE = keccak256("WHITELISTED_ROLE"); constructor(string memory name, string memory symbol, address admin) BaseContentSign(name, symbol) { _grantRole(DEFAULT_ADMIN_ROLE, admin); } function supportsInterface(bytes4 interfaceId) public view override(BaseContentSign, AccessControl) returns (bool) { return BaseContentSign.supportsInterface(interfaceId) || AccessControl.supportsInterface(interfaceId); } function _userIsWhitelisted(address user) internal view override returns (bool) { return hasRole(WHITELISTED_ROLE, user); } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.23; import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title Grants * @notice Manages time-based token vesting schedules for ERC-20 tokens, allowing for the creation, * claiming, and cancellation of vesting schedules. * @dev Uses the SafeERC20 library to interact with ERC20 tokens securely. */ contract Grants { using SafeERC20 for IERC20; // Token used for vesting. IERC20 public immutable token; // Minimum amount of tokens that can be vested per period. This is a safety bound to prevent dusting attacks. uint256 public immutable perPeriodMinAmount; // Maximum number of vesting schedules per address per page. uint8 public immutable pageLimit; // Mapping of addresses to the current page of their vesting schedules. // The current page is the last page that has been used to store a vesting schedule. mapping(address => uint256) public currentPage; // Mapping of addresses to their vesting schedules split into pages. mapping(address => mapping(uint256 => VestingSchedule[])) public vestingSchedules; struct VestingSchedule { address cancelAuthority; // Address authorized to cancel the vesting. uint256 start; // Timestamp when vesting starts. uint256 period; // Duration of each period. uint32 periodCount; // Total number of periods. uint256 perPeriodAmount; // Amount of tokens distributed each period. } // Events event VestingScheduleAdded(address indexed to, VestingSchedule schedule); // start and end indicate the range of the grant pages that are iterated over for claiming. event Claimed(address indexed who, uint256 amount, uint256 start, uint256 end); // start and end indicate the range of the grant pages that are iterated over for cancelling. event VestingSchedulesCanceled(address indexed from, address indexed to, uint256 start, uint256 end); // start and end indicate the range of the grant pages that are iterated over for renouncing. event Renounced(address indexed from, address indexed to, uint256 start, uint256 end); // Errors error InvalidZeroParameter(); // Parameters such as some addresses and periods, periodCounts must be non-zero. error VestingToSelf(); // Thrown when the creator attempts to vest tokens to themselves. error NoOpIsFailure(); // Thrown when an operation that should change state does not. error LowVestingAmount(); // Thrown when the amount to be vested is below the minimum allowed. error InvalidPage(); // Thrown when the page is invalid. constructor(address _token, uint256 _perPeriodMinAmount, uint8 _pageLimit) { if (_pageLimit == 0) { revert InvalidZeroParameter(); } token = IERC20(_token); perPeriodMinAmount = _perPeriodMinAmount; pageLimit = _pageLimit; } /** * @notice Adds a vesting schedule to an account. * @param to Recipient of the tokens under the vesting schedule. * @param start Start time of the vesting schedule as a Unix timestamp. * @param period Duration of each period in seconds. * @param periodCount Number of periods in the vesting schedule. * @param perPeriodAmount Amount of tokens to be released each period. * @param cancelAuthority Address that has the authority to cancel the vesting. If set to address(0), no one can cancel. */ function addVestingSchedule( address to, uint256 start, uint256 period, uint32 periodCount, uint256 perPeriodAmount, address cancelAuthority ) external { validateVestingSchedule(to, period, periodCount, perPeriodAmount); VestingSchedule memory schedule = VestingSchedule(cancelAuthority, start, period, periodCount, perPeriodAmount); uint256 page = currentPage[to]; if (vestingSchedules[to][page].length == pageLimit) { page += 1; currentPage[to] = page; } vestingSchedules[to][page].push(schedule); token.safeTransferFrom(msg.sender, address(this), perPeriodAmount * periodCount); emit VestingScheduleAdded(to, schedule); } /** * @notice Checks if the vesting schedule parameters are valid. * @param to Recipient of the tokens under the vesting schedule. * @param period Duration of each period in seconds. * @param periodCount Number of periods in the vesting schedule. * @param perPeriodAmount Amount of tokens to be released each period. */ function validateVestingSchedule(address to, uint256 period, uint32 periodCount, uint256 perPeriodAmount) public view { _mustBeNonZeroAddress(to); _mustNotBeSelf(to); _mustBeNonZero(period); _mustBeNonZero(periodCount); _mustBeEqualOrExceedMinAmount(perPeriodAmount); } /** * @notice Claims all vested tokens available for msg.sender up to the current block timestamp. * @param start Start page of the vesting schedules to claim from. * @param end the page after the last page of the vesting schedules to claim from. * @dev if start == end == 0, all pages will be used for claim. */ function claim(uint256 start, uint256 end) external { uint256 totalClaimable = 0; uint256 currentTime = block.timestamp; (start, end) = _sanitizePageRange(msg.sender, start, end); for (uint256 page = start; page < end; page++) { uint256 i = 0; VestingSchedule[] storage schedules = vestingSchedules[msg.sender][page]; while (i < schedules.length) { VestingSchedule storage schedule = schedules[i]; if (currentTime > schedule.start) { uint256 periodsElapsed = (currentTime - schedule.start) / schedule.period; uint256 effectivePeriods = periodsElapsed > schedule.periodCount ? schedule.periodCount : periodsElapsed; uint256 claimable = effectivePeriods * schedule.perPeriodAmount; schedule.periodCount -= uint32(effectivePeriods); schedule.start += periodsElapsed * schedule.period; totalClaimable += claimable; if (schedule.periodCount == 0) { schedules[i] = schedules[schedules.length - 1]; schedules.pop(); continue; } } i++; } } if (totalClaimable > 0) { token.safeTransfer(msg.sender, totalClaimable); emit Claimed(msg.sender, totalClaimable, start, end); } else { revert NoOpIsFailure(); } } /** * @notice Renounces the cancel authority for all of the msg.sender's vesting schedules directed to a specific recipient. * @param to Recipient of the vesting whose schedules are affected. * @param start Start page of the vesting schedules to renounce from. * @param end the page after the last page of the vesting schedules to renounce from. * @dev if start == end == 0, all pages will be used for renounce. */ function renounce(address to, uint256 start, uint256 end) external { bool anySchedulesFound = false; (start, end) = _sanitizePageRange(to, start, end); for (uint256 page = start; page < end; page++) { VestingSchedule[] storage schedules = vestingSchedules[to][page]; for (uint256 i = 0; i < schedules.length; i++) { if (schedules[i].cancelAuthority == msg.sender) { schedules[i].cancelAuthority = address(0); anySchedulesFound = true; } } } if (!anySchedulesFound) { revert NoOpIsFailure(); } else { emit Renounced(msg.sender, to, start, end); } } /** * @notice Cancels all vesting schedules of a specific recipient, initiated by the cancel authority. * @param to Recipient whose schedules will be canceled. * @param start Start page of the vesting schedules to cancel. * @param end the page after the last page of the vesting schedules to cancel. * @dev if start == end == 0, all pages will be used for cancel. */ function cancelVestingSchedules(address to, uint256 start, uint256 end) external { uint256 totalClaimable = 0; uint256 totalRedeemable = 0; uint256 currentTime = block.timestamp; (start, end) = _sanitizePageRange(to, start, end); for (uint256 page = start; page < end; page++) { uint256 i = 0; VestingSchedule[] storage schedules = vestingSchedules[to][page]; while (i < schedules.length) { VestingSchedule storage schedule = schedules[i]; if (schedule.cancelAuthority == msg.sender) { uint256 periodsElapsed = currentTime > schedule.start ? (currentTime - schedule.start) / schedule.period : 0; uint256 effectivePeriods = periodsElapsed > schedule.periodCount ? schedule.periodCount : periodsElapsed; uint256 claimable = effectivePeriods * schedule.perPeriodAmount; uint256 redeemable = (schedule.periodCount - effectivePeriods) * schedule.perPeriodAmount; totalClaimable += claimable; totalRedeemable += redeemable; schedules[i] = schedules[schedules.length - 1]; schedules.pop(); continue; } i++; } } if (totalClaimable == 0 && totalRedeemable == 0) { revert NoOpIsFailure(); } if (totalClaimable > 0) { token.safeTransfer(to, totalClaimable); } if (totalRedeemable > 0) { token.safeTransfer(msg.sender, totalRedeemable); } emit VestingSchedulesCanceled(msg.sender, to, start, end); } /** * @notice Returns the number of vesting schedules associated with a given address. * @param to The address whose schedule count is to be queried. * @return The number of vesting schedules associated with the address. */ function getGrantsCount(address to) external view returns (uint256) { uint256 count = 0; for (uint256 i = 0; i <= currentPage[to]; i++) { count += vestingSchedules[to][i].length; } return count; } // Private helper functions function _mustBeNonZero(uint256 value) private pure { if (value == 0) { revert InvalidZeroParameter(); } } function _mustBeNonZeroAddress(address value) private pure { if (value == address(0)) { revert InvalidZeroParameter(); } } function _mustNotBeSelf(address to) private view { if (msg.sender == to) { revert VestingToSelf(); } } function _mustBeEqualOrExceedMinAmount(uint256 amount) private view { if (amount < perPeriodMinAmount) { revert LowVestingAmount(); } } function _sanitizePageRange(address grantee, uint256 start, uint256 end) private view returns (uint256, uint256) { uint256 endPage = currentPage[grantee] + 1; if (start > end || start >= endPage) { revert InvalidPage(); } if (end > endPage || end == 0) { end = endPage; } return (start, end); } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol"; contract NODL is ERC20Burnable, AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); constructor(address admin) ERC20("Nodle Token", "NODL") { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(MINTER_ROLE, admin); } function mint(address to, uint256 amount) public { _checkRole(MINTER_ROLE); _mint(to, amount); } }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import { IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC } from "zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol"; import {IPaymasterFlow} from "zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol"; import {Transaction} from "zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; import {BOOTLOADER_FORMAL_ADDRESS} from "zksync-contracts/l2/system-contracts/Constants.sol"; import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol"; /// @notice This smart contract serves as a base for any other paymaster contract. abstract contract BasePaymaster is IPaymaster, AccessControl { bytes32 public constant WITHDRAWER_ROLE = keccak256("WITHDRAWER_ROLE"); /** * @notice Emitted when the paymaster withdraws funds to the specified address. * @param amount The amount of funds withdrawn. */ event Withdrawn(address to, uint256 amount); error AccessRestrictedToBootloader(); error PaymasterFlowNotSupported(); error NotEnoughETHInPaymasterToPayForTransaction(); error InvalidPaymasterInput(string message); error FailedToWithdraw(); constructor(address admin, address withdrawer) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(WITHDRAWER_ROLE, withdrawer); } function validateAndPayForPaymasterTransaction(bytes32, bytes32, Transaction calldata transaction) external payable returns (bytes4 magic, bytes memory /* context */ ) { _mustBeBootloader(); // By default we consider the transaction as accepted. magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; if (transaction.paymasterInput.length < 4) { revert InvalidPaymasterInput("The standard paymaster input must be at least 4 bytes long"); } bytes4 paymasterInputSelector = bytes4(transaction.paymasterInput[0:4]); // Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit, // neither paymaster nor account are allowed to access this context variable. uint256 requiredETH = transaction.gasLimit * transaction.maxFeePerGas; address destAddress = address(uint160(transaction.to)); address userAddress = address(uint160(transaction.from)); if (paymasterInputSelector == IPaymasterFlow.general.selector) { _validateAndPayGeneralFlow(userAddress, destAddress, requiredETH); } else if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { (address token, uint256 minimalAllowance, bytes memory data) = abi.decode(transaction.paymasterInput[4:], (address, uint256, bytes)); _validateAndPayApprovalBasedFlow(userAddress, destAddress, token, minimalAllowance, data, requiredETH); } else { revert PaymasterFlowNotSupported(); } // The bootloader never returns any data, so it can safely be ignored here. (bool success,) = payable(BOOTLOADER_FORMAL_ADDRESS).call{value: requiredETH}(""); if (!success) { revert NotEnoughETHInPaymasterToPayForTransaction(); } return (magic, ""); } function postTransaction(bytes calldata, Transaction calldata, bytes32, bytes32, ExecutionResult, uint256) external payable override { _mustBeBootloader(); // Refunds are not supported yet. } function withdraw(address to, uint256 amount) external { _checkRole(WITHDRAWER_ROLE); (bool success,) = payable(to).call{value: amount}(""); if (!success) revert FailedToWithdraw(); emit Withdrawn(to, amount); } receive() external payable {} function _mustBeBootloader() internal view { if (msg.sender != BOOTLOADER_FORMAL_ADDRESS) { revert AccessRestrictedToBootloader(); } } function _validateAndPayGeneralFlow(address from, address to, uint256 requiredETH) internal virtual; function _validateAndPayApprovalBasedFlow( address from, address to, address token, uint256 tokenAmount, bytes memory data, uint256 requiredETH ) internal virtual; }
// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity 0.8.23; import {BasePaymaster} from "./BasePaymaster.sol"; /// @notice a paymaster that allow whitelisted users to do free txs to restricted contracts contract WhitelistPaymaster is BasePaymaster { bytes32 public constant WHITELIST_ADMIN_ROLE = keccak256("WHITELIST_ADMIN_ROLE"); mapping(address => bool) public isWhitelistedUser; mapping(address => bool) public isWhitelistedContract; event WhitelistedContractsAdded(address[] contracts); event WhitelistedContractsRemoved(address[] contracts); event WhitelistedUsersAdded(address[] users); event WhitelistedUsersRemoved(address[] users); error UserIsNotWhitelisted(); error DestIsNotWhitelisted(); constructor(address admin, address withdrawer) BasePaymaster(admin, withdrawer) { _grantRole(WHITELIST_ADMIN_ROLE, admin); } function addWhitelistedContracts(address[] calldata whitelistedContracts) external { _checkRole(WHITELIST_ADMIN_ROLE); for (uint256 i = 0; i < whitelistedContracts.length; i++) { isWhitelistedContract[whitelistedContracts[i]] = true; } emit WhitelistedContractsAdded(whitelistedContracts); } function removeWhitelistedContracts(address[] calldata whitelistedContracts) external { _checkRole(WHITELIST_ADMIN_ROLE); for (uint256 i = 0; i < whitelistedContracts.length; i++) { isWhitelistedContract[whitelistedContracts[i]] = false; } emit WhitelistedContractsRemoved(whitelistedContracts); } function addWhitelistedUsers(address[] calldata users) external { _checkRole(WHITELIST_ADMIN_ROLE); for (uint256 i = 0; i < users.length; i++) { isWhitelistedUser[users[i]] = true; } emit WhitelistedUsersAdded(users); } function removeWhitelistedUsers(address[] calldata users) external { _checkRole(WHITELIST_ADMIN_ROLE); for (uint256 i = 0; i < users.length; i++) { isWhitelistedUser[users[i]] = false; } emit WhitelistedUsersRemoved(users); } function _validateAndPayGeneralFlow(address from, address to, uint256 /* requiredETH */ ) internal view override { if (!isWhitelistedContract[to]) { revert DestIsNotWhitelisted(); } if (!isWhitelistedUser[from]) { revert UserIsNotWhitelisted(); } } function _validateAndPayApprovalBasedFlow(address, address, address, uint256, bytes memory, uint256) internal pure override { revert PaymasterFlowNotSupported(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IBootloaderUtilities.sol"; import "./libraries/TransactionHelper.sol"; import "./libraries/RLPEncoder.sol"; import "./libraries/EfficientCall.sol"; /** * @author Matter Labs * @notice A contract that provides some utility methods for the bootloader * that is very hard to write in Yul. */ contract BootloaderUtilities is IBootloaderUtilities { using TransactionHelper for *; /// @notice Calculates the canonical transaction hash and the recommended transaction hash. /// @param _transaction The transaction. /// @return txHash and signedTxHash of the transaction, i.e. the transaction hash to be used in the explorer and commits to all /// the fields of the transaction and the recommended hash to be signed for this transaction. /// @dev txHash must be unique for all transactions. function getTransactionHashes( Transaction calldata _transaction ) external view override returns (bytes32 txHash, bytes32 signedTxHash) { signedTxHash = _transaction.encodeHash(); if (_transaction.txType == EIP_712_TX_TYPE) { txHash = keccak256(bytes.concat(signedTxHash, EfficientCall.keccak(_transaction.signature))); } else if (_transaction.txType == LEGACY_TX_TYPE) { txHash = encodeLegacyTransactionHash(_transaction); } else if (_transaction.txType == EIP_1559_TX_TYPE) { txHash = encodeEIP1559TransactionHash(_transaction); } else if (_transaction.txType == EIP_2930_TX_TYPE) { txHash = encodeEIP2930TransactionHash(_transaction); } else { revert("Unsupported tx type"); } } /// @notice Calculates the hash for a legacy transaction. /// @param _transaction The legacy transaction. /// @return txHash The hash of the transaction. function encodeLegacyTransactionHash(Transaction calldata _transaction) internal view returns (bytes32 txHash) { // Hash of legacy transactions are encoded as one of the: // - RLP(nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0) // - RLP(nonce, gasPrice, gasLimit, to, value, data) // // In this RLP encoding, only the first one above list appears, so we encode each element // inside list and then concatenate the length of all elements with them. bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); // Encode `gasPrice` and `gasLimit` together to prevent "stack too deep error". bytes memory encodedGasParam; { bytes memory encodedGasPrice = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); encodedGasParam = bytes.concat(encodedGasPrice, encodedGasLimit); } bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } bytes memory rEncoded; { uint256 rInt = uint256(bytes32(_transaction.signature[0:32])); rEncoded = RLPEncoder.encodeUint256(rInt); } bytes memory sEncoded; { uint256 sInt = uint256(bytes32(_transaction.signature[32:64])); sEncoded = RLPEncoder.encodeUint256(sInt); } bytes memory vEncoded; { uint256 vInt = uint256(uint8(_transaction.signature[64])); require(vInt == 27 || vInt == 28, "Invalid v value"); // If the `chainId` is specified in the transaction, then the `v` value is encoded as // `35 + y + 2 * chainId == vInt + 8 + 2 * chainId`, where y - parity bit (see EIP-155). if (_transaction.reserved[0] != 0) { vInt += 8 + block.chainid * 2; } vEncoded = RLPEncoder.encodeUint256(vInt); } bytes memory encodedListLength; unchecked { uint256 listLength = encodedNonce.length + encodedGasParam.length + encodedTo.length + encodedValue.length + encodedDataLength.length + _transaction.data.length + rEncoded.length + sEncoded.length + vEncoded.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( bytes.concat( encodedListLength, encodedNonce, encodedGasParam, encodedTo, encodedValue, encodedDataLength, _transaction.data, vEncoded, rEncoded, sEncoded ) ); } /// @notice Calculates the hash for an EIP2930 transaction. /// @param _transaction The EIP2930 transaction. /// @return txHash The hash of the transaction. function encodeEIP2930TransactionHash(Transaction calldata _transaction) internal view returns (bytes32) { // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; { bytes memory encodedChainId = RLPEncoder.encodeUint256(block.chainid); bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); bytes memory encodedGasPrice = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); encodedFixedLengthParams = bytes.concat( encodedChainId, encodedNonce, encodedGasPrice, encodedGasLimit, encodedTo, encodedValue ); } // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // On zkSync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory rEncoded; { uint256 rInt = uint256(bytes32(_transaction.signature[0:32])); rEncoded = RLPEncoder.encodeUint256(rInt); } bytes memory sEncoded; { uint256 sInt = uint256(bytes32(_transaction.signature[32:64])); sEncoded = RLPEncoder.encodeUint256(sInt); } bytes memory vEncoded; { uint256 vInt = uint256(uint8(_transaction.signature[64])); require(vInt == 27 || vInt == 28, "Invalid v value"); vEncoded = RLPEncoder.encodeUint256(vInt - 27); } bytes memory encodedListLength; unchecked { uint256 listLength = encodedFixedLengthParams.length + encodedDataLength.length + _transaction.data.length + encodedAccessListLength.length + rEncoded.length + sEncoded.length + vEncoded.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( bytes.concat( "\x01", encodedListLength, encodedFixedLengthParams, encodedDataLength, _transaction.data, encodedAccessListLength, vEncoded, rEncoded, sEncoded ) ); } /// @notice Calculates the hash for an EIP1559 transaction. /// @param _transaction The legacy transaction. /// @return txHash The hash of the transaction. function encodeEIP1559TransactionHash(Transaction calldata _transaction) internal view returns (bytes32) { // The formula for hash of EIP1559 transaction in the original proposal: // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; { bytes memory encodedChainId = RLPEncoder.encodeUint256(block.chainid); bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); bytes memory encodedMaxPriorityFeePerGas = RLPEncoder.encodeUint256(_transaction.maxPriorityFeePerGas); bytes memory encodedMaxFeePerGas = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); encodedFixedLengthParams = bytes.concat( encodedChainId, encodedNonce, encodedMaxPriorityFeePerGas, encodedMaxFeePerGas, encodedGasLimit, encodedTo, encodedValue ); } // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // On zkSync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory rEncoded; { uint256 rInt = uint256(bytes32(_transaction.signature[0:32])); rEncoded = RLPEncoder.encodeUint256(rInt); } bytes memory sEncoded; { uint256 sInt = uint256(bytes32(_transaction.signature[32:64])); sEncoded = RLPEncoder.encodeUint256(sInt); } bytes memory vEncoded; { uint256 vInt = uint256(uint8(_transaction.signature[64])); require(vInt == 27 || vInt == 28, "Invalid v value"); vEncoded = RLPEncoder.encodeUint256(vInt - 27); } bytes memory encodedListLength; unchecked { uint256 listLength = encodedFixedLengthParams.length + encodedDataLength.length + _transaction.data.length + encodedAccessListLength.length + rEncoded.length + sEncoded.length + vEncoded.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( bytes.concat( "\x02", encodedListLength, encodedFixedLengthParams, encodedDataLength, _transaction.data, encodedAccessListLength, vEncoded, rEncoded, sEncoded ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IAccountCodeStorage.sol"; import "./interfaces/INonceHolder.sol"; import "./interfaces/IContractDeployer.sol"; import "./interfaces/IKnownCodesStorage.sol"; import "./interfaces/IImmutableSimulator.sol"; import "./interfaces/IEthToken.sol"; import "./interfaces/IL1Messenger.sol"; import "./interfaces/ISystemContext.sol"; import "./interfaces/IBytecodeCompressor.sol"; import "./BootloaderUtilities.sol"; /// @dev All the system contracts introduced by zkSync have their addresses /// started from 2^15 in order to avoid collision with Ethereum precompiles. uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15 /// @dev All the system contracts must be located in the kernel space, /// i.e. their addresses must be below 2^16. uint160 constant MAX_SYSTEM_CONTRACT_ADDRESS = 0xffff; // 2^16 - 1 address constant ECRECOVER_SYSTEM_CONTRACT = address(0x01); address constant SHA256_SYSTEM_CONTRACT = address(0x02); /// @dev The current maximum deployed precompile address. /// Note: currently only two precompiles are deployed: /// 0x01 - ecrecover /// 0x02 - sha256 /// Important! So the constant should be updated if more precompiles are deployed. uint256 constant CURRENT_MAX_PRECOMPILE_ADDRESS = uint256(uint160(SHA256_SYSTEM_CONTRACT)); address payable constant BOOTLOADER_FORMAL_ADDRESS = payable(address(SYSTEM_CONTRACTS_OFFSET + 0x01)); IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( address(SYSTEM_CONTRACTS_OFFSET + 0x02) ); INonceHolder constant NONCE_HOLDER_SYSTEM_CONTRACT = INonceHolder(address(SYSTEM_CONTRACTS_OFFSET + 0x03)); IKnownCodesStorage constant KNOWN_CODE_STORAGE_CONTRACT = IKnownCodesStorage(address(SYSTEM_CONTRACTS_OFFSET + 0x04)); IImmutableSimulator constant IMMUTABLE_SIMULATOR_SYSTEM_CONTRACT = IImmutableSimulator( address(SYSTEM_CONTRACTS_OFFSET + 0x05) ); IContractDeployer constant DEPLOYER_SYSTEM_CONTRACT = IContractDeployer(address(SYSTEM_CONTRACTS_OFFSET + 0x06)); // A contract that is allowed to deploy any codehash // on any address. To be used only during an upgrade. address constant FORCE_DEPLOYER = address(SYSTEM_CONTRACTS_OFFSET + 0x07); IL1Messenger constant L1_MESSENGER_CONTRACT = IL1Messenger(address(SYSTEM_CONTRACTS_OFFSET + 0x08)); address constant MSG_VALUE_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x09); IEthToken constant ETH_TOKEN_SYSTEM_CONTRACT = IEthToken(address(SYSTEM_CONTRACTS_OFFSET + 0x0a)); address constant KECCAK256_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x10); ISystemContext constant SYSTEM_CONTEXT_CONTRACT = ISystemContext(payable(address(SYSTEM_CONTRACTS_OFFSET + 0x0b))); BootloaderUtilities constant BOOTLOADER_UTILITIES = BootloaderUtilities(address(SYSTEM_CONTRACTS_OFFSET + 0x0c)); address constant EVENT_WRITER_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x0d); IBytecodeCompressor constant BYTECODE_COMPRESSOR_CONTRACT = IBytecodeCompressor( address(SYSTEM_CONTRACTS_OFFSET + 0x0e) ); /// @dev If the bitwise AND of the extraAbi[2] param when calling the MSG_VALUE_SIMULATOR /// is non-zero, the call will be assumed to be a system one. uint256 constant MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT = 1; /// @dev The maximal msg.value that context can have uint256 constant MAX_MSG_VALUE = 2 ** 128 - 1; /// @dev Prefix used during derivation of account addresses using CREATE2 /// @dev keccak256("zksyncCreate2") bytes32 constant CREATE2_PREFIX = 0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494; /// @dev Prefix used during derivation of account addresses using CREATE /// @dev keccak256("zksyncCreate") bytes32 constant CREATE_PREFIX = 0x63bae3a9951d38e8a3fbb7b70909afc1200610fc5bc55ade242f815974674f23;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IAccountCodeStorage { function storeAccountConstructingCodeHash(address _address, bytes32 _hash) external; function storeAccountConstructedCodeHash(address _address, bytes32 _hash) external; function markAccountCodeHashAsConstructed(address _address) external; function getRawCodeHash(address _address) external view returns (bytes32 codeHash); function getCodeHash(uint256 _input) external view returns (bytes32 codeHash); function getCodeSize(uint256 _input) external view returns (uint256 codeSize); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../libraries/TransactionHelper.sol"; interface IBootloaderUtilities { function getTransactionHashes( Transaction calldata _transaction ) external view returns (bytes32 txHash, bytes32 signedTxHash); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IBytecodeCompressor { function publishCompressedBytecode( bytes calldata _bytecode, bytes calldata _rawCompressedData ) external payable returns (bytes32 bytecodeHash); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IContractDeployer { /// @notice Defines the version of the account abstraction protocol /// that a contract claims to follow. /// - `None` means that the account is just a contract and it should never be interacted /// with as a custom account /// - `Version1` means that the account follows the first version of the account abstraction protocol enum AccountAbstractionVersion { None, Version1 } /// @notice Defines the nonce ordering used by the account /// - `Sequential` means that it is expected that the nonces are monotonic and increment by 1 /// at a time (the same as EOAs). /// - `Arbitrary` means that the nonces for the accounts can be arbitrary. The operator /// should serve the transactions from such an account on a first-come-first-serve basis. /// @dev This ordering is more of a suggestion to the operator on how the AA expects its transactions /// to be processed and is not considered as a system invariant. enum AccountNonceOrdering { Sequential, Arbitrary } struct AccountInfo { AccountAbstractionVersion supportedAAVersion; AccountNonceOrdering nonceOrdering; } event ContractDeployed( address indexed deployerAddress, bytes32 indexed bytecodeHash, address indexed contractAddress ); event AccountNonceOrderingUpdated(address indexed accountAddress, AccountNonceOrdering nonceOrdering); event AccountVersionUpdated(address indexed accountAddress, AccountAbstractionVersion aaVersion); function getNewAddressCreate2( address _sender, bytes32 _bytecodeHash, bytes32 _salt, bytes calldata _input ) external view returns (address newAddress); function getNewAddressCreate(address _sender, uint256 _senderNonce) external pure returns (address newAddress); function create2( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input ) external payable returns (address newAddress); function create2Account( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input, AccountAbstractionVersion _aaVersion ) external payable returns (address newAddress); /// @dev While the `_salt` parameter is not used anywhere here, /// it is still needed for consistency between `create` and /// `create2` functions (required by the compiler). function create( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input ) external payable returns (address newAddress); /// @dev While `_salt` is never used here, we leave it here as a parameter /// for the consistency with the `create` function. function createAccount( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input, AccountAbstractionVersion _aaVersion ) external payable returns (address newAddress); /// @notice Returns the information about a certain AA. function getAccountInfo(address _address) external view returns (AccountInfo memory info); /// @notice Can be called by an account to update its account version function updateAccountVersion(AccountAbstractionVersion _version) external; /// @notice Can be called by an account to update its nonce ordering function updateNonceOrdering(AccountNonceOrdering _nonceOrdering) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IEthToken { function balanceOf(uint256) external view returns (uint256); function transferFromTo(address _from, address _to, uint256 _amount) external; function totalSupply() external view returns (uint256); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function mint(address _account, uint256 _amount) external; function withdraw(address _l1Receiver) external payable; event Mint(address indexed account, uint256 amount); event Transfer(address indexed from, address indexed to, uint256 value); event Withdrawal(address indexed _l2Sender, address indexed _l1Receiver, uint256 _amount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; struct ImmutableData { uint256 index; bytes32 value; } interface IImmutableSimulator { function getImmutable(address _dest, uint256 _index) external view returns (bytes32); function setImmutables(address _dest, ImmutableData[] calldata _immutables) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IKnownCodesStorage { event MarkedAsKnown(bytes32 indexed bytecodeHash, bool indexed sendBytecodeToL1); function markFactoryDeps(bool _shouldSendToL1, bytes32[] calldata _hashes) external; function markBytecodeAsPublished( bytes32 _bytecodeHash, bytes32 _l1PreimageHash, uint256 _l1PreimageBytesLen ) external; function getMarker(bytes32 _hash) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IL1Messenger { // Possibly in the future we will be able to track the messages sent to L1 with // some hooks in the VM. For now, it is much easier to track them with L2 events. event L1MessageSent(address indexed _sender, bytes32 indexed _hash, bytes _message); function sendToL1(bytes memory _message) external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @author Matter Labs * @dev Interface of the nonce holder contract -- a contract used by the system to ensure * that there is always a unique identifier for a transaction with a particular account (we call it nonce). * In other words, the pair of (address, nonce) should always be unique. * @dev Custom accounts should use methods of this contract to store nonces or other possible unique identifiers * for the transaction. */ interface INonceHolder { event ValueSetUnderNonce(address indexed accountAddress, uint256 indexed key, uint256 value); /// @dev Returns the current minimal nonce for account. function getMinNonce(address _address) external view returns (uint256); /// @dev Returns the raw version of the current minimal nonce /// (equal to minNonce + 2^128 * deployment nonce). function getRawNonce(address _address) external view returns (uint256); /// @dev Increases the minimal nonce for the msg.sender. function increaseMinNonce(uint256 _value) external returns (uint256); /// @dev Sets the nonce value `key` as used. function setValueUnderNonce(uint256 _key, uint256 _value) external; /// @dev Gets the value stored inside a custom nonce. function getValueUnderNonce(uint256 _key) external view returns (uint256); /// @dev A convenience method to increment the minimal nonce if it is equal /// to the `_expectedNonce`. function incrementMinNonceIfEquals(uint256 _expectedNonce) external; /// @dev Returns the deployment nonce for the accounts used for CREATE opcode. function getDeploymentNonce(address _address) external view returns (uint256); /// @dev Increments the deployment nonce for the account and returns the previous one. function incrementDeploymentNonce(address _address) external returns (uint256); /// @dev Determines whether a certain nonce has been already used for an account. function validateNonceUsage(address _address, uint256 _key, bool _shouldBeUsed) external view; /// @dev Returns whether a nonce has been used for an account. function isNonceUsed(address _address, uint256 _nonce) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../libraries/TransactionHelper.sol"; enum ExecutionResult { Revert, Success } bytes4 constant PAYMASTER_VALIDATION_SUCCESS_MAGIC = IPaymaster.validateAndPayForPaymasterTransaction.selector; interface IPaymaster { /// @dev Called by the bootloader to verify that the paymaster agrees to pay for the /// fee for the transaction. This transaction should also send the necessary amount of funds onto the bootloader /// address. /// @param _txHash The hash of the transaction /// @param _suggestedSignedHash The hash of the transaction that is signed by an EOA /// @param _transaction The transaction itself. /// @return magic The value that should be equal to the signature of the validateAndPayForPaymasterTransaction /// if the paymaster agrees to pay for the transaction. /// @return context The "context" of the transaction: an array of bytes of length at most 1024 bytes, which will be /// passed to the `postTransaction` method of the account. /// @dev The developer should strive to preserve as many steps as possible both for valid /// and invalid transactions as this very method is also used during the gas fee estimation /// (without some of the necessary data, e.g. signature). function validateAndPayForPaymasterTransaction( bytes32 _txHash, bytes32 _suggestedSignedHash, Transaction calldata _transaction ) external payable returns (bytes4 magic, bytes memory context); /// @dev Called by the bootloader after the execution of the transaction. Please note that /// there is no guarantee that this method will be called at all. Unlike the original EIP4337, /// this method won't be called if the transaction execution results in out-of-gas. /// @param _context, the context of the execution, returned by the "validateAndPayForPaymasterTransaction" method. /// @param _transaction, the users' transaction. /// @param _txResult, the result of the transaction execution (success or failure). /// @param _maxRefundedGas, the upper bound on the amout of gas that could be refunded to the paymaster. /// @dev The exact amount refunded depends on the gas spent by the "postOp" itself and so the developers should /// take that into account. function postTransaction( bytes calldata _context, Transaction calldata _transaction, bytes32 _txHash, bytes32 _suggestedSignedHash, ExecutionResult _txResult, uint256 _maxRefundedGas ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @author Matter Labs * @dev The interface that is used for encoding/decoding of * different types of paymaster flows. * @notice This is NOT an interface to be implementated * by contracts. It is just used for encoding. */ interface IPaymasterFlow { function general(bytes calldata input) external; function approvalBased(address _token, uint256 _minAllowance, bytes calldata _innerInput) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @author Matter Labs * @notice Contract that stores some of the context variables, that may be either * block-scoped, tx-scoped or system-wide. */ interface ISystemContext { function chainId() external view returns (uint256); function origin() external view returns (address); function gasPrice() external view returns (uint256); function blockGasLimit() external view returns (uint256); function coinbase() external view returns (address); function difficulty() external view returns (uint256); function baseFee() external view returns (uint256); function blockHash(uint256 _block) external view returns (bytes32); function getBlockHashEVM(uint256 _block) external view returns (bytes32); function getBlockNumberAndTimestamp() external view returns (uint256 blockNumber, uint256 blockTimestamp); // Note, that for now, the implementation of the bootloader allows this variables to // be incremented multiple times inside a block, so it should not relied upon right now. function getBlockNumber() external view returns (uint256); function getBlockTimestamp() external view returns (uint256); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.0; import "./SystemContractHelper.sol"; import "./Utils.sol"; import {SHA256_SYSTEM_CONTRACT, KECCAK256_SYSTEM_CONTRACT} from "../Constants.sol"; /** * @author Matter Labs * @notice This library is used to perform ultra-efficient calls using zkEVM-specific features. * @dev EVM calls always accept a memory slice as input and return a memory slice as output. * Therefore, even if the user has a ready-made calldata slice, they still need to copy it to memory * before calling. This is especially inefficient for large inputs (proxies, multi-calls, etc.). * In turn, zkEVM operates over a fat pointer, which is a set of (memory page, offset, start, length) in the memory/calldata/returndata. * This allows forwarding the calldata slice as is, without copying it to memory. * @dev Fat pointer is not just an integer, it is an extended data type supported on the VM level. * zkEVM creates the wellformed fat pointers for all the calldata/returndata regions, later * the contract may manipulate the already created fat pointers to forward a slice of the data, but not * to create new fat pointers! * @dev The allowed operation on fat pointers are: * 1. `ptr.add` - Transforms `ptr.offset` into `ptr.offset + u32(_value)`. If overflow happens then it panics. * 2. `ptr.sub` - Transforms `ptr.offset` into `ptr.offset - u32(_value)`. If underflow happens then it panics. * 3. `ptr.pack` - Do the concatenation between the lowest 128 bits of the pointer itself and the highest 128 bits of `_value`. It is typically used to prepare the ABI for external calls. * 4. `ptr.shrink` - Transforms `ptr.length` into `ptr.length - u32(_shrink)`. If underflow happens then it panics. * @dev The call opcodes accept the fat pointer and change it to its canonical form before passing it to the child call * 1. `ptr.start` is transformed into `ptr.offset + ptr.start` * 2. `ptr.length` is transformed into `ptr.length - ptr.offset` * 3. `ptr.offset` is transformed into `0` */ library EfficientCall { /// @notice Call the `keccak256` without copying calldata to memory. /// @param _data The preimage data. /// @return The `keccak256` hash. function keccak(bytes calldata _data) internal view returns (bytes32) { bytes memory returnData = staticCall(gasleft(), KECCAK256_SYSTEM_CONTRACT, _data); require(returnData.length == 32, "keccak256 returned invalid data"); return bytes32(returnData); } /// @notice Call the `sha256` precompile without copying calldata to memory. /// @param _data The preimage data. /// @return The `sha256` hash. function sha(bytes calldata _data) internal view returns (bytes32) { bytes memory returnData = staticCall(gasleft(), SHA256_SYSTEM_CONTRACT, _data); require(returnData.length == 32, "sha returned invalid data"); return bytes32(returnData); } /// @notice Perform a `call` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _value The `msg.value` to send. /// @param _data The calldata to use for the call. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return returnData The copied to memory return data. function call( uint256 _gas, address _address, uint256 _value, bytes calldata _data, bool _isSystem ) internal returns (bytes memory returnData) { bool success = rawCall(_gas, _address, _value, _data, _isSystem); returnData = _verifyCallResult(success); } /// @notice Perform a `staticCall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return returnData The copied to memory return data. function staticCall( uint256 _gas, address _address, bytes calldata _data ) internal view returns (bytes memory returnData) { bool success = rawStaticCall(_gas, _address, _data); returnData = _verifyCallResult(success); } /// @notice Perform a `delegateCall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return returnData The copied to memory return data. function delegateCall( uint256 _gas, address _address, bytes calldata _data ) internal returns (bytes memory returnData) { bool success = rawDelegateCall(_gas, _address, _data); returnData = _verifyCallResult(success); } /// @notice Perform a `mimicCall` (a call with custom msg.sender) without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @param _whoToMimic The `msg.sender` for the next call. /// @param _isConstructor Whether the call should contain the `isConstructor` flag. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return returnData The copied to memory return data. function mimicCall( uint256 _gas, address _address, bytes calldata _data, address _whoToMimic, bool _isConstructor, bool _isSystem ) internal returns (bytes memory returnData) { bool success = rawMimicCall(_gas, _address, _data, _whoToMimic, _isConstructor, _isSystem); returnData = _verifyCallResult(success); } /// @notice Perform a `call` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _value The `msg.value` to send. /// @param _data The calldata to use for the call. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return success whether the call was successful. function rawCall( uint256 _gas, address _address, uint256 _value, bytes calldata _data, bool _isSystem ) internal returns (bool success) { if (_value == 0) { _loadFarCallABIIntoActivePtr(_gas, _data, false, _isSystem); address callAddr = RAW_FAR_CALL_BY_REF_CALL_ADDRESS; assembly { success := call(_address, callAddr, 0, 0, 0xFFFF, 0, 0) } } else { _loadFarCallABIIntoActivePtr(_gas, _data, false, true); // If there is provided `msg.value` call the `MsgValueSimulator` to forward ether. address msgValueSimulator = MSG_VALUE_SYSTEM_CONTRACT; address callAddr = SYSTEM_CALL_BY_REF_CALL_ADDRESS; // We need to supply the mask to the MsgValueSimulator to denote // that the call should be a system one. uint256 forwardMask = _isSystem ? MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT : 0; assembly { success := call(msgValueSimulator, callAddr, _value, _address, 0xFFFF, forwardMask, 0) } } } /// @notice Perform a `staticCall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return success whether the call was successful. function rawStaticCall(uint256 _gas, address _address, bytes calldata _data) internal view returns (bool success) { _loadFarCallABIIntoActivePtr(_gas, _data, false, false); address callAddr = RAW_FAR_CALL_BY_REF_CALL_ADDRESS; assembly { success := staticcall(_address, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Perform a `delegatecall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return success whether the call was successful. function rawDelegateCall(uint256 _gas, address _address, bytes calldata _data) internal returns (bool success) { _loadFarCallABIIntoActivePtr(_gas, _data, false, false); address callAddr = RAW_FAR_CALL_BY_REF_CALL_ADDRESS; assembly { success := delegatecall(_address, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Perform a `mimicCall` (call with custom msg.sender) without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @param _whoToMimic The `msg.sender` for the next call. /// @param _isConstructor Whether the call should contain the `isConstructor` flag. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return success whether the call was successful. /// @dev If called not in kernel mode, it will result in a revert (enforced by the VM) function rawMimicCall( uint256 _gas, address _address, bytes calldata _data, address _whoToMimic, bool _isConstructor, bool _isSystem ) internal returns (bool success) { _loadFarCallABIIntoActivePtr(_gas, _data, _isConstructor, _isSystem); address callAddr = MIMIC_CALL_BY_REF_CALL_ADDRESS; uint256 cleanupMask = ADDRESS_MASK; assembly { // Clearing values before usage in assembly, since Solidity // doesn't do it by default _whoToMimic := and(_whoToMimic, cleanupMask) success := call(_address, callAddr, 0, 0, _whoToMimic, 0, 0) } } /// @dev Verify that a low-level call was successful, and revert if it wasn't, by bubbling the revert reason. /// @param _success Whether the call was successful. /// @return returnData The copied to memory return data. function _verifyCallResult(bool _success) private pure returns (bytes memory returnData) { if (_success) { uint256 size; assembly { size := returndatasize() } returnData = new bytes(size); assembly { returndatacopy(add(returnData, 0x20), 0, size) } } else { propagateRevert(); } } /// @dev Propagate the revert reason from the current call to the caller. function propagateRevert() internal pure { assembly { let size := returndatasize() returndatacopy(0, 0, size) revert(0, size) } } /// @dev Load the far call ABI into active ptr, that will be used for the next call by reference. /// @param _gas The gas to be passed to the call. /// @param _data The calldata to be passed to the call. /// @param _isConstructor Whether the call is a constructor call. /// @param _isSystem Whether the call is a system call. function _loadFarCallABIIntoActivePtr( uint256 _gas, bytes calldata _data, bool _isConstructor, bool _isSystem ) private view { SystemContractHelper.loadCalldataIntoActivePtr(); // Currently, zkEVM considers the pointer valid if(ptr.offset < ptr.length || (ptr.length == 0 && ptr.offset == 0)), otherwise panics. // So, if the data is empty we need to make the `ptr.length = ptr.offset = 0`, otherwise follow standard logic. if (_data.length == 0) { // Safe to cast, offset is never bigger than `type(uint32).max` SystemContractHelper.ptrShrinkIntoActive(uint32(msg.data.length)); } else { uint256 dataOffset; assembly { dataOffset := _data.offset } // Safe to cast, offset is never bigger than `type(uint32).max` SystemContractHelper.ptrAddIntoActive(uint32(dataOffset)); // Safe to cast, `data.length` is never bigger than `type(uint32).max` uint32 shrinkTo = uint32(msg.data.length - (_data.length + dataOffset)); SystemContractHelper.ptrShrinkIntoActive(shrinkTo); } uint32 gas = Utils.safeCastToU32(_gas); uint256 farCallAbi = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( gas, // Only rollup is supported for now 0, CalldataForwardingMode.ForwardFatPointer, _isConstructor, _isSystem ); SystemContractHelper.ptrPackIntoActivePtr(farCallAbi); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library RLPEncoder { function encodeAddress(address _val) internal pure returns (bytes memory encoded) { // The size is equal to 20 bytes of the address itself + 1 for encoding bytes length in RLP. encoded = new bytes(0x15); bytes20 shiftedVal = bytes20(_val); assembly { // In the first byte we write the encoded length as 0x80 + 0x14 == 0x94. mstore(add(encoded, 0x20), 0x9400000000000000000000000000000000000000000000000000000000000000) // Write address data without stripping zeros. mstore(add(encoded, 0x21), shiftedVal) } } function encodeUint256(uint256 _val) internal pure returns (bytes memory encoded) { unchecked { if (_val < 128) { encoded = new bytes(1); // Handle zero as a non-value, since stripping zeroes results in an empty byte array encoded[0] = (_val == 0) ? bytes1(uint8(128)) : bytes1(uint8(_val)); } else { uint256 hbs = _highestByteSet(_val); encoded = new bytes(hbs + 2); encoded[0] = bytes1(uint8(hbs + 0x81)); uint256 lbs = 31 - hbs; uint256 shiftedVal = _val << (lbs * 8); assembly { mstore(add(encoded, 0x21), shiftedVal) } } } } /// @notice Encodes the size of bytes in RLP format. /// @param _len The length of the bytes to encode. It has a `uint64` type since as larger values are not supported. /// NOTE: panics if the length is 1 since the length encoding is ambiguous in this case. function encodeNonSingleBytesLen(uint64 _len) internal pure returns (bytes memory) { assert(_len != 1); return _encodeLength(_len, 0x80); } /// @notice Encodes the size of list items in RLP format. /// @param _len The length of the bytes to encode. It has a `uint64` type since as larger values are not supported. function encodeListLen(uint64 _len) internal pure returns (bytes memory) { return _encodeLength(_len, 0xc0); } function _encodeLength(uint64 _len, uint256 _offset) private pure returns (bytes memory encoded) { unchecked { if (_len < 56) { encoded = new bytes(1); encoded[0] = bytes1(uint8(_len + _offset)); } else { uint256 hbs = _highestByteSet(uint256(_len)); encoded = new bytes(hbs + 2); encoded[0] = bytes1(uint8(_offset + hbs + 56)); uint256 lbs = 31 - hbs; uint256 shiftedVal = uint256(_len) << (lbs * 8); assembly { mstore(add(encoded, 0x21), shiftedVal) } } } } /// @notice Computes the index of the highest byte set in number. /// @notice Uses little endian ordering (The least significant byte has index `0`). /// NOTE: returns `0` for `0` function _highestByteSet(uint256 _number) private pure returns (uint256 hbs) { unchecked { if (_number > type(uint128).max) { _number >>= 128; hbs += 16; } if (_number > type(uint64).max) { _number >>= 64; hbs += 8; } if (_number > type(uint32).max) { _number >>= 32; hbs += 4; } if (_number > type(uint16).max) { _number >>= 16; hbs += 2; } if (_number > type(uint8).max) { hbs += 1; } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8; import {MAX_SYSTEM_CONTRACT_ADDRESS, MSG_VALUE_SYSTEM_CONTRACT} from "../Constants.sol"; import "./SystemContractsCaller.sol"; import "./Utils.sol"; uint256 constant UINT32_MASK = 0xffffffff; uint256 constant UINT128_MASK = 0xffffffffffffffffffffffffffffffff; /// @dev The mask that is used to convert any uint256 to a proper address. /// It needs to be padded with `00` to be treated as uint256 by Solidity uint256 constant ADDRESS_MASK = 0x00ffffffffffffffffffffffffffffffffffffffff; struct ZkSyncMeta { uint32 gasPerPubdataByte; uint32 heapSize; uint32 auxHeapSize; uint8 shardId; uint8 callerShardId; uint8 codeShardId; } enum Global { CalldataPtr, CallFlags, ExtraABIData1, ExtraABIData2, ReturndataPtr } /** * @author Matter Labs * @notice Library used for accessing zkEVM-specific opcodes, needed for the development * of system contracts. * @dev While this library will be eventually available to public, some of the provided * methods won't work for non-system contracts. We will not recommend this library * for external use. */ library SystemContractHelper { /// @notice Send an L2Log to L1. /// @param _isService The `isService` flag. /// @param _key The `key` part of the L2Log. /// @param _value The `value` part of the L2Log. /// @dev The meaning of all these parameters is context-dependent, but they /// have no intrinsic meaning per se. function toL1(bool _isService, bytes32 _key, bytes32 _value) internal { address callAddr = TO_L1_CALL_ADDRESS; assembly { // Ensuring that the type is bool _isService := and(_isService, 1) // This `success` is always 0, but the method always succeeds // (except for the cases when there is not enough gas) let success := call(_isService, callAddr, _key, _value, 0xFFFF, 0, 0) } } /// @notice Get address of the currently executed code. /// @dev This allows differentiating between `call` and `delegatecall`. /// During the former `this` and `codeAddress` are the same, while /// during the latter they are not. function getCodeAddress() internal view returns (address addr) { address callAddr = CODE_ADDRESS_CALL_ADDRESS; assembly { addr := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Provide a compiler hint, by placing calldata fat pointer into virtual `ACTIVE_PTR`, /// that can be manipulated by `ptr.add`/`ptr.sub`/`ptr.pack`/`ptr.shrink` later. /// @dev This allows making a call by forwarding calldata pointer to the child call. /// It is a much more efficient way to forward calldata, than standard EVM bytes copying. function loadCalldataIntoActivePtr() internal view { address callAddr = LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS; assembly { pop(staticcall(0, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice Compiler simulation of the `ptr.pack` opcode for the virtual `ACTIVE_PTR` pointer. /// @dev Do the concatenation between lowest part of `ACTIVE_PTR` and highest part of `_farCallAbi` /// forming packed fat pointer for a far call or ret ABI when necessary. /// Note: Panics if the lowest 128 bits of `_farCallAbi` are not zeroes. function ptrPackIntoActivePtr(uint256 _farCallAbi) internal view { address callAddr = PTR_PACK_INTO_ACTIVE_CALL_ADDRESS; assembly { pop(staticcall(_farCallAbi, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice Compiler simulation of the `ptr.add` opcode for the virtual `ACTIVE_PTR` pointer. /// @dev Transforms `ACTIVE_PTR.offset` into `ACTIVE_PTR.offset + u32(_value)`. If overflow happens then it panics. function ptrAddIntoActive(uint32 _value) internal view { address callAddr = PTR_ADD_INTO_ACTIVE_CALL_ADDRESS; uint256 cleanupMask = UINT32_MASK; assembly { // Clearing input params as they are not cleaned by Solidity by default _value := and(_value, cleanupMask) pop(staticcall(_value, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice Compiler simulation of the `ptr.shrink` opcode for the virtual `ACTIVE_PTR` pointer. /// @dev Transforms `ACTIVE_PTR.length` into `ACTIVE_PTR.length - u32(_shrink)`. If underflow happens then it panics. function ptrShrinkIntoActive(uint32 _shrink) internal view { address callAddr = PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS; uint256 cleanupMask = UINT32_MASK; assembly { // Clearing input params as they are not cleaned by Solidity by default _shrink := and(_shrink, cleanupMask) pop(staticcall(_shrink, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice packs precompile parameters into one word /// @param _inputMemoryOffset The memory offset in 32-byte words for the input data for calling the precompile. /// @param _inputMemoryLength The length of the input data in words. /// @param _outputMemoryOffset The memory offset in 32-byte words for the output data. /// @param _outputMemoryLength The length of the output data in words. /// @param _perPrecompileInterpreted The constant, the meaning of which is defined separately for /// each precompile. For information, please read the documentation of the precompilecall log in /// the VM. function packPrecompileParams( uint32 _inputMemoryOffset, uint32 _inputMemoryLength, uint32 _outputMemoryOffset, uint32 _outputMemoryLength, uint64 _perPrecompileInterpreted ) internal pure returns (uint256 rawParams) { rawParams = _inputMemoryOffset; rawParams |= uint256(_inputMemoryLength) << 32; rawParams |= uint256(_outputMemoryOffset) << 64; rawParams |= uint256(_outputMemoryLength) << 96; rawParams |= uint256(_perPrecompileInterpreted) << 192; } /// @notice Call precompile with given parameters. /// @param _rawParams The packed precompile params. They can be retrieved by /// the `packPrecompileParams` method. /// @param _gasToBurn The number of gas to burn during this call. /// @return success Whether the call was successful. /// @dev The list of currently available precompiles sha256, keccak256, ecrecover. /// NOTE: The precompile type depends on `this` which calls precompile, which means that only /// system contracts corresponding to the list of precompiles above can do `precompileCall`. /// @dev If used not in the `sha256`, `keccak256` or `ecrecover` contracts, it will just burn the gas provided. function precompileCall(uint256 _rawParams, uint32 _gasToBurn) internal view returns (bool success) { address callAddr = PRECOMPILE_CALL_ADDRESS; // After `precompileCall` gas will be burned down to 0 if there are not enough of them, // thats why it should be checked before the call. require(gasleft() >= _gasToBurn); uint256 cleanupMask = UINT32_MASK; assembly { // Clearing input params as they are not cleaned by Solidity by default _gasToBurn := and(_gasToBurn, cleanupMask) success := staticcall(_rawParams, callAddr, _gasToBurn, 0xFFFF, 0, 0) } } /// @notice Set `msg.value` to next far call. /// @param _value The msg.value that will be used for the *next* call. /// @dev If called not in kernel mode, it will result in a revert (enforced by the VM) function setValueForNextFarCall(uint128 _value) internal returns (bool success) { uint256 cleanupMask = UINT128_MASK; address callAddr = SET_CONTEXT_VALUE_CALL_ADDRESS; assembly { // Clearing input params as they are not cleaned by Solidity by default _value := and(_value, cleanupMask) success := call(0, callAddr, _value, 0, 0xFFFF, 0, 0) } } /// @notice Initialize a new event. /// @param initializer The event initializing value. /// @param value1 The first topic or data chunk. function eventInitialize(uint256 initializer, uint256 value1) internal { address callAddr = EVENT_INITIALIZE_ADDRESS; assembly { pop(call(initializer, callAddr, value1, 0, 0xFFFF, 0, 0)) } } /// @notice Continue writing the previously initialized event. /// @param value1 The first topic or data chunk. /// @param value2 The second topic or data chunk. function eventWrite(uint256 value1, uint256 value2) internal { address callAddr = EVENT_WRITE_ADDRESS; assembly { pop(call(value1, callAddr, value2, 0, 0xFFFF, 0, 0)) } } /// @notice Get the packed representation of the `ZkSyncMeta` from the current context. /// @return meta The packed representation of the ZkSyncMeta. /// @dev The fields in ZkSyncMeta are NOT tightly packed, i.e. there is a special rule on how /// they are packed. For more information, please read the documentation on ZkSyncMeta. function getZkSyncMetaBytes() internal view returns (uint256 meta) { address callAddr = META_CALL_ADDRESS; assembly { meta := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns the bits [offset..offset+size-1] of the meta. /// @param meta Packed representation of the ZkSyncMeta. /// @param offset The offset of the bits. /// @param size The size of the extracted number in bits. /// @return result The extracted number. function extractNumberFromMeta(uint256 meta, uint256 offset, uint256 size) internal pure returns (uint256 result) { // Firstly, we delete all the bits after the field uint256 shifted = (meta << (256 - size - offset)); // Then we shift everything back result = (shifted >> (256 - size)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the number of gas /// that a single byte sent to L1 as pubdata costs. /// @param meta Packed representation of the ZkSyncMeta. /// @return gasPerPubdataByte The current price in gas per pubdata byte. function getGasPerPubdataByteFromMeta(uint256 meta) internal pure returns (uint32 gasPerPubdataByte) { gasPerPubdataByte = uint32(extractNumberFromMeta(meta, META_GAS_PER_PUBDATA_BYTE_OFFSET, 32)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the number of the current size /// of the heap in bytes. /// @param meta Packed representation of the ZkSyncMeta. /// @return heapSize The size of the memory in bytes byte. /// @dev The following expression: getHeapSizeFromMeta(getZkSyncMetaBytes()) is /// equivalent to the MSIZE in Solidity. function getHeapSizeFromMeta(uint256 meta) internal pure returns (uint32 heapSize) { heapSize = uint32(extractNumberFromMeta(meta, META_HEAP_SIZE_OFFSET, 32)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the number of the current size /// of the auxilary heap in bytes. /// @param meta Packed representation of the ZkSyncMeta. /// @return auxHeapSize The size of the auxilary memory in bytes byte. /// @dev You can read more on auxilary memory in the VM1.2 documentation. function getAuxHeapSizeFromMeta(uint256 meta) internal pure returns (uint32 auxHeapSize) { auxHeapSize = uint32(extractNumberFromMeta(meta, META_AUX_HEAP_SIZE_OFFSET, 32)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the shardId of `this`. /// @param meta Packed representation of the ZkSyncMeta. /// @return shardId The shardId of `this`. /// @dev Currently only shard 0 (zkRollup) is supported. function getShardIdFromMeta(uint256 meta) internal pure returns (uint8 shardId) { shardId = uint8(extractNumberFromMeta(meta, META_SHARD_ID_OFFSET, 8)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the shardId of /// the msg.sender. /// @param meta Packed representation of the ZkSyncMeta. /// @return callerShardId The shardId of the msg.sender. /// @dev Currently only shard 0 (zkRollup) is supported. function getCallerShardIdFromMeta(uint256 meta) internal pure returns (uint8 callerShardId) { callerShardId = uint8(extractNumberFromMeta(meta, META_CALLER_SHARD_ID_OFFSET, 8)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the shardId of /// the currently executed code. /// @param meta Packed representation of the ZkSyncMeta. /// @return codeShardId The shardId of the currently executed code. /// @dev Currently only shard 0 (zkRollup) is supported. function getCodeShardIdFromMeta(uint256 meta) internal pure returns (uint8 codeShardId) { codeShardId = uint8(extractNumberFromMeta(meta, META_CODE_SHARD_ID_OFFSET, 8)); } /// @notice Retrieves the ZkSyncMeta structure. /// @return meta The ZkSyncMeta execution context parameters. function getZkSyncMeta() internal view returns (ZkSyncMeta memory meta) { uint256 metaPacked = getZkSyncMetaBytes(); meta.gasPerPubdataByte = getGasPerPubdataByteFromMeta(metaPacked); meta.shardId = getShardIdFromMeta(metaPacked); meta.callerShardId = getCallerShardIdFromMeta(metaPacked); meta.codeShardId = getCodeShardIdFromMeta(metaPacked); } /// @notice Returns the call flags for the current call. /// @return callFlags The bitmask of the callflags. /// @dev Call flags is the value of the first register /// at the start of the call. /// @dev The zero bit of the callFlags indicates whether the call is /// a constructor call. The first bit of the callFlags indicates whether /// the call is a system one. function getCallFlags() internal view returns (uint256 callFlags) { address callAddr = CALLFLAGS_CALL_ADDRESS; assembly { callFlags := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns the current calldata pointer. /// @return ptr The current calldata pointer. /// @dev NOTE: This file is just an integer and it can not be used /// to forward the calldata to the next calls in any way. function getCalldataPtr() internal view returns (uint256 ptr) { address callAddr = PTR_CALLDATA_CALL_ADDRESS; assembly { ptr := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns the N-th extraAbiParam for the current call. /// @return extraAbiData The value of the N-th extraAbiParam for this call. /// @dev It is equal to the value of the (N+2)-th register /// at the start of the call. function getExtraAbiData(uint256 index) internal view returns (uint256 extraAbiData) { require(index < 10, "There are only 10 accessible registers"); address callAddr = GET_EXTRA_ABI_DATA_ADDRESS; assembly { extraAbiData := staticcall(index, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Retuns whether the current call is a system call. /// @return `true` or `false` based on whether the current call is a system call. function isSystemCall() internal view returns (bool) { uint256 callFlags = getCallFlags(); // When the system call is passed, the 2-bit it set to 1 return (callFlags & 2) != 0; } /// @notice Returns whether the address is a system contract. /// @param _address The address to test /// @return `true` or `false` based on whether the `_address` is a system contract. function isSystemContract(address _address) internal pure returns (bool) { return uint160(_address) <= uint160(MAX_SYSTEM_CONTRACT_ADDRESS); } } /// @dev Solidity does not allow exporting modifiers via libraries, so /// the only way to do reuse modifiers is to have a base contract abstract contract ISystemContract { /// @notice Modifier that makes sure that the method /// can only be called via a system call. modifier onlySystemCall() { require( SystemContractHelper.isSystemCall() || SystemContractHelper.isSystemContract(msg.sender), "This method require system call flag" ); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8; import {MSG_VALUE_SYSTEM_CONTRACT, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT} from "../Constants.sol"; import "./Utils.sol"; // Addresses used for the compiler to be replaced with the // zkSync-specific opcodes during the compilation. // IMPORTANT: these are just compile-time constants and are used // only if used in-place by Yul optimizer. address constant TO_L1_CALL_ADDRESS = address((1 << 16) - 1); address constant CODE_ADDRESS_CALL_ADDRESS = address((1 << 16) - 2); address constant PRECOMPILE_CALL_ADDRESS = address((1 << 16) - 3); address constant META_CALL_ADDRESS = address((1 << 16) - 4); address constant MIMIC_CALL_CALL_ADDRESS = address((1 << 16) - 5); address constant SYSTEM_MIMIC_CALL_CALL_ADDRESS = address((1 << 16) - 6); address constant MIMIC_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 7); address constant SYSTEM_MIMIC_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 8); address constant RAW_FAR_CALL_CALL_ADDRESS = address((1 << 16) - 9); address constant RAW_FAR_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 10); address constant SYSTEM_CALL_CALL_ADDRESS = address((1 << 16) - 11); address constant SYSTEM_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 12); address constant SET_CONTEXT_VALUE_CALL_ADDRESS = address((1 << 16) - 13); address constant SET_PUBDATA_PRICE_CALL_ADDRESS = address((1 << 16) - 14); address constant INCREMENT_TX_COUNTER_CALL_ADDRESS = address((1 << 16) - 15); address constant PTR_CALLDATA_CALL_ADDRESS = address((1 << 16) - 16); address constant CALLFLAGS_CALL_ADDRESS = address((1 << 16) - 17); address constant PTR_RETURNDATA_CALL_ADDRESS = address((1 << 16) - 18); address constant EVENT_INITIALIZE_ADDRESS = address((1 << 16) - 19); address constant EVENT_WRITE_ADDRESS = address((1 << 16) - 20); address constant LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS = address((1 << 16) - 21); address constant LOAD_LATEST_RETURNDATA_INTO_ACTIVE_PTR_CALL_ADDRESS = address((1 << 16) - 22); address constant PTR_ADD_INTO_ACTIVE_CALL_ADDRESS = address((1 << 16) - 23); address constant PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS = address((1 << 16) - 24); address constant PTR_PACK_INTO_ACTIVE_CALL_ADDRESS = address((1 << 16) - 25); address constant MULTIPLICATION_HIGH_ADDRESS = address((1 << 16) - 26); address constant GET_EXTRA_ABI_DATA_ADDRESS = address((1 << 16) - 27); // All the offsets are in bits uint256 constant META_GAS_PER_PUBDATA_BYTE_OFFSET = 0 * 8; uint256 constant META_HEAP_SIZE_OFFSET = 8 * 8; uint256 constant META_AUX_HEAP_SIZE_OFFSET = 12 * 8; uint256 constant META_SHARD_ID_OFFSET = 28 * 8; uint256 constant META_CALLER_SHARD_ID_OFFSET = 29 * 8; uint256 constant META_CODE_SHARD_ID_OFFSET = 30 * 8; /// @notice The way to forward the calldata: /// - Use the current heap (i.e. the same as on EVM). /// - Use the auxiliary heap. /// - Forward via a pointer /// @dev Note, that currently, users do not have access to the auxiliary /// heap and so the only type of forwarding that will be used by the users /// are UseHeap and ForwardFatPointer for forwarding a slice of the current calldata /// to the next call. enum CalldataForwardingMode { UseHeap, ForwardFatPointer, UseAuxHeap } /** * @author Matter Labs * @notice A library that allows calling contracts with the `isSystem` flag. * @dev It is needed to call ContractDeployer and NonceHolder. */ library SystemContractsCaller { /// @notice Makes a call with the `isSystem` flag. /// @param gasLimit The gas limit for the call. /// @param to The address to call. /// @param value The value to pass with the transaction. /// @param data The calldata. /// @return success Whether the transaction has been successful. /// @dev Note, that the `isSystem` flag can only be set when calling system contracts. function systemCall(uint32 gasLimit, address to, uint256 value, bytes memory data) internal returns (bool success) { address callAddr = SYSTEM_CALL_CALL_ADDRESS; uint32 dataStart; assembly { dataStart := add(data, 0x20) } uint32 dataLength = uint32(Utils.safeCastToU32(data.length)); uint256 farCallAbi = SystemContractsCaller.getFarCallABI( 0, 0, dataStart, dataLength, gasLimit, // Only rollup is supported for now 0, CalldataForwardingMode.UseHeap, false, true ); if (value == 0) { // Doing the system call directly assembly { success := call(to, callAddr, 0, 0, farCallAbi, 0, 0) } } else { address msgValueSimulator = MSG_VALUE_SYSTEM_CONTRACT; // We need to supply the mask to the MsgValueSimulator to denote // that the call should be a system one. uint256 forwardMask = MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT; assembly { success := call(msgValueSimulator, callAddr, value, to, farCallAbi, forwardMask, 0) } } } /// @notice Makes a call with the `isSystem` flag. /// @param gasLimit The gas limit for the call. /// @param to The address to call. /// @param value The value to pass with the transaction. /// @param data The calldata. /// @return success Whether the transaction has been successful. /// @return returnData The returndata of the transaction (revert reason in case the transaction has failed). /// @dev Note, that the `isSystem` flag can only be set when calling system contracts. function systemCallWithReturndata( uint32 gasLimit, address to, uint128 value, bytes memory data ) internal returns (bool success, bytes memory returnData) { success = systemCall(gasLimit, to, value, data); uint256 size; assembly { size := returndatasize() } returnData = new bytes(size); assembly { returndatacopy(add(returnData, 0x20), 0, size) } } /// @notice Makes a call with the `isSystem` flag. /// @param gasLimit The gas limit for the call. /// @param to The address to call. /// @param value The value to pass with the transaction. /// @param data The calldata. /// @return returnData The returndata of the transaction. In case the transaction reverts, the error /// bubbles up to the parent frame. /// @dev Note, that the `isSystem` flag can only be set when calling system contracts. function systemCallWithPropagatedRevert( uint32 gasLimit, address to, uint128 value, bytes memory data ) internal returns (bytes memory returnData) { bool success; (success, returnData) = systemCallWithReturndata(gasLimit, to, value, data); if (!success) { assembly { let size := mload(returnData) revert(add(returnData, 0x20), size) } } } /// @notice Calculates the packed representation of the FarCallABI. /// @param dataOffset Calldata offset in memory. Provide 0 unless using custom pointer. /// @param memoryPage Memory page to use. Provide 0 unless using custom pointer. /// @param dataStart The start of the calldata slice. Provide the offset in memory /// if not using custom pointer. /// @param dataLength The calldata length. Provide the length of the calldata in bytes /// unless using custom pointer. /// @param gasPassed The gas to pass with the call. /// @param shardId Of the account to call. Currently only 0 is supported. /// @param forwardingMode The forwarding mode to use: /// - provide CalldataForwardingMode.UseHeap when using your current memory /// - provide CalldataForwardingMode.ForwardFatPointer when using custom pointer. /// @param isConstructorCall Whether the call will be a call to the constructor /// (ignored when the caller is not a system contract). /// @param isSystemCall Whether the call will have the `isSystem` flag. /// @return farCallAbi The far call ABI. /// @dev The `FarCallABI` has the following structure: /// pub struct FarCallABI { /// pub memory_quasi_fat_pointer: FatPointer, /// pub gas_passed: u32, /// pub shard_id: u8, /// pub forwarding_mode: FarCallForwardPageType, /// pub constructor_call: bool, /// pub to_system: bool, /// } /// /// The FatPointer struct: /// /// pub struct FatPointer { /// pub offset: u32, // offset relative to `start` /// pub memory_page: u32, // memory page where slice is located /// pub start: u32, // absolute start of the slice /// pub length: u32, // length of the slice /// } /// /// @dev Note, that the actual layout is the following: /// /// [0..32) bits -- the calldata offset /// [32..64) bits -- the memory page to use. Can be left blank in most of the cases. /// [64..96) bits -- the absolute start of the slice /// [96..128) bits -- the length of the slice. /// [128..192) bits -- empty bits. /// [192..224) bits -- gasPassed. /// [224..232) bits -- forwarding_mode /// [232..240) bits -- shard id. /// [240..248) bits -- constructor call flag /// [248..256] bits -- system call flag function getFarCallABI( uint32 dataOffset, uint32 memoryPage, uint32 dataStart, uint32 dataLength, uint32 gasPassed, uint8 shardId, CalldataForwardingMode forwardingMode, bool isConstructorCall, bool isSystemCall ) internal pure returns (uint256 farCallAbi) { // Fill in the call parameter fields farCallAbi = getFarCallABIWithEmptyFatPointer( gasPassed, shardId, forwardingMode, isConstructorCall, isSystemCall ); // Fill in the fat pointer fields farCallAbi |= dataOffset; farCallAbi |= (uint256(memoryPage) << 32); farCallAbi |= (uint256(dataStart) << 64); farCallAbi |= (uint256(dataLength) << 96); } /// @notice Calculates the packed representation of the FarCallABI with zero fat pointer fields. /// @param gasPassed The gas to pass with the call. /// @param shardId Of the account to call. Currently only 0 is supported. /// @param forwardingMode The forwarding mode to use: /// - provide CalldataForwardingMode.UseHeap when using your current memory /// - provide CalldataForwardingMode.ForwardFatPointer when using custom pointer. /// @param isConstructorCall Whether the call will be a call to the constructor /// (ignored when the caller is not a system contract). /// @param isSystemCall Whether the call will have the `isSystem` flag. /// @return farCallAbiWithEmptyFatPtr The far call ABI with zero fat pointer fields. function getFarCallABIWithEmptyFatPointer( uint32 gasPassed, uint8 shardId, CalldataForwardingMode forwardingMode, bool isConstructorCall, bool isSystemCall ) internal pure returns (uint256 farCallAbiWithEmptyFatPtr) { farCallAbiWithEmptyFatPtr |= (uint256(gasPassed) << 192); farCallAbiWithEmptyFatPtr |= (uint256(forwardingMode) << 224); farCallAbiWithEmptyFatPtr |= (uint256(shardId) << 232); if (isConstructorCall) { farCallAbiWithEmptyFatPtr |= (1 << 240); } if (isSystemCall) { farCallAbiWithEmptyFatPtr |= (1 << 248); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../openzeppelin/token/ERC20/IERC20.sol"; import "../openzeppelin/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/IPaymasterFlow.sol"; import "../interfaces/IContractDeployer.sol"; import {ETH_TOKEN_SYSTEM_CONTRACT, BOOTLOADER_FORMAL_ADDRESS} from "../Constants.sol"; import "./RLPEncoder.sol"; import "./EfficientCall.sol"; /// @dev The type id of zkSync's EIP-712-signed transaction. uint8 constant EIP_712_TX_TYPE = 0x71; /// @dev The type id of legacy transactions. uint8 constant LEGACY_TX_TYPE = 0x0; /// @dev The type id of legacy transactions. uint8 constant EIP_2930_TX_TYPE = 0x01; /// @dev The type id of EIP1559 transactions. uint8 constant EIP_1559_TX_TYPE = 0x02; /// @notice Structure used to represent zkSync transaction. struct Transaction { // The type of the transaction. uint256 txType; // The caller. uint256 from; // The callee. uint256 to; // The gasLimit to pass with the transaction. // It has the same meaning as Ethereum's gasLimit. uint256 gasLimit; // The maximum amount of gas the user is willing to pay for a byte of pubdata. uint256 gasPerPubdataByteLimit; // The maximum fee per gas that the user is willing to pay. // It is akin to EIP1559's maxFeePerGas. uint256 maxFeePerGas; // The maximum priority fee per gas that the user is willing to pay. // It is akin to EIP1559's maxPriorityFeePerGas. uint256 maxPriorityFeePerGas; // The transaction's paymaster. If there is no paymaster, it is equal to 0. uint256 paymaster; // The nonce of the transaction. uint256 nonce; // The value to pass with the transaction. uint256 value; // In the future, we might want to add some // new fields to the struct. The `txData` struct // is to be passed to account and any changes to its structure // would mean a breaking change to these accounts. In order to prevent this, // we should keep some fields as "reserved". // It is also recommended that their length is fixed, since // it would allow easier proof integration (in case we will need // some special circuit for preprocessing transactions). uint256[4] reserved; // The transaction's calldata. bytes data; // The signature of the transaction. bytes signature; // The properly formatted hashes of bytecodes that must be published on L1 // with the inclusion of this transaction. Note, that a bytecode has been published // before, the user won't pay fees for its republishing. bytes32[] factoryDeps; // The input to the paymaster. bytes paymasterInput; // Reserved dynamic type for the future use-case. Using it should be avoided, // But it is still here, just in case we want to enable some additional functionality. bytes reservedDynamic; } /** * @author Matter Labs * @notice Library is used to help custom accounts to work with common methods for the Transaction type. */ library TransactionHelper { using SafeERC20 for IERC20; /// @notice The EIP-712 typehash for the contract's domain bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId)"); bytes32 constant EIP712_TRANSACTION_TYPE_HASH = keccak256( "Transaction(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 paymaster,uint256 nonce,uint256 value,bytes data,bytes32[] factoryDeps,bytes paymasterInput)" ); /// @notice Whether the token is Ethereum. /// @param _addr The address of the token /// @return `true` or `false` based on whether the token is Ether. /// @dev This method assumes that address is Ether either if the address is 0 (for convenience) /// or if the address is the address of the L2EthToken system contract. function isEthToken(uint256 _addr) internal pure returns (bool) { return _addr == uint256(uint160(address(ETH_TOKEN_SYSTEM_CONTRACT))) || _addr == 0; } /// @notice Calculate the suggested signed hash of the transaction, /// i.e. the hash that is signed by EOAs and is recommended to be signed by other accounts. function encodeHash(Transaction calldata _transaction) internal view returns (bytes32 resultHash) { if (_transaction.txType == LEGACY_TX_TYPE) { resultHash = _encodeHashLegacyTransaction(_transaction); } else if (_transaction.txType == EIP_712_TX_TYPE) { resultHash = _encodeHashEIP712Transaction(_transaction); } else if (_transaction.txType == EIP_1559_TX_TYPE) { resultHash = _encodeHashEIP1559Transaction(_transaction); } else if (_transaction.txType == EIP_2930_TX_TYPE) { resultHash = _encodeHashEIP2930Transaction(_transaction); } else { // Currently no other transaction types are supported. // Any new transaction types will be processed in a similar manner. revert("Encoding unsupported tx"); } } /// @notice Encode hash of the zkSync native transaction type. /// @return keccak256 hash of the EIP-712 encoded representation of transaction function _encodeHashEIP712Transaction(Transaction calldata _transaction) private view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( EIP712_TRANSACTION_TYPE_HASH, _transaction.txType, _transaction.from, _transaction.to, _transaction.gasLimit, _transaction.gasPerPubdataByteLimit, _transaction.maxFeePerGas, _transaction.maxPriorityFeePerGas, _transaction.paymaster, _transaction.nonce, _transaction.value, EfficientCall.keccak(_transaction.data), keccak256(abi.encodePacked(_transaction.factoryDeps)), EfficientCall.keccak(_transaction.paymasterInput) ) ); bytes32 domainSeparator = keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256("zkSync"), keccak256("2"), block.chainid) ); return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } /// @notice Encode hash of the legacy transaction type. /// @return keccak256 of the serialized RLP encoded representation of transaction function _encodeHashLegacyTransaction(Transaction calldata _transaction) private view returns (bytes32) { // Hash of legacy transactions are encoded as one of the: // - RLP(nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0) // - RLP(nonce, gasPrice, gasLimit, to, value, data) // // In this RLP encoding, only the first one above list appears, so we encode each element // inside list and then concatenate the length of all elements with them. bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); // Encode `gasPrice` and `gasLimit` together to prevent "stack too deep error". bytes memory encodedGasParam; { bytes memory encodedGasPrice = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); encodedGasParam = bytes.concat(encodedGasPrice, encodedGasLimit); } bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // Encode `chainId` according to EIP-155, but only if the `chainId` is specified in the transaction. bytes memory encodedChainId; if (_transaction.reserved[0] != 0) { encodedChainId = bytes.concat(RLPEncoder.encodeUint256(block.chainid), hex"80_80"); } bytes memory encodedListLength; unchecked { uint256 listLength = encodedNonce.length + encodedGasParam.length + encodedTo.length + encodedValue.length + encodedDataLength.length + _transaction.data.length + encodedChainId.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( bytes.concat( encodedListLength, encodedNonce, encodedGasParam, encodedTo, encodedValue, encodedDataLength, _transaction.data, encodedChainId ) ); } /// @notice Encode hash of the EIP2930 transaction type. /// @return keccak256 of the serialized RLP encoded representation of transaction function _encodeHashEIP2930Transaction(Transaction calldata _transaction) private view returns (bytes32) { // Hash of EIP2930 transactions is encoded the following way: // H(0x01 || RLP(chain_id, nonce, gas_price, gas_limit, destination, amount, data, access_list)) // // Note, that on zkSync access lists are not supported and should always be empty. // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; { bytes memory encodedChainId = RLPEncoder.encodeUint256(block.chainid); bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); bytes memory encodedGasPrice = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); encodedFixedLengthParams = bytes.concat( encodedChainId, encodedNonce, encodedGasPrice, encodedGasLimit, encodedTo, encodedValue ); } // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // On zkSync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory encodedListLength; unchecked { uint256 listLength = encodedFixedLengthParams.length + encodedDataLength.length + _transaction.data.length + encodedAccessListLength.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( bytes.concat( "\x01", encodedListLength, encodedFixedLengthParams, encodedDataLength, _transaction.data, encodedAccessListLength ) ); } /// @notice Encode hash of the EIP1559 transaction type. /// @return keccak256 of the serialized RLP encoded representation of transaction function _encodeHashEIP1559Transaction(Transaction calldata _transaction) private view returns (bytes32) { // Hash of EIP1559 transactions is encoded the following way: // H(0x02 || RLP(chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list)) // // Note, that on zkSync access lists are not supported and should always be empty. // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; { bytes memory encodedChainId = RLPEncoder.encodeUint256(block.chainid); bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); bytes memory encodedMaxPriorityFeePerGas = RLPEncoder.encodeUint256(_transaction.maxPriorityFeePerGas); bytes memory encodedMaxFeePerGas = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); encodedFixedLengthParams = bytes.concat( encodedChainId, encodedNonce, encodedMaxPriorityFeePerGas, encodedMaxFeePerGas, encodedGasLimit, encodedTo, encodedValue ); } // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // On zkSync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory encodedListLength; unchecked { uint256 listLength = encodedFixedLengthParams.length + encodedDataLength.length + _transaction.data.length + encodedAccessListLength.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( bytes.concat( "\x02", encodedListLength, encodedFixedLengthParams, encodedDataLength, _transaction.data, encodedAccessListLength ) ); } /// @notice Processes the common paymaster flows, e.g. setting proper allowance /// for tokens, etc. For more information on the expected behavior, check out /// the "Paymaster flows" section in the documentation. function processPaymasterInput(Transaction calldata _transaction) internal { require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long"); bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]); if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { require( _transaction.paymasterInput.length >= 68, "The approvalBased paymaster input must be at least 68 bytes long" ); // While the actual data consists of address, uint256 and bytes data, // the data is needed only for the paymaster, so we ignore it here for the sake of optimization (address token, uint256 minAllowance) = abi.decode(_transaction.paymasterInput[4:68], (address, uint256)); address paymaster = address(uint160(_transaction.paymaster)); uint256 currentAllowance = IERC20(token).allowance(address(this), paymaster); if (currentAllowance < minAllowance) { // Some tokens, e.g. USDT require that the allowance is firsty set to zero // and only then updated to the new value. IERC20(token).safeApprove(paymaster, 0); IERC20(token).safeApprove(paymaster, minAllowance); } } else if (paymasterInputSelector == IPaymasterFlow.general.selector) { // Do nothing. general(bytes) paymaster flow means that the paymaster must interpret these bytes on his own. } else { revert("Unsupported paymaster flow"); } } /// @notice Pays the required fee for the transaction to the bootloader. /// @dev Currently it pays the maximum amount "_transaction.maxFeePerGas * _transaction.gasLimit", /// it will change in the future. function payToTheBootloader(Transaction calldata _transaction) internal returns (bool success) { address bootloaderAddr = BOOTLOADER_FORMAL_ADDRESS; uint256 amount = _transaction.maxFeePerGas * _transaction.gasLimit; assembly { success := call(gas(), bootloaderAddr, amount, 0, 0, 0, 0) } } // Returns the balance required to process the transaction. function totalRequiredBalance(Transaction calldata _transaction) internal pure returns (uint256 requiredBalance) { if (address(uint160(_transaction.paymaster)) != address(0)) { // Paymaster pays for the fee requiredBalance = _transaction.value; } else { // The user should have enough balance for both the fee and the value of the transaction requiredBalance = _transaction.maxFeePerGas * _transaction.gasLimit + _transaction.value; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import "./EfficientCall.sol"; /** * @author Matter Labs * @dev Common utilities used in zkSync system contracts */ library Utils { /// @dev Bit mask of bytecode hash "isConstructor" marker bytes32 constant IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK = 0x00ff000000000000000000000000000000000000000000000000000000000000; /// @dev Bit mask to set the "isConstructor" marker in the bytecode hash bytes32 constant SET_IS_CONSTRUCTOR_MARKER_BIT_MASK = 0x0001000000000000000000000000000000000000000000000000000000000000; function safeCastToU128(uint256 _x) internal pure returns (uint128) { require(_x <= type(uint128).max, "Overflow"); return uint128(_x); } function safeCastToU32(uint256 _x) internal pure returns (uint32) { require(_x <= type(uint32).max, "Overflow"); return uint32(_x); } function safeCastToU24(uint256 _x) internal pure returns (uint24) { require(_x <= type(uint24).max, "Overflow"); return uint24(_x); } /// @return codeLength The bytecode length in bytes function bytecodeLenInBytes(bytes32 _bytecodeHash) internal pure returns (uint256 codeLength) { codeLength = bytecodeLenInWords(_bytecodeHash) << 5; // _bytecodeHash * 32 } /// @return codeLengthInWords The bytecode length in machine words function bytecodeLenInWords(bytes32 _bytecodeHash) internal pure returns (uint256 codeLengthInWords) { unchecked { codeLengthInWords = uint256(uint8(_bytecodeHash[2])) * 256 + uint256(uint8(_bytecodeHash[3])); } } /// @notice Denotes whether bytecode hash corresponds to a contract that already constructed function isContractConstructed(bytes32 _bytecodeHash) internal pure returns (bool) { return _bytecodeHash[1] == 0x00; } /// @notice Denotes whether bytecode hash corresponds to a contract that is on constructor or has already been constructed function isContractConstructing(bytes32 _bytecodeHash) internal pure returns (bool) { return _bytecodeHash[1] == 0x01; } /// @notice Sets "isConstructor" flag to TRUE for the bytecode hash /// @param _bytecodeHash The bytecode hash for which it is needed to set the constructing flag /// @return The bytecode hash with "isConstructor" flag set to TRUE function constructingBytecodeHash(bytes32 _bytecodeHash) internal pure returns (bytes32) { // Clear the "isConstructor" marker and set it to 0x01. return constructedBytecodeHash(_bytecodeHash) | SET_IS_CONSTRUCTOR_MARKER_BIT_MASK; } /// @notice Sets "isConstructor" flag to FALSE for the bytecode hash /// @param _bytecodeHash The bytecode hash for which it is needed to set the constructing flag /// @return The bytecode hash with "isConstructor" flag set to FALSE function constructedBytecodeHash(bytes32 _bytecodeHash) internal pure returns (bytes32) { return _bytecodeHash & ~IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK; } /// @notice Validate the bytecode format and calculate its hash. /// @param _bytecode The bytecode to hash. /// @return hashedBytecode The 32-byte hash of the bytecode. /// Note: The function reverts the execution if the bytecode has non expected format: /// - Bytecode bytes length is not a multiple of 32 /// - Bytecode bytes length is not less than 2^21 bytes (2^16 words) /// - Bytecode words length is not odd function hashL2Bytecode(bytes calldata _bytecode) internal view returns (bytes32 hashedBytecode) { // Note that the length of the bytecode must be provided in 32-byte words. require(_bytecode.length % 32 == 0, "po"); uint256 bytecodeLenInWords = _bytecode.length / 32; require(bytecodeLenInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words require(bytecodeLenInWords % 2 == 1, "pr"); // bytecode length in words must be odd hashedBytecode = EfficientCall.sha(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // Setting the version of the hash hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248))); // Setting the length hashedBytecode = hashedBytecode | bytes32(bytecodeLenInWords << 224); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed 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. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (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. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` 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. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transfer.selector, to, value) ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, value) ); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require( oldAllowance >= value, "SafeERC20: decreased allowance below zero" ); uint256 newAllowance = oldAllowance - value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require( nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed" ); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall( data, "SafeERC20: low-level call failed" ); if (returndata.length > 0) { // Return data is optional require( abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed" ); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require( address(this).balance >= amount, "Address: insufficient balance" ); (bool success, ) = recipient.call{value: amount}(""); require( success, "Address: unable to send value, recipient may have reverted" ); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue( target, data, 0, "Address: low-level call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); (bool success, bytes memory returndata) = target.call{value: value}( data ); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall( target, data, "Address: low-level static call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall( target, data, "Address: low-level delegate call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
{ "evmVersion": "paris", "optimizer": { "enabled": true, "mode": "3" }, "outputSelection": { "*": { "*": [ "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract NODL","name":"token","type":"address"},{"internalType":"uint256","name":"initialQuota","type":"uint256"},{"internalType":"uint256","name":"initialPeriod","type":"uint256"},{"internalType":"address","name":"oracleAddress","type":"address"},{"internalType":"uint16","name":"rewardBasisPoints","type":"uint16"},{"internalType":"address","name":"admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"InvalidBatchSequence","type":"error"},{"inputs":[],"name":"InvalidBatchStructure","type":"error"},{"inputs":[],"name":"InvalidRecipientSequence","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"OutOfRangeValue","type":"error"},{"inputs":[],"name":"QuotaExceeded","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"TooLongPeriod","type":"error"},{"inputs":[],"name":"UnauthorizedOracle","type":"error"},{"inputs":[],"name":"ZeroPeriod","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"batchSum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalRewardsClaimed","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"BatchMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"bp","type":"uint16"}],"name":"BatchSubmitterRewardSet","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalRewardsClaimed","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"PeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"quota","type":"uint256"}],"name":"QuotaSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"BASIS_POINTS_DIVISOR","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BATCH_REWARD_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNATURE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNING_DOMAIN","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authorizedOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchSequence","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchSubmitterRewardBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"sequence","type":"uint256"}],"internalType":"struct Rewards.BatchReward","name":"batch","type":"tuple"}],"name":"digestBatchReward","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"sequence","type":"uint256"}],"internalType":"struct Rewards.Reward","name":"reward","type":"tuple"}],"name":"digestReward","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBatchDetails","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBatchRewardDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"sequence","type":"uint256"}],"internalType":"struct Rewards.BatchReward","name":"batch","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mintBatchReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"sequence","type":"uint256"}],"internalType":"struct Rewards.Reward","name":"reward","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mintReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nodl","outputs":[{"internalType":"contract NODL","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"period","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quota","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quotaRenewalTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"sequences","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"newBasisPoints","type":"uint16"}],"name":"setBatchSubmitterRewardBasisPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPeriod","type":"uint256"}],"name":"setPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newQuota","type":"uint256"}],"name":"setQuota","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
9c4d535b00000000000000000000000000000000000000000000000000000000000000000100041d772caa514f8412ee813d34e6f426719c82272049e8b5bfccb6c4f2c8000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000bd4372e44c5ee654dd838304006e1f0f699831540000000000000000000000000000000000000000000167fd2f45f5fa5e8000000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000eca65b589d70659415f43f91af9909f577dc7aec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e097ac1bcf81e7ff2657045f72caa6cf06486c9
Deployed Bytecode
0x0003000000000002001100000000000200000000030100190000006003300270000003a203300197000200000031035500010000000103550000000102200190000001840000c13d0000008002000039000000400020043f000000040230008c000008700000413d000000000201043b000000e002200270000003b90420009c000001cd0000213d000003d10420009c000002600000213d000003dd0420009c000002bb0000213d000003e30420009c000002ea0000213d000003e60420009c000003950000613d000003e70220009c000008700000c13d0000000002000416000000440430008c000008700000413d000000000202004b000008700000c13d0000000402100370000000000202043b000003a80420009c000008700000213d000000040220003900000000042300490000040605000041000000600640008c000000000600001900000000060540190000040604400197000000000704004b000000000500a019000004060440009c000000000506c019000000000405004b000008700000c13d000000e004000039000d00000004001d000000400040043f000000000421034f000000000404043b000003a80540009c000008700000213d00000000042400190000001f05400039000000000535004b000008700000813d000000000541034f000000000605043b000003a80560009c000001c70000213d00000005056002100000003f075000390000040707700197000003f80870009c000001c70000213d000000e007700039000000400070043f000000e00060043f00000020044000390000000005450019000000000735004b000008700000213d000000000606004b000000570000613d0000010006000039000000000741034f000000000707043b000003a40870009c000008700000213d00000000067604360000002004400039000000000754004b0000004f0000413d0000000d04000029000000800040043f0000002004200039000000000541034f000000000505043b000003a80650009c000008700000213d00000000052500190000001f025000390000040606000041000000000732004b000000000700001900000000070680190000040602200197000000000802004b0000000006008019000004060220009c000000000607c019000000000206004b000008700000c13d000000000251034f000000000602043b000003a80260009c000001c70000213d00000005076002100000003f027000390000040708200197000000400200043d0000000008820019000000000928004b00000000090000190000000109004039000003a80a80009c000001c70000213d0000000109900190000001c70000c13d000000400080043f000000000062043500000020055000390000000006570019000000000736004b000008700000213d000000000765004b0000008b0000813d0000000007020019000000000851034f000000000808043b000000200770003900000000008704350000002005500039000000000865004b000000840000413d000000a00020043f0000002002400039000000000221034f000000000202043b000000c00020043f0000002402100370000000000502043b000003a80250009c000008700000213d00000023025000390000040604000041000000000632004b000000000600001900000000060480190000040602200197000000000702004b0000000004008019000004060220009c000000000406c019000000000204004b000008700000c13d0000000406500039000000000261034f000000000202043b000003a80420009c000001c70000213d0000001f04200039000000200700008a000000000474016f0000003f04400039000000000474016f000000400700043d0000000004470019000c00000007001d000000000774004b00000000070000190000000107004039000003a80840009c000001c70000213d0000000107700190000001c70000c13d000000400040043f0000000c04000029000000000424043600000000052500190000002405500039000000000335004b000008700000213d0000002003600039000000000331034f0000001f0120018f0000000505200272000000c90000613d000000000600001900000005076002100000000008740019000000000773034f000000000707043b00000000007804350000000106600039000000000756004b000000c10000413d000000000601004b000000d80000613d0000000505500210000000000353034f00000000055400190000000301100210000000000605043300000000061601cf000000000616022f000000000303043b0000010001100089000000000313022f00000000011301cf000000000161019f000000000015043500000000012400190000000000010435000000a00100043d0000000001010433000000800200043d0000000002020433000000000112004b000008bd0000c13d0000000801000039000b00000001001d000000000101041a000000c00200043d000000000121004b000008e30000c13d00000080010000390e810b3f0000040f000800000001001d0000000c020000290e810c950000040f0000000501000039000a00000001001d000000000101041a000c00000001001d000003b4010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f00000001022001900000096a0000613d000000000101043b0000000c0210006c000008e60000813d000000a00100043d0000000032010434000000000102004b0000000004000019000700000000001d000600000000001d000008fa0000c13d0000000601000039000500000001001d000000000201041a0000000001420019000000000221004b0000000002000019000000010200403900000001022001900000025d0000c13d0000000402000039000000000202041a000000000221004b0000025d0000213d0000000502000029000000000012041b000000c00100043d000000010200008a000000000221004b000008760000613d00000001011000390000000b02000029000000000012041b00000009010000390000000802000029000000000021041b000003f0010000410000000000100439000000000100041200000004001004430000000d010000290000002400100443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003f1011001c700008005020000390e810e7c0000040f00000001022001900000096a0000613d000000000101043b000b03a40010019b000000800100043d0000000002010433000000000202004b0000091d0000c13d000003fa0100004100000000001004390000000b010000290000000400100443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003fb011001c700008002020000390e810e7c0000040f00000001022001900000096a0000613d000000000101043b000000000101004b000008700000613d000000400300043d000000240130003900000007020000290000000000210435000003fc010000410000000001130436000c00000001001d0000000001000411000003a401100197000d00000003001d0000000402300039000000000012043500000000010004140000000b02000029000000040220008c000001680000613d000003a202000041000003a20310009c00000000010280190000000d04000029000003a20340009c00000000020440190000004002200210000000c001100210000000000121019f000003ef011001c70000000b020000290e810e770000040f00000000030100190000006003300270000003a20030019d000003a20330019700020000000103550000000102200190000009810000613d0000000d01000029000003a80110009c000001c70000213d0000000d04000029000000400040043f0000000501000029000000000101041a0000004002400039000000080300002900000000003204350000000c02000029000000000012043500000006010000290000000000140435000003a2010000410000000002000414000003a20320009c0000000002018019000003a20340009c00000000040180190000004001400210000000c002200210000000000112019f0000040a011001c70000800d0200003900000001030000390000040b04000041000005480000013d0000000002000416000000000202004b000008700000c13d0000001f02300039000003a302200197000001a002200039000000400020043f0000001f0230018f0000000504300272000001970000613d00000000050000190000000506500210000000000761034f000000000707043b000001a00660003900000000007604350000000105500039000000000645004b0000018f0000413d000000000502004b000001a60000613d0000000504400210000000000141034f0000000302200210000001a004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f0000000000140435000000c00130008c000008700000413d000001a00600043d000003a40160009c000008700000213d000001e00100043d000d00000001001d000001c00100043d000c00000001001d000002000100043d000b00000001001d000003a40110009c000008700000213d000002200100043d000a00000001001d0000ffff0110008c000008700000213d000002400100043d000900000001001d000003a40110009c000008700000213d000000400900043d000003a50190009c000001c70000213d0000004001900039000000400010043f0000001301000039000000000a190436000003a60100004100000000001a0435000000400800043d000003a50180009c000004b90000a13d000003f60100004100000000001004350000004101000039000000040010043f000003f70100004100000e8300010430000003ba0420009c000002ae0000213d000003c60420009c000002c80000213d000003cc0420009c000002f70000213d000003cf0420009c000003a60000613d000003d00220009c000008700000c13d0000000002000416000000840430008c000008700000413d000000000202004b000008700000c13d000000e002000039000000400020043f0000000402100370000000000202043b000003a40420009c000008700000213d000000800020043f0000002402100370000000000202043b000000a00020043f0000004402100370000000000202043b000000c00020043f0000006402100370000000000402043b000003a80240009c000008700000213d0000002302400039000000000232004b000008700000813d0000000405400039000000000251034f000000000202043b000003a80620009c000001c70000213d0000001f06200039000000200700008a000000000676016f0000003f06600039000000000676016f000003f80760009c000001c70000213d000000e006600039000000400060043f000000e00020043f00000000042400190000002404400039000000000334004b000008700000213d0000002003500039000000000131034f0000001f0320018f0000000504200272000002110000613d00000000050000190000000506500210000000000761034f000000000707043b000001000660003900000000007604350000000105500039000000000645004b000002090000413d000000000503004b000002200000613d0000000504400210000000000141034f00000003033002100000010004400039000000000504043300000000053501cf000000000535022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f000000000014043500000100012000390000000000010435000000800100043d000003a401100197000000c00200043d000d00000002001d00000000001004350000000701000039000c00000001001d000000200010043f000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000101041a0000000d0110006c0000070b0000c13d00000080010000390e810a4f0000040f000000e002000039000a00000002001d0e810c950000040f0000000501000039000b00000001001d000000000101041a000d00000001001d000003b4010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f00000001022001900000096a0000613d000000000101043b0000000d0210006c0000081b0000813d0000000601000039000000000101041a000000a00200043d0000000001120019000000000221004b0000000002000019000000010200403900000001022001900000025d0000c13d0000000402000039000000000202041a000000000221004b0000082d0000a13d000000400100043d0000040c02000041000005730000013d000003d20420009c000002d40000213d000003d80420009c000003290000213d000003db0420009c000003b10000613d000003dc0220009c000008700000c13d0000000002000416000000440330008c000008700000413d000000000202004b000008700000c13d0000000402100370000000000202043b000d00000002001d0000002401100370000000000101043b000c00000001001d000003a40110009c000008700000213d0000000d010000290000000000100435000000200000043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b0000000101100039000000000101041a000b00000001001d0000000000100435000000200000043f0000000001000414000003a20210009c000003a201008041000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b0000000002000411000a00000002001d0000000000200435000000200010043f000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000101041a000000ff01100190000005eb0000c13d000000400100043d00000024021000390000000b030000290000000000320435000003ee02000041000000000021043500000004021000390000000a030000290000000000320435000004ab0000013d000003bb0420009c000002df0000213d000003c10420009c0000033e0000213d000003c40120009c000003ba0000613d000003c50120009c000008700000c13d0000000001000416000000000101004b000008700000c13d0000000401000039000004b50000013d000003de0420009c000003490000213d000003e10120009c000003c10000613d000003e20120009c000008700000c13d0000000001000416000000000101004b000008700000c13d0000040301000041000000800010043f000003e90100004100000e820001042e000003c70420009c0000035b0000213d000003ca0420009c000003c80000613d000003cb0120009c000008700000c13d0000000001000416000000000101004b000008700000c13d000000800000043f000003e90100004100000e820001042e000003d30420009c000003680000213d000003d60120009c000003e70000613d000003d70120009c000008700000c13d0000000001000416000000000101004b000008700000c13d0000000901000039000004b50000013d000003bc0420009c0000037c0000213d000003bf0120009c000003ec0000613d000003c00120009c000008700000c13d0000000001000416000000000101004b000008700000c13d0000000601000039000004b50000013d000003e40420009c000004010000613d000003e50120009c000008700000c13d0000000001000416000000640230008c000008700000413d000000000101004b000008700000c13d00000000010300190e810a160000040f0e810a4f0000040f0000038d0000013d000003cd0120009c000004220000613d000003ce0120009c000008700000c13d0000000001000416000000000101004b000008700000c13d000003f00100004100000000001004390000000001000412000d00000001001d0000000400100443000000a0010000390000002400100443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003f1011001c700008005020000390e810e7c0000040f00000001022001900000096a0000613d000000400700043d000000000101043b000000ff0210008c0000054d0000c13d0000000104000039000000000304041a000000010630019000000001013002700000007f0510018f00000000010560190000001f0210008c00000000020000190000000102002039000000000223013f0000000102200190000005be0000c13d0000000002170436000000000606004b000005830000c13d000001000100008a000000000113016f0000000000120435000000000105004b00000020030000390000000003006019000005900000013d000003d90420009c000004330000613d000003da0220009c000008700000c13d0000000002000416000000440330008c000008700000413d000000000202004b000008700000c13d0000002402100370000000000302043b000003a40230009c000008700000213d0000000002000411000000000323004b000005580000c13d0000000401100370000000000101043b0e810dee0000040f000000000100001900000e820001042e000003c20420009c000004380000613d000003c30120009c000008700000c13d0000000001000416000000000101004b000008700000c13d000003eb01000041000000800010043f000003e90100004100000e820001042e000003df0420009c000004520000613d000003e00220009c000008700000c13d0000000002000416000000240330008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b0000000000100435000000200000043f000000400200003900000000010000190e810e420000040f0000000101100039000004b50000013d000003c80420009c0000045d0000613d000003c90120009c000008700000c13d0000000001000416000000000101004b000008700000c13d000000c001000039000000400010043f0000000101000039000000800010043f000003a701000041000003f40000013d000003d40420009c000004860000613d000003d50220009c000008700000c13d0000000002000416000000240330008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b000003a40210009c000008700000213d00000000001004350000000701000039000000200010043f000000400200003900000000010000190e810e420000040f000004b50000013d000003bd0420009c000004b10000613d000003be0220009c000008700000c13d0000000002000416000000240430008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b000003a80210009c000008700000213d000000040110003900000000020300190e8109910000040f0e810b3f0000040f000000400200043d0000000000120435000003a201000041000003a20320009c00000000020180190000004001200210000003e8011001c700000e820001042e0000000002000416000000240330008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b0000040d02100198000008700000c13d0000040e0210009c000000000200001900000001020060390000040f0110009c00000001022061bf000000800020043f000003e90100004100000e820001042e0000000001000416000000000101004b000008700000c13d0000000001000412001100000001001d001001000000003d000080050100003900000044030000390000000004000415000000110440008a0000042c0000013d0000000001000416000000000101004b000008700000c13d0000000a01000039000000000101041a0000ffff0110018f000000800010043f000003e90100004100000e820001042e0000000001000416000000000101004b000008700000c13d000003ec01000041000000800010043f000003e90100004100000e820001042e0000000001000416000000000101004b000008700000c13d0000271001000039000000800010043f000003e90100004100000e820001042e0000000002000416000000440330008c000008700000413d000000000202004b000008700000c13d0000002402100370000000000202043b000d00000002001d000003a40220009c000008700000213d0000000401100370000000000101043b0000000000100435000000200000043f0000004002000039000c00000002001d00000000010000190e810e420000040f0000000d020000290000000000200435000000200010043f00000000010000190000000c020000290e810e420000040f000000000101041a000000ff011001900000000001000019000000010100c039000000800010043f000003e90100004100000e820001042e0000000001000416000000000101004b000008700000c13d0000000501000039000004b50000013d0000000001000416000000000101004b000008700000c13d000000c001000039000000400010043f0000001301000039000000800010043f000003a601000041000000a00010043f0000002001000039000000c00010043f0000008001000039000000e0020000390e810a3c0000040f000000c00110008a000003a202000041000003a20310009c00000000010280190000006001100210000003ea011001c700000e820001042e0000000002000416000000240330008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b000d00000001001d0000000001000411000c00000001001d0000000000100435000003b101000041000000200010043f000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000101041a000000ff01100190000004a30000613d0000000d02000029000000000102004b000005680000c13d000000400100043d000003b702000041000005730000013d0000000001000416000000000101004b000008700000c13d0000000001000412000f00000001001d000e00e00000003d0000800501000039000000440300003900000000040004150000000f0440008a0000000504400210000003f0020000410e810e580000040f000003a401100197000000800010043f000003e90100004100000e820001042e0000000001000416000000000101004b000008700000c13d0000000801000039000004b50000013d0000000002000416000000440330008c000008700000413d000000000202004b000008700000c13d0000002402100370000000000202043b000d00000002001d000003a40220009c000008700000213d0000000401100370000000000101043b000c00000001001d0000000000100435000000200000043f000000400200003900000000010000190e810e420000040f0000000101100039000000000101041a0e810dbc0000040f0000000c010000290000000d020000290e810dee0000040f000000000100001900000e820001042e0000000001000416000000000101004b000008700000c13d0000000901000039000000000101041a0000000802000039000000000202041a000000800020043f000000a00010043f000004020100004100000e820001042e0000000002000416000000240330008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b000d00000001001d0000000001000411000c00000001001d0000000000100435000003b101000041000000200010043f000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000400200043d000000000101043b000000000101041a000000ff01100190000005370000c13d000003ee01000041000000000012043500000004012000390000000c03000029000000000031043500000024012000390000000000010435000003a201000041000003a20320009c00000000020180190000004001200210000003ef011001c700000e83000104300000000002000416000000240330008c000008700000413d000000000202004b000008700000c13d0000000401100370000000000101043b000d00000001001d0000ffff0110008c000008700000213d0000000001000411000c00000001001d0000000000100435000003b101000041000000200010043f000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000101041a000000ff011001900000056d0000c13d000000400100043d000003ee02000041000000000021043500000004021000390000000c03000029000000000032043500000024021000390000000000020435000003a202000041000003a20310009c00000000010280190000004001100210000003ef011001c700000e83000104300000000001000416000000000101004b000008700000c13d0000000301000039000000000101041a000000800010043f000003e90100004100000e820001042e0000004001800039000000400010043f00000001040000390000000007480436000003a70100004100000000001704350000000003090433000000200130008c000005050000413d000003a80130009c000001c70000213d000000000104041a000000010210019000000001011002700000007f0510018f000000000501c0190000001f0150008c00000000010000190000000101002039000000000112004b000005be0000c13d000500000003001d00020000000a001d000300000009001d000600000007001d000700000008001d000800000006001d000000200150008c000400000004001d000004f30000413d000100000005001d0000000000400435000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003a9011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000201043b00000005010000290000001f011000390000000501100270000000000112001900000001030000290000001f0330003900000005033002700000000002320019000000000321004b0000000404000029000004f30000813d000000000001041b0000000101100039000000000321004b000004ef0000413d0000000000400435000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003a9011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000200200008a0000000503200180000000000101043b000006ea0000c13d00000020020000390000000309000029000006f50000013d00000003013002100000010001100089000000010200008a00000000011201cf000000000203004b000000000100601900000000020a0433000000000112016f000000000131019f000001200010043f0000000001080433000000200210008c000800000006001d0000055c0000413d000003a80210009c000001c70000213d0000000202000039000000000402041a000000010340019000000001054002700000007f0350018f000000000305c0190000001f0530008c00000000050000190000000105002039000000000454013f0000000104400190000005be0000c13d000000200430008c0000052f0000413d0000001f033000390000000505300270000003aa035000410000001f041000390000000504400270000000000554004b0000052f0000813d000003aa04400041000000000004041b0000000104400039000000000534004b0000052b0000413d000600000007001d0000000000200435000000200300008a0000000005310170000006440000c13d0000002004000039000003aa030000410000064f0000013d00000004010000390000000d03000029000000000031041b0000000000320435000003a2010000410000000003000414000003a20430009c0000000003018019000003a20420009c00000000020180190000004001200210000000c002300210000000000112019f000003a9011001c70000800d020000390000000103000039000003ed040000410e810e770000040f0000000101200190000008700000613d000000000100001900000e820001042e000000ff0210018f000000200320008c0000057a0000413d000003f2010000410000000000170435000003a201000041000003a20270009c00000000070180190000004001700210000003b8011001c700000e83000104300000040001000041000000800010043f000004010100004100000e8300010430000700000008001d00000003021002100000010002200089000000010300008a00000000022301cf000000000301004b0000000002006019000600000007001d0000000003070433000000000223016f000000000112019f0000065f0000013d000003ec0120009c000005c40000a13d000000400100043d0000040502000041000005730000013d0000000d010000290000ffff0110018f000027100210008c000005d60000a13d000000400100043d000003ff020000410000000000210435000003a202000041000003a20310009c00000000010280190000004001100210000003b8011001c700000e8300010430000003a50370009c000001c70000213d0000004003700039000000400030043f00000020037000390000000000130435000c00000007001d00000000002704350000059d0000013d0000000000400435000000020330008c0000000003000019000005900000413d000003f30400004100000000030000190000000005320019000000000604041a000000000065043500000001044000390000002003300039000000000513004b000005890000413d0000003f01300039000000200200008a000000000221016f0000000001720019000000000221004b00000000020000190000000102004039000003a80310009c000001c70000213d0000000102200190000001c70000c13d000c00000007001d000000400010043f000003f00100004100000000001004390000000d010000290000000400100443000000c0010000390000002400100443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003f1011001c700008005020000390e810e7c0000040f00000001022001900000096a0000613d000000400200043d000000000101043b000000ff0310008c000006390000c13d0000000205000039000000000405041a000000010740019000000001014002700000007f0610018f00000000010660190000001f0310008c00000000030000190000000103002039000000000334013f00000001033001900000000c08000029000006d50000613d000003f60100004100000000001004350000002201000039000000040010043f000003f70100004100000e83000104300000000301000039000000000021041b000000400100043d0000000000210435000003a2020000410000000003000414000003a20430009c0000000003028019000003a20410009c00000000010280190000004001100210000000c002300210000000000112019f000003a9011001c70000800d0200003900000001030000390000040404000041000005480000013d0000000a02000039000000000302041a000003b503300197000000000313019f000000000032041b000000400200043d0000000000120435000003a2010000410000000003000414000003a20430009c0000000003018019000003a20420009c00000000020180190000004001200210000000c002300210000000000112019f000003a9011001c70000800d020000390000000103000039000003fe04000041000005480000013d0000000d010000290000000000100435000000200000043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b0000000c020000290000000000200435000000200010043f0000000001000414000003a20210009c000003a201008041000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000101041a000000ff011001900000054b0000c13d0000000d010000290000000000100435000000200000043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b0000000c020000290000000000200435000000200010043f0000000001000414000003a20210009c000003a201008041000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ab011001c70000800d020000390000000403000039000003b3040000410000000d050000290000000c060000290000000a070000290e810e770000040f0000000101200190000008700000613d0000054b0000013d000000ff0310018f000000200430008c000006df0000413d000003f2010000410000000000120435000003a201000041000003a20320009c00000000020180190000004001200210000003b8011001c700000e8300010430000003aa030000410000002004000039000000000600001900000000078400190000000007070433000000000073041b000000200440003900000001033000390000002006600039000000000756004b000006470000413d000000000515004b0000065a0000813d0000000305100210000000f80550018f000000010600008a000000000556022f000000000565013f00000000048400190000000004040433000000000454016f000000000043041b000700000008001d000000010110021000000001011001bf000000000012041b000000ff01000039000001400010043f000003a204000041000003a201a0009c000000000a0480190000004001a002100000000002090433000003a20320009c00000000020480190000006002200210000000000112019f0000000002000414000003a20320009c0000000002048019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000500000001001d000000e00010043f0000000602000029000003a20120009c000003a2050000410000000002058019000000400120021000000007020000290000000002020433000003a20320009c00000000020580190000006002200210000000000112019f0000000002000414000003a20320009c0000000002058019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000700000001001d000001000010043f000003ac010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f00000001022001900000096a0000613d000000000201043b000000a00020043f000000400100043d00000080031000390000000000230435000000600210003900000007030000290000000000320435000000400210003900000005030000290000000000320435000000a002000039000600000002001d0000000002210436000000a0031000390000000004000410000700000004001d0000000000430435000003ae030000410000000000320435000003af0310009c000001c70000213d000000c003100039000500000003001d000000400030043f000003a203000041000003a20420009c000000000203801900000040022002100000000001010433000003a20410009c00000000010380190000006001100210000000000121019f0000000002000414000003a20420009c0000000002038019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000800010043f0000000701000029000000c00010043f0000000d0100006b000007910000c13d000003b70100004100000005030000290000000000130435000003a201000041000003a20230009c00000000030180190000004001300210000003b8011001c700000e83000104300000000003120436000000000707004b0000070e0000c13d000001000100008a000000000114016f0000000000130435000000000106004b000000200400003900000000040060190000071b0000013d000003a50420009c0000000c08000029000001c70000213d0000004004200039000000400040043f000000200420003900000000001404350000000000320435000000400100043d000d00000001001d000007280000013d00000020020000390000000004000019000000030900002900000000059200190000000005050433000000000051041b000000200220003900000001011000390000002004400039000000000534004b000006ed0000413d0000000505000029000000000353004b000007010000813d0000000303500210000000f80330018f000000010400008a000000000334022f000000000343013f00000000029200190000000002020433000000000232016f000000000021041b000000010150021000000001011001bf0000000402000029000000000012041b000000ff01000039000000080600002900000007080000290000000607000029000000020a0000290000050e0000013d000000400100043d000003f902000041000005730000013d0000000000500435000000020440008c00000000040000190000071b0000413d000003aa0500004100000000040000190000000006430019000000000705041a000000000076043500000001055000390000002004400039000000000614004b000007140000413d0000003f01400039000000200300008a000000000131016f0000000004210019000000000114004b00000000010000190000000101004039000003a80340009c000001c70000213d0000000101100190000001c70000c13d000d00000004001d000000400040043f0000000d03000029000003f40130009c000001c70000213d0000002001300039000800000001001d000000400010043f0000000000030435000000400500043d0000002001500039000000e0030000390000000000310435000003f50100004100000000001504350000000041080434000000e0035000390000000000130435000c00000005001d0000010003500039000000000501004b000007440000613d000000000500001900000000063500190000000007540019000000000707043300000000007604350000002005500039000000000615004b0000073d0000413d000000000413001900000000000404350000001f01100039000b0020000000920000000b0110017f00000000031300190000000c0400002900000000014300490000004004400039000000000014043500000000160204340000000005630436000000000206004b0000075a0000613d000000000200001900000000035200190000000004210019000000000404043300000000004304350000002002200039000000000362004b000007530000413d000a00000005001d000900000006001d00000000016500190000000000010435000003ac010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f00000001022001900000096a0000613d000000000101043b0000000c040000290000008002400039000000000300041000000000003204350000006002400039000000000012043500000009010000290000001f011000390000000b0110017f0000000a011000290000000002410049000000c0034000390000000000230435000000a00240003900000000000204350000000d0200002900000000020204330000000001210436000000000302004b000007860000613d00000000030000190000000805000029000000005405043400000000014104360000000103300039000000000423004b000007810000413d0000000c040000290000000001410049000003a202000041000003a20310009c0000000001028019000003a20340009c000000000402801900000040024002100000006001100210000000000121019f00000e820001042e0000000d01000029000003b00110009c0000056a0000813d0000000a010000290000ffff0110018f000a00000001001d000027110110008c000005710000813d0000000901000029000003a401100197000900000001001d0000000000100435000003b101000041000000200010043f000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003b2011001c700008010020000390e810e7c0000040f00000001022001900000000803000029000008700000613d000000000101043b000000000101041a000000ff01100190000007d10000c13d00000009010000290000000000100435000003b101000041000000200010043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b0000000001000414000003a20210009c000003a201008041000000c001100210000003ab011001c70000800d0200003900000004030000390000000007000411000003b304000041000000000500001900000009060000290e810e770000040f00000008030000290000000101200190000008700000613d000001600030043f00000004010000390000000c02000029000000000021041b00000003010000390000000d02000029000000000021041b000003b4010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f00000001022001900000096a0000613d000000000201043b0000000d01200029000000000221004b00000000020000190000000102004039000000010220008c000008760000613d0000000502000039000000000012041b0000000b04000029000001800040043f0000000a01000039000000000201041a000003b5022001970000000a022001af000000000021041b000000800100043d000001400000044300000160001004430000002001000039000000a00200043d0000018000100443000001a0002004430000004002000039000000c00300043d000001c000200443000001e0003004430000006002000039000000e00300043d000002000020044300000220003004430000008002000039000001000300043d00000240002004430000026000300443000001200200043d00000006030000290000028000300443000002a000200443000000c002000039000001400300043d000002c000200443000002e000300443000000e002000039000001600300043d00000300002004430000032000300443000001000200003900000340002004430000036000400443000001000010044300000009010000390000012000100443000003b60100004100000e820001042e0000000602000039000000000002041b0000000302000039000000000302041a0000000002130019000000000432004b000000000400001900000001040040390000000104400190000008760000c13d000000000403004b000008720000c13d000003f60100004100000000001004350000001201000039000000040010043f000003f70100004100000e83000104300000000602000039000b00000002001d000000000012041b000000c00100043d000d00010010003e000000000100001900000001010060390000000101100190000008760000c13d000000800100043d000003a40110019700000000001004350000000c01000029000000200010043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f0000000102200190000008700000613d000000000101043b0000000d02000029000000000021041b000003f0010000410000000000100439000000000100041200000004001004430000000a0100002900000024001004430000000001000414000003a20210009c000003a201008041000000c001100210000003f1011001c700008005020000390e810e7c0000040f00000001022001900000096a0000613d000000000101043b000000a00200043d000a00000002001d000000800200043d000d00000002001d000003fa020000410000000000200439000003a401100197000c00000001001d0000000400100443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003fb011001c700008002020000390e810e7c0000040f0000000d03000029000003a40330019700000001022001900000096a0000613d000000000101043b000000000101004b000008810000c13d000000000100001900000e83000104300000000d0110006a00000000133100d9000000000312004b0000087c0000813d000003f60100004100000000001004350000001101000039000000040010043f000003f70100004100000e830001043000000000011200490000000b02000029000000000012041b000000a00100043d000002590000013d000000400200043d00000024012000390000000a040000290000000000410435000003fc010000410000000001120436000a00000001001d000d00000002001d0000000401200039000000000031043500000000010004140000000c02000029000000040220008c000008a20000613d000003a202000041000003a20310009c00000000010280190000000d04000029000003a20340009c00000000020440190000004002200210000000c001100210000000000121019f000003ef011001c70000000c020000290e810e770000040f00000000030100190000006003300270000003a20030019d000003a20330019700020000000103550000000102200190000008c00000613d0000000d01000029000003a80110009c000001c70000213d0000000d05000029000000400050043f0000000b01000029000000000101041a000000800200043d000000a00300043d0000000a0400002900000000001404350000000000350435000003a2010000410000000003000414000003a20430009c0000000003018019000003a20450009c00000000050180190000004001500210000000c003300210000000000113019f000003b2011001c7000003a4052001970000800d020000390000000203000039000003fd04000041000005480000013d000000400100043d0000040802000041000005730000013d000000400200043d0000001f0430018f0000000505300272000008cd0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000008c50000413d000000000604004b000008dc0000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000003a201000041000003a20420009c000000000201801900000040012002100000006002300210000000000121019f00000e8300010430000000400100043d0000040902000041000005730000013d0000000602000039000000000002041b0000000302000039000000000302041a0000000002130019000000000432004b000000000400001900000001040040390000000104400190000008760000c13d000000000403004b000008270000613d0000000c0110006a00000000133100d9000000000312004b000008760000413d00000000011200490000000a02000029000000000012041b000000fe0000013d000000000400001900000000010000190000000505400210000000000553001900000000050504330000000001150019000000000551004b000000000500001900000001050040390000000105500190000008760000c13d0000000104400039000000000524004b000008fc0000413d000000000201004b0000000004000019000700000000001d000600000000001d000001050000613d0000000a02000039000000000202041a0000ffff0320018f00000000421300a900000000541200d9000000000343004b000008760000c13d00072710202001220000000704100029000000070240006c000000000200001900000001020040390000000102200190000600000001001d000001050000613d000008760000013d000980020000003d000c00000000001d0000000c040000290000000502400210000000200220003900000000011200190000000001010433000a03a40010019b000000a00100043d0000000003010433000000000343004b0000096b0000a13d00000000011200190000000001010433000d00000001001d000003fa0100004100000000001004390000000b0100002900000004001004430000000001000414000003a20210009c000003a201008041000000c001100210000003fb011001c700000009020000290e810e7c0000040f00000001022001900000096a0000613d000000000101043b000000000101004b000008700000613d000000400200043d00000024012000390000000d030000290000000000310435000003fc010000410000000000120435000d00000002001d00000004012000390000000a02000029000000000021043500000000010004140000000b02000029000000040220008c0000095e0000613d000003a20210009c000003a20300004100000000010380190000000d04000029000003a20240009c000000000203001900000000020440190000004002200210000000c001100210000000000121019f000003ef011001c70000000b020000290e810e770000040f00000000030100190000006003300270000003a20030019d000003a20330019700020000000103550000000102200190000009710000613d0000000d01000029000003a80110009c000001c70000213d0000000d01000029000000400010043f0000000c03000029000c00010030003d000000800100043d00000000020104330000000c0220006b0000091f0000413d000001340000013d000000000001042f000003f60100004100000000001004350000003201000039000000040010043f000003f70100004100000e8300010430000000400200043d0000001f0430018f00000005053002720000097e0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000009760000413d000000000604004b000008cf0000c13d000008dc0000013d000000400200043d0000001f0430018f00000005053002720000098e0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000009860000413d000000000604004b000008dc0000613d000008cf0000013d0000000003010019000000000132004900000406040000410000005f0510008c000000000500001900000000050420190000040601100197000000000601004b0000000004008019000004060110009c000000000405c019000000000104004b00000a0e0000613d000000400100043d000004100410009c00000a100000813d0000006005100039000000400050043f0000000104000367000000000634034f000000000606043b000003a80760009c00000a0e0000213d00000000063600190000001f076000390000040608000041000000000927004b000000000900001900000000090880190000040607700197000004060a200197000000000ba7004b00000000080080190000000007a7013f000004060770009c000000000809c019000000000708004b00000a0e0000c13d000000000764034f000000000707043b000003a80870009c00000a100000213d00000005087002100000003f0980003900000407099001970000000009590019000003a80a90009c00000a100000213d000000400090043f000000000075043500000020066000390000000007860019000000000827004b00000a0e0000213d000000000876004b000009d20000813d0000008008100039000000000964034f000000000909043b000003a40a90009c00000a0e0000213d00000000089804360000002006600039000000000976004b000009ca0000413d00000000065104360000002005300039000000000754034f000000000707043b000003a80870009c00000a0e0000213d00000000033700190000001f073000390000040608000041000000000927004b000000000900001900000000090880190000040607700197000004060a200197000000000ba7004b00000000080080190000000007a7013f000004060770009c000000000809c019000000000708004b00000a0e0000c13d000000000734034f000000000807043b000003a80780009c00000a100000213d00000005098002100000003f07900039000004070a700197000000400700043d000000000aa70019000000000b7a004b000000000b000019000000010b004039000003a80ca0009c00000a100000213d000000010bb0019000000a100000c13d0000004000a0043f000000000087043500000020033000390000000008930019000000000228004b00000a0e0000213d000000000283004b00000a070000813d0000000002070019000000000934034f000000000909043b000000200220003900000000009204350000002003300039000000000983004b00000a000000413d00000000007604350000002002500039000000000224034f000000000202043b00000040031000390000000000230435000000000001042d000000000100001900000e8300010430000003f60100004100000000001004350000004101000039000000040010043f000003f70100004100000e83000104300000040602000041000000630310008c000000000300001900000000030220190000040601100197000000000401004b0000000002008019000004060110009c000000000203c019000000000102004b00000a340000613d000000400100043d000004100210009c00000a360000813d0000006002100039000000400020043f00000001020003670000000403200370000000000303043b000003a40430009c00000a340000213d00000000033104360000002404200370000000000404043b00000000004304350000004402200370000000000202043b00000040031000390000000000230435000000000001042d000000000100001900000e8300010430000003f60100004100000000001004350000004101000039000000040010043f000003f70100004100000e830001043000000000430104340000000001320436000000000203004b00000a480000613d000000000200001900000000052100190000000006240019000000000606043300000000006504350000002002200039000000000532004b00000a410000413d000000000231001900000000000204350000001f02300039000000200300008a000000000232016f0000000001210019000000000001042d000600000000000200000020021000390000000002020433000000000301043300000040011000390000000004010433000000400100043d0000008005100039000000000045043500000060041000390000000000240435000003a402300197000000400310003900000000002304350000002002100039000003eb0300004100000000003204350000008003000039000300000003001d0000000000310435000004110310009c00000b390000813d000000a003100039000000400030043f000003a204000041000003a20320009c000000000204801900000040022002100000000001010433000003a20310009c00000000010480190000006001100210000000000121019f0000000002000414000003a20320009c0000000002048019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000b370000613d000000000101043b000400000001001d000003f00100004100000000001004390000000001000412000500000001001d0000000400100443000000400100003900000024001004430000000001000414000003a20210009c000003a201008041000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000b360000613d000000000101043b000003a4011001970000000002000410000200000002001d000000000112004b00000ac20000c13d000003f00100004100000000001004390000000501000029000000040010044300000020010000390000002400100443000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000b360000613d000000000101043b000600000001001d000003ac0100004100000000001004390000000001000414000003a20210009c000003a201008041000000c001100210000003ad011001c70000800b020000390e810e7c0000040f000000010220019000000b360000613d000000000101043b000000060110006c00000ac20000c13d000003f0010000410000000000100439000000050100002900000004001004430000002400000443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000b1d0000c13d00000b360000013d000000400100043d000600000001001d0000002002100039000003ae01000041000100000002001d0000000000120435000003f00100004100000000001004390000000501000029000000040010044300000060010000390000002400100443000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000b360000613d000000000101043b000000060200002900000040022000390000000000120435000003f001000041000000000010043900000005010000290000000400100443000000030100002900000024001004430000000001000414000003a20210009c000003a201008041000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000b360000613d000000000101043b000000060200002900000060022000390000000000120435000003ac010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f000000010220019000000b360000613d000000000101043b0000000604000029000000a0024000390000000203000029000000000032043500000080024000390000000000120435000000a0010000390000000000140435000003af0140009c00000b390000213d0000000603000029000000c001300039000000400010043f000003a2010000410000000104000029000003a20240009c000000000401801900000040024002100000000003030433000003a20430009c00000000030180190000006003300210000000000223019f0000000003000414000003a20430009c0000000003018019000000c001300210000000000121019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000b370000613d0000000404000029000000000101043b000000400200043d000000220320003900000000004304350000041203000041000000000032043500000002032000390000000000130435000003a2010000410000000003000414000003a20430009c0000000003018019000003a20420009c00000000020180190000004001200210000000c002300210000000000121019f00000413011001c700008010020000390e810e7c0000040f000000010220019000000b370000613d000000000101043b000000000001042d000000000001042f000000000100001900000e8300010430000003f60100004100000000001004350000004101000039000000040010043f000003f70100004100000e83000104300006000000000002000000400800043d0000002002800039000400000001001d0000000013010434000600000001001d0000000004030433000000000504004b000000000502001900000b520000613d0000000006000019000000000502001900000020033000390000000007030433000003a40770019700000000057504360000000106600039000000000746004b00000b4b0000413d0000000003850049000000200430008a00000000004804350000001f033000390005002000000092000000050430017f0000000003840019000000000443004b00000000040000190000000104004039000003a80530009c00000c8f0000213d000000010440019000000c8f0000c13d000000400030043f000003a203000041000003a20420009c000000000203801900000040022002100000000001080433000003a20410009c00000000010380190000006001100210000000000121019f0000000002000414000003a20420009c0000000002038019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000c8c0000613d000000400200043d0000002003200039000000000101043b000300000001001d000000060100002900000000010104330000000004010433000000000504004b000000000503001900000b860000613d000000000600001900000000050300190000002001100039000000000701043300000000057504360000000106600039000000000746004b00000b800000413d0000000001250049000000200410008a00000000004204350000001f01100039000000050410017f0000000001240019000000000441004b00000000040000190000000104004039000003a80510009c00000c8f0000213d000000010440019000000c8f0000c13d000000400010043f000003a201000041000003a20430009c000000000301801900000040033002100000000002020433000003a20420009c00000000020180190000006002200210000000000232019f0000000003000414000003a20430009c0000000003018019000000c001300210000000000121019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000c8c0000613d000000000201043b000000040100002900000040011000390000000003010433000000400100043d00000080041000390000000000340435000000600310003900000000002304350000004002100039000000030300002900000000003204350000002002100039000004030300004100000000003204350000008003000039000300000003001d0000000000310435000004140310009c00000c8f0000213d000000a003100039000000400030043f000003a204000041000003a20320009c000000000204801900000040022002100000000001010433000003a20310009c00000000010480190000006001100210000000000121019f0000000002000414000003a20320009c0000000002048019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000c8c0000613d000000000101043b000400000001001d000003f00100004100000000001004390000000001000412000500000001001d0000000400100443000000400100003900000024001004430000000001000414000003a20210009c000003a201008041000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000c8e0000613d000000000101043b000003a4011001970000000002000410000200000002001d000000000112004b00000c180000c13d000003f00100004100000000001004390000000501000029000000040010044300000020010000390000002400100443000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000c8e0000613d000000000101043b000600000001001d000003ac0100004100000000001004390000000001000414000003a20210009c000003a201008041000000c001100210000003ad011001c70000800b020000390e810e7c0000040f000000010220019000000c8e0000613d000000000101043b000000060110006c00000c180000c13d000003f0010000410000000000100439000000050100002900000004001004430000002400000443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000c8e0000613d00000c730000013d000000400100043d000600000001001d0000002002100039000003ae01000041000100000002001d0000000000120435000003f00100004100000000001004390000000501000029000000040010044300000060010000390000002400100443000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000c8e0000613d000000000101043b000000060200002900000040022000390000000000120435000003f001000041000000000010043900000005010000290000000400100443000000030100002900000024001004430000000001000414000003a20210009c000003a201008041000000c001100210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000c8e0000613d000000000101043b000000060200002900000060022000390000000000120435000003ac010000410000000000100439000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ad011001c70000800b020000390e810e7c0000040f000000010220019000000c8e0000613d000000000101043b0000000604000029000000a0024000390000000203000029000000000032043500000080024000390000000000120435000000a0010000390000000000140435000003af0140009c00000c8f0000213d0000000603000029000000c001300039000000400010043f000003a2010000410000000104000029000003a20240009c000000000401801900000040024002100000000003030433000003a20430009c00000000030180190000006003300210000000000223019f0000000003000414000003a20430009c0000000003018019000000c001300210000000000121019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000c8c0000613d000000000101043b000000400200043d0000002203200039000000040400002900000000004304350000041203000041000000000032043500000002032000390000000000130435000003a2010000410000000003000414000003a20430009c0000000003018019000003a20420009c00000000020180190000004001200210000000c002300210000000000121019f00000413011001c700008010020000390e810e7c0000040f000000010220019000000c8c0000613d000000000101043b000000000001042d000000000100001900000e8300010430000000000001042f000003f60100004100000000001004350000004101000039000000040010043f000003f70100004100000e83000104300004000000000002000400000002001d000300000001001d000003f00100004100000000001004390000000001000412000000040010044300000100010000390000002400100443000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003f1011001c700008005020000390e810e7c0000040f000000010220019000000d960000613d000000000201043b00000004040000290000000091040434000000410110008c00000cf90000c13d00000040014000390000000001010433000004150310009c00000cf90000213d000200000002001d00000060024000390000000002020433000100000009001d0000000003090433000000400400043d0000006005400039000000000015043500000040014000390000000000310435000000f80120027000000020024000390000000000120435000000030100002900000000001404350000000000000435000003a2010000410000000002000414000003a20320009c0000000002018019000003a20340009c00000000040180190000004001400210000000c002200210000000000112019f00000416011001c700000001020000390e810e7c0000040f00000000030100190000006003300270000003a203300197000000200430008c000000000403001900000020040080390000001f0540018f000000050440027200000cde0000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000746004b00000cd70000413d000000000605004b00000cec0000613d00000003055002100000000504400210000000000604043300000000065601cf000000000656022f000000000741034f000000000707043b0000010005500089000000000757022f00000000055701cf000000000565019f0000000000540435000000000003001f000200000001035500000001022001900000000202000029000000010900002900000d990000613d0000000001000433000003a403100198000000040400002900000cf90000613d000000000121013f000003a40110019800000d860000613d000000400800043d0000004401800039000000400300003900000000003104350000002001800039000004170300004100000000003104350000002403800039000000030500002900000000005304350000000004040433000000640380003900000000004304350000008403800039000000000504004b00000d110000613d000000000500001900000000063500190000000007590019000000000707043300000000007604350000002005500039000000000645004b00000d0a0000413d000000000543001900000000000504350000001f04400039000000200700008a000000000474016f00000000048400490000000003340019000000200430008a00000000004804350000001f03300039000000000473016f0000000003840019000000000443004b00000000040000190000000104004039000003a80530009c00000d900000213d000000010440019000000d900000c13d000000400030043f00000000030804330000000006000414000000040420008c00000d5b0000c13d00000001020000390000000004000031000000000104004b00000d710000613d000003a80140009c00000d900000213d0000001f01400039000000000171016f0000003f01100039000000000171016f000000400300043d0000000001130019000000000531004b00000000050000190000000105004039000003a80610009c00000d900000213d000000010550019000000d900000c13d000000400010043f0000001f0540018f00000000014304360000000206000367000000050440027200000d4b0000613d000000000700001900000005087002100000000009810019000000000886034f000000000808043b00000000008904350000000107700039000000000847004b00000d430000413d000000000705004b00000d730000613d0000000504400210000000000646034f00000000044100190000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f000000000054043500000d730000013d000003a204000041000003a20510009c00000000010480190000004001100210000003a20530009c00000000030480190000006003300210000000000113019f000003a20360009c0000000006048019000000c003600210000000000131019f000400000007001d0e810e7c0000040f0000000407000029000000010220018f00020000000103550000006001100270000003a20010019d000003a204100197000000000104004b00000d2d0000c13d00000060030000390000008001000039000000000202004b00000d870000613d0000000002030433000000200320008c00000d870000413d00000406030000410000001f0420008c000000000400001900000000040320190000040602200197000000000502004b0000000003008019000004060220009c000000000304c019000000000203004b00000d970000613d0000000001010433000004170110009c00000d870000c13d000000000001042d000000400100043d00000418020000410000000000210435000003a202000041000003a20310009c00000000010280190000004001100210000003b8011001c700000e8300010430000003f60100004100000000001004350000004101000039000000040010043f000003f70100004100000e8300010430000000000001042f000000000100001900000e8300010430000000400200043d0000001f0430018f000000050530027200000da60000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b00000d9e0000413d000000000604004b00000db50000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000003a201000041000003a20420009c000000000201801900000040012002100000006002300210000000000121019f00000e83000104300002000000000002000200000001001d0000000000100435000000200000043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f000000010220019000000ddd0000613d000000000101043b0000000002000411000100000002001d0000000000200435000000200010043f0000000001000414000003a20210009c000003a201008041000000c001100210000003b2011001c700008010020000390e810e7c0000040f000000010220019000000ddd0000613d000000000101043b000000000101041a000000ff0110019000000ddf0000613d000000000001042d000000000100001900000e8300010430000000400100043d000000240210003900000002030000290000000000320435000003ee020000410000000000210435000000040210003900000001030000290000000000320435000003a202000041000003a20310009c00000000010280190000004001100210000003ef011001c700000e83000104300002000000000002000100000002001d000200000001001d0000000000100435000000200000043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f000000010220019000000e3f0000613d000000000101043b0000000102000029000003a402200197000100000002001d0000000000200435000000200010043f0000000001000414000003a20210009c000003a201008041000000c001100210000003b2011001c700008010020000390e810e7c0000040f000000010220019000000e3f0000613d000000000101043b000000000101041a000000ff0110019000000e3e0000613d00000002010000290000000000100435000000200000043f000003a2030000410000000001000414000003a20210009c0000000001038019000000c001100210000003b2011001c700008010020000390e810e7c0000040f000000010220019000000e3f0000613d000000000101043b00000001020000290000000000200435000000200010043f0000000001000414000003a20210009c000003a201008041000000c001100210000003b2011001c700008010020000390e810e7c0000040f000000010220019000000e3f0000613d000000000101043b000000000201041a000001000300008a000000000232016f000000000021041b000003a2010000410000000002000414000003a20320009c0000000002018019000000c001200210000003ab011001c70000800d02000039000000040300003900000000070004110000041904000041000000020500002900000001060000290e810e770000040f000000010120019000000e3f0000613d000000000001042d000000000100001900000e8300010430000000000001042f000003a203000041000003a20410009c00000000010380190000004001100210000003a20420009c00000000020380190000006002200210000000000112019f0000000002000414000003a20420009c0000000002038019000000c002200210000000000112019f000003ab011001c700008010020000390e810e7c0000040f000000010220019000000e560000613d000000000101043b000000000001042d000000000100001900000e830001043000000000050100190000000000200439000000050130008c00000e660000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000631004b00000e5e0000413d000003a2010000410000000002000414000003a20420009c0000000002018019000003a20430009c00000000030180190000006001300210000000c002200210000000000112019f0000041a011001c700000000020500190e810e7c0000040f000000010220019000000e760000613d000000000101043b000000000001042d000000000001042f00000e7a002104210000000102000039000000000001042d0000000002000019000000000001042d00000e7f002104230000000102000039000000000001042d0000000002000019000000000001042d00000e810000043200000e820001042e00000e8300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffbf726577617264732e646570696e2e6e6f646c65000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff0200000000000000000000000000000000000020000000000000000000000000405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace02000000000000000000000000000000000000000000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b02000002000000000000000000000000000000040000000000000000000000008b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f000000000000000000000000000000000000000000000000ffffffffffffff3f0000000000000000000000000000000000000000000000000000000000278d01ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb502000000000000000000000000000000000000400000000000000000000000002f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000200000000000000000000000000000280000001000000000000000000586e5acb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000054bede8c00000000000000000000000000000000000000000000000000000000c810b7fd00000000000000000000000000000000000000000000000000000000e3faad9300000000000000000000000000000000000000000000000000000000ef78d4fc00000000000000000000000000000000000000000000000000000000ef78d4fd00000000000000000000000000000000000000000000000000000000f034ace700000000000000000000000000000000000000000000000000000000e3faad9400000000000000000000000000000000000000000000000000000000e834a83400000000000000000000000000000000000000000000000000000000d547741e00000000000000000000000000000000000000000000000000000000d547741f00000000000000000000000000000000000000000000000000000000d5f836f000000000000000000000000000000000000000000000000000000000c810b7fe00000000000000000000000000000000000000000000000000000000cebe09c90000000000000000000000000000000000000000000000000000000091d1485300000000000000000000000000000000000000000000000000000000a257db8d00000000000000000000000000000000000000000000000000000000a257db8e00000000000000000000000000000000000000000000000000000000a41572960000000000000000000000000000000000000000000000000000000091d1485400000000000000000000000000000000000000000000000000000000a217fddf00000000000000000000000000000000000000000000000000000000720a524200000000000000000000000000000000000000000000000000000000720a52430000000000000000000000000000000000000000000000000000000084b0196e0000000000000000000000000000000000000000000000000000000054bede8d000000000000000000000000000000000000000000000000000000005889320100000000000000000000000000000000000000000000000000000000265de169000000000000000000000000000000000000000000000000000000003a32f4f60000000000000000000000000000000000000000000000000000000049d024b80000000000000000000000000000000000000000000000000000000049d024b9000000000000000000000000000000000000000000000000000000004fc608a3000000000000000000000000000000000000000000000000000000003a32f4f7000000000000000000000000000000000000000000000000000000004495e6eb00000000000000000000000000000000000000000000000000000000303ab98d00000000000000000000000000000000000000000000000000000000303ab98e0000000000000000000000000000000000000000000000000000000036568abe00000000000000000000000000000000000000000000000000000000265de16a000000000000000000000000000000000000000000000000000000002f2ff15d00000000000000000000000000000000000000000000000000000000126082ce000000000000000000000000000000000000000000000000000000001a762a61000000000000000000000000000000000000000000000000000000001a762a6200000000000000000000000000000000000000000000000000000000248a9ca300000000000000000000000000000000000000000000000000000000126082cf0000000000000000000000000000000000000000000000000000000012ade88c000000000000000000000000000000000000000000000000000000000f3a9f64000000000000000000000000000000000000000000000000000000000f3a9f6500000000000000000000000000000000000000000000000000000000113d1bea0000000000000000000000000000000000000000000000000000000001ffc9a7000000000000000000000000000000000000000000000000000000000cd91814000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000c000000000000000009afe599134cb380257be882707d0696f9b54795d12e804273ab01ba8d0f3e80e0000000000000000000000000000000000000000000000000000000000278d00f2cec1c0909645d369dca406099b68cf94d77019c00e158af16ca7dbd4c0cf62e2517d3f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e0200000200000000000000000000000000000044000000000000000000000000b3512b0c00000000000000000000000000000000000000000000000000000000b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6000000000000000000000000000000000000000000000000ffffffffffffffdf0f000000000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff1fb2a72022000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000040c10f190000000000000000000000000000000000000000000000000000000025b428dfde728ccfaddad7e29e4ac23c24ed7fd1a6e3e3f91894a9a073f5dfff6b90055ec545c74b3288ac907d260854dadaa2b4d2376c123751cfefe7a6da750bee642b000000000000000000000000000000000000000000000000000000006697b232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000800000000000000000000000000000000000000000000000000000004000000080000000000000000016b4f5bedc4d177db8c57c60922cd42f91c253b363ff8392d7e7ac07a4e1a0516649c90b5089688430ab3e855e2eedb017ca17f6eb1aed93805dcf4996a4da7dc9d8d00e0000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03863f35a00000000000000000000000000000000000000000000000000000000c3028de4000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000c8c4e324209ac638aad1be111ddf398e19faa6d7499c7735366bf22126d594a704e221010000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff01ffc9a7000000000000000000000000000000000000000000000000000000007965db0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa0000000000000000000000000000000000000000000000000ffffffffffffff6019010000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff5f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a000000000000000000000000000000000000000800000000000000000000000001626ba7e00000000000000000000000000000000000000000000000000000000db8d1fb700000000000000000000000000000000000000000000000000000000f6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b0200000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052246b273f0f45325543bbeaabe79f510c3e8c077f56227970c55be1a00929ce
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bd4372e44c5ee654dd838304006e1f0f699831540000000000000000000000000000000000000000000167fd2f45f5fa5e8000000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000eca65b589d70659415f43f91af9909f577dc7aec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e097ac1bcf81e7ff2657045f72caa6cf06486c9
-----Decoded View---------------
Arg [0] : token (address): 0xBD4372e44c5eE654dd838304006E1f0f69983154
Arg [1] : initialQuota (uint256): 1700000000000000000000000
Arg [2] : initialPeriod (uint256): 86400
Arg [3] : oracleAddress (address): 0xeCa65b589d70659415F43f91af9909f577Dc7aEC
Arg [4] : rewardBasisPoints (uint16): 0
Arg [5] : admin (address): 0x5e097AC1BCF81E7Ff2657045F72cAa6cF06486C9
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000bd4372e44c5ee654dd838304006e1f0f69983154
Arg [1] : 0000000000000000000000000000000000000000000167fd2f45f5fa5e800000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [3] : 000000000000000000000000eca65b589d70659415f43f91af9909f577dc7aec
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000005e097ac1bcf81e7ff2657045f72caa6cf06486c9
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ZKSYNC | 100.00% | $0.003921 | 260.226 | $1.02 |
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.