Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
FakePools
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 1337 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Contracts/Libraries/Modifiers import { LibCore } from "../../../libraries/LibCore.sol"; import { LibFakePools } from "../../../libraries/LibFakePools.sol"; import { LibTokens } from "../../../libraries/LibTokens.sol"; import { LibUsd } from "../../../libraries/LibUsd.sol"; import { Diamondable } from "../../../Diamondable.sol"; // Facets import { Core } from "../Core.sol"; // Third Party import { FixedPointMathLib } from "solady/src/utils/FixedPointMathLib.sol"; contract FakePools is Diamondable { function swapExactTokensForETH(LibFakePools.FakePool storage pool, uint256 tokens) internal returns (uint256) { uint256 out = getAmountOut(tokens, pool.tokenReserve, pool.ethReserve + pool.fakeEth); pool.tokenReserve += tokens; pool.ethReserve -= out; return out; } function swapExactETHForTokens(LibFakePools.FakePool storage pool, uint256 eth) internal returns (uint256) { uint256 out = getAmountOut(eth, pool.ethReserve + pool.fakeEth, pool.tokenReserve); pool.tokenReserve -= out; pool.ethReserve += eth; return out; } function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256) { uint256 numerator = amountIn * reserveOut; uint256 denominator = reserveIn + amountIn; return numerator / denominator; } function price(LibFakePools.FakePool storage pool, uint256 amount, bool ethOut) internal view returns (uint256) { if (ethOut) { return (amount * (pool.ethReserve + pool.fakeEth)) / pool.tokenReserve; } else { return (amount * pool.tokenReserve) / (pool.ethReserve + pool.fakeEth); } } function checkMarketCapThreshold(LibFakePools.FakePool storage pool) internal { uint256 ethPrice = price(pool, 1 ether, true); uint256 usdPrice = LibUsd.ethToUsd(ethPrice); uint256 usdMcap = FixedPointMathLib.mulWad(LibCore.store().tokenSupply, usdPrice); if (usdMcap >= LibFakePools.store().usdMcapThreshold) { Core(address(this)).launch(pool.token); } } // PUBLIC function fakepool_quote(address token, uint256 amount, bool ethOut) public view returns (uint256) { LibFakePools.FakePool storage pool = LibFakePools.store().pools[token]; if (ethOut) { // sell uint256 eth = getAmountOut(amount, pool.tokenReserve, (pool.ethReserve + pool.fakeEth)); eth -= LibCore.calculateTradeFee(eth); return eth; } else { // buy uint256 txFee = LibCore.calculateTradeFee(amount); return getAmountOut(amount - txFee, (pool.ethReserve + pool.fakeEth), pool.tokenReserve); } } function fakepool_create(address token, uint256 supply, bytes calldata data) external onlyDiamond returns (uint256) { LibFakePools.FakePool storage pool = LibFakePools.store().pools[token]; pool.token = token; pool.fakeEth = LibFakePools.store().fakeEth; pool.ethReserve = 0; pool.tokenReserve = supply; return price(pool, 1 ether, true); } function fakepool_close(address token) public onlyDiamond returns (uint256, uint256, uint256) { LibFakePools.Storage storage fp = LibFakePools.store(); LibFakePools.FakePool memory pool = fp.pools[token]; delete fp.pools[token]; return (pool.ethReserve, pool.tokenReserve, pool.fakeEth); } function fakepool_buy(address token) external onlyDiamond payable returns (uint256 tokensOut, uint256 p) { LibFakePools.FakePool storage pool = LibFakePools.store().pools[token]; require(pool.token != address(0)); uint256 ethIn = LibCore.deductTradeFee(msg.value); tokensOut = swapExactETHForTokens(pool, ethIn); p = price(pool, 1 ether, true); checkMarketCapThreshold(pool); } function fakepool_sell(address token, uint256 amount) external onlyDiamond returns (uint256 ethOut, uint256 p) { LibFakePools.FakePool storage pool = LibFakePools.store().pools[token]; require(pool.token != address(0)); ethOut = swapExactTokensForETH(pool, amount); ethOut = LibCore.deductTradeFee(ethOut); p = price(pool, 1 ether, true); checkMarketCapThreshold(pool); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; import { LibDiamond } from "./libraries/LibDiamond.sol"; contract Diamondable { error Unauthorized(address account); modifier onlyDiamond() { LibDiamond.enforceDiamondItself(); _; } function diamond() internal view returns (address diamond_) { diamond_ = LibDiamond.diamondStorage().diamondAddress; } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Contracts/Libraries/Modifiers import { LibCore } from "../../libraries/LibCore.sol"; import { LibUsd } from "../../libraries/LibUsd.sol"; import { LibTokens } from "../../libraries/LibTokens.sol"; import { LibDex } from "../../libraries/LibDex.sol"; import { LibLST } from "../../libraries/LibLST.sol"; import { Diamondable } from "../../Diamondable.sol"; // Facets import { FakePools } from "./LaunchStrategies/FakePools.sol"; import { Launcher } from "./Launcher.sol"; import { Degen } from "./Degen.sol"; // Interfaces import { Token } from "../../../Token.sol"; // Third Party import { DynamicBufferLib } from "solady/src/utils/DynamicBufferLib.sol"; contract Core is Diamondable { event TokenCreated( address token, address creator, LibTokens.LaunchStrategy strategy, LibDex.Dex dex, bytes data, uint256 price ); event TokenLaunched( address token, address creator, LibTokens.LaunchStrategy strategy, LibDex.Dex dex, address pair ); function create( string calldata name, string calldata symbol, string calldata description, bytes calldata image, string[] calldata links, bytes calldata data, LibTokens.LaunchStrategy strategy, LibDex.Dex dex, uint256 initialBuy ) public payable { Core(address(this))._create(msg.sender, name, symbol, description, image, links, data, strategy, dex, initialBuy, msg.value); } function _create( address creator, string calldata name, string calldata symbol, string calldata description, bytes calldata image, string[] calldata links, bytes calldata data, LibTokens.LaunchStrategy strategy, LibDex.Dex dex, uint256 initialBuy, uint256 eth ) public payable onlyDiamond { require( bytes(name).length <= 18 && bytes(symbol).length <= 18 && bytes(image).length <= 1e7, "invalid name/symbol/image" ); require(links.length < 5, "4 links max"); for (uint8 i = 0; i < links.length; i++) { require(bytes(links[i]).length <= 128, "link too long"); } LibCore.Storage storage d = LibCore.store(); Token token = new Token(creator, name, symbol, description, image, links, d.tokenSupply, address(this)); address tokenAddress = address(token); uint256 price; if (strategy == LibTokens.LaunchStrategy.FakeLiquidity) { (price) = FakePools(address(this)).fakepool_create(tokenAddress, d.tokenSupply, data); } else { revert("invalid strategy"); } LibTokens.store().tokens[tokenAddress] = LibTokens.TokenInfo( creator, strategy, dex ); emit TokenCreated(tokenAddress, creator, strategy, dex, data, price); uint256 creationEth = LibUsd.usdToEth(d.creationPrice); require(eth >= creationEth, "usd price changed"); eth -= creationEth; LibCore.gatherProceeds(creationEth); if (initialBuy > 0) { _buy(creator, tokenAddress, initialBuy, 0); eth -= initialBuy; } if (eth > 0) payable(creator).transfer(eth); // refund dust } function quote(address token, uint256 amount, bool ethOut) public view returns(uint256) { LibTokens.LaunchStrategy strategy = LibTokens.store().tokens[token].strategy; if (strategy == LibTokens.LaunchStrategy.FakeLiquidity) { return FakePools(address(this)).fakepool_quote(token, amount, ethOut); } else { revert("invalid strategy"); } } event Bought(address buyer, address token, uint256 ethIn, uint256 tokensOut, uint256 priceNew); function buy(address token, uint256 min) public payable { Core(address(this))._buy(msg.sender, token, msg.value, min); } function _buy(address buyer, address token, uint256 ethIn, uint256 min) public onlyDiamond { LibTokens.LaunchStrategy strategy = LibTokens.store().tokens[token].strategy; (uint256 tokensOut, uint256 price) = (0, 0); if (strategy == LibTokens.LaunchStrategy.FakeLiquidity) { (tokensOut, price) = FakePools(address(this)).fakepool_buy{ value: ethIn }(token); } else { revert("invalid strategy"); } if (min != 0) require(tokensOut >= min, "amount out lower than min"); LibLST.addLiquidity(ethIn); Degen(address(this)).attributeXp(buyer, Degen.XpType.Buy, ethIn); Token(token).transfer(buyer, tokensOut); // Transfer tokens to buyer emit Bought(buyer, token, ethIn, tokensOut, price); } event Sold(address seller, address token, uint256 ethOut, uint256 tokensIn, uint256 priceNew); function sell(address token, uint256 amount, uint256 min) public { Core(address(this))._sell(msg.sender, token, amount, min); } function _sell(address seller, address token, uint256 amount, uint256 min) public onlyDiamond { LibTokens.LaunchStrategy strategy = LibTokens.store().tokens[token].strategy; (uint256 ethOut, uint256 price) = (0, 0); if (strategy == LibTokens.LaunchStrategy.FakeLiquidity) { (ethOut, price) = FakePools(address(this)).fakepool_sell(token, amount); } else { revert("invalid strategy"); } if (min != 0) require(ethOut >= min, "amount out lower than min"); LibLST.removeLiquidity(ethOut); Degen(address(this)).attributeXp(seller, Degen.XpType.Sell, ethOut); Token(token).transferFrom(seller, address(this), amount); // Transfer tokens from seller payable(seller).transfer(ethOut); // Transfer eth to seller emit Sold(seller, token, ethOut, amount, price); } function launch(address token) public onlyDiamond { LibTokens.TokenInfo storage tokenInfo = LibTokens.store().tokens[token]; require(tokenInfo.creator != address(0), "invalid token"); Token(token).unlock(); (address pair, uint256 eth,) = Launcher(address(this)).launch(token, tokenInfo); Degen(address(this)).attributeXp(tokenInfo.creator, Degen.XpType.Launch, eth); emit TokenLaunched(token, tokenInfo.creator, tokenInfo.strategy, tokenInfo.dex, pair); } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Contracts/Libraries/Modifiers import { LibUsd } from "../../libraries/LibUsd.sol"; import { Diamondable } from "../../Diamondable.sol"; // Interfaces import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // Third Party import { FixedPointMathLib } from "solady/src/utils/FixedPointMathLib.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; contract Degen is Diamondable { struct Storage { mapping(address => bytes) pfps; mapping(address => uint256) xp; } function store() internal pure returns (Storage storage s) { bytes32 position = keccak256("diamond.degen.storage"); assembly { s.slot := position } } event PfpSet(address degen); function pfp(address degen) public view returns (string memory) { return string.concat("data:image/webp;base64,", Base64.encode(store().pfps[degen])); } function setPfp(bytes memory image) public { require( bytes(image).length <= 1e7, // 1mb "invalid image" ); store().pfps[msg.sender] = image; emit PfpSet(msg.sender); } event XP(address degen, uint256 xp, uint256 totalXp); enum XpType { Buy, Sell, Launch } function attributeXp(address degen, XpType xpType, uint256 amount) public onlyDiamond { amount = FixedPointMathLib.mulWad(amount, LibUsd.getPrice() / 3000); uint256 xp; if (xpType == XpType.Buy) { xp = amount * 800; } else if (xpType == XpType.Sell) { xp = amount * 600; } else if (xpType == XpType.Launch) { xp = amount * 400; } store().xp[degen] += xp; emit XP(degen, xp, store().xp[degen]); } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Contracts/Libraries/Modifiers import { Diamondable } from "../../../Diamondable.sol"; // Libraries import { FixedPointMathLib } from "solady/src/utils/FixedPointMathLib.sol"; // Interfaces import { Token } from "../../../../Token.sol"; interface IEqualV2Pair { function totalSupply() external view returns (uint); function getReserves() external view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast); } interface IEqualV3Router { function weth() external view returns (address); function pairFor(address tokenA, address tokenB, bool stable) external view returns (address pair); function addLiquidityETH( address token, bool stable, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidityETH( address token, bool stable, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); } contract EqualizerLpHandler is Diamondable { struct Storage { mapping (address => address) positions; } function store() internal pure returns (Storage storage s) { bytes32 position = keccak256("diamond.equallp.storage"); assembly { s.slot := position } } IEqualV3Router constant router = IEqualV3Router(address(0xcC6169aA1E879d3a4227536671F85afdb2d23fAD)); function equal_pairFor(address token) public view returns (address) { return router.pairFor(token, router.weth(), false); } function equal_addLiquidty( address token, uint256 ethAmount, uint256 tokenAmount ) public onlyDiamond { Token(token).approve(address(router), tokenAmount); router.addLiquidityETH{value: ethAmount}( token, false, tokenAmount, 0, 0, address(this), block.timestamp ); store().positions[token] = equal_pairFor(token); } function equal_decreaseLiquidity(address token, uint256 amount) public onlyDiamond { address pair = store().positions[token]; (uint reserve0, uint reserve1,) = IEqualV2Pair(pair).getReserves(); (uint reserveETH,) = token < router.weth() ? (reserve1, reserve0) : (reserve0, reserve1); uint256 lpTokensToBurn = FixedPointMathLib.mulDivUp(amount, IEqualV2Pair(pair).totalSupply(), reserveETH); Token(pair).approve(address(router), lpTokensToBurn); router.removeLiquidityETH( token, false, lpTokensToBurn, 0, amount, address(this), block.timestamp ); } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Contracts/Libraries/Modifiers import { LibDex } from "../../libraries/LibDex.sol"; import { LibUtils } from "../../libraries/LibUtils.sol"; import { LibTokens } from "../../libraries/LibTokens.sol"; import { Diamondable } from "../../Diamondable.sol"; // Facets import { FakePools } from "./LaunchStrategies/FakePools.sol"; contract Launcher is Diamondable { function launch(address token, LibTokens.TokenInfo calldata tokenInfo) public onlyDiamond returns (address pair, uint256 eth, uint256 tokens) { if (tokenInfo.strategy == LibTokens.LaunchStrategy.FakeLiquidity) { uint256 fakeEth; (eth, tokens, fakeEth) = FakePools(address(this)).fakepool_close(token); LibDex.addLiquidty(tokenInfo.dex, token, eth + fakeEth, tokens); LibDex.decreaseLiquidity(tokenInfo.dex, token, fakeEth); } else { revert("invalid strategy"); } pair = LibDex.getPair(tokenInfo.dex, token); } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; interface IChainlinkAggregatorV3 { function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ interface IDiamondCut { enum FacetCutAction { Add, Replace, Remove } // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; import { LibUtils } from "./LibUtils.sol"; library LibCore { bytes32 constant STORAGE_POSITION = keccak256("diamond.core.storage"); struct Storage { uint256 proceeds; uint256 creationPrice; uint16 tradeFee; uint256 tokenSupply; } function store() internal pure returns (Storage storage s) { bytes32 position = STORAGE_POSITION; assembly { s.slot := position } } function gatherProceeds(uint256 amount) internal { store().proceeds += amount; } function calculateTradeFee(uint256 eth) internal view returns (uint256) { return LibUtils.calculatePercentage(store().tradeFee, eth); } function deductTradeFee(uint256 eth) internal returns (uint256) { uint256 fee = calculateTradeFee(eth); gatherProceeds(fee); return eth - fee; } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Facets import { EqualizerLpHandler } from "../facets/degen/dexes/EqualizerLpHandler.sol"; library LibDex { enum Dex { Equalizer, // https://ftmscan.com/address/0x2B52294425a9a229322228de659eDE9D146D7c2f#writeContract, https://ftmscan.com/address/0xE6dA85feb3B4E0d6AEd95c41a125fba859bB9d24#writeContract Shadow // https://github.com/code-423n4/2024-10-ramses-exchange/blob/main/contracts/CL/periphery/NonfungiblePositionManager.sol, https://github.com/code-423n4/2024-10-ramses-exchange/blob/main/contracts/CL/core/RamsesV3Factory.sol } function getPair(Dex dex, address token) internal view returns (address pair) { if (dex == Dex.Shadow) { // TODO pair = address(0); } else if (dex == Dex.Equalizer) { pair = EqualizerLpHandler(address(this)).equal_pairFor(token); } } function addLiquidty(Dex dex, address token, uint256 ethAmount, uint256 tokenAmount) internal { if (dex == Dex.Shadow) { // TODO revert("shadow not supported"); } else if (dex == Dex.Equalizer) { EqualizerLpHandler(address(this)).equal_addLiquidty(token, ethAmount, tokenAmount); } } function removeLiquidity(Dex dex, address token) internal { // TODO } function decreaseLiquidity(Dex dex, address token, uint256 amount) internal { if (dex == Dex.Shadow) { // TODO } else if (dex == Dex.Equalizer) { EqualizerLpHandler(address(this)).equal_decreaseLiquidity(token, amount); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import {IDiamondCut} from "../interfaces/IDiamondCut.sol"; // Remember to add the loupe functions from DiamondLoupeFacet to the diamond. // The loupe functions are required by the EIP2535 Diamonds standard error InitializationFunctionReverted( address _initializationContractAddress, bytes _calldata ); library LibDiamond { bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); struct FacetAddressAndPosition { address facetAddress; uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array } struct FacetFunctionSelectors { bytes4[] functionSelectors; uint256 facetAddressPosition; // position of facetAddress in facetAddresses array } struct DiamondStorage { // maps function selector to the facet address and // the position of the selector in the facetFunctionSelectors.selectors array mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition; // maps facet addresses to function selectors mapping(address => FacetFunctionSelectors) facetFunctionSelectors; // facet addresses address[] facetAddresses; // Used to query if a contract implements an interface. // Used to implement ERC-165. mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; // owner of the diamond itself address diamondAddress; } function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } } event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } function contractOwner() internal view returns (address contractOwner_) { contractOwner_ = diamondStorage().contractOwner; } function enforceIsContractOwner() internal view { require( msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner" ); } function enforceDiamondItself() internal view { require( msg.sender == diamondStorage().diamondAddress, "LibDiamond: Must be the diamond" ); } event DiamondCut( IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata ); // Internal function version of diamondCut function diamondCut( IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata ) internal { for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) { IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamondCut.FacetCutAction.Add) { addFunctions( _diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors ); } else if (action == IDiamondCut.FacetCutAction.Replace) { replaceFunctions( _diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors ); } else if (action == IDiamondCut.FacetCutAction.Remove) { removeFunctions( _diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors ); } else { revert("LibDiamondCut: Incorrect FacetCutAction"); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } function addFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { require( _functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut" ); DiamondStorage storage ds = diamondStorage(); require( _facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)" ); uint96 selectorPosition = uint96( ds.facetFunctionSelectors[_facetAddress].functionSelectors.length ); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .selectorToFacetAndPosition[selector] .facetAddress; require( oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists" ); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } function replaceFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { require( _functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut" ); DiamondStorage storage ds = diamondStorage(); require( _facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)" ); uint96 selectorPosition = uint96( ds.facetFunctionSelectors[_facetAddress].functionSelectors.length ); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .selectorToFacetAndPosition[selector] .facetAddress; require( oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function" ); removeFunction(ds, oldFacetAddress, selector); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } function removeFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { require( _functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut" ); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require( _facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)" ); for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .selectorToFacetAndPosition[selector] .facetAddress; removeFunction(ds, oldFacetAddress, selector); } } function addFacet(DiamondStorage storage ds, address _facetAddress) internal { enforceHasContractCode( _facetAddress, "LibDiamondCut: New facet has no code" ); ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds .facetAddresses .length; ds.facetAddresses.push(_facetAddress); } function addFunction( DiamondStorage storage ds, bytes4 _selector, uint96 _selectorPosition, address _facetAddress ) internal { ds .selectorToFacetAndPosition[_selector] .functionSelectorPosition = _selectorPosition; ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector); ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress; } function removeFunction( DiamondStorage storage ds, address _facetAddress, bytes4 _selector ) internal { require( _facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist" ); // an immutable function is a function defined directly in a diamond require( _facetAddress != address(this), "LibDiamondCut: Can't remove immutable function" ); // replace selector with last selector, then delete last selector uint256 selectorPosition = ds .selectorToFacetAndPosition[_selector] .functionSelectorPosition; uint256 lastSelectorPosition = ds .facetFunctionSelectors[_facetAddress] .functionSelectors .length - 1; // if not the same then replace _selector with lastSelector if (selectorPosition != lastSelectorPosition) { bytes4 lastSelector = ds .facetFunctionSelectors[_facetAddress] .functionSelectors[lastSelectorPosition]; ds.facetFunctionSelectors[_facetAddress].functionSelectors[ selectorPosition ] = lastSelector; ds .selectorToFacetAndPosition[lastSelector] .functionSelectorPosition = uint96(selectorPosition); } // delete the last selector ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop(); delete ds.selectorToFacetAndPosition[_selector]; // if no more selectors for facet address then delete the facet address if (lastSelectorPosition == 0) { // replace facet address with last facet address and delete last facet address uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1; uint256 facetAddressPosition = ds .facetFunctionSelectors[_facetAddress] .facetAddressPosition; if (facetAddressPosition != lastFacetAddressPosition) { address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition]; ds.facetAddresses[facetAddressPosition] = lastFacetAddress; ds .facetFunctionSelectors[lastFacetAddress] .facetAddressPosition = facetAddressPosition; } ds.facetAddresses.pop(); delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; } } function initializeDiamondCut( address _init, bytes memory _calldata ) internal { if (_init == address(0)) { return; } enforceHasContractCode(_init, "LibDiamondCut: _init address has no code"); (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up error /// @solidity memory-safe-assembly assembly { let returndata_size := mload(error) revert(add(32, error), returndata_size) } } else { revert InitializationFunctionReverted(_init, _calldata); } } } function enforceHasContractCode( address _contract, string memory _errorMessage ) internal view { uint256 contractSize; assembly { contractSize := extcodesize(_contract) } require(contractSize > 0, _errorMessage); } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; library LibFakePools { bytes32 constant STORAGE_POSITION = keccak256("diamond.fakepools.storage"); struct FakePool { address token; uint256 fakeEth; uint256 ethReserve; uint256 tokenReserve; } struct Storage { uint256 fakeEth; uint256 usdMcapThreshold; mapping(address => FakePool) pools; } function store() internal pure returns (Storage storage s) { bytes32 position = STORAGE_POSITION; assembly { s.slot := position } } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; library LibLST { bytes32 constant STORAGE_POSITION = keccak256("diamond.lst.storage"); struct Storage { uint256 staked; } function store() internal pure returns (Storage storage s) { bytes32 position = STORAGE_POSITION; assembly { s.slot := position } } function addLiquidity(uint256 ethAmount) internal { store().staked += ethAmount; } function removeLiquidity(uint256 ethAmount) internal { store().staked -= ethAmount; } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; import { LibDex } from "./LibDex.sol"; library LibTokens { bytes32 constant STORAGE_POSITION = keccak256("diamond.tokens.storage"); enum LaunchStrategy { FakeLiquidity } struct TokenInfo { address creator; LaunchStrategy strategy; LibDex.Dex dex; } struct Storage { mapping(address => TokenInfo) tokens; } function store() internal pure returns (Storage storage s) { bytes32 position = STORAGE_POSITION; assembly { s.slot := position } } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; import { IChainlinkAggregatorV3 } from "../interfaces/IChainlinkAggregatorV3.sol"; import { FixedPointMathLib } from "solady/src/utils/FixedPointMathLib.sol"; library LibUsd { bytes32 constant STORAGE_POSITION = keccak256("diamond.usd.storage"); struct ChainlinkOracle { address priceFeed; uint256 heartBeat; } struct Storage { ChainlinkOracle usdOracle; } function store() internal pure returns (Storage storage s) { bytes32 position = STORAGE_POSITION; assembly { s.slot := position } } function ethToUsd(uint256 ethAmount) internal view returns (uint256) { return FixedPointMathLib.mulWad(ethAmount, getPrice()); } function usdToEth(uint256 usdAmount) internal view returns (uint256) { return FixedPointMathLib.divWad(usdAmount, getPrice()); } function getPrice() internal view returns (uint256) { ChainlinkOracle storage oracle = store().usdOracle; (, int256 price, uint256 timeStamp,,) = IChainlinkAggregatorV3(oracle.priceFeed).latestRoundData(); require(uint256(timeStamp) >= block.timestamp - oracle.heartBeat, "stale pricefeed"); // usd oracle returns the price in 8 decimals, we want 18 return uint256(price) * (10 ** 10); } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; library LibUtils { function calculatePercentage(uint16 fee, uint256 amount) internal pure returns (uint256) { return amount * fee / 1000; } }
// SPDX-License-Identifier: UNKNOWN pragma solidity 0.8.18; // Contracts/Libraries/Modifiers import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; import { LibString } from "solady/src/utils/LibString.sol"; contract Token is ERC20 { address internal protocol; bool internal locked = true; address internal creator; string internal descripiton; bytes internal image; string[] internal links; constructor(address _creator, string memory name, string memory symbol, string memory _desc, bytes memory _image, string[] memory _links, uint256 _supply, address _protocol) ERC20(name, symbol) { protocol = _protocol; creator = _creator; descripiton = _desc; image = _image; links = _links; _mint(msg.sender, _supply); } function unlock() external { require(msg.sender == protocol && locked == true); locked = false; } function updateMetadata( string calldata _desc, bytes calldata _image, string[] calldata _links ) external { require(msg.sender == creator); if (bytes(_desc).length > 0) { descripiton = _desc; } if (_image.length > 0) { image = _image; } if (_links.length != links.length) { links = _links; } } function tokenURI( uint256 _unused ) public view returns (string memory) { string memory linksString = ''; for (uint256 i = 0; i < links.length; i++) { linksString = string.concat(linksString, '"', links[i], '"'); if (i < links.length - 1) { linksString = string.concat(linksString, ","); } } return string.concat("data:application/json;base64,", Base64.encode( bytes( string.concat( "{", '"creator":"', LibString.toHexString(creator), '",', '"name":"', name(), '",', '"symbol":"', symbol(), '",', '"supply":"', LibString.toString(totalSupply() / (10 ** 18)), '",', '"description":"', descripiton, '",', '"links":[',linksString,'],', '"image_data":"data:image/webp;base64,', Base64.encode(image), '",', '"background_color":"000000"', "}" ) ) ) ); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override { if (locked) { require(from == protocol || to == protocol, "transfer not allowed before launch"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) let dataEnd := add(add(0x20, data), dataLength) let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot. mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits. // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`. mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for buffers with automatic capacity resizing. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/DynamicBufferLib.sol) /// @author Modified from cozyco (https://github.com/samkingco/cozyco/blob/main/contracts/utils/DynamicBuffer.sol) library DynamicBufferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Type to represent a dynamic buffer in memory. /// You can directly assign to `data`, and the `p` function will /// take care of the memory allocation. struct DynamicBuffer { bytes data; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Some of these functions returns the same buffer for function chaining. // `e.g. `buffer.p("1").p("2")`. /// @dev Shorthand for `buffer.data.length`. function length(DynamicBuffer memory buffer) internal pure returns (uint256) { return buffer.data.length; } /// @dev Reserves at least `minimum` amount of contiguous memory. function reserve(DynamicBuffer memory buffer, uint256 minimum) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = buffer; uint256 n = buffer.data.length; if (minimum > n) { uint256 i = 0x40; do {} while ((i <<= 1) < minimum); bytes memory data; /// @solidity memory-safe-assembly assembly { data := 0x01 mstore(data, sub(i, n)) } result = p(result, data); } } /// @dev Clears the buffer without deallocating the memory. function clear(DynamicBuffer memory buffer) internal pure returns (DynamicBuffer memory result) { _deallocate(result); /// @solidity memory-safe-assembly assembly { mstore(mload(buffer), 0) } result = buffer; } /// @dev Returns a string pointing to the underlying bytes data. /// Note: The string WILL change if the buffer is updated. function s(DynamicBuffer memory buffer) internal pure returns (string memory) { return string(buffer.data); } /// @dev Appends `data` to `buffer`. function p(DynamicBuffer memory buffer, bytes memory data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = buffer; if (data.length == uint256(0)) return result; /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let bufData := mload(buffer) let bufDataLen := mload(bufData) let newBufDataLen := add(mload(data), bufDataLen) // Some random prime number to multiply `cap`, so that // we know that the `cap` is for a dynamic buffer. // Selected to be larger than any memory pointer realistically. let prime := 1621250193422201 let cap := mload(add(bufData, w)) // `mload(sub(bufData, 0x20))`. // Extract `cap`, initializing it to zero if it is not a multiple of `prime`. cap := mul(div(cap, prime), iszero(mod(cap, prime))) // Expand / Reallocate memory if required. // Note that we need to allocate an extra word for the length, and // and another extra word as a safety word (giving a total of 0x40 bytes). // Without the safety word, the backwards copying can cause a buffer overflow. for {} iszero(lt(newBufDataLen, cap)) {} { // Approximately more than double the capacity to ensure more than enough space. let newCap := and(add(cap, add(or(cap, newBufDataLen), 0x20)), w) // If the memory is contiguous, we can simply expand it. if iszero(or(xor(mload(0x40), add(bufData, add(0x40, cap))), eq(bufData, 0x60))) { // Store `cap * prime` in the word before the length. mstore(add(bufData, w), mul(prime, newCap)) mstore(0x40, add(bufData, add(0x40, newCap))) // Expand the memory allocation. break } // Set the `newBufData` to point to the word after `cap`. let newBufData := add(mload(0x40), 0x20) mstore(0x40, add(newBufData, add(0x40, newCap))) // Reallocate the memory. mstore(buffer, newBufData) // Store the `newBufData`. // Copy `bufData` one word at a time, backwards. for { let o := and(add(bufDataLen, 0x20), w) } 1 {} { mstore(add(newBufData, o), mload(add(bufData, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Store `cap * prime` in the word before the length. mstore(add(newBufData, w), mul(prime, newCap)) bufData := newBufData // Assign `newBufData` to `bufData`. break } // If it's a reserve operation, set the variables to skip the appending. if eq(data, 0x01) { mstore(data, 0x00) newBufDataLen := bufDataLen } // Copy `data` one word at a time, backwards. for { let o := and(add(mload(data), 0x20), w) } 1 {} { mstore(add(add(bufData, bufDataLen), o), mload(add(data, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } mstore(add(add(bufData, 0x20), newBufDataLen), 0) // Zeroize the word after the buffer. mstore(bufData, newBufDataLen) // Store the length. } } /// @dev Appends `data0`, `data1` to `buffer`. function p(DynamicBuffer memory buffer, bytes memory data0, bytes memory data1) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(p(buffer, data0), data1); } /// @dev Appends `data0` .. `data2` to `buffer`. function p( DynamicBuffer memory buffer, bytes memory data0, bytes memory data1, bytes memory data2 ) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(p(p(buffer, data0), data1), data2); } /// @dev Appends `data0` .. `data3` to `buffer`. function p( DynamicBuffer memory buffer, bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3 ) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(p(p(p(buffer, data0), data1), data2), data3); } /// @dev Appends `data0` .. `data4` to `buffer`. function p( DynamicBuffer memory buffer, bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3, bytes memory data4 ) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(p(p(p(p(buffer, data0), data1), data2), data3), data4); } /// @dev Appends `data0` .. `data5` to `buffer`. function p( DynamicBuffer memory buffer, bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3, bytes memory data4, bytes memory data5 ) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(p(p(p(p(p(buffer, data0), data1), data2), data3), data4), data5); } /// @dev Appends `data0` .. `data6` to `buffer`. function p( DynamicBuffer memory buffer, bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3, bytes memory data4, bytes memory data5, bytes memory data6 ) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(p(p(p(p(p(p(buffer, data0), data1), data2), data3), data4), data5), data6); } /// @dev Appends `abi.encodePacked(bool(data))` to buffer. function pBool(DynamicBuffer memory buffer, bool data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); uint256 casted; /// @solidity memory-safe-assembly assembly { casted := iszero(iszero(data)) } result = p(buffer, _single(casted, 1)); } /// @dev Appends `abi.encodePacked(address(data))` to buffer. function pAddress(DynamicBuffer memory buffer, address data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(uint256(uint160(data)), 20)); } /// @dev Appends `abi.encodePacked(uint8(data))` to buffer. function pUint8(DynamicBuffer memory buffer, uint8 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 1)); } /// @dev Appends `abi.encodePacked(uint16(data))` to buffer. function pUint16(DynamicBuffer memory buffer, uint16 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 2)); } /// @dev Appends `abi.encodePacked(uint24(data))` to buffer. function pUint24(DynamicBuffer memory buffer, uint24 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 3)); } /// @dev Appends `abi.encodePacked(uint32(data))` to buffer. function pUint32(DynamicBuffer memory buffer, uint32 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 4)); } /// @dev Appends `abi.encodePacked(uint40(data))` to buffer. function pUint40(DynamicBuffer memory buffer, uint40 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 5)); } /// @dev Appends `abi.encodePacked(uint48(data))` to buffer. function pUint48(DynamicBuffer memory buffer, uint48 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 6)); } /// @dev Appends `abi.encodePacked(uint56(data))` to buffer. function pUint56(DynamicBuffer memory buffer, uint56 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 7)); } /// @dev Appends `abi.encodePacked(uint64(data))` to buffer. function pUint64(DynamicBuffer memory buffer, uint64 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 8)); } /// @dev Appends `abi.encodePacked(uint72(data))` to buffer. function pUint72(DynamicBuffer memory buffer, uint72 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 9)); } /// @dev Appends `abi.encodePacked(uint80(data))` to buffer. function pUint80(DynamicBuffer memory buffer, uint80 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 10)); } /// @dev Appends `abi.encodePacked(uint88(data))` to buffer. function pUint88(DynamicBuffer memory buffer, uint88 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 11)); } /// @dev Appends `abi.encodePacked(uint96(data))` to buffer. function pUint96(DynamicBuffer memory buffer, uint96 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 12)); } /// @dev Appends `abi.encodePacked(uint104(data))` to buffer. function pUint104(DynamicBuffer memory buffer, uint104 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 13)); } /// @dev Appends `abi.encodePacked(uint112(data))` to buffer. function pUint112(DynamicBuffer memory buffer, uint112 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 14)); } /// @dev Appends `abi.encodePacked(uint120(data))` to buffer. function pUint120(DynamicBuffer memory buffer, uint120 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 15)); } /// @dev Appends `abi.encodePacked(uint128(data))` to buffer. function pUint128(DynamicBuffer memory buffer, uint128 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 16)); } /// @dev Appends `abi.encodePacked(uint136(data))` to buffer. function pUint136(DynamicBuffer memory buffer, uint136 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 17)); } /// @dev Appends `abi.encodePacked(uint144(data))` to buffer. function pUint144(DynamicBuffer memory buffer, uint144 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 18)); } /// @dev Appends `abi.encodePacked(uint152(data))` to buffer. function pUint152(DynamicBuffer memory buffer, uint152 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 19)); } /// @dev Appends `abi.encodePacked(uint160(data))` to buffer. function pUint160(DynamicBuffer memory buffer, uint160 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 20)); } /// @dev Appends `abi.encodePacked(uint168(data))` to buffer. function pUint168(DynamicBuffer memory buffer, uint168 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 21)); } /// @dev Appends `abi.encodePacked(uint176(data))` to buffer. function pUint176(DynamicBuffer memory buffer, uint176 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 22)); } /// @dev Appends `abi.encodePacked(uint184(data))` to buffer. function pUint184(DynamicBuffer memory buffer, uint184 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 23)); } /// @dev Appends `abi.encodePacked(uint192(data))` to buffer. function pUint192(DynamicBuffer memory buffer, uint192 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 24)); } /// @dev Appends `abi.encodePacked(uint200(data))` to buffer. function pUint200(DynamicBuffer memory buffer, uint200 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 25)); } /// @dev Appends `abi.encodePacked(uint208(data))` to buffer. function pUint208(DynamicBuffer memory buffer, uint208 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 26)); } /// @dev Appends `abi.encodePacked(uint216(data))` to buffer. function pUint216(DynamicBuffer memory buffer, uint216 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 27)); } /// @dev Appends `abi.encodePacked(uint224(data))` to buffer. function pUint224(DynamicBuffer memory buffer, uint224 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 28)); } /// @dev Appends `abi.encodePacked(uint232(data))` to buffer. function pUint232(DynamicBuffer memory buffer, uint232 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 29)); } /// @dev Appends `abi.encodePacked(uint240(data))` to buffer. function pUint240(DynamicBuffer memory buffer, uint240 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 30)); } /// @dev Appends `abi.encodePacked(uint248(data))` to buffer. function pUint248(DynamicBuffer memory buffer, uint248 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 31)); } /// @dev Appends `abi.encodePacked(uint256(data))` to buffer. function pUint256(DynamicBuffer memory buffer, uint256 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(data, 32)); } /// @dev Appends `abi.encodePacked(bytes1(data))` to buffer. function pBytes1(DynamicBuffer memory buffer, bytes1 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 1)); } /// @dev Appends `abi.encodePacked(bytes2(data))` to buffer. function pBytes2(DynamicBuffer memory buffer, bytes2 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 2)); } /// @dev Appends `abi.encodePacked(bytes3(data))` to buffer. function pBytes3(DynamicBuffer memory buffer, bytes3 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 3)); } /// @dev Appends `abi.encodePacked(bytes4(data))` to buffer. function pBytes4(DynamicBuffer memory buffer, bytes4 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 4)); } /// @dev Appends `abi.encodePacked(bytes5(data))` to buffer. function pBytes5(DynamicBuffer memory buffer, bytes5 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 5)); } /// @dev Appends `abi.encodePacked(bytes6(data))` to buffer. function pBytes6(DynamicBuffer memory buffer, bytes6 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 6)); } /// @dev Appends `abi.encodePacked(bytes7(data))` to buffer. function pBytes7(DynamicBuffer memory buffer, bytes7 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 7)); } /// @dev Appends `abi.encodePacked(bytes8(data))` to buffer. function pBytes8(DynamicBuffer memory buffer, bytes8 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 8)); } /// @dev Appends `abi.encodePacked(bytes9(data))` to buffer. function pBytes9(DynamicBuffer memory buffer, bytes9 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 9)); } /// @dev Appends `abi.encodePacked(bytes10(data))` to buffer. function pBytes10(DynamicBuffer memory buffer, bytes10 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 10)); } /// @dev Appends `abi.encodePacked(bytes11(data))` to buffer. function pBytes11(DynamicBuffer memory buffer, bytes11 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 11)); } /// @dev Appends `abi.encodePacked(bytes12(data))` to buffer. function pBytes12(DynamicBuffer memory buffer, bytes12 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 12)); } /// @dev Appends `abi.encodePacked(bytes13(data))` to buffer. function pBytes13(DynamicBuffer memory buffer, bytes13 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 13)); } /// @dev Appends `abi.encodePacked(bytes14(data))` to buffer. function pBytes14(DynamicBuffer memory buffer, bytes14 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 14)); } /// @dev Appends `abi.encodePacked(bytes15(data))` to buffer. function pBytes15(DynamicBuffer memory buffer, bytes15 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 15)); } /// @dev Appends `abi.encodePacked(bytes16(data))` to buffer. function pBytes16(DynamicBuffer memory buffer, bytes16 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 16)); } /// @dev Appends `abi.encodePacked(bytes17(data))` to buffer. function pBytes17(DynamicBuffer memory buffer, bytes17 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 17)); } /// @dev Appends `abi.encodePacked(bytes18(data))` to buffer. function pBytes18(DynamicBuffer memory buffer, bytes18 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 18)); } /// @dev Appends `abi.encodePacked(bytes19(data))` to buffer. function pBytes19(DynamicBuffer memory buffer, bytes19 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 19)); } /// @dev Appends `abi.encodePacked(bytes20(data))` to buffer. function pBytes20(DynamicBuffer memory buffer, bytes20 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 20)); } /// @dev Appends `abi.encodePacked(bytes21(data))` to buffer. function pBytes21(DynamicBuffer memory buffer, bytes21 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 21)); } /// @dev Appends `abi.encodePacked(bytes22(data))` to buffer. function pBytes22(DynamicBuffer memory buffer, bytes22 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 22)); } /// @dev Appends `abi.encodePacked(bytes23(data))` to buffer. function pBytes23(DynamicBuffer memory buffer, bytes23 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 23)); } /// @dev Appends `abi.encodePacked(bytes24(data))` to buffer. function pBytes24(DynamicBuffer memory buffer, bytes24 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 24)); } /// @dev Appends `abi.encodePacked(bytes25(data))` to buffer. function pBytes25(DynamicBuffer memory buffer, bytes25 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 25)); } /// @dev Appends `abi.encodePacked(bytes26(data))` to buffer. function pBytes26(DynamicBuffer memory buffer, bytes26 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 26)); } /// @dev Appends `abi.encodePacked(bytes27(data))` to buffer. function pBytes27(DynamicBuffer memory buffer, bytes27 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 27)); } /// @dev Appends `abi.encodePacked(bytes28(data))` to buffer. function pBytes28(DynamicBuffer memory buffer, bytes28 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 28)); } /// @dev Appends `abi.encodePacked(bytes29(data))` to buffer. function pBytes29(DynamicBuffer memory buffer, bytes29 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 29)); } /// @dev Appends `abi.encodePacked(bytes30(data))` to buffer. function pBytes30(DynamicBuffer memory buffer, bytes30 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 30)); } /// @dev Appends `abi.encodePacked(bytes31(data))` to buffer. function pBytes31(DynamicBuffer memory buffer, bytes31 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 31)); } /// @dev Appends `abi.encodePacked(bytes32(data))` to buffer. function pBytes32(DynamicBuffer memory buffer, bytes32 data) internal pure returns (DynamicBuffer memory result) { _deallocate(result); result = p(buffer, _single(bytes32(data), 32)); } /// @dev Shorthand for returning a new buffer. function p() internal pure returns (DynamicBuffer memory result) {} /// @dev Shorthand for `p(p(), data)`. function p(bytes memory data) internal pure returns (DynamicBuffer memory result) { p(result, data); } /// @dev Shorthand for `p(p(), data0, data1)`. function p(bytes memory data0, bytes memory data1) internal pure returns (DynamicBuffer memory result) { p(p(result, data0), data1); } /// @dev Shorthand for `p(p(), data0, .., data2)`. function p(bytes memory data0, bytes memory data1, bytes memory data2) internal pure returns (DynamicBuffer memory result) { p(p(p(result, data0), data1), data2); } /// @dev Shorthand for `p(p(), data0, .., data3)`. function p(bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3) internal pure returns (DynamicBuffer memory result) { p(p(p(p(result, data0), data1), data2), data3); } /// @dev Shorthand for `p(p(), data0, .., data4)`. function p( bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3, bytes memory data4 ) internal pure returns (DynamicBuffer memory result) { p(p(p(p(p(result, data0), data1), data2), data3), data4); } /// @dev Shorthand for `p(p(), data0, .., data5)`. function p( bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3, bytes memory data4, bytes memory data5 ) internal pure returns (DynamicBuffer memory result) { p(p(p(p(p(p(result, data0), data1), data2), data3), data4), data5); } /// @dev Shorthand for `p(p(), data0, .., data6)`. function p( bytes memory data0, bytes memory data1, bytes memory data2, bytes memory data3, bytes memory data4, bytes memory data5, bytes memory data6 ) internal pure returns (DynamicBuffer memory result) { p(p(p(p(p(p(p(result, data0), data1), data2), data3), data4), data5), data6); } /// @dev Shorthand for `pBool(p(), data)`. function pBool(bool data) internal pure returns (DynamicBuffer memory result) { pBool(result, data); } /// @dev Shorthand for `pAddress(p(), data)`. function pAddress(address data) internal pure returns (DynamicBuffer memory result) { pAddress(result, data); } /// @dev Shorthand for `pUint8(p(), data)`. function pUint8(uint8 data) internal pure returns (DynamicBuffer memory result) { pUint8(result, data); } /// @dev Shorthand for `pUint16(p(), data)`. function pUint16(uint16 data) internal pure returns (DynamicBuffer memory result) { pUint16(result, data); } /// @dev Shorthand for `pUint24(p(), data)`. function pUint24(uint24 data) internal pure returns (DynamicBuffer memory result) { pUint24(result, data); } /// @dev Shorthand for `pUint32(p(), data)`. function pUint32(uint32 data) internal pure returns (DynamicBuffer memory result) { pUint32(result, data); } /// @dev Shorthand for `pUint40(p(), data)`. function pUint40(uint40 data) internal pure returns (DynamicBuffer memory result) { pUint40(result, data); } /// @dev Shorthand for `pUint48(p(), data)`. function pUint48(uint48 data) internal pure returns (DynamicBuffer memory result) { pUint48(result, data); } /// @dev Shorthand for `pUint56(p(), data)`. function pUint56(uint56 data) internal pure returns (DynamicBuffer memory result) { pUint56(result, data); } /// @dev Shorthand for `pUint64(p(), data)`. function pUint64(uint64 data) internal pure returns (DynamicBuffer memory result) { pUint64(result, data); } /// @dev Shorthand for `pUint72(p(), data)`. function pUint72(uint72 data) internal pure returns (DynamicBuffer memory result) { pUint72(result, data); } /// @dev Shorthand for `pUint80(p(), data)`. function pUint80(uint80 data) internal pure returns (DynamicBuffer memory result) { pUint80(result, data); } /// @dev Shorthand for `pUint88(p(), data)`. function pUint88(uint88 data) internal pure returns (DynamicBuffer memory result) { pUint88(result, data); } /// @dev Shorthand for `pUint96(p(), data)`. function pUint96(uint96 data) internal pure returns (DynamicBuffer memory result) { pUint96(result, data); } /// @dev Shorthand for `pUint104(p(), data)`. function pUint104(uint104 data) internal pure returns (DynamicBuffer memory result) { pUint104(result, data); } /// @dev Shorthand for `pUint112(p(), data)`. function pUint112(uint112 data) internal pure returns (DynamicBuffer memory result) { pUint112(result, data); } /// @dev Shorthand for `pUint120(p(), data)`. function pUint120(uint120 data) internal pure returns (DynamicBuffer memory result) { pUint120(result, data); } /// @dev Shorthand for `pUint128(p(), data)`. function pUint128(uint128 data) internal pure returns (DynamicBuffer memory result) { pUint128(result, data); } /// @dev Shorthand for `pUint136(p(), data)`. function pUint136(uint136 data) internal pure returns (DynamicBuffer memory result) { pUint136(result, data); } /// @dev Shorthand for `pUint144(p(), data)`. function pUint144(uint144 data) internal pure returns (DynamicBuffer memory result) { pUint144(result, data); } /// @dev Shorthand for `pUint152(p(), data)`. function pUint152(uint152 data) internal pure returns (DynamicBuffer memory result) { pUint152(result, data); } /// @dev Shorthand for `pUint160(p(), data)`. function pUint160(uint160 data) internal pure returns (DynamicBuffer memory result) { pUint160(result, data); } /// @dev Shorthand for `pUint168(p(), data)`. function pUint168(uint168 data) internal pure returns (DynamicBuffer memory result) { pUint168(result, data); } /// @dev Shorthand for `pUint176(p(), data)`. function pUint176(uint176 data) internal pure returns (DynamicBuffer memory result) { pUint176(result, data); } /// @dev Shorthand for `pUint184(p(), data)`. function pUint184(uint184 data) internal pure returns (DynamicBuffer memory result) { pUint184(result, data); } /// @dev Shorthand for `pUint192(p(), data)`. function pUint192(uint192 data) internal pure returns (DynamicBuffer memory result) { pUint192(result, data); } /// @dev Shorthand for `pUint200(p(), data)`. function pUint200(uint200 data) internal pure returns (DynamicBuffer memory result) { pUint200(result, data); } /// @dev Shorthand for `pUint208(p(), data)`. function pUint208(uint208 data) internal pure returns (DynamicBuffer memory result) { pUint208(result, data); } /// @dev Shorthand for `pUint216(p(), data)`. function pUint216(uint216 data) internal pure returns (DynamicBuffer memory result) { pUint216(result, data); } /// @dev Shorthand for `pUint224(p(), data)`. function pUint224(uint224 data) internal pure returns (DynamicBuffer memory result) { pUint224(result, data); } /// @dev Shorthand for `pUint232(p(), data)`. function pUint232(uint232 data) internal pure returns (DynamicBuffer memory result) { pUint232(result, data); } /// @dev Shorthand for `pUint240(p(), data)`. function pUint240(uint240 data) internal pure returns (DynamicBuffer memory result) { pUint240(result, data); } /// @dev Shorthand for `pUint248(p(), data)`. function pUint248(uint248 data) internal pure returns (DynamicBuffer memory result) { pUint248(result, data); } /// @dev Shorthand for `pUint256(p(), data)`. function pUint256(uint256 data) internal pure returns (DynamicBuffer memory result) { pUint256(result, data); } /// @dev Shorthand for `pBytes1(p(), data)`. function pBytes1(bytes1 data) internal pure returns (DynamicBuffer memory result) { pBytes1(result, data); } /// @dev Shorthand for `pBytes2(p(), data)`. function pBytes2(bytes2 data) internal pure returns (DynamicBuffer memory result) { pBytes2(result, data); } /// @dev Shorthand for `pBytes3(p(), data)`. function pBytes3(bytes3 data) internal pure returns (DynamicBuffer memory result) { pBytes3(result, data); } /// @dev Shorthand for `pBytes4(p(), data)`. function pBytes4(bytes4 data) internal pure returns (DynamicBuffer memory result) { pBytes4(result, data); } /// @dev Shorthand for `pBytes5(p(), data)`. function pBytes5(bytes5 data) internal pure returns (DynamicBuffer memory result) { pBytes5(result, data); } /// @dev Shorthand for `pBytes6(p(), data)`. function pBytes6(bytes6 data) internal pure returns (DynamicBuffer memory result) { pBytes6(result, data); } /// @dev Shorthand for `pBytes7(p(), data)`. function pBytes7(bytes7 data) internal pure returns (DynamicBuffer memory result) { pBytes7(result, data); } /// @dev Shorthand for `pBytes8(p(), data)`. function pBytes8(bytes8 data) internal pure returns (DynamicBuffer memory result) { pBytes8(result, data); } /// @dev Shorthand for `pBytes9(p(), data)`. function pBytes9(bytes9 data) internal pure returns (DynamicBuffer memory result) { pBytes9(result, data); } /// @dev Shorthand for `pBytes10(p(), data)`. function pBytes10(bytes10 data) internal pure returns (DynamicBuffer memory result) { pBytes10(result, data); } /// @dev Shorthand for `pBytes11(p(), data)`. function pBytes11(bytes11 data) internal pure returns (DynamicBuffer memory result) { pBytes11(result, data); } /// @dev Shorthand for `pBytes12(p(), data)`. function pBytes12(bytes12 data) internal pure returns (DynamicBuffer memory result) { pBytes12(result, data); } /// @dev Shorthand for `pBytes13(p(), data)`. function pBytes13(bytes13 data) internal pure returns (DynamicBuffer memory result) { pBytes13(result, data); } /// @dev Shorthand for `pBytes14(p(), data)`. function pBytes14(bytes14 data) internal pure returns (DynamicBuffer memory result) { pBytes14(result, data); } /// @dev Shorthand for `pBytes15(p(), data)`. function pBytes15(bytes15 data) internal pure returns (DynamicBuffer memory result) { pBytes15(result, data); } /// @dev Shorthand for `pBytes16(p(), data)`. function pBytes16(bytes16 data) internal pure returns (DynamicBuffer memory result) { pBytes16(result, data); } /// @dev Shorthand for `pBytes17(p(), data)`. function pBytes17(bytes17 data) internal pure returns (DynamicBuffer memory result) { pBytes17(result, data); } /// @dev Shorthand for `pBytes18(p(), data)`. function pBytes18(bytes18 data) internal pure returns (DynamicBuffer memory result) { pBytes18(result, data); } /// @dev Shorthand for `pBytes19(p(), data)`. function pBytes19(bytes19 data) internal pure returns (DynamicBuffer memory result) { pBytes19(result, data); } /// @dev Shorthand for `pBytes20(p(), data)`. function pBytes20(bytes20 data) internal pure returns (DynamicBuffer memory result) { pBytes20(result, data); } /// @dev Shorthand for `pBytes21(p(), data)`. function pBytes21(bytes21 data) internal pure returns (DynamicBuffer memory result) { pBytes21(result, data); } /// @dev Shorthand for `pBytes22(p(), data)`. function pBytes22(bytes22 data) internal pure returns (DynamicBuffer memory result) { pBytes22(result, data); } /// @dev Shorthand for `pBytes23(p(), data)`. function pBytes23(bytes23 data) internal pure returns (DynamicBuffer memory result) { pBytes23(result, data); } /// @dev Shorthand for `pBytes24(p(), data)`. function pBytes24(bytes24 data) internal pure returns (DynamicBuffer memory result) { pBytes24(result, data); } /// @dev Shorthand for `pBytes25(p(), data)`. function pBytes25(bytes25 data) internal pure returns (DynamicBuffer memory result) { pBytes25(result, data); } /// @dev Shorthand for `pBytes26(p(), data)`. function pBytes26(bytes26 data) internal pure returns (DynamicBuffer memory result) { pBytes26(result, data); } /// @dev Shorthand for `pBytes27(p(), data)`. function pBytes27(bytes27 data) internal pure returns (DynamicBuffer memory result) { pBytes27(result, data); } /// @dev Shorthand for `pBytes28(p(), data)`. function pBytes28(bytes28 data) internal pure returns (DynamicBuffer memory result) { pBytes28(result, data); } /// @dev Shorthand for `pBytes29(p(), data)`. function pBytes29(bytes29 data) internal pure returns (DynamicBuffer memory result) { pBytes29(result, data); } /// @dev Shorthand for `pBytes30(p(), data)`. function pBytes30(bytes30 data) internal pure returns (DynamicBuffer memory result) { pBytes30(result, data); } /// @dev Shorthand for `pBytes31(p(), data)`. function pBytes31(bytes31 data) internal pure returns (DynamicBuffer memory result) { pBytes31(result, data); } /// @dev Shorthand for `pBytes32(p(), data)`. function pBytes32(bytes32 data) internal pure returns (DynamicBuffer memory result) { pBytes32(result, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helper for deallocating a automatically allocated `buffer` pointer. function _deallocate(DynamicBuffer memory result) private pure { /// @solidity memory-safe-assembly assembly { mstore(0x40, result) // Deallocate, as we have already allocated. } } /// @dev Returns a temporary bytes string of length `n` for `data`. function _single(uint256 data, uint256 n) private pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := 0x00 mstore(n, data) mstore(result, n) } } /// @dev Returns a temporary bytes string of length `n` for `data`. function _single(bytes32 data, uint256 n) private pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := 0x00 mstore(0x20, data) mstore(result, n) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if gt(x, div(not(0), y)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if iszero(eq(div(z, y), x)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := add(iszero(iszero(mod(z, WAD))), div(z, WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(mul(y, eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. /// Note: This function is an approximation. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. /// Note: This function is an approximation. Monotonically increasing. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. (int256 wad, int256 p) = (int256(WAD), x); uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (uint256(w >> 63) == uint256(0)) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == uint256(0)) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != uint256(0)); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c == uint256(0)) return w; int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `a * b == x * y`, with full precision. function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0)))) } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. for {} 1 {} { // If overflows. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. let r := mulmod(x, y, d) // Compute remainder using mulmod. let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`. // Make sure `z` is less than `2**256`. Also prevents `d == 0`. // Placing the check here seems to give more optimal stack operations. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } d := div(d, t) // Divide `d` by `t`, which is a power of two. // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use 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. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 z := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256 ) break } z := div(z, d) break } } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits. /// Performs the full 512 bit calculation regardless. function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) let t := and(d, sub(0, d)) let r := mulmod(x, y, d) d := div(d, t) let inv := xor(2, mul(3, d)) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) z := mul( or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) ) } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { z = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { z := add(z, 1) if iszero(z) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Calculates `floor(x * y / 2 ** n)` with full precision. /// Throws if result overflows a uint256. /// Credit to Philogy under MIT license: /// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`. for {} 1 {} { if iszero(or(iszero(x), eq(div(z, x), y))) { let k := and(n, 0xff) // `n`, cleaned. let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. // | p1 | z | // Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 | // Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 | // Check that final `z` doesn't overflow by checking that p1_0 = 0. if iszero(shr(k, p1)) { z := add(shl(sub(256, k), p1), shr(k, z)) break } mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } z := shr(and(n, 0xff), z) break } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(z, d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(z, d))), div(z, d)) } } /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`. function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) { /// @solidity memory-safe-assembly assembly { let g := n let r := mod(a, n) for { let y := 1 } 1 {} { let q := div(g, r) let t := g g := r r := sub(t, mul(r, q)) let u := x x := y y := sub(u, mul(y, q)) if iszero(r) { break } } x := mul(eq(g, 1), add(x, mul(slt(x, 0), n))) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if x { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`, rounded down. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`, rounded down. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // Makeshift lookup table to nudge the approximate log2 result. z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) // Newton-Raphson's. z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) // Round down. z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18); z = (1 + sqrt(x)) * 10 ** 9; z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1; } /// @solidity memory-safe-assembly assembly { z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down. } } /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down. /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36); z = (1 + cbrt(x)) * 10 ** 12; z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3; } /// @solidity memory-safe-assembly assembly { let p := x for {} 1 {} { if iszero(shr(229, p)) { if iszero(shr(199, p)) { p := mul(p, 100000000000000000) // 10 ** 17. break } p := mul(p, 100000000) // 10 ** 8. break } if iszero(shr(249, p)) { p := mul(p, 100) } break } let t := mulmod(mul(z, z), z, p) z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down. } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := 1 if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for {} x { x := sub(x, 1) } { z := mul(z, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. Rounds towards zero. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { unchecked { z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255); } } /// @dev Returns the absolute distance between `x` and `y`. function dist(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`, /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end) internal pure returns (uint256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; unchecked { if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin); return a - fullMulDiv(a - b, t - begin, end - begin); } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`. /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end) internal pure returns (int256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; // forgefmt: disable-next-item unchecked { if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a), uint256(t - begin), uint256(end - begin))); return int256(uint256(a) - fullMulDiv(uint256(a - b), uint256(t - begin), uint256(end - begin))); } } /// @dev Returns if `x` is an even number. Some people may need this. function isEven(uint256 x) internal pure returns (bool) { return x & uint256(1) == uint256(0); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for byte related operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol) library LibBytes { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Goated bytes storage struct that totally MOGs, no cap, fr. /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af. /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. struct BytesStorage { bytes32 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the bytes. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STORAGE OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sets the value of the bytes storage `$` to `s`. function set(BytesStorage storage $, bytes memory s) internal { /// @solidity memory-safe-assembly assembly { let n := mload(s) let packed := or(0xff, shl(8, n)) for { let i := 0 } 1 {} { if iszero(gt(n, 0xfe)) { i := 0x1f packed := or(n, shl(8, mload(add(s, i)))) if iszero(gt(n, i)) { break } } let o := add(s, 0x20) mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { sstore(add(p, shr(5, i)), mload(add(o, i))) i := add(i, 0x20) if iszero(lt(i, n)) { break } } break } sstore($.slot, packed) } } /// @dev Sets the value of the bytes storage `$` to `s`. function setCalldata(BytesStorage storage $, bytes calldata s) internal { /// @solidity memory-safe-assembly assembly { let packed := or(0xff, shl(8, s.length)) for { let i := 0 } 1 {} { if iszero(gt(s.length, 0xfe)) { i := 0x1f packed := or(s.length, shl(8, shr(8, calldataload(s.offset)))) if iszero(gt(s.length, i)) { break } } mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { sstore(add(p, shr(5, i)), calldataload(add(s.offset, i))) i := add(i, 0x20) if iszero(lt(i, s.length)) { break } } break } sstore($.slot, packed) } } /// @dev Sets the value of the bytes storage `$` to the empty bytes. function clear(BytesStorage storage $) internal { delete $._spacer; } /// @dev Returns whether the value stored is `$` is the empty bytes "". function isEmpty(BytesStorage storage $) internal view returns (bool) { return uint256($._spacer) & 0xff == uint256(0); } /// @dev Returns the length of the value stored in `$`. function length(BytesStorage storage $) internal view returns (uint256 result) { result = uint256($._spacer); /// @solidity memory-safe-assembly assembly { let n := and(0xff, result) result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n)))) } } /// @dev Returns the value stored in `$`. function get(BytesStorage storage $) internal view returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) let packed := sload($.slot) let n := shr(8, packed) for { let i := 0 } 1 {} { if iszero(eq(and(packed, 0xff), 0xff)) { mstore(o, packed) n := and(0xff, packed) i := 0x1f if iszero(gt(n, i)) { break } } mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { mstore(add(o, i), sload(add(p, shr(5, i)))) i := add(i, 0x20) if iszero(lt(i, n)) { break } } break } mstore(result, n) // Store the length of the memory. mstore(add(o, n), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(o, n), 0x20)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTES OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(bytes memory subject, bytes memory needle, bytes memory replacement) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let needleLen := mload(needle) let replacementLen := mload(replacement) let d := sub(result, subject) // Memory difference. let i := add(subject, 0x20) // Subject bytes pointer. mstore(0x00, add(i, mload(subject))) // End of subject. if iszero(gt(needleLen, mload(subject))) { let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, needleLen), h)) { mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let j := 0 } 1 {} { mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) j := add(j, 0x20) if iszero(lt(j, replacementLen)) { break } } d := sub(add(d, replacementLen), needleLen) if needleLen { i := add(i, needleLen) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } } let end := mload(0x00) let n := add(sub(d, add(result, 0x20)), end) // Copy the rest of the bytes one word at a time. for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } let o := add(i, d) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := not(0) // Initialize to `NOT_FOUND`. for { let subjectLen := mload(subject) } 1 {} { if iszero(mload(needle)) { result := from if iszero(gt(from, subjectLen)) { break } result := subjectLen break } let needleLen := mload(needle) let subjectStart := add(subject, 0x20) subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) let m := shl(3, sub(0x20, and(needleLen, 0x1f))) let s := mload(add(needle, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } if iszero(lt(needleLen, 0x20)) { for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, needleLen), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { return indexOf(subject, needle, 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let needleLen := mload(needle) if gt(needleLen, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), needleLen) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if eq(keccak256(subject, needleLen), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { return lastIndexOf(subject, needle, type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) { return indexOf(subject, needle) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `needle`. function startsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let n := mload(needle) // Just using keccak256 directly is actually cheaper. let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n)) result := lt(gt(n, mload(subject)), t) } } /// @dev Returns whether `subject` ends with `needle`. function endsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let n := mload(needle) let notInRange := gt(n, mload(subject)) // `subject + 0x20 + max(subject.length - needle.length, 0)`. let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n))) // Just using keccak256 directly is actually cheaper. result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange) } } /// @dev Returns `subject` repeated `times`. function repeat(bytes memory subject, uint256 times) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let l := mload(subject) // Subject length. if iszero(or(iszero(times), iszero(l))) { result := mload(0x40) subject := add(subject, 0x20) let o := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let j := 0 } 1 {} { mstore(add(o, j), mload(add(subject, j))) j := add(j, 0x20) if iszero(lt(j, l)) { break } } o := add(o, l) times := sub(times, 1) if iszero(times) { break } } mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, sub(o, add(result, 0x20))) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(bytes memory subject, uint256 start, uint256 end) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let l := mload(subject) // Subject length. if iszero(gt(l, end)) { end := l } if iszero(gt(l, start)) { start := l } if lt(start, end) { result := mload(0x40) let n := sub(end, start) let i := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let j := and(add(n, 0x1f), w) } 1 {} { mstore(add(result, j), mload(add(i, j))) j := add(j, w) // `sub(j, 0x20)`. if iszero(j) { break } } let o := add(add(result, 0x20), n) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. /// `start` is a byte offset. function slice(bytes memory subject, uint256 start) internal pure returns (bytes memory result) { result = slice(subject, start, type(uint256).max); } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. Faster than Solidity's native slicing. function sliceCalldata(bytes calldata subject, uint256 start, uint256 end) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { end := xor(end, mul(xor(end, subject.length), lt(subject.length, end))) start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) result.offset := add(subject.offset, start) result.length := mul(lt(start, end), sub(end, start)) } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. /// `start` is a byte offset. Faster than Solidity's native slicing. function sliceCalldata(bytes calldata subject, uint256 start) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) result.offset := add(subject.offset, start) result.length := mul(lt(start, subject.length), sub(subject.length, start)) } } /// @dev Reduces the size of `subject` to `n`. /// If `n` is greater than the size of `subject`, this will be a no-op. function truncate(bytes memory subject, uint256 n) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := subject mstore(mul(lt(n, mload(result)), result), n) } } /// @dev Returns a copy of `subject`, with the length reduced to `n`. /// If `n` is greater than the size of `subject`, this will be a no-op. function truncatedCalldata(bytes calldata subject, uint256 n) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { result.offset := subject.offset result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n))) } } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(bytes memory subject, bytes memory needle) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let searchLen := mload(needle) if iszero(gt(searchLen, mload(subject))) { result := mload(0x40) let i := add(subject, 0x20) let o := add(result, 0x20) let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, searchLen), h)) { i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. o := add(o, 0x20) i := add(i, searchLen) // Advance `i` by `searchLen`. if searchLen { if iszero(lt(i, subjectSearchEnd)) { break } continue } } i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(o, 0x20)) } } } /// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes. function split(bytes memory subject, bytes memory delimiter) internal pure returns (bytes[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) for { let prevIndex := 0 } 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let l := sub(index, prevIndex) mstore(element, l) // Store the length of the element. // Copy the `subject` one word at a time, backwards. for { let o := and(add(l, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes. // Allocate memory for the length and the bytes, rounded up to a multiple of 32. mstore(0x40, add(element, and(add(l, 0x3f), w))) mstore(indexPtr, element) // Store the `element` into the array. } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated bytes of `a` and `b`. /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer. function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let w := not(0x1f) let aLen := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLen, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLen := mload(b) let output := add(result, aLen) // Copy `b` one word at a time, backwards. for { let o := and(add(bLen, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLen := add(aLen, bLen) let last := add(add(result, 0x20), totalLen) mstore(last, 0) // Zeroize the slot after the bytes. mstore(result, totalLen) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(bytes memory a, bytes memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes. function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Directly returns `a` without copying. function directReturn(bytes memory a) internal pure { assembly { // Assumes that the bytes does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the bytes is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the bytes. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } /// @dev Directly returns `a` with minimal copying. function directReturn(bytes[] memory a) internal pure { assembly { let n := mload(a) // `a.length`. let o := add(a, 0x20) // Start of elements in `a`. let u := a // Highest memory slot. let w := not(0x1f) for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { let c := add(o, shl(5, i)) // Location of pointer to `a[i]`. let s := mload(c) // `a[i]`. let l := mload(s) // `a[i].length`. let r := and(l, 0x1f) // `a[i].length % 32`. let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`. // If `s` comes before `o`, or `s` is not zero right padded. if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) { let m := mload(0x40) mstore(m, l) // Copy `a[i].length`. for {} 1 {} { mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards. z := add(z, w) // `sub(z, 0x20)`. if iszero(z) { break } } let e := add(add(m, 0x20), l) mstore(e, 0) // Zeroize the slot after the copied bytes. mstore(0x40, add(e, 0x20)) // Allocate memory. s := m } mstore(c, sub(s, o)) // Convert to calldata offset. let t := add(l, add(s, 0x20)) if iszero(lt(t, u)) { u := t } } let retStart := add(a, w) // Assumes `a` doesn't start from scratch space. mstore(retStart, 0x20) // Store the return offset. return(retStart, add(0x40, sub(u, retStart))) // End the transaction. } } /// @dev Returns the word at `offset`, without any bounds checks. /// To load an address, you can use `address(bytes20(load(a, offset)))`. function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(add(add(a, 0x20), offset)) } } /// @dev Returns the word at `offset`, without any bounds checks. /// To load an address, you can use `address(bytes20(loadCalldata(a, offset)))`. function loadCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := calldataload(add(a.offset, offset)) } } /// @dev Returns empty calldata bytes. For silencing the compiler. function emptyCalldata() internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { result.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {LibBytes} from "./LibBytes.sol"; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Goated string storage struct that totally MOGs, no cap, fr. /// Uses less gas and bytecode than Solidity's native string storage. It's meta af. /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. struct StringStorage { bytes32 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /// @dev The input string must be a 7-bit ASCII. error StringNot7BitASCII(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; /// @dev Lookup for '0123456789'. uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; /// @dev Lookup for '0123456789abcdefABCDEF'. uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; /// @dev Lookup for '01234567'. uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; /// @dev Lookup for ' \t\n\r\x0b\x0c'. uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRING STORAGE OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sets the value of the string storage `$` to `s`. function set(StringStorage storage $, string memory s) internal { LibBytes.set(bytesStorage($), bytes(s)); } /// @dev Sets the value of the string storage `$` to `s`. function setCalldata(StringStorage storage $, string calldata s) internal { LibBytes.setCalldata(bytesStorage($), bytes(s)); } /// @dev Sets the value of the string storage `$` to the empty string. function clear(StringStorage storage $) internal { delete $._spacer; } /// @dev Returns whether the value stored is `$` is the empty string "". function isEmpty(StringStorage storage $) internal view returns (bool) { return uint256($._spacer) & 0xff == uint256(0); } /// @dev Returns the length of the value stored in `$`. function length(StringStorage storage $) internal view returns (uint256) { return LibBytes.length(bytesStorage($)); } /// @dev Returns the value stored in `$`. function get(StringStorage storage $) internal view returns (string memory) { return string(LibBytes.get(bytesStorage($))); } /// @dev Helper to cast `$` to a `BytesStorage`. function bytesStorage(StringStorage storage $) internal pure returns (LibBytes.BytesStorage storage casted) { /// @solidity memory-safe-assembly assembly { casted.slot := $.slot } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end of the memory to calculate the length later. let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 1)`. // Store the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(result, add(48, mod(temp, 10))) temp := div(temp, 10) // Keep dividing `temp` until zero. if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length. mstore(result, n) // Store the length. } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory result) { if (value >= 0) return toString(uint256(value)); unchecked { result = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let n := mload(result) // Load the string length. mstore(result, 0x2d) // Store the '-' character. result := sub(result, 1) // Move back the string pointer by a byte. mstore(result, add(n, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `byteCount` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `byteCount * 2 + 2` bytes. /// Reverts if `byteCount` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 byteCount) internal pure returns (string memory result) { result = toHexStringNoPrefix(value, byteCount); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `byteCount` bytes. /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte, /// giving a total length of `byteCount * 2` bytes. /// Reverts if `byteCount` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 byteCount) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f))) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(result, add(byteCount, byteCount)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(result, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := add(mload(result), 2) // Compute the length. mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := mload(result) // Get the length. result := add(result, o) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory result) { result = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(result, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Allocate memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(result, 0x80)) mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. result := add(result, 2) mstore(result, 40) // Store the length. let o := add(result, 0x20) mstore(add(o, 40), 0) // Zeroize the slot after the string. value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory result) { result = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(raw) result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(result, add(n, n)) // Store the length of the output. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let o := add(result, 0x20) let end := add(raw, n) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 let mask := shl(7, div(not(0), 255)) let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /// @dev Returns if this string is a 7-bit ASCII string, /// AND all characters are in the `allowed` lookup. /// Note: If `s` is empty, returns true regardless of `allowed`. function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if mload(s) { let allowed_ := shr(128, shl(128, allowed)) let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := and(result, shr(byte(0, mload(o)), allowed_)) o := add(o, 1) if iszero(and(result, lt(o, end))) { break } } } } } /// @dev Converts the bytes in the 7-bit ASCII string `s` to /// an allowed lookup for use in `is7BitASCII(s, allowed)`. /// To save runtime gas, you can cache the result in an immutable variable. function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := or(result, shl(byte(0, mload(o)), 1)) o := add(o, 1) if iszero(lt(o, end)) { break } } if shr(128, result) { mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. revert(0x1c, 0x04) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(string memory subject, string memory needle, string memory replacement) internal pure returns (string memory) { return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement))); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { return LibBytes.indexOf(bytes(subject), bytes(needle), from); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle) internal pure returns (uint256) { return LibBytes.indexOf(bytes(subject), bytes(needle), 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle) internal pure returns (uint256) { return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.contains(bytes(subject), bytes(needle)); } /// @dev Returns whether `subject` starts with `needle`. function startsWith(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.startsWith(bytes(subject), bytes(needle)); } /// @dev Returns whether `subject` ends with `needle`. function endsWith(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.endsWith(bytes(subject), bytes(needle)); } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory) { return string(LibBytes.repeat(bytes(subject), times)); } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory) { return string(LibBytes.slice(bytes(subject), start, end)); } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory) { return string(LibBytes.slice(bytes(subject), start, type(uint256).max)); } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory needle) internal pure returns (uint256[] memory) { return LibBytes.indicesOf(bytes(subject), bytes(needle)); } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter)); /// @solidity memory-safe-assembly assembly { result := a } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory) { return string(LibBytes.concat(bytes(a), bytes(b))); } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(subject) if n { result := mload(0x40) let o := add(result, 0x20) let d := sub(subject, result) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) for { let end := add(o, n) } 1 {} { let b := byte(0, mload(add(d, o))) mstore8(o, xor(and(shr(b, flags), 0x20), b)) o := add(o, 1) if eq(o, end) { break } } mstore(result, n) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) // Store the length. let o := add(result, 0x20) mstore(o, s) // Store the bytes of the string. mstore(add(o, n), 0) // Zeroize the slot after the string. mstore(0x40, add(result, 0x40)) // Allocate memory. } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let end := add(s, mload(s)) let o := add(result, 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(o, c) o := add(o, 1) continue } let t := shr(248, mload(c)) mstore(o, mload(and(t, 0x1f))) o := add(o, shr(5, t)) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(o, c) o := add(o, 1) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), c) o := add(o, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(o, mload(0x19)) // "\\u00XX". o := add(o, 6) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), mload(add(c, 8))) o := add(o, 2) } if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Encodes `s` so that it can be safely used in a URI, /// just like `encodeURIComponent` in JavaScript. /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent /// See: https://datatracker.ietf.org/doc/html/rfc2396 /// See: https://datatracker.ietf.org/doc/html/rfc3986 function encodeURIComponent(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Store "0123456789ABCDEF" in scratch space. // Uppercased to be consistent with JavaScript's implementation. mstore(0x0f, 0x30313233343536373839414243444546) let o := add(result, 0x20) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // If not in `[0-9A-Z-a-z-_.!~*'()]`. if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) { mstore8(o, 0x25) // '%'. mstore8(add(o, 1), mload(and(shr(4, c), 15))) mstore8(add(o, 2), mload(and(c, 15))) o := add(o, 3) continue } mstore8(o, c) o := add(o, 1) } mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Grab the free memory pointer. mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(result, 0) // Zeroize the length slot. mstore(add(result, 0x1f), packed) // Store the length and bytes. mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLen := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( or( // Load the length and the bytes of `a` and `b`. shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))), // `totalLen != 0 && totalLen < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLen, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { resultA := mload(0x40) // Grab the free memory pointer. resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the string. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } }
{ "optimizer": { "enabled": true, "runs": 1337 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"fakepool_buy","outputs":[{"internalType":"uint256","name":"tokensOut","type":"uint256"},{"internalType":"uint256","name":"p","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"fakepool_close","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"fakepool_create","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"ethOut","type":"bool"}],"name":"fakepool_quote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"fakepool_sell","outputs":[{"internalType":"uint256","name":"ethOut","type":"uint256"},{"internalType":"uint256","name":"p","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60808060405234610016576109ea908161001c8239f35b600080fdfe604060808152600436101561001357600080fd5b6000803560e01c80631a1109b714610323578063327dca72146102165780633960fa37146101845780634765f669146101405763fab021b71461005557600080fd5b3461013d578160031936011261013d5761006d610449565b6100b46024359161007c6108f6565b6001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b916001600160a01b038354161561013d575061011e9060038301610117815460028601928354906101106101086100f86100f260018c015486610487565b8961059b565b6101028987610487565b906105ae565b968794610487565b9055610464565b9055610892565b9061013161012b826105ce565b91610604565b82519182526020820152f35b80fd5b5090346101805760603660031901126101805761015b610449565b60443592831515840361013d57506020926101799160243590610494565b9051908152f35b5080fd5b50602036600319011261013d576101a461019c610449565b61007c6108f6565b906001600160a01b038254161561013d57506101bf34610892565b90600281016102088154936101d8600185015486610487565b94600385016102016101fa825498610102866101f48c8261059b565b92610487565b8098610464565b9055610487565b905561013161012b826105ce565b50903461018057606036600319011261018057610231610449565b60443567ffffffffffffffff80821161031f573660238301121561031f57816004013590811161031f573691016024011161031b57610179906020936102756108f6565b6001600160a01b036102b9836001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b92167fffffffffffffffffffffffff00000000000000000000000000000000000000008354161782557f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe3546001830155600282015560243560038201556105ce565b8280fd5b8480fd5b5090346101805760203660031901126101805761033e610449565b6103466108f6565b610382816001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b918051926080840184811067ffffffffffffffff821117610435579460609583526001600160a01b038254168552600361040f600184015495602088019687528883600287015496888b01978852015498019788526001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b828155826001820155826002820155015551925191519181519384526020840152820152f35b602486634e487b7160e01b81526041600452fd5b600435906001600160a01b038216820361045f57565b600080fd5b9190820391821161047157565b634e487b7160e01b600052601160045260246000fd5b9190820180921161047157565b6104d3909291926001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b9015610542578061010261053f936101f46105006003610506960154946001600282015491015490610487565b8261059b565b6103e861053861ffff7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8854168361059b565b0490610464565b90565b61010261057e61053f936103e861053861ffff7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8854168361059b565b6101f460036105966002860154600187015490610487565b940154825b8181029291811591840414171561047157565b81156105b8570490565b634e487b7160e01b600052601260045260246000fd5b6105e16002820154600183015490610487565b670de0b6b3a7640000908082029182040361047157600361053f920154906105ae565b60a090610610816105ce565b906001600160a01b0390817f88acb08f71068c878012515a2672f2b1a3f7940ce7bd383fbab30a631a76b77454166040938451958680937ffeaf968c00000000000000000000000000000000000000000000000000000000825260049889915afa801561088757600092839161080c575b506106ad7f88acb08f71068c878012515a2672f2b1a3f7940ce7bd383fbab30a631a76b7755442610464565b116107c9576402540be400918281029281840414901517156107b4576106fd916106d691610984565b7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8954610984565b7f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe454111561072c575b50505050565b541691303b1561045f578151927f214013ca0000000000000000000000000000000000000000000000000000000084528184015260008360248183305af180156107a95761077b575b80610726565b67ffffffffffffffff8311610794575052388080610775565b604190634e487b7160e01b6000525260246000fd5b82513d6000823e3d90fd5b601186634e487b7160e01b6000525260246000fd5b606486602087519162461bcd60e51b8352820152600f60248201527f7374616c652070726963656665656400000000000000000000000000000000006044820152fd5b92905060a03d8111610880575b601f8101601f1916840167ffffffffffffffff81118582101761086d5760a091859189528101031261013d575061084f8261096d565b506020820151610865608087850151940161096d565b509138610681565b60248360418b634e487b7160e01b835252fd5b503d610819565b85513d6000823e3d90fd5b61053f906103e86108c861ffff7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8854168361059b565b04907fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da86610110838254610487565b6001600160a01b037fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c13215416330361092957565b606460405162461bcd60e51b815260206004820152601f60248201527f4c69624469616d6f6e643a204d75737420626520746865206469616d6f6e64006044820152fd5b519069ffffffffffffffffffff8216820361045f57565b90806000190482116109a0575b670de0b6b3a764000091020490565b80156109915763bac65e5b6000526004601cfdfea2646970667358221220bd9b19e0c66307c9c4525c3a51ac22a643922d37acd969e88c3345971171d8c764736f6c63430008120033
Deployed Bytecode
0x604060808152600436101561001357600080fd5b6000803560e01c80631a1109b714610323578063327dca72146102165780633960fa37146101845780634765f669146101405763fab021b71461005557600080fd5b3461013d578160031936011261013d5761006d610449565b6100b46024359161007c6108f6565b6001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b916001600160a01b038354161561013d575061011e9060038301610117815460028601928354906101106101086100f86100f260018c015486610487565b8961059b565b6101028987610487565b906105ae565b968794610487565b9055610464565b9055610892565b9061013161012b826105ce565b91610604565b82519182526020820152f35b80fd5b5090346101805760603660031901126101805761015b610449565b60443592831515840361013d57506020926101799160243590610494565b9051908152f35b5080fd5b50602036600319011261013d576101a461019c610449565b61007c6108f6565b906001600160a01b038254161561013d57506101bf34610892565b90600281016102088154936101d8600185015486610487565b94600385016102016101fa825498610102866101f48c8261059b565b92610487565b8098610464565b9055610487565b905561013161012b826105ce565b50903461018057606036600319011261018057610231610449565b60443567ffffffffffffffff80821161031f573660238301121561031f57816004013590811161031f573691016024011161031b57610179906020936102756108f6565b6001600160a01b036102b9836001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b92167fffffffffffffffffffffffff00000000000000000000000000000000000000008354161782557f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe3546001830155600282015560243560038201556105ce565b8280fd5b8480fd5b5090346101805760203660031901126101805761033e610449565b6103466108f6565b610382816001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b918051926080840184811067ffffffffffffffff821117610435579460609583526001600160a01b038254168552600361040f600184015495602088019687528883600287015496888b01978852015498019788526001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b828155826001820155826002820155015551925191519181519384526020840152820152f35b602486634e487b7160e01b81526041600452fd5b600435906001600160a01b038216820361045f57565b600080fd5b9190820391821161047157565b634e487b7160e01b600052601160045260246000fd5b9190820180921161047157565b6104d3909291926001600160a01b03166000527f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe5602052604060002090565b9015610542578061010261053f936101f46105006003610506960154946001600282015491015490610487565b8261059b565b6103e861053861ffff7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8854168361059b565b0490610464565b90565b61010261057e61053f936103e861053861ffff7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8854168361059b565b6101f460036105966002860154600187015490610487565b940154825b8181029291811591840414171561047157565b81156105b8570490565b634e487b7160e01b600052601260045260246000fd5b6105e16002820154600183015490610487565b670de0b6b3a7640000908082029182040361047157600361053f920154906105ae565b60a090610610816105ce565b906001600160a01b0390817f88acb08f71068c878012515a2672f2b1a3f7940ce7bd383fbab30a631a76b77454166040938451958680937ffeaf968c00000000000000000000000000000000000000000000000000000000825260049889915afa801561088757600092839161080c575b506106ad7f88acb08f71068c878012515a2672f2b1a3f7940ce7bd383fbab30a631a76b7755442610464565b116107c9576402540be400918281029281840414901517156107b4576106fd916106d691610984565b7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8954610984565b7f916ab52dffd1db05d6a10f7578f4d548a96925978b2fcd1de633cf8ab832dbe454111561072c575b50505050565b541691303b1561045f578151927f214013ca0000000000000000000000000000000000000000000000000000000084528184015260008360248183305af180156107a95761077b575b80610726565b67ffffffffffffffff8311610794575052388080610775565b604190634e487b7160e01b6000525260246000fd5b82513d6000823e3d90fd5b601186634e487b7160e01b6000525260246000fd5b606486602087519162461bcd60e51b8352820152600f60248201527f7374616c652070726963656665656400000000000000000000000000000000006044820152fd5b92905060a03d8111610880575b601f8101601f1916840167ffffffffffffffff81118582101761086d5760a091859189528101031261013d575061084f8261096d565b506020820151610865608087850151940161096d565b509138610681565b60248360418b634e487b7160e01b835252fd5b503d610819565b85513d6000823e3d90fd5b61053f906103e86108c861ffff7fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da8854168361059b565b04907fb08236d4879334bece1965ab3a812fad8e40dec4929b65f11b873dfaf386da86610110838254610487565b6001600160a01b037fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c13215416330361092957565b606460405162461bcd60e51b815260206004820152601f60248201527f4c69624469616d6f6e643a204d75737420626520746865206469616d6f6e64006044820152fd5b519069ffffffffffffffffffff8216820361045f57565b90806000190482116109a0575b670de0b6b3a764000091020490565b80156109915763bac65e5b6000526004601cfdfea2646970667358221220bd9b19e0c66307c9c4525c3a51ac22a643922d37acd969e88c3345971171d8c764736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.