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/OrochiERC20.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 { Blockhash as B } from "@openzeppelin/contracts/utils/Blockhash.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 ERC20 Token with extensions (EIP-2612, ERC-3156, ERC-7674).
* @notice Extended ERC20 implementation supporting flash loans, ephemeral approvals, and off-chain signatures.
* @author @anonyanzk
* @custom:social X(Twitter) https://x.com/orochizk
* @custom:social Telegram https://t.me/orochitg
* @custom:source https://github.com/anonyanzk/orochi-erc20
* @dev Decentralized token with capped total supply and burn mechanisms.
*/
contract OrochiERC20 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;
/**
* @dev Reverts when the mint 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 allowed for `token`.
* @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 invalid selector.
* @param receiver The receiver contract address.
*/
error ERC3156InvalidReceiver(address receiver);
/**
* @dev Reverts when the token name constructor argument is empty.
*/
error EmptyInitialName();
/**
* @dev Reverts when the token symbol constructor argument is empty.
*/
error EmptyInitialSymbol();
/**
* @dev Reverts when the initial supply constructor argument is zero.
*/
error ZeroInitialSupply();
/**
* @dev Reverts when the feeReceiver is an invalid address.
*/
error InvalidFeeReceiver();
/**
* @dev Reverts if the cap is not strictly greater than the current total supply,
* as this would block flash-minting.
* Total supply remains fixed during normal operation.
* @param initialSupply The initial minted amount.
* @param cap The provided cap value.
*/
error InvalidInitialCap(uint256 initialSupply, uint256 cap);
/**
* @dev Reverts on reentrant calls when {nonReentrant} is active.
*/
error ReentrantCall();
/**
* @dev Reverts when the contract receives ETH via {receive}.
* @param sender The caller that triggered the receive.
* @param value The amount of ETH sent.
*/
error ReceiveDisable(address sender, uint256 value);
/**
* @dev Reverts when the contract is 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);
/**
* @dev Emitted when {temporaryApproveAndCall} is executed.
* @param owner The account granting the ephemeral allowance.
* @param spender The contract being called with that allowance.
* @param selector The function selector from the call data.
* @param value The temporary allowance granted for this call.
*/
event CalledWithTemporaryApprove(
address indexed owner,
address indexed spender,
bytes4 indexed selector,
uint256 value
);
/**
* @dev Emitted when a transient allowance is set
* via {temporaryApprove} or {temporaryApproveAndCall}.
* @param owner The account granting the allowance.
* @param spender The spender being approved.
* @param value The temporary allowance value.
*/
event TemporaryApproval(
address indexed owner,
address indexed spender,
uint256 value
);
/**
* @dev Emitted after a successful flash loan when the fee is paid.
* @param payer The flash-loan receiver who repaid the loan and fee.
* @param receiver The fee recipient.
* @param value The fee amount paid.
*/
event FlashFeePaid(
address indexed payer,
address indexed receiver,
uint256 value
);
/**
* @dev Storage seed used for deriving transient allowance slots.
* See {_temporaryAllowanceSlot}.
*/
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}.
* Required by ERC-3156 to validate a receiver’s callback.
*/
bytes32 private constant _FLASH_ON_LOAN_RETVAL =
keccak256("ERC3156FlashBorrower.onFlashLoan");
/**
* @dev ERC-20 token name.
*/
ShortString private _name;
string private _nameFallback;
/**
* @dev ERC-20 token symbol.
*/
ShortString private _symbol;
string private _symbolFallback;
/**
* @dev Fixed decimals for ERC-20 token.
*/
uint8 private constant _decimals = 18;
/**
* @dev Address that receives collected flashloan fees.
*/
address private immutable _feeReceiver;
/**
* @dev Flash loan fee, expressed in parts-per-million = 0.1337%.
*/
uint256 private constant _FLASH_FEE_PPM = 1337;
/**
* @dev Total minted supply.
*/
uint256 private _totalSupply;
/**
* @dev The immutable upper bound on total token supply.
*/
uint256 private immutable _cap;
/**
* @dev Transient reentrancy guard flag.
*/
uint256 private transient _flag;
/**
* @dev Token balances for each account.
*/
mapping(address user => uint256 balance)
private _balances;
/**
* @dev Allowances granted by token holders.
*/
mapping(address user => mapping(address spender => uint256 allowance))
private _allowances;
/**
* @dev Initializes the Orochi ERC20 token.
* @param name_ Token name (ERC-20 metadata).
* @param symbol_ Token symbol (ERC-20 metadata).
* @param initialSupply Initial total supply minted to the deployer.
* @param cap_ Maximum total token supply.
* @param feeReceiver_ Address that receives 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_ / 2 >= initialSupply,
InvalidInitialCap({
initialSupply: initialSupply,
cap: cap_
})
);
_name = name_ .toShortStringWithFallback(_nameFallback);
_symbol = symbol_.toShortStringWithFallback(_symbolFallback);
_cap = cap_;
_feeReceiver = feeReceiver_;
_mint(_msgSender(), initialSupply);
}
/**
* @dev Transient Reentrancy guard modifier.
* Ensures no reentrant calls to functions.
*
* Reverts with {ReentrantCall} if already entered.
*/
modifier nonReentrant() {
require(_flag == 0, ReentrantCall());
_flag = 1;
_;
_flag = 0;
}
/**
* @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
*/
function transferFrom(address from, address to, uint256 amount)
public
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);
}
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
*/
function approve(address spender, uint256 value)
external
override(IERC20)
returns (bool)
{
_setAllowance(_msgSender(), spender, value);
return true;
}
/**
* @notice Grants a transient allowance and immediately calls `spender`.
* @dev Sets a transient allowance for `spender` of `value`,
* then performs a low-level call to `spender` with `data`.
* The allowance exists only for the current transaction (EIP-1153).
* Passing `type(uint256).max` sets an infinite transient allowance.
*
* Requirements:
* - `spender` must not be the zero address.
*
* Emits {CalledWithTemporaryApprove} with `selector` equal to the first
* 4 bytes of `data` or 0x if `data.length < 4`, and
* {TemporaryApproval} event via {_temporaryApprove}.
*
* @param spender Target to call.
* @param value Transient allowance for this call.
* @param data Calldata for the low-level call.
* @return ret Raw return data from the call.
*/
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;
}
/**
* @notice Sets a transient allowance for `spender` over the caller’s tokens.
* @dev The allowance exists only for the current transaction (EIP-1153).
* Passing `type(uint256).max` sets an infinite transient allowance.
*
* Emits a {TemporaryApproval} event via {_temporaryApprove}.
*
* @param spender The spender address.
* @param value The transient allowance amount.
* @return true If the temporary approve operation succeeded.
*/
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);
}
/**
* @notice Executes an ERC-3156 flash loan.
* @dev Temporarily mints `value` tokens to `receiver`, calls its {onFlashLoan},
* then requires repayment of `value + fee` in the same transaction.
* The principal is burned after repayment.
*
* Requirements:
* - `token` must be `address(this)`.
* - `value` must be greater than zero.
* - `value` must not exceed {maxFlashLoan(address(this))}.
* - `receiver` must not be the {_feeReceiver}.
*
* @param receiver The receiver of the flash loan. Should implement the
* {IERC3156FlashBorrower-onFlashLoan} interface.
* @param token The token to be flash loaned.
* @param value The amount of tokens to be loaned.
* @param data An arbitrary datafield that is passed to the receiver.
* @return true If the flash loan operation succeeded.
*/
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 = maxFlashLoan(token);
require(
value <= maxLoan,
ERC3156ExceededMaxLoan({ maxLoan: maxLoan })
);
address feeTo = feeReceiver();
require(
address(receiver) != feeTo,
ERC3156InvalidReceiver({ receiver: address(receiver) })
);
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) })
);
uint256 repay = value + fee;
_spendWithTemporary(address(receiver), self, repay);
_update (address(receiver), self, repay);
_burn(self, value);
_move(self, feeTo, fee);
emit FlashFeePaid({
payer: address(receiver),
receiver: feeTo,
value: fee
});
return true;
}
/**
* @notice Burns `amount` from `from`, decreasing total supply.
* @dev Consumes allowance in this order: transient (from {temporaryApprove}),
* then persistent ({_allowances}). `type(uint256).max` is treated as unlimited.
*
* Requirements:
* - `from` must not be the zero address.
* - Available allowance must cover `amount`.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* @param from The account from which tokens are burned.
* @param amount The number of tokens to burn.
* @return true If the burn operation succeeded.
*/
function burnFrom(address from, uint256 amount)
public
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 `spender`'s allowance by `added`.
*
* Requirements:
* - `spender` must not be the zero address.
*
* Emits {Approval} with the new allowance.
*
* @param spender The address allowed to spend.
* @param added The amount to add to the current allowance.
* @return true If the increase allowance operation succeeded.
*/
function increaseAllowance(address spender, uint256 added)
external
returns (bool)
{
address owner = _msgSender();
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
uint256 current = _allowances[owner][spender];
if (added == 0) {
emit Approval({
owner: owner,
spender: spender,
value: current
});
return true;
}
unchecked {
uint256 updated = M.saturatingAdd(current, added);
_allowances[owner][spender] = updated;
emit Approval({
owner: owner,
spender: spender,
value: updated
});
}
return true;
}
/**
* @notice Decreases `spender`'s allowance by `subtracted`.
*
* Requirements:
* - `spender` must not be the zero address.
* - Allowance must be at least `subtracted`.
*
* Emits {Approval} with the new allowance.
*
* @param spender The address allowed to spend.
* @param subtracted The amount to subtract from the allowance.
* @return true If the decrease allowance operation succeeded.
*/
function decreaseAllowance(address spender, uint256 subtracted)
external
returns (bool)
{
address owner = _msgSender();
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
uint256 current = _allowances[owner][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;
_allowances[owner][spender] = updated;
emit Approval({
owner: owner,
spender: spender,
value: updated
});
}
return true;
}
/**
* @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 a {Transfer} event with `from` set to the zero address.
*/
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 a `amount` of tokens `from`, decreasing the total supply.
*
* Requirements:
* - `from` must not be the zero address.
* - `from` must have at least `amount` tokens.
*
* Emits a {Transfer} event with `to` set to the zero address.
*/
function _burn(address from, uint256 amount)
private
{
require(
from != address(0),
ERC20InvalidSender({ sender: from })
);
if (amount == 0) {
emit Transfer({
from: from,
to: address(0),
value: 0
});
return;
}
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 Moves `amount` from `from` to `to`.
*
* Requirements:
* - `from` and `to` must not be the zero address.
*
* Forwards to {_update} after validation.
*/
function _move(address from, address to, uint256 amount)
private
{
require(
from != address(0),
ERC20InvalidSender({ sender: from })
);
require(
to != address(0),
ERC20InvalidReceiver({ receiver: to })
);
_update(from, to, amount);
}
/**
* @dev Updates balances to transfer `amount` from `from` to `to`.
*
* Requirements:
* - `from` must have at least `amount` balance.
*
* Emits a {Transfer} event.
*/
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 an {Approval} event.
*/
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 a {TemporaryApproval} event.
*/
function _temporaryApprove(address owner, address spender, uint256 value)
private
{
require(
owner != address(0),
ERC20InvalidApprover({ approver: owner })
);
require(
spender != address(0),
ERC20InvalidSpender({ spender: spender })
);
_temporaryAllowanceSlot(owner, spender).tstore(value);
emit TemporaryApproval({
owner: owner,
spender: spender,
value: value
});
}
/**
* @dev Low-level variant of {_temporaryApprove}.
*
* Differences:
* - Does not validate `owner` or `spender`.
* - Does not emit a {TemporaryApproval} event.
*
* Intended for internal use when safety checks are redundant
* (e.g. updating an existing transient allowance).
*/
function _temporaryApproveUnsafe(address owner, address spender, uint256 value)
private
{
_temporaryAllowanceSlot(owner, spender).tstore(value);
}
/**
* @dev Computes the transient storage slot used to track
* transient allowance for `owner` and `spender`.
*
* Based on {ERC20_TEMPORARY_APPROVAL_STORAGE} with double mapping derivation.
*/
function _temporaryAllowanceSlot(address owner, address spender)
private
pure
returns (TransientSlot.Uint256Slot)
{
return ERC20_TEMPORARY_APPROVAL_STORAGE.deriveMapping(owner).deriveMapping(spender).asUint256();
}
/**
* @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:
* - Available allowance must cover `amount`.
*
* Emits {Approval} when persistent allowance is reduced.
*
* Updates the remaining allowance accordingly.
*/
function _spendWithTemporary(address owner, address spender, uint256 amount)
private
{
uint256 need = amount;
uint256 t = temporaryAllowance(owner, spender);
if (t > 0) {
if (t == type(uint256).max) {
need = 0;
} else {
uint256 useT = M.min(need, t);
unchecked {
_temporaryApproveUnsafe(owner, spender, t - useT);
}
need -= useT;
}
}
if (need > 0) {
uint256 allowed = _allowances[owner][spender];
if (allowed != type(uint256).max) {
require(
allowed >= need,
ERC20InsufficientAllowance({
spender: spender,
allowance: allowed,
needed: need
})
);
unchecked {
uint256 updated = allowed - need;
_allowances[owner][spender] = updated;
emit Approval({
owner: owner,
spender: spender,
value: updated
});
}
}
}
}
/**
* @dev Computes the flash loan fee for a given `value`.
* @param value The loan amount.
* @return The fee amount.
*/
function _flashFee(address /*token*/, uint256 value)
private
pure
returns (uint256)
{
return M.mulDiv(value, _FLASH_FEE_PPM, 1_000_000, M.Rounding.Ceil);
}
/**
* @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
*/
function allowance(address owner, address spender)
external
view
override(IERC20)
returns (uint256)
{
(bool ok, uint256 sum) =
M.tryAdd(_allowances[owner][spender], temporaryAllowance(owner, spender));
return M.ternary(ok, sum, type(uint256).max);
}
/**
* @dev Returns the transient allowance set by {temporaryApprove}.
* Lives only within the current transaction (EIP-1153) and resets to zero
* after the transaction completes.
*
* @param owner The account granting the transient allowance.
* @param spender The account allowed to spend within this transaction.
* @return The current transient allowance value.
*/
function temporaryAllowance(address owner, address spender)
public
view
returns (uint256)
{
return _temporaryAllowanceSlot(owner, spender).tload();
}
/**
* @dev Returns the receiver address of the flash fee.
* @return The address that receives flash-loan fees.
*/
function feeReceiver()
public
view
returns (address)
{
return _feeReceiver;
}
/**
* @dev Returns the fee applied when doing flash loans. This function calls
* the {_flashFee} function which returns the fee applied when doing flash loans.
* @param token The token to be flash loaned.
* @param value The amount of tokens to be loaned.
* @return The fees applied to the corresponding flash loan.
*/
function flashFee(address token, uint256 value)
external
view
override(IERC3156FlashLender)
returns (uint256)
{
require(
token == address(this),
ERC3156UnsupportedToken({ token: token })
);
return _flashFee(token, value);
}
/**
* @dev Returns the maximum amount of tokens available for loan.
* @param token The address of the token that is requested.
* @return The amount of token that can be loaned.
*/
function maxFlashLoan(address token)
public
view
override(IERC3156FlashLender)
returns (uint256)
{
if (token != address(this)) {
return 0;
}
return M.saturatingSub(_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);
}
/**
* @dev Blesses the caller with Anonyan-chan's sacred blessing.
*
* Requirements:
* - Caller must believe in the rofl.
* - Function must be called with love.
* - Function must be called via `cast`.
* - The terminal size must be set to exactly 69x25.
*
* @return blessing The official enlightenment of Anonyan-chan.
*/
function secretBlessing(address sender)
external
view
returns (string[] memory blessing)
{
string[] memory lines = new string[](29);
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"⣿⣧⢀⣤⣾⣿⣷⠟⠁⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⣞⣻⠇⡗⣿⢿⣽⠀⢉⠄⠐⡡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠄⡡⢀⢎⠔⡡⣑⢎⢌⡱⡃⠜";
lines[27] = string.concat(
"Blessing of Anonyan-chan received by: ",
Strings.toChecksumHexString(sender)
);
uint256 prevN = M.saturatingSub(T.blockNumber(), 1);
bytes32 prev = B.blockHash(prevN);
uint256 r = uint256(
keccak256(
abi.encodePacked(block.prevrandao, prev, sender, bytes32("anonyan-blessing"))
)
);
(uint256 p, ) = M.mul512(r, 101);
string[4] memory tips = [
string.concat(unicode" - Uh... ", Strings.toString(p), "%... Jump on one leg 3 times and call again!"),
unicode" - Call the function with more love >_<",
unicode" - Anonyan-chan is shy today, try again >_< ♥",
""
];
uint256 idx = M.ternary(p < 20, 0, M.ternary(p < 50, 1 + (r >> 137) & 1, 3));
lines[28] = string.concat(
"Anonyan-chan's blessing power: ", Strings.toString(p), "%", tips[idx]
);
return lines;
}
/**
* @dev Receive function is disabled.
*/
receive() external payable {
revert ReceiveDisable(_msgSender(), msg.value);
}
/**
* @dev Fallback function is disabled.
*/
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 tha
Submitted on: 2025-09-21 19:46:22
Comments
Log in to comment.
No comments yet.