Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/AnonyaERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import { Time as T } from "@openzeppelin/contracts/utils/types/Time.sol";
import { Math as M } from "@openzeppelin/contracts/utils/math/Math.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import { Nonces } from "@openzeppelin/contracts/utils/Nonces.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ShortString,
ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
import { TransientSlot } from "@openzeppelin/contracts/utils/TransientSlot.sol";
import { SlotDerivation } from "@openzeppelin/contracts/utils/SlotDerivation.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import { IERC20Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC7674 } from "@openzeppelin/contracts/interfaces/draft-IERC7674.sol";
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import { IERC3156FlashLender } from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";
/**
* @title ERC-20 token with extensions (EIP-2612, ERC-3156, ERC-7674).
* @notice Extended ERC-20 implementation supporting flash loans, transient approvals, and off-chain signatures.
* @author @anonyanzk
* @custom:social X(Twitter) https://x.com/anonyanzk
* @custom:social Telegram https://t.me/anonyantg
* @dev Decentralized token with capped total supply and burn mechanisms.
*/
contract AnonyaERC20 is
IERC20,
IERC20Metadata,
IERC20Errors,
IERC7674,
IERC20Permit,
IERC3156FlashLender,
EIP712,
Nonces,
Context
{
using ShortStrings for *;
using SlotDerivation for bytes32;
using TransientSlot for bytes32;
using TransientSlot for TransientSlot.Uint256Slot;
/* ───────────────────────────── Errors ──────────────────────────────── */
/**
* @dev Reverts when minting would push the total supply above the cap.
* @param newSupply The total supply that would result after minting.
* @param cap The maximum allowed supply.
*/
error ERC20MintCapExceeded(uint256 newSupply, uint256 cap);
/**
* @dev Reverts when the recovered signer does not match the expected owner.
* @param signer The recovered address from the signature.
* @param owner The expected token owner.
*/
error ERC2612InvalidSigner(address signer, address owner);
/**
* @dev Reverts when the permit signature has expired.
* @param deadline The timestamp after which the signature is invalid.
*/
error ERC2612ExpiredSignature(uint256 deadline);
/**
* @dev Reverts when the loan amount is zero.
* @param amount The invalid loan amount.
*/
error ERC3156ZeroAmount(uint256 amount);
/**
* @dev Reverts when the loan amount exceeds the maximum loanable amount.
* @param maxLoan The maximum loanable amount.
*/
error ERC3156ExceededMaxLoan(uint256 maxLoan);
/**
* @dev Reverts when the given token is not supported for flash loans.
* @param token The unsupported token address.
*/
error ERC3156UnsupportedToken(address token);
/**
* @dev Reverts when the flash loan receiver callback returns an unexpected value.
* @param receiver The receiver contract address.
*/
error ERC3156InvalidReceiver(address receiver);
/**
* @dev Reverts when the token name constructor parameter is empty.
*/
error EmptyInitialName();
/**
* @dev Reverts when the token symbol constructor parameter is empty.
*/
error EmptyInitialSymbol();
/**
* @dev Reverts when the initial supply constructor parameter is zero.
*/
error ZeroInitialSupply();
/**
* @dev Reverts when the fee receiver constructor parameter is the zero address.
*/
error InvalidFeeReceiver();
/**
* @dev Reverts when the provided cap is not greater than the initial supply,
* preventing flash-minting.
* @param initialSupply The initial minted amount.
* @param cap The provided cap value.
*/
error InvalidInitialCap(uint256 initialSupply, uint256 cap);
/**
* @dev Reverts on reentrant call.
*/
error ReentrantCall();
/**
* @dev Reverts when receiving ETH via receive.
* @param sender The caller that sent ETH.
* @param value The amount of ETH sent.
*/
error ReceiveDisable(address sender, uint256 value);
/**
* @dev Reverts when invoked via fallback.
* @param sender The caller that triggered the fallback.
* @param value The amount of ETH sent with the call.
* @param data The calldata passed to the fallback.
*/
error FallbackDisable(address sender, uint256 value, bytes data);
// ───────────────────────────── Events ────────────────────────────────
/**
* @dev Emitted when temporaryApproveAndCall is executed.
* @param owner The account granting the transient allowance.
* @param spender The contract invoked with that allowance.
* @param selector The first four bytes of calldata, the function selector.
* @param value The transient allowance granted for the call.
*/
event CalledWithTemporaryApprove(
address indexed owner,
address indexed spender,
bytes4 indexed selector,
uint256 value
);
/**
* @dev Emitted when a transient allowance is granted.
* @param owner The account granting the transient allowance.
* @param spender The spender receiving the transient allowance.
* @param value The transient allowance amount.
*/
event TemporaryApproval(
address indexed owner,
address indexed spender,
uint256 value
);
/**
* @dev Emitted when a flash loan fee is paid.
* @param payer The borrower that repaid the loan and fee.
* @param receiver The address receiving the fee.
* @param value The fee amount paid.
*/
event FlashFeePaid(
address indexed payer,
address indexed receiver,
uint256 value
);
/* ───────────────────────────── Constants ───────────────────────────── */
/**
* @dev Storage seed used for deriving transient allowance slots.
*/
bytes32 private constant ERC20_TEMPORARY_APPROVAL_STORAGE = 0xea2d0e77a01400d0111492b1321103eed560d8fe44b9a7c2410407714583c400;
/**
* @dev EIP-2612 permit typehash used to build the EIP-712 struct hash.
*/
bytes32 private constant _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/**
* @dev Expected return value from IERC3156FlashBorrower.onFlashLoan.
* Used to validate the receiver callback in flash loans.
*/
bytes32 private constant _FLASH_ON_LOAN_RETVAL = keccak256("ERC3156FlashBorrower.onFlashLoan");
/**
* @dev ERC-20 decimals.
*/
uint8 private constant _decimals = 18;
/**
* @dev Flash loan fee rate in parts-per-million.
*/
uint256 private constant _FLASH_FEE_PPM = 1337;
/* ───────────────────────────── Immutables ──────────────────────────── */
/**
* @dev Token name stored as ShortString immutable.
*/
ShortString private immutable _name;
/**
* @dev Token symbol stored as ShortString immutable.
*/
ShortString private immutable _symbol;
/**
* @dev Immutable address that receives flash loan fees.
*/
address private immutable _feeReceiver;
/**
* @dev Immutable cap on the total token supply.
*/
uint256 private immutable _cap;
/* ────────────────────────────── Storage ────────────────────────────── */
/**
* @dev Storage fallback for the token name.
*/
string private _nameFallback;
/**
* @dev Storage fallback for the token symbol.
*/
string private _symbolFallback;
/**
* @dev Current total token supply.
*/
uint256 private _totalSupply;
/* ───────────────────────────── Transient ───────────────────────────── */
/**
* @dev Transient reentrancy guard flag.
*/
uint256 private transient _flag;
/* ───────────────────────────── Mappings ────────────────────────────── */
/**
* @dev Mapping of account balances.
*/
mapping(address account => uint256 balance)
private _balances;
/**
* @dev Mapping of allowances per owner and spender.
*/
mapping(address owner => mapping(address spender => uint256 allowance))
private _allowances;
/* ───────────────────────────── Modifiers ───────────────────────────── */
/**
* @dev Transient reentrancy guard modifier.
*/
modifier nonReentrant() {
_nonReentrantEnter();
_;
_nonReentrantExit ();
}
/**
* @dev Enter transient reentrancy flag.
*/
function _nonReentrantEnter() private {
require(_flag == 0, ReentrantCall());
_flag = 1;
}
/**
* @dev Exit transient reentrancy flag.
*/
function _nonReentrantExit() private {
_flag = 0;
}
/* ───────────────────────────── ERC-20 implementation ─────────────────────── */
/**
* @dev Initializes the ERC-20 token.
* @param name_ Token name (ERC-20 metadata).
* @param symbol_ Token symbol (ERC-20 metadata).
* @param initialSupply Tokens minted to the deployer.
* @param cap_ Maximum allowed total supply.
* @param feeReceiver_ Recipient of flash loan fees.
*/
constructor(
string memory name_,
string memory symbol_,
uint256 initialSupply,
uint256 cap_,
address feeReceiver_
) EIP712(name_, "1") {
require(bytes(name_) .length != 0, EmptyInitialName());
require(bytes(symbol_).length != 0, EmptyInitialSymbol());
require(initialSupply != 0, ZeroInitialSupply());
require(
feeReceiver_ != address(0) &&
feeReceiver_ != address(this),
InvalidFeeReceiver()
);
require(
cap_ > initialSupply,
InvalidInitialCap({
initialSupply: initialSupply,
cap: cap_
})
);
_name = name_ .toShortStringWithFallback(_nameFallback);
_symbol = symbol_.toShortStringWithFallback(_symbolFallback);
_cap = cap_;
_feeReceiver = feeReceiver_;
_mint(_msgSender(), initialSupply);
}
/* ───────────────────────────── ERC-20 external ─────────────────────── */
/**
* @inheritdoc IERC20
*/
function transfer(address to, uint256 amount)
external
override(IERC20)
returns (bool)
{
address from = _msgSender();
require(
to != address(0),
ERC20InvalidReceiver({ receiver: to })
);
if (amount == 0) {
emit Transfer({
from: from,
to: to,
value: 0
});
return true;
}
if (to == from) {
uint256 fromBal = _balances[from];
require(
fromBal >= amount,
ERC20InsufficientBalance({
sender: from,
balance: fromBal,
needed: amount
})
);
emit Transfer({
from: from,
to: to,
value: amount
});
return true;
}
_update(from, to, amount);
return true;
}
/**
* @inheritdoc IERC20
* @dev Implements IERC7674 semantics using EIP-1153 transient storage.
*/
function transferFrom(address from, address to, uint256 amount)
external
override(IERC20)
returns (bool)
{
address spender = _msgSender();
require(
from != address(0),
ERC20InvalidSender({ sender: from })
);
require(
to != address(0),
ERC20InvalidReceiver({ receiver: to })
);
if (amount == 0) {
emit Transfer({
from: from,
to: to,
value: 0
});
return true;
}
if (spender != from) {
_spendWithTemporary(from, spender, amount);
}
_update(from, to, amount);
return true;
}
/**
* @inheritdoc IERC20
*/
function approve(address spender, uint256 value)
external
override(IERC20)
returns (bool)
{
_setAllowance(_msgSender(), spender, value);
return true;
}
/*
* @inheritdoc IERC7674
* @dev Executes a low-level call to `spender` with `data`.
*/
function temporaryApproveAndCall(
address spender,
uint256 value,
bytes calldata data
)
external
nonReentrant
returns (bytes memory ret)
{
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
address owner = _msgSender();
_temporaryApprove(owner, spender, value);
ret = Address.functionCall(spender, data);
bytes4 selector = data.length >= 4 ? bytes4(data) : bytes4(0);
emit CalledWithTemporaryApprove({
owner: owner,
spender: spender,
value: value,
selector: selector
});
return ret;
}
/**
* @inheritdoc IERC7674
*/
function temporaryApprove(address spender, uint256 value)
external
override(IERC7674)
returns (bool)
{
_temporaryApprove(_msgSender(), spender, value);
return true;
}
/**
* @inheritdoc IERC20Permit
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v, bytes32 r, bytes32 s
)
external
override(IERC20Permit)
{
require(
T.timestamp() <= deadline,
ERC2612ExpiredSignature({ deadline: deadline })
);
bytes32 structHash = keccak256(
abi.encode(
_PERMIT_TYPEHASH,
owner,
spender,
value,
_useNonce(owner),
deadline
)
);
bytes32 digest = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(digest, v, r, s);
require(
signer == owner,
ERC2612InvalidSigner({
signer: signer,
owner: owner
})
);
_setAllowance(owner, spender, value);
}
/**
* @inheritdoc IERC3156FlashLender
* @dev Before returning from onFlashLoan the borrower must approve
* or temporaryApprove value plus fee to this contract.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 value,
bytes calldata data
)
external
override(IERC3156FlashLender)
nonReentrant
returns (bool)
{
address self = address(this);
require(
token == self,
ERC3156UnsupportedToken({ token: token })
);
require(
value != 0,
ERC3156ZeroAmount({ amount: value })
);
uint256 maxLoan; unchecked {
maxLoan = _cap - _totalSupply;
}
require(
value <= maxLoan,
ERC3156ExceededMaxLoan({ maxLoan: maxLoan })
);
uint256 fee = _flashFee(token, value);
_mint(address(receiver), value);
require(
receiver.onFlashLoan(
_msgSender(),
token,
value,
fee,
data
) == _FLASH_ON_LOAN_RETVAL,
ERC3156InvalidReceiver({ receiver: address(receiver) })
);
address feeTo = _feeReceiver;
uint256 repay = value + fee;
_spendWithTemporary(address(receiver), self, repay);
_update (address(receiver), self, repay);
_burn (self, value);
_update(self, feeTo, fee);
emit FlashFeePaid({
payer: address(receiver),
receiver: feeTo,
value: fee
});
return true;
}
/**
* @notice Burns `amount` of tokens from the caller.
* @param amount The number of tokens to burn.
*/
function burn(uint256 amount)
external
returns (bool)
{
address from = _msgSender();
if (amount == 0) {
emit Transfer({
from: from,
to: address(0),
value: 0
});
return true;
}
_burn(from, amount);
return true;
}
/**
* @notice Burns `amount` tokens from `from` using the caller’s allowance.
* @param from The account from which tokens are deducted.
* @param amount The number of tokens to burn.
*/
function burnFrom(address from, uint256 amount)
external
returns (bool)
{
address spender = _msgSender();
require(
from != address(0),
ERC20InvalidSender({ sender: from })
);
if (amount == 0) {
emit Transfer({
from: from,
to: address(0),
value: 0
});
return true;
}
if (spender != from) {
_spendWithTemporary(from, spender, amount);
}
_burn(from, amount);
return true;
}
/**
* @notice Increases the allowance of `spender` granted by the caller by `added`.
* @param spender The address whose allowance is increased.
* @param added The amount by which the allowance is increased.
*/
function increaseAllowance(address spender, uint256 added)
external
returns (bool)
{
address owner = _msgSender();
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
mapping(address => uint256) storage a = _allowances[owner];
uint256 current = a[spender];
if (added == 0) {
emit Approval({
owner: owner,
spender: spender,
value: current
});
return true;
}
unchecked {
uint256 updated = M.saturatingAdd(current, added);
a[spender] = updated;
emit Approval({
owner: owner,
spender: spender,
value: updated
});
}
return true;
}
/**
* @notice Decreases the allowance of `spender` granted by the caller by `subtracted`.
* @param spender The address whose allowance is decreased.
* @param subtracted The amount by which the allowance is decreased.
*/
function decreaseAllowance(address spender, uint256 subtracted)
external
returns (bool)
{
address owner = _msgSender();
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
mapping(address => uint256) storage a = _allowances[owner];
uint256 current = a[spender];
if (subtracted == 0) {
emit Approval({
owner: owner,
spender: spender,
value: current
});
return true;
}
require(
current >= subtracted,
ERC20InsufficientAllowance({
spender: spender,
allowance: current,
needed: subtracted
})
);
unchecked {
uint256 updated = current - subtracted;
a[spender] = updated;
emit Approval({
owner: owner,
spender: spender,
value: updated
});
}
return true;
}
/* ───────────────────────────── ERC-20 internal ─────────────────────── */
/**
* @dev Creates `amount` tokens and assigns them to `to`, increasing the total supply.
*
* Requirements:
* - `to` must not be the zero address.
* - Total supply after minting must not exceed {_cap}.
*
* Emits:
* - {Transfer}
*/
function _mint(address to, uint256 amount)
private
{
require(
to != address(0),
ERC20InvalidReceiver({ receiver: to })
);
uint256 newSupply = _totalSupply + amount;
require(
newSupply <= _cap,
ERC20MintCapExceeded({
newSupply: newSupply,
cap: _cap
})
);
_totalSupply = newSupply;
unchecked {
_balances[to] += amount;
}
emit Transfer({
from: address(0),
to: to,
value: amount
});
}
/**
* @dev Destroys `amount` tokens from `from`, decreasing the total supply.
*
* Requirements:
* - `from` must have at least `amount` tokens.
*
* Emits:
* - {Transfer}
*/
function _burn(address from, uint256 amount)
private
{
uint256 fromBal = _balances[from];
require(
fromBal >= amount,
ERC20InsufficientBalance({
sender: from,
balance: fromBal,
needed: amount
})
);
unchecked {
_balances[from] = fromBal - amount;
_totalSupply -= amount;
}
emit Transfer({
from: from,
to: address(0),
value: amount
});
}
/**
* @dev Updates balances to transfer `amount` from `from` to `to`.
*
* Requirements:
* - `from` must have at least `amount` balance.
*
* Emits:
* - {Transfer}
*/
function _update(address from, address to, uint256 amount)
private
{
uint256 fromBal = _balances[from];
require(
fromBal >= amount,
ERC20InsufficientBalance({
sender: from,
balance: fromBal,
needed: amount
}));
unchecked {
_balances[from] = fromBal - amount;
_balances[to] += amount;
}
emit Transfer({
from: from,
to: to,
value: amount
});
}
/**
* @dev Sets allowance of `spender` over `owner`'s tokens to `value`.
*
* Requirements:
* - `owner` and `spender` must not be the zero address.
*
* Emits:
* - {Approval}
*/
function _setAllowance(address owner, address spender, uint256 value)
private
{
require(
owner != address(0),
ERC20InvalidApprover({ approver: owner })
);
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
uint256 prev = _allowances[owner][spender];
if (prev != value) {
_allowances[owner][spender] = value;
}
emit Approval({
owner: owner,
spender: spender,
value: value
});
}
/**
* @dev Sets transient allowance of `spender` over `owner`'s tokens to `value`.
*
* Requirements:
* - `owner` and `spender` must not be the zero address.
*
* Emits:
* - {TemporaryApproval}
*/
function _temporaryApprove(address owner, address spender, uint256 value)
private
{
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
_temporaryAllowanceSlot(owner, spender).tstore(value);
emit TemporaryApproval({
owner: owner,
spender: spender,
value: value
});
}
/**
* @dev Deducts allowance for `spender` on behalf of `owner`.
*
* Resolution order:
* - First consumes transient allowance from {temporaryApprove}.
* - Then consumes persistent allowance from {_allowances}, if needed.
*
* Requirements:
* - The combined transient and persistent allowance must be enough to cover `amount`.
*
* Emits:
* - {Approval} when persistent allowance is reduced.
*/
function _spendWithTemporary(
address owner,
address spender,
uint256 amount
)
private
{
TransientSlot.Uint256Slot slot = _temporaryAllowanceSlot(owner, spender);
uint256 t = slot.tload();
if (t == type(uint256).max) {
return;
}
if (t >= amount) {
unchecked {
slot.tstore(t - amount);
}
return;
}
unchecked {
amount -= t;
}
slot.tstore(0);
uint256 allowed = _allowances[owner][spender];
if (allowed != type(uint256).max) {
require(
allowed >= amount,
ERC20InsufficientAllowance({
spender: spender,
allowance: allowed,
needed: amount
})
);
unchecked {
uint256 updated = allowed - amount;
_allowances[owner][spender] = updated;
emit Approval({
owner: owner,
spender: spender,
value: updated
});
}
}
}
/**
* @dev Computes the transient allowance slot for `owner` and `spender`.
*/
function _temporaryAllowanceSlot(address owner, address spender)
private
pure
returns (TransientSlot.Uint256Slot)
{
return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256();
}
/**
* @dev Computes the flash loan fee for `value`, rounding up.
*/
function _flashFee(address /*token*/, uint256 value)
private
pure
returns (uint256)
{
return M.mulDiv(value, _FLASH_FEE_PPM, 1_000_000, M.Rounding.Ceil);
}
/* ───────────────────────────── ERC-20 viewers ─────────────────────── */
/**
* @inheritdoc IERC20Metadata
*/
function name()
external
view
override(IERC20Metadata)
returns (string memory)
{
return _name.toStringWithFallback(_nameFallback);
}
/**
* @inheritdoc IERC20Metadata
*/
function symbol()
external
view
override(IERC20Metadata)
returns (string memory)
{
return _symbol.toStringWithFallback(_symbolFallback);
}
/**
* @inheritdoc IERC20Metadata
*/
function decimals()
external
pure
override(IERC20Metadata)
returns (uint8)
{
return _decimals;
}
/**
* @inheritdoc IERC20
*/
function totalSupply()
external
view
override(IERC20)
returns (uint256)
{
return _totalSupply;
}
/**
* @dev Returns the cap on the token's total supply.
*/
function cap()
external
view
returns (uint256)
{
return _cap;
}
/**
* @inheritdoc IERC20
*/
function balanceOf(address account)
external
view
override(IERC20)
returns (uint256)
{
return _balances[account];
}
/**
* @inheritdoc IERC20
* @dev Implements IERC7674 semantics using EIP-1153 transient storage.
* @return The sum of persistent and transient allowance, capped at max on overflow
*/
function allowance(address owner, address spender)
external
view
override(IERC20)
returns (uint256)
{
(bool ok, uint256 sum) =
M.tryAdd(_allowances[owner][spender], _temporaryAllowanceSlot(owner, spender).tload());
return M.ternary(ok, sum, type(uint256).max);
}
/**
* @dev Transient allowance of `spender` over `owner` for the current transaction.
*/
function temporaryAllowance(address owner, address spender)
external
view
returns (uint256)
{
return _temporaryAllowanceSlot(owner, spender).tload();
}
/**
* @dev Returns the receiver address of the flash fee.
*/
function feeReceiver()
external
view
returns (address)
{
return _feeReceiver;
}
/**
* @inheritdoc IERC3156FlashLender
*/
function flashFee(address token, uint256 value)
external
view
override(IERC3156FlashLender)
returns (uint256)
{
require(
token == address(this),
ERC3156UnsupportedToken({ token: token })
);
return _flashFee(token, value);
}
/**
* @inheritdoc IERC3156FlashLender
*/
function maxFlashLoan(address token)
external
view
override(IERC3156FlashLender)
returns (uint256)
{
if (token != address(this)) {
return 0;
}
unchecked {
return _cap - _totalSupply;
}
}
/**
* @inheritdoc IERC20Permit
*/
function DOMAIN_SEPARATOR()
external
view
override(IERC20Permit)
returns (bytes32)
{
return _domainSeparatorV4();
}
/**
* @inheritdoc IERC20Permit
*/
function nonces(address owner)
public
view
override(IERC20Permit, Nonces)
returns (uint256)
{
return super.nonces(owner);
}
/* ───────────────────────────── Easter egg ───────────────────────────── */
/**
* @notice Grants the caller Anonyan-chan’s holy blessing.
* Recommended to call via `cast`, terminal size: ~ 69x30.
*
* Requirements:
* - Function must be called with love.
*
* @param sender The one to enlighten.
* @return blessing The official blessing of Anonyan-chan.
*/
function secretBlessing(address sender)
external
view
returns (string[] memory blessing)
{
string[] memory lines = new string[](28);
lines[0] = unicode"⣿⣿⣿⣿⣿⣿⣿⣤⡘⡍⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠋⡡⠊⠉⢀⠞⡻⠊⡐⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[1] = unicode"⣿⣿⣿⣿⣿⣿⣿⡟⢿⠻⡀⠀⠀⠉⠛⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠉⠀⠀⣠⠞⠃⠀⢀⡀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[2] = unicode"⣿⣿⣿⣿⣿⣿⣿⡄⠀⢀⠳⡀⠀⠀⠀⠀⠀⠈⠙⢿⣿⣿⡿⠟⣻⠟⠉⠀⠀⠀⠀⠀⠀⠠⠟⠁⠀⠀⠀⣠⡞⠀⠀⡀⠠⢜⣡⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[3] = unicode"⣿⣿⣿⣿⣿⣿⣿⡇⠂⣰⣧⠐⡄⠀⠀⠀⠀⠀⣐⣮⣤⠤⠀⠨⠴⣶⡶⡶⠤⣀⠀⠀⠀⠀⠀⠀⠑⠲⣿⣋⣭⣛⠁⠠⠒⢵⣏⡀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[4] = unicode"⣿⣿⣿⣿⣿⣿⣿⣹⣄⢘⣧⠀⢺⣆⠀⣠⠴⠛⠉⡱⠁⠀⠀⠀⠀⠀⠀⠀⠑⠢⡹⣦⡀⠀⠀⠀⠀⠀⠈⠻⡗⠀⠀⣀⣀⣒⡓⠧⡀⠀⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[5] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⡈⣙⡿⠂⢈⡿⠋⠀⠀⠀⠈⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠙⢝⣆⠑⡄⠀⠀⠀⠀⠘⢶⣀⣈⠉⣻⢿⡧⠀⠀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[6] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣿⣀⠞⠀⠀⡀⠀⠠⠂⠀⠀⠀⠀⠀⠱⠀⠀⠠⠀⠀⠀⠀⠀⠻⡱⣼⡄⠀⠀⠀⠀⠈⢗⠤⣅⣴⣟⣇⣠⠀⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[7] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⡿⠁⠀⠀⡰⠀⠀⡆⢰⠀⠀⠀⠀⠀⠀⢇⠀⠀⠑⡀⠀⠀⠀⠠⡘⢜⢿⡄⠀⢀⠀⠀⠈⢇⢨⣿⣿⠃⢀⣴⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[8] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⢠⢃⠀⣰⠀⠘⠀⠀⠀⠀⣇⠀⢸⣧⡀⠀⠘⢦⠀⠠⠀⠉⢌⠺⣷⠀⠈⡆⠀⠀⠘⣿⢟⡿⢶⣿⡟⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[9] = unicode"⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⣤⠇⢠⡟⡆⠀⡄⠀⠀⠀⠘⡄⠀⢏⠓⢄⠀⠣⠳⣄⠑⢄⠀⠣⡹⣇⠀⢰⠀⠀⠀⢳⠈⣰⣿⣿⢅⠘⣱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[10] = unicode"⣿⣿⣿⣿⣿⣿⠏⢠⠃⠀⠀⠀⢠⡟⠀⡾⠀⡇⠀⠂⠀⠀⠀⢳⠸⡄⠘⣄⣧⡦⡔⠒⠘⢯⡙⢍⠒⠚⢾⡀⠐⡆⠀⢡⠸⡮⠿⢫⡇⠘⡄⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[11] = unicode"⣿⣿⣿⣿⠟⠁⢠⠃⠀⠀⠀⠀⢸⠇⣸⠇⢠⢡⢀⢸⡀⠀⠀⠸⣧⢳⡠⢻⠀⠑⢜⣆⠘⠄⠑⢌⡳⡀⠀⠇⠀⣧⠀⢸⠀⣇⡰⠋⠀⠀⣷⠀⡀⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[12] = unicode"⣿⣿⠟⠁⢀⣴⡏⠀⡄⠀⠀⠀⢸⢀⣿⡀⠤⢼⡞⡄⣷⡘⣆⠀⠹⣍⣷⡀⢣⠀⠀⣙⣻⣦⣤⣤⣭⣛⣲⣤⠀⢹⠀⠀⠀⣍⣠⣤⠁⡰⢿⠀⠰⡀⠱⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[13] = unicode"⠋⢀⣠⣴⣿⣿⠁⠀⠁⠀⣸⠀⣾⠜⡏⠀⠀⠈⢿⡰⡘⣷⠘⣧⡀⠻⣿⣧⣀⣶⡿⢿⣿⣿⣿⣿⣿⡝⠻⣿⡶⠏⠀⠀⠀⢹⣿⣁⠜⡀⡿⣧⠀⡙⡄⠈⡢⡀⠀⠀⠀⠀⠀⠀⠀";
lines[14] = unicode"⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⢿⠀⣿⠀⠃⠀⢀⣀⣨⠷⡑⢼⣧⡽⣷⣄⡀⢻⡠⡏⠀⠸⠏⢹⣿⣿⠙⡇⠀⣼⡇⠀⠀⠀⡆⣎⡙⢇⡰⢁⡇⣿⣧⣿⢮⠢⡀⠀⠑⠢⡀⠀⠀⠀⠀";
lines[15] = unicode"⣿⣿⣿⣿⣿⡇⠀⠀⡇⠀⢸⡇⢻⠀⢐⣾⠟⣿⣿⣿⣗⠀⠈⠻⣆⠝⠣⢄⠈⠀⠀⠀⠰⣟⠹⢻⣿⠁⠀⠃⠁⠀⠀⢸⡇⣃⡁⢸⠁⣼⢧⢸⠙⡟⢷⣕⡌⠒⠤⣀⠀⠀⠀⠀⠀";
lines[16] = unicode"⣿⣿⣿⣿⣿⡇⢸⠀⣧⠀⠸⣷⠘⣄⣾⠇⠀⠿⠛⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣈⣁⠉⣁⣀⣀⢀⡁⠀⠀⢸⡄⡏⣡⢟⣿⣿⠸⠀⠄⠸⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀";
lines[17] = unicode"⣿⣿⢻⣿⣿⡇⢸⡆⢹⡄⠀⢹⣧⣻⡻⣇⠀⠀⢰⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠟⢁⠠⠀⢸⠇⠀⠀⠸⠃⡗⣡⣾⡏⢿⠀⡇⡇⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[18] = unicode"⣿⣿⣸⣿⣿⡇⢸⣷⡘⣷⡀⠈⣿⣿⣧⠈⠂⠀⠀⠉⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⣾⠀⠀⠀⣀⠀⣿⣿⢿⡇⢸⡄⠀⢩⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀";
lines[19] = unicode"⣿⣿⢸⣿⣿⣿⠘⣿⣷⣹⣷⣄⠘⣎⢻⣇⠀⠔⢫⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡔⢸⠀⠀⠀⣿⢠⣿⡇⢸⡇⠀⢷⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[20] = unicode"⣿⣿⣿⣿⣿⣿⣇⢿⣿⣿⣿⣿⡿⣏⠙⢿⠘⠒⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠊⢀⣼⠀⡄⢠⡏⢸⣿⣧⠘⣿⠀⠈⣇⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[21] = unicode"⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⡿⢁⣿⠀⠸⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⠟⣿⠀⠁⢸⡁⣼⣿⣿⠀⡟⡇⠀⠼⡀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[22] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣿⢟⡄⠀⢛⠢⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣾⠟⠁⢀⡏⠸⠀⣇⡆⣿⣿⣿⣇⣧⣿⡤⣶⣷⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[23] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢸⣇⠀⠸⡀⢸⡏⠓⣦⣤⣀⣀⠀⠀⠀⠀⠀⣀⣤⣾⣿⠟⠁⣠⠐⠁⠃⡆⢠⣾⢱⣿⡏⢉⣀⣠⣴⢤⣤⣬⣁⡒⠢⠤⣄⣀⡀⠀⠀⠀⠀⠀";
lines[24] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⣼⣿⠀⠀⠃⠘⡇⢀⣿⢸⣿⣿⣿⣿⣷⣶⣿⣿⣿⠟⠁⡠⠊⠀⠀⠀⣷⠁⢸⣟⣸⠿⠿⢧⡅⢱⣧⠀⡅⡇⠇⢳⠈⠁⠢⡀⠁⠀⠀⠀⠀⠀";
lines[25] = unicode"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢃⣿⢸⡇⠀⠰⠀⣿⢸⣿⣿⣿⣿⣿⠟⢛⣩⣿⡏⠁⠔⠈⢀⣠⠄⠒⢸⡟⠀⣿⡇⡇⠀⠀⢸⠃⠘⣿⠀⡁⢁⢸⠈⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀";
lines[26] = unicode"⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⣼⣿⢸⣿⡀⠀⠀⢸⣿⣿⣿⡿⠋⠵⡽⠿⠛⠛⠋⠉⠉⠉⠁⡁⠀⠀⣿⡇⢠⣿⣹⠁⠀⠀⣿⠀⢰⢿⠀⠙⠘⢸⡀⣷⠀⠀⠀⠀⠀⠀⠀⠀⠌";
address beacon = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;
bytes32 broot = bytes32(0);
assembly ("memory-safe") {
mstore(0x00, timestamp())
if iszero(staticcall(gas(), beacon, 0x00, 0x20, 0x00, 0x20)) { mstore(0x00, 0) }
broot := mload(0x00)
}
uint256 rnd = uint256(
keccak256(abi.encode(sender, "anonyan-blessing", block.prevrandao, broot))
);
(uint256 hi, ) = M.mul512(rnd, 101); uint256 power = hi;
lines[27] = string.concat(
"Blessing of Anonyan-chan received by: ",
Strings.toChecksumHexString(sender), " with power ", Strings.toString(power), "%"
);
return lines;
}
/* ───────────────────────────── Fallbacks ───────────────────────────── */
/**
* @dev Rejects direct ETH transfers via receive.
*/
receive() external payable {
revert ReceiveDisable(_msgSender(), msg.value);
}
/**
* @dev Rejects calls with ETH or data via fallback.
*/
fallback() external payable {
revert FallbackDisable(_msgSender(), msg.value, _msgData());
}
}"
},
"lib/openzeppelin-contracts/contracts/utils/types/Time.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @dev This library provides helpers for manipulating time-related objects.
*
* It uses the following types:
* - `uint48` for timepoints
* - `uint32` for durations
*
* While the library doesn't provide specific types for timepoints and duration, it does provide:
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
* - additional helper functions
*/
library Time {
using Time for *;
/**
* @dev Get the block timestamp as a Timepoint.
*/
function timestamp() internal view returns (uint48) {
return SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(
Delay self,
uint48 timepoint
) private pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
(valueBefore, valueAfter, effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(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.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* 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 {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 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 low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, 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 ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
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⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// 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²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev 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) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
/
Submitted on: 2025-09-24 20:45:51
Comments
Log in to comment.
No comments yet.