账户
0xac...d6f9
Fuck You!

Fuck You!

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.28+commit.7893614a
语言
Solidity
合同源代码
文件 1 的 46:512Math.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import {Panic} from "./Panic.sol";
import {UnsafeMath} from "./UnsafeMath.sol";

/*

WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING
  ***                                                                     ***
WARNING                     This code is unaudited                      WARNING
  ***                                                                     ***
WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING

*/

/// The type uint512 behaves as if it were declared as
///     struct uint512 {
///         uint256 hi;
///         uint256 lo;
///     }
/// However, returning `memory` references from internal functions is impossible
/// to do efficiently, especially when the functions are small and are called
/// frequently. Therefore, we assume direct control over memory allocation using
/// the functions `tmp()` and `alloc()` defined below. If you need to pass
/// 512-bit integers between contracts (generally a bad idea), the struct
/// `uint512_external` defined at the end of this file is provided for this
/// purpose and has exactly the definition you'd expect (as well as convenient
/// conversion functions).
///
/// MAKING A DECLARATION OF THE FOLLOWING FORM WILL CAUSE UNEXPECTED BEHAVIOR:
///     uint512 x;
/// INSTEAD OF DOING THAT, YOU MUST USE `alloc()`, LIKE THIS:
///     uint512 x = alloc();
/// IF YOU REALLY WANTED TO DO THAT (ADVANCED USAGE) THEN FOR CLARITY, WRITE THE
/// FOLLOWING:
///     uint512 x = tmp();
///
/// While user-defined arithmetic operations (i.e. +, -, *, %, /) are provided
/// for `uint512`, they are not gas-optimal, full-featured, or composable. You
/// will get a revert upon incorrect usage. Their primary usage is when a simple
/// arithmetic operation needs to be performed followed by a comparison (e.g. <,
/// >, ==, etc.) or conversion to a pair of `uint256`s (i.e. `.into()`). The use
/// of the user-defined arithmetic operations is not composable with the usage
/// of `tmp()`.
///
/// In general, correct usage of `uint512` requires always specifying the output
/// location of each operation. For each `o*` operation (mnemonic:
/// out-of-place), the first argument is the output location and the remaining
/// arguments are the input. For each `i*` operation (mnemonic: in-place), the
/// first argument is both input and output and the remaining arguments are
/// purely input. For each `ir*` operation (mnemonic: in-place reverse; only for
/// non-commutative operations), the semantics of the input arguments are
/// flipped (i.e. `irsub(foo, bar)` is semantically equivalent to `foo = bar -
/// foo`); the first argument is still the output location. Only `irsub`,
/// `irmod`, `irdiv`, `irmod`, and `irdiv` exist. Unless otherwise noted, the
/// return value of each function is the output location. This supports
/// chaining/pipeline/tacit-style programming.
///
/// All provided arithmetic operations behave as if they were inside an
/// `unchecked` block. We assume that because you're reaching for 512-bit math,
/// you have domain knowledge about the range of values that you will
/// encounter. Overflow causes truncation, not a revert. Division or modulo by
/// zero still causes a panic revert with code 18 (identical behavior to
/// "normal" unchecked arithmetic).
///
/// Three additional arithmetic operations are provided, bare `sub`, `mod`, and
/// `div`. These are provided for use when it is known that the result of the
/// operation will fit into 256 bits. This fact is not checked, but more
/// efficient algorithms are employed assuming this. The result is a `uint256`.
///
/// ## Full list of provided functions
///
/// Unless otherwise noted, all functions return `(uint512)`
///
/// ### Utility
///
/// * from(uint256)
/// * from(uint256,uint256) -- The EVM is big-endian. The most-significant word is first.
/// * from(uint512) -- performs a copy
/// * into() returns (uint256,uint256) -- Again, the most-significant word is first.
/// * toExternal(uint512) returns (uint512_external memory)
///
/// ### Comparison (all functions return `(bool)`)
///
/// * isZero(uint512)
/// * isMax(uint512)
/// * eq(uint512,uint256)
/// * eq(uint512,uint512)
/// * ne(uint512,uint256)
/// * ne(uint512,uint512)
/// * gt(uint512,uint256)
/// * gt(uint512,uint512)
/// * ge(uint512,uint256)
/// * ge(uint512,uint512)
/// * lt(uint512,uint256)
/// * lt(uint512,uint512)
/// * le(uint512,uint256)
/// * le(uint512,uint512)
///
/// ### Addition
///
/// * oadd(uint512,uint256,uint256) -- iadd(uint256,uint256) is not provided for somewhat obvious reasons
/// * oadd(uint512,uint512,uint256)
/// * iadd(uint512,uint256)
/// * oadd(uint512,uint512,uint512)
/// * iadd(uint512,uint512)
///
/// ### Subtraction
///
/// * sub(uint512,uint256) returns (uint256)
/// * sub(uint512,uint512) returns (uint256)
/// * osub(uint512,uint512,uint256)
/// * isub(uint512,uint256)
/// * osub(uint512,uint512,uint512)
/// * isub(uint512,uint512)
/// * irsub(uint512,uint512)
///
/// ### Multiplication
///
/// * omul(uint512,uint256,uint256)
/// * omul(uint512,uint512,uint256)
/// * imul(uint512,uint256)
/// * omul(uint512,uint512,uint512)
/// * imul(uint512,uint512)
///
/// ### Modulo
///
/// * mod(uint512,uint256) returns (uint256) -- mod(uint512,uint512) is not provided for less obvious reasons
/// * omod(uint512,uint512,uint512)
/// * imod(uint512,uint512)
/// * irmod(uint512,uint512)
///
/// ### Division
///
/// * div(uint512,uint256) returns (uint256)
/// * div(uint512,uint512) returns (uint256)
/// * odiv(uint512,uint512,uint256)
/// * idiv(uint512,uint256)
/// * odiv(uint512,uint512,uint512)
/// * idiv(uint512,uint512)
/// * irdiv(uint512,uint512)
///
/// ### Multi-division
///
/// * divMulti(uint512,uint512,uint256) returns (uint256,uint256) -- the last argument is the denominator
///
/// The implementation of other variants of multi-division is left as an
/// exercise for the reader.
type uint512 is bytes32;

function alloc() pure returns (uint512 r) {
    assembly ("memory-safe") {
        r := mload(0x40)
        mstore(0x40, add(0x40, r))
    }
}

function tmp() pure returns (uint512 r) {}

library Lib512MathAccessors {
    function from(uint512 r, uint256 x) internal pure returns (uint512 r_out) {
        assembly ("memory-safe") {
            mstore(r, 0x00)
            mstore(add(0x20, r), x)
            r_out := r
        }
    }

    // slither-disable-next-line naming-convention
    function from(uint512 r, uint256 x_hi, uint256 x_lo) internal pure returns (uint512 r_out) {
        assembly ("memory-safe") {
            mstore(r, x_hi)
            mstore(add(0x20, r), x_lo)
            r_out := r
        }
    }

    function from(uint512 r, uint512 x) internal pure returns (uint512 r_out) {
        assembly ("memory-safe") {
            // Paradoxically, using `mload` and `mstore` here (instead of
            // `mcopy`) produces more optimal code because it gives solc the
            // opportunity to optimize-out the use of memory entirely, in
            // typical usage. As a happy side effect, it also means that we
            // don't have to deal with Cancun hardfork compatibility issues.
            mstore(r, mload(x))
            mstore(add(0x20, r), mload(add(0x20, x)))
            r_out := r
        }
    }

    function into(uint512 x) internal pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            r_hi := mload(x)
            r_lo := mload(add(0x20, x))
        }
    }
}

using Lib512MathAccessors for uint512 global;

library Lib512MathComparisons {
    function isZero(uint512 x) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        assembly ("memory-safe") {
            r := iszero(or(x_hi, x_lo))
        }
    }

    function isMax(uint512 x) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        assembly ("memory-safe") {
            r := iszero(not(and(x_hi, x_lo)))
        }
    }

    function eq(uint512 x, uint256 y) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        assembly ("memory-safe") {
            r := and(iszero(x_hi), eq(x_lo, y))
        }
    }

    function gt(uint512 x, uint256 y) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        assembly ("memory-safe") {
            r := or(gt(x_hi, 0x00), gt(x_lo, y))
        }
    }

    function lt(uint512 x, uint256 y) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        assembly ("memory-safe") {
            r := and(iszero(x_hi), lt(x_lo, y))
        }
    }

    function ne(uint512 x, uint256 y) internal pure returns (bool) {
        return !eq(x, y);
    }

    function ge(uint512 x, uint256 y) internal pure returns (bool) {
        return !lt(x, y);
    }

    function le(uint512 x, uint256 y) internal pure returns (bool) {
        return !gt(x, y);
    }

    function eq(uint512 x, uint512 y) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 y_hi, uint256 y_lo) = y.into();
        assembly ("memory-safe") {
            r := and(eq(x_hi, y_hi), eq(x_lo, y_lo))
        }
    }

    function gt(uint512 x, uint512 y) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 y_hi, uint256 y_lo) = y.into();
        assembly ("memory-safe") {
            r := or(gt(x_hi, y_hi), and(eq(x_hi, y_hi), gt(x_lo, y_lo)))
        }
    }

    function lt(uint512 x, uint512 y) internal pure returns (bool r) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 y_hi, uint256 y_lo) = y.into();
        assembly ("memory-safe") {
            r := or(lt(x_hi, y_hi), and(eq(x_hi, y_hi), lt(x_lo, y_lo)))
        }
    }

    function ne(uint512 x, uint512 y) internal pure returns (bool) {
        return !eq(x, y);
    }

    function ge(uint512 x, uint512 y) internal pure returns (bool) {
        return !lt(x, y);
    }

    function le(uint512 x, uint512 y) internal pure returns (bool) {
        return !gt(x, y);
    }
}

using Lib512MathComparisons for uint512 global;

function __eq(uint512 x, uint512 y) pure returns (bool) {
    return x.eq(y);
}

function __gt(uint512 x, uint512 y) pure returns (bool) {
    return x.gt(y);
}

function __lt(uint512 x, uint512 y) pure returns (bool r) {
    return x.lt(y);
}

function __ne(uint512 x, uint512 y) pure returns (bool) {
    return x.ne(y);
}

function __ge(uint512 x, uint512 y) pure returns (bool) {
    return x.ge(y);
}

function __le(uint512 x, uint512 y) pure returns (bool) {
    return x.le(y);
}

using {__eq as ==, __gt as >, __lt as <, __ne as !=, __ge as >=, __le as <=} for uint512 global;

library Lib512MathArithmetic {
    using UnsafeMath for uint256;

    function oadd(uint512 r, uint256 x, uint256 y) internal pure returns (uint512) {
        uint256 r_hi;
        uint256 r_lo;
        assembly ("memory-safe") {
            r_lo := add(x, y)
            // `lt(r_lo, x)` indicates overflow in the lower addition. We can
            // add the bool directly to the integer to perform carry
            r_hi := lt(r_lo, x)
        }
        return r.from(r_hi, r_lo);
    }

    function oadd(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        uint256 r_hi;
        uint256 r_lo;
        assembly ("memory-safe") {
            r_lo := add(x_lo, y)
            // `lt(r_lo, x_lo)` indicates overflow in the lower
            // addition. Overflow in the high limb is simply ignored
            r_hi := add(x_hi, lt(r_lo, x_lo))
        }
        return r.from(r_hi, r_lo);
    }

    function iadd(uint512 r, uint256 y) internal pure returns (uint512) {
        return oadd(r, r, y);
    }

    function _add(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo)
        private
        pure
        returns (uint256 r_hi, uint256 r_lo)
    {
        assembly ("memory-safe") {
            r_lo := add(x_lo, y_lo)
            // `lt(r_lo, x_lo)` indicates overflow in the lower
            // addition. Overflow in the high limb is simply ignored.
            r_hi := add(add(x_hi, y_hi), lt(r_lo, x_lo))
        }
    }

    function oadd(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 y_hi, uint256 y_lo) = y.into();
        (uint256 r_hi, uint256 r_lo) = _add(x_hi, x_lo, y_hi, y_lo);
        return r.from(r_hi, r_lo);
    }

    function iadd(uint512 r, uint512 y) internal pure returns (uint512) {
        return oadd(r, r, y);
    }

    function _sub(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            r_lo := sub(x_lo, y)
            // `gt(r_lo, x_lo)` indicates underflow in the lower subtraction. We
            // can subtract the bool directly from the integer to perform carry.
            r_hi := sub(x_hi, gt(r_lo, x_lo))
        }
    }

    function osub(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 r_hi, uint256 r_lo) = _sub(x_hi, x_lo, y);
        return r.from(r_hi, r_lo);
    }

    function isub(uint512 r, uint256 y) internal pure returns (uint512) {
        return osub(r, r, y);
    }

    function _sub(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo)
        private
        pure
        returns (uint256 r_hi, uint256 r_lo)
    {
        assembly ("memory-safe") {
            r_lo := sub(x_lo, y_lo)
            // `gt(r_lo, x_lo)` indicates underflow in the lower subtraction.
            // Underflow in the high limb is simply ignored.
            r_hi := sub(sub(x_hi, y_hi), gt(r_lo, x_lo))
        }
    }

    function osub(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 y_hi, uint256 y_lo) = y.into();
        (uint256 r_hi, uint256 r_lo) = _sub(x_hi, x_lo, y_hi, y_lo);
        return r.from(r_hi, r_lo);
    }

    function isub(uint512 r, uint512 y) internal pure returns (uint512) {
        return osub(r, r, y);
    }

    function irsub(uint512 r, uint512 y) internal pure returns (uint512) {
        return osub(r, y, r);
    }

    function sub(uint512 x, uint256 y) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := sub(mload(add(0x20, x)), y)
        }
    }

    function sub(uint512 x, uint512 y) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := sub(mload(add(0x20, x)), mload(add(0x20, y)))
        }
    }

    //// The technique implemented in the following functions for multiplication is
    //// adapted from Remco Bloemen's work https://2π.com/17/full-mul/ .
    //// The original code was released under the MIT license.

    function _mul(uint256 x, uint256 y) private pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            let mm := mulmod(x, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            r_lo := mul(x, y)
            r_hi := sub(sub(mm, r_lo), lt(mm, r_lo))
        }
    }

    function omul(uint512 r, uint256 x, uint256 y) internal pure returns (uint512) {
        (uint256 r_hi, uint256 r_lo) = _mul(x, y);
        return r.from(r_hi, r_lo);
    }

    function _mul(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            let mm := mulmod(x_lo, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            r_lo := mul(x_lo, y)
            r_hi := add(mul(x_hi, y), sub(sub(mm, r_lo), lt(mm, r_lo)))
        }
    }

    function omul(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, y);
        return r.from(r_hi, r_lo);
    }

    function imul(uint512 r, uint256 y) internal pure returns (uint512) {
        return omul(r, r, y);
    }

    function _mul(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo)
        private
        pure
        returns (uint256 r_hi, uint256 r_lo)
    {
        assembly ("memory-safe") {
            let mm := mulmod(x_lo, y_lo, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            r_lo := mul(x_lo, y_lo)
            r_hi := add(add(mul(x_hi, y_lo), mul(x_lo, y_hi)), sub(sub(mm, r_lo), lt(mm, r_lo)))
        }
    }

    function omul(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) {
        (uint256 x_hi, uint256 x_lo) = x.into();
        (uint256 y_hi, uint256 y_lo) = y.into();
        (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, y_hi, y_lo);
        return r.from(r_hi, r_lo);
    }

    function imul(uint512 r, uint512 y) internal pure returns (uint512) {
        return omul(r, r, y);
    }

    function mod(uint512 n, uint256 d) internal pure returns (uint256 r) {
        if (d == 0) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        (uint256 n_hi, uint256 n_lo) = n.into();
        assembly ("memory-safe") {
            r := mulmod(n_hi, sub(0x00, d), d)
            r := addmod(n_lo, r, d)
        }
    }

    /// Multiply 512-bit [x_hi x_lo] by 256-bit [y] giving 768-bit [r_ex r_hi r_lo]
    function _mul768(uint256 x_hi, uint256 x_lo, uint256 y)
        private
        pure
        returns (uint256 r_ex, uint256 r_hi, uint256 r_lo)
    {
        assembly ("memory-safe") {
            let mm0 := mulmod(x_lo, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            r_lo := mul(x_lo, y)
            let mm1 := mulmod(x_hi, y, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            let r_partial := mul(x_hi, y)
            r_ex := sub(sub(mm1, r_partial), lt(mm1, r_partial))

            r_hi := add(r_partial, sub(sub(mm0, r_lo), lt(mm0, r_lo)))
            // `lt(r_hi, r_partial)` indicates overflow in the addition to form
            // `r_hi`. We can add the bool directly to the integer to perform
            // carry.
            r_ex := add(r_ex, lt(r_hi, r_partial))
        }
    }

    //// The technique implemented in the following functions for division is
    //// adapted from Remco Bloemen's work https://2π.com/21/muldiv/ .
    //// The original code was released under the MIT license.

    function _roundDown(uint256 x_hi, uint256 x_lo, uint256 d) private pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            // Get the remainder [n_hi n_lo] % d (< 2²⁵⁶ - 1)
            // 2**256 % d = -d % 2**256 % d -- https://2π.com/17/512-bit-division/
            let rem := mulmod(x_hi, sub(0x00, d), d)
            rem := addmod(x_lo, rem, d)

            r_hi := sub(x_hi, gt(rem, x_lo))
            r_lo := sub(x_lo, rem)
        }
    }

    function _twos(uint256 x) private pure returns (uint256 twos, uint256 twosInv) {
        assembly ("memory-safe") {
            // Compute largest power of two divisor of `x`. `x` is nonzero, so
            // this is always ≥ 1.
            twos := and(sub(0x00, x), x)

            // To shift up (bits from the high limb into the low limb) we need
            // the inverse of `twos`. That is, 2²⁵⁶ / twos.
            //     2**256 / twos = -twos % 2**256 / twos + 1 -- https://2π.com/17/512-bit-division/
            // If `twos` is zero, then `twosInv` becomes one (not possible)
            twosInv := add(div(sub(0x00, twos), twos), 0x01)
        }
    }

    function _toOdd256(uint256 x_hi, uint256 x_lo, uint256 y) private pure returns (uint256 rx_lo, uint256 ry) {
        // Factor powers of two out of `y` and apply the same shift to [x_hi
        // x_lo]
        (uint256 twos, uint256 twosInv) = _twos(y);

        assembly ("memory-safe") {
            // Divide `y` by the power of two
            ry := div(y, twos)

            // Divide [x_hi x_lo] by the power of two
            rx_lo := or(div(x_lo, twos), mul(x_hi, twosInv))
        }
    }

    function _toOdd256Multi(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo, uint256 d)
        private
        pure
        returns (uint256 rx_lo, uint256 ry_lo, uint256 rd)
    {
        // Factor powers of two out of `d` and apply the same shift to [x_hi
        // x_lo] and [y_hi y_lo]
        (uint256 twos, uint256 twosInv) = _twos(d);

        assembly ("memory-safe") {
            // Divide `d` by the power of two
            rd := div(d, twos)

            // Divide [x_hi x_lo] by the power of two
            rx_lo := or(div(x_lo, twos), mul(x_hi, twosInv))

            // Divide [y_hi y_lo] by the power of two
            ry_lo := or(div(y_lo, twos), mul(y_hi, twosInv))
        }
    }

    function _toOdd512(uint256 x_hi, uint256 x_lo, uint256 y)
        private
        pure
        returns (uint256 rx_hi, uint256 rx_lo, uint256 ry)
    {
        // Factor powers of two out of `y` and apply the same shift to [x_hi
        // x_lo]
        (uint256 twos, uint256 twosInv) = _twos(y);

        assembly ("memory-safe") {
            // Divide `y` by the power of two
            ry := div(y, twos)

            // Divide [x_hi x_lo] by the power of two
            rx_hi := div(x_hi, twos)
            rx_lo := or(div(x_lo, twos), mul(x_hi, twosInv))
        }
    }

    function _invert256(uint256 d) private pure returns (uint256 inv) {
        assembly ("memory-safe") {
            // Invert `d` mod 2²⁵⁶ -- https://2π.com/18/multiplitcative-inverses/
            // `d` is an odd number (from _toOdd*). It has an inverse modulo
            // 2²⁵⁶ such that d * inv ≡ 1 mod 2²⁵⁶.
            // We use Newton-Raphson iterations compute inv. Thanks to Hensel's
            // lifting lemma, this also works in modular arithmetic, doubling
            // the correct bits in each step. The Newton-Raphson-Hensel step is:
            //    inv_{n+1} = inv_n * (2 - d*inv_n) % 2**256

            // To kick off Newton-Raphson-Hensel iterations, we start with a
            // seed of the inverse that is correct correct for four bits.
            //     d * inv ≡ 1 mod 2⁴
            inv := xor(mul(0x03, d), 0x02)

            // Each Newton-Raphson-Hensel step doubles the number of correct
            // bits in `inv`. After 6 iterations, full convergence is
            // guaranteed.
            inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2⁸
            inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2¹⁶
            inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2³²
            inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2⁶⁴
            inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2¹²⁸
            inv := mul(inv, sub(0x02, mul(d, inv))) // inverse mod 2²⁵⁶
        }
    }

    function _invert512(uint256 d) private pure returns (uint256 inv_hi, uint256 inv_lo) {
        // First, we get the inverse of `d` mod 2²⁵⁶
        inv_lo = _invert256(d);

        // To extend this to the inverse mod 2⁵¹², we perform a more elaborate
        // 7th Newton-Raphson-Hensel iteration with 512 bits of precision.

        // tmp = d * inv_lo % 2**512
        (uint256 tmp_hi, uint256 tmp_lo) = _mul(d, inv_lo);
        // tmp = 2 - tmp % 2**512
        (tmp_hi, tmp_lo) = _sub(0, 2, tmp_hi, tmp_lo);

        assembly ("memory-safe") {
            // inv_hi = inv_lo * tmp / 2**256 % 2**256
            let mm := mulmod(inv_lo, tmp_lo, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            inv_hi := add(mul(inv_lo, tmp_hi), sub(sub(mm, inv_lo), lt(mm, inv_lo)))
        }
    }

    function div(uint512 n, uint256 d) internal pure returns (uint256) {
        if (d == 0) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        (uint256 n_hi, uint256 n_lo) = n.into();
        if (n_hi == 0) {
            return n_lo.unsafeDiv(d);
        }

        // Round the numerator down to a multiple of the denominator. This makes
        // the division exact without affecting the result.
        (n_hi, n_lo) = _roundDown(n_hi, n_lo, d);

        // Make `d` odd so that it has a multiplicative inverse mod 2²⁵⁶
        // After this we can discard `n_hi` because our result is only 256 bits
        (n_lo, d) = _toOdd256(n_hi, n_lo, d);

        // We perform division by multiplying by the multiplicative inverse of
        // the denominator mod 2²⁵⁶. Since `d` is odd, this inverse
        // exists. Compute that inverse
        d = _invert256(d);

        unchecked {
            // Because the division is now exact (we rounded `n` down to a
            // multiple of `d`), we perform it by multiplying with the modular
            // inverse of the denominator. This is the correct result mod 2²⁵⁶.
            return n_lo * d;
        }
    }

    function divMulti(uint512 n0, uint512 n1, uint256 d) internal pure returns (uint256, uint256) {
        if (d == 0) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        (uint256 n0_hi, uint256 n0_lo) = n0.into();
        (uint256 n1_hi, uint256 n1_lo) = n1.into();
        {
            bool condition;
            assembly ("memory-safe") {
                condition := iszero(or(n0_hi, n1_hi))
            }
            if (condition) {
                return (n0_lo.unsafeDiv(d), n1_lo.unsafeDiv(d));
            }
        }

        // Round the numerators down to multiples of the denominator. This makes
        // division exact without affecting the result.
        (n0_hi, n0_lo) = _roundDown(n0_hi, n0_lo, d);
        (n1_hi, n1_lo) = _roundDown(n1_hi, n1_lo, d);

        // Make `d` odd so that it has a multiplicative inverse mod 2²⁵⁶ After
        // this we can discard `n0_hi` and `n1_hi` because our results are only
        // 256 bits
        (n0_lo, n1_lo, d) = _toOdd256Multi(n0_hi, n0_lo, n1_hi, n1_lo, d);

        // We perform division by multiplying by the multiplicative inverse of
        // the denominator mod 2²⁵⁶. Since `d` is odd, this inverse
        // exists. Compute that inverse
        d = _invert256(d);

        unchecked {
            // Because the divisions are now exact (we rounded `n0` and `n1`
            // down to multiples of `d`), we perform them by multiplying with
            // the modular inverse of the denominator. These are the correct
            // results mod 2²⁵⁶.
            return (n0_lo * d, n1_lo * d);
        }
    }

    function _gt(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (bool r) {
        assembly ("memory-safe") {
            r := or(gt(x_hi, y_hi), and(eq(x_hi, y_hi), gt(x_lo, y_lo)))
        }
    }

    function odiv(uint512 r, uint512 x, uint256 y) internal pure returns (uint512) {
        if (y == 0) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        (uint256 x_hi, uint256 x_lo) = x.into();
        if (x_hi == 0) {
            return r.from(0, x_lo.unsafeDiv(y));
        }

        // Round the numerator down to a multiple of the denominator. This makes
        // the division exact without affecting the result.
        (x_hi, x_lo) = _roundDown(x_hi, x_lo, y);

        // Make `y` odd so that it has a multiplicative inverse mod 2⁵¹²
        (x_hi, x_lo, y) = _toOdd512(x_hi, x_lo, y);

        // We perform division by multiplying by the multiplicative inverse of
        // the denominator mod 2⁵¹². Since `y` is odd, this inverse
        // exists. Compute that inverse
        (uint256 inv_hi, uint256 inv_lo) = _invert512(y);

        // Because the division is now exact (we rounded `x` down to a multiple
        // of `y`), we perform it by multiplying with the modular inverse of the
        // denominator.
        (uint256 r_hi, uint256 r_lo) = _mul(x_hi, x_lo, inv_hi, inv_lo);
        return r.from(r_hi, r_lo);
    }

    function idiv(uint512 r, uint256 y) internal pure returns (uint512) {
        return odiv(r, r, y);
    }

    function _gt(uint256 x_ex, uint256 x_hi, uint256 x_lo, uint256 y_ex, uint256 y_hi, uint256 y_lo)
        private
        pure
        returns (bool r)
    {
        assembly ("memory-safe") {
            r :=
                or(
                    or(gt(x_ex, y_ex), and(eq(x_ex, y_ex), gt(x_hi, y_hi))),
                    and(and(eq(x_ex, y_ex), eq(x_hi, y_hi)), gt(x_lo, y_lo))
                )
        }
    }

    /// The technique implemented in the following helper function for Knuth
    /// Algorithm D (a modification of the citation further below) is adapted
    /// from ridiculous fish's (aka corydoras) work
    /// https://ridiculousfish.com/blog/posts/labor-of-division-episode-iv.html
    /// and
    /// https://ridiculousfish.com/blog/posts/labor-of-division-episode-v.html .

    function _correctQ(uint256 q, uint256 r, uint256 x_next, uint256 y_next, uint256 y_whole)
        private
        pure
        returns (uint256 q_out)
    {
        assembly ("memory-safe") {
            let c1 := mul(q, y_next)
            let c2 := or(shl(0x80, r), x_next)
            q_out := sub(q, shl(gt(sub(c1, c2), y_whole), gt(c1, c2)))
        }
    }

    /// The technique implemented in the following function for division is
    /// adapted from Donald Knuth, The Art of Computer Programming (TAOCP)
    /// Volume 2, Section 4.3.1, Algorithm D.

    function _algorithmD(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo) private pure returns (uint256 q) {
        // We treat `x` and `y` each as ≤4-limb bigints where each limb is half
        // a machine word (128 bits). This lets us perform 2-limb ÷ 1-limb
        // divisions as a single operation (`div`) as required by Algorithm
        // D. It also simplifies/optimizes some of the multiplications.

        if (y_hi >> 128 != 0) {
            // y is 4 limbs, x is 4 limbs, q is 1 limb

            // Normalize. Ensure the uppermost limb of y ≥ 2¹²⁷ (equivalently
            // y_hi >= 2**255). This is step D1 of Algorithm D
            // The author's copy of TAOCP (3rd edition) states to set `d = (2 **
            // 128 - 1) // y_hi`, however this is incorrect. Setting `d` in this
            // fashion may result in overflow in the subsequent `_mul`. Setting
            // `d` as implemented below still satisfies the postcondition (`y_hi
            // >> 128 >= 1 << 127`) but never results in overflow.
            uint256 d = uint256(1 << 128).unsafeDiv((y_hi >> 128).unsafeInc());
            uint256 x_ex;
            (x_ex, x_hi, x_lo) = _mul768(x_hi, x_lo, d);
            (y_hi, y_lo) = _mul(y_hi, y_lo, d);

            // `n_approx` is the 2 most-significant limbs of x, after
            // normalization
            uint256 n_approx = (x_ex << 128) | (x_hi >> 128);
            // `d_approx` is the most significant limb of y, after normalization
            uint256 d_approx = y_hi >> 128;
            // Normalization ensures that result of this division is an
            // approximation of the most significant (and only) limb of the
            // quotient and is too high by at most 3. This is the "Calculate
            // q-hat" (D3) step of Algorithm D. (did you know that U+0302,
            // COMBINING CIRCUMFLEX ACCENT cannot be combined with q? shameful)
            q = n_approx.unsafeDiv(d_approx);
            uint256 r_hat = n_approx.unsafeMod(d_approx);

            // The process of `_correctQ` subtracts up to 2 from `q`, to make it
            // more accurate. This is still part of the "Calculate q-hat" (D3)
            // step of Algorithm D.
            q = _correctQ(q, r_hat, x_hi & type(uint128).max, y_hi & type(uint128).max, y_hi);

            // This final, low-probability, computationally-expensive correction
            // conditionally subtracts 1 from `q` to make it exactly the
            // most-significant limb of the quotient. This is the "Multiply and
            // subtract" (D4), "Test remainder" (D5), and "Add back" (D6) steps
            // of Algorithm D, with substantial shortcutting
            {
                (uint256 tmp_ex, uint256 tmp_hi, uint256 tmp_lo) = _mul768(y_hi, y_lo, q);
                bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo);
                assembly ("memory-safe") {
                    q := sub(q, neg)
                }
            }
        } else {
            // y is 3 limbs

            // Normalize. Ensure the most significant limb of y ≥ 2¹²⁷ (step D1)
            // See above comment about the error in TAOCP.
            uint256 d = uint256(1 << 128).unsafeDiv(y_hi.unsafeInc());
            (y_hi, y_lo) = _mul(y_hi, y_lo, d);
            // `y_next` is the second-most-significant, nonzero, normalized limb
            // of y
            uint256 y_next = y_lo >> 128;
            // `y_whole` is the 2 most-significant, nonzero, normalized limbs of
            // y
            uint256 y_whole = (y_hi << 128) | y_next;

            if (x_hi >> 128 != 0) {
                // x is 4 limbs, q is 2 limbs

                // Finish normalizing (step D1)
                uint256 x_ex;
                (x_ex, x_hi, x_lo) = _mul768(x_hi, x_lo, d);

                uint256 n_approx = (x_ex << 128) | (x_hi >> 128);
                // As before, `q_hat` is the most significant limb of the
                // quotient and too high by at most 3 (step D3)
                uint256 q_hat = n_approx.unsafeDiv(y_hi);
                uint256 r_hat = n_approx.unsafeMod(y_hi);

                // Subtract up to 2 from `q_hat`, improving our estimate (step
                // D3)
                q_hat = _correctQ(q_hat, r_hat, x_hi & type(uint128).max, y_next, y_whole);
                q = q_hat << 128;

                {
                    // "Multiply and subtract" (D4) step of Algorithm D
                    (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat);
                    uint256 tmp_ex = tmp_hi >> 128;
                    tmp_hi = (tmp_hi << 128) | (tmp_lo >> 128);
                    tmp_lo <<= 128;

                    // "Test remainder" (D5) step of Algorithm D
                    bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo);
                    // Finish step D4
                    (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo);

                    // "Add back" (D6) step of Algorithm D
                    if (neg) {
                        // This branch is quite rare, so it's gas-advantageous
                        // to actually branch and usually skip the costly `_add`
                        unchecked {
                            q -= 1 << 128;
                        }
                        (x_hi, x_lo) = _add(x_hi, x_lo, y_whole, y_lo << 128);
                    }
                }
                // `x_ex` is now zero (implicitly)

                // Run another loop (steps D3 through D6) of Algorithm D to get
                // the lower limb of the quotient
                q_hat = x_hi.unsafeDiv(y_hi);
                r_hat = x_hi.unsafeMod(y_hi);

                q_hat = _correctQ(q_hat, r_hat, x_lo >> 128, y_next, y_whole);

                {
                    (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat);
                    bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo);
                    assembly ("memory-safe") {
                        q_hat := sub(q_hat, neg)
                    }
                }

                q |= q_hat;
            } else {
                // x is 3 limbs, q is 1 limb

                // Finish normalizing (step D1)
                (x_hi, x_lo) = _mul(x_hi, x_lo, d);

                // `q` is the most significant (and only) limb of the quotient
                // and too high by at most 3 (step D3)
                q = x_hi.unsafeDiv(y_hi);
                uint256 r_hat = x_hi.unsafeMod(y_hi);

                // Subtract up to 2 from `q`, improving our estimate (step D3)
                q = _correctQ(q, r_hat, x_lo >> 128, y_next, y_whole);

                // Subtract up to 1 from `q` to make it exact (steps D4 through
                // D6)
                {
                    (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q);
                    bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo);
                    assembly ("memory-safe") {
                        q := sub(q, neg)
                    }
                }
            }
        }
        // All other cases are handled by the checks that y ≥ 2²⁵⁶ (equivalently
        // y_hi != 0) and that x ≥ y
    }

    /// Modified from Solady (https://github.com/Vectorized/solady/blob/a3d6a974f9c9f00dcd95b235619a209a63c61d94/src/utils/LibBit.sol#L33-L45)
    /// The original code was released under the MIT license.
    function _clzLower(uint256 x) private pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := shl(0x06, lt(0xffffffffffffffff, x))
            r := or(r, shl(0x05, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(0x04, lt(0xffff, shr(r, x))))
            r := or(r, shl(0x03, lt(0xff, shr(r, x))))
            // We use a 5-bit deBruijn Sequence to convert `x`'s 8
            // most-significant bits into an index. We then index the lookup
            // table (bytewise) by the deBruijn symbol to obtain the bitwise
            // inverse of its logarithm.
            // slither-disable-next-line incorrect-shift
            r :=
                xor(
                    r,
                    byte(
                        and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                        0x7879797a797d7a7b797d7c7d7a7b7c7e797a7d7a7c7c7b7e7a7a7c7b7f7f7f7f
                    )
                )
        }
    }

    function _clzUpper(uint256 x) private pure returns (uint256) {
        return _clzLower(x >> 128);
    }

    function _shl(uint256 x_hi, uint256 x_lo, uint256 s) private pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            r_hi := or(shl(s, x_hi), shr(sub(0x100, s), x_lo))
            r_lo := shl(s, x_lo)
        }
    }

    function _shl768(uint256 x_hi, uint256 x_lo, uint256 s)
        private
        pure
        returns (uint256 r_ex, uint256 r_hi, uint256 r_lo)
    {
        assembly ("memory-safe") {
            let neg_s := sub(0x100, s)
            r_ex := shr(neg_s, x_hi)
            r_hi := or(shl(s, x_hi), shr(neg_s, x_lo))
            r_lo := shl(s, x_lo)
        }
    }

    function _shr(uint256 x_hi, uint256 x_lo, uint256 s) private pure returns (uint256 r_hi, uint256 r_lo) {
        assembly ("memory-safe") {
            r_hi := shr(s, x_hi)
            r_lo := or(shl(sub(0x100, s), x_hi), shr(s, x_lo))
        }
    }

    // This function is a different modification of Knuth's Algorithm D. In this
    // case, we're only interested in the (normalized) remainder instead of the
    // quotient. We also substitute the normalization by division for
    // normalization by shifting because it makes un-normalization more
    // gas-efficient.

    function _algorithmDRemainder(uint256 x_hi, uint256 x_lo, uint256 y_hi, uint256 y_lo)
        private
        pure
        returns (uint256, uint256)
    {
        // We treat `x` and `y` each as ≤4-limb bigints where each limb is half
        // a machine word (128 bits). This lets us perform 2-limb ÷ 1-limb
        // divisions as a single operation (`div`) as required by Algorithm D.

        uint256 s;
        if (y_hi >> 128 != 0) {
            // y is 4 limbs, x is 4 limbs

            // Normalize. Ensure the uppermost limb of y ≥ 2¹²⁷ (equivalently
            // y_hi >= 2**255). This is step D1 of Algorithm D. Unlike the
            // preceeding implementation of Algorithm D, we use a binary shift
            // instead of a multiply to normalize. This performs a costly "count
            // leading zeroes" operation, but it lets us transform an
            // even-more-costly division-by-inversion operation later into a
            // simple shift. This still ultimately satisfies the postcondition
            // (y_hi >> 128 >= 1 << 127) without overflowing.
            s = _clzUpper(y_hi);
            uint256 x_ex;
            (x_ex, x_hi, x_lo) = _shl768(x_hi, x_lo, s);
            (y_hi, y_lo) = _shl(y_hi, y_lo, s);

            // `n_approx` is the 2 most-significant limbs of x, after
            // normalization
            uint256 n_approx = (x_ex << 128) | (x_hi >> 128); // TODO: this can probably be optimized (combined with `_shl`)
            // `d_approx` is the most significant limb of y, after normalization
            uint256 d_approx = y_hi >> 128;
            // Normalization ensures that result of this division is an
            // approximation of the most significant (and only) limb of the
            // quotient and is too high by at most 3. This is the "Calculate
            // q-hat" (D3) step of Algorithm D. (did you know that U+0302,
            // COMBINING CIRCUMFLEX ACCENT cannot be combined with q? shameful)
            uint256 q_hat = n_approx.unsafeDiv(d_approx);
            uint256 r_hat = n_approx.unsafeMod(d_approx);

            // The process of `_correctQ` subtracts up to 2 from `q_hat`, to
            // make it more accurate. This is still part of the "Calculate
            // q-hat" (D3) step of Algorithm D.
            q_hat = _correctQ(q_hat, r_hat, x_hi & type(uint128).max, y_hi & type(uint128).max, y_hi);

            {
                // This penultimate correction subtracts q-hat × y from x to
                // obtain the normalized remainder. This is the "Multiply and
                // subtract" (D4) and "Test remainder" (D5) steps of Algorithm
                // D, with some shortcutting
                (uint256 tmp_ex, uint256 tmp_hi, uint256 tmp_lo) = _mul768(y_hi, y_lo, q_hat);
                bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo);
                (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo);
                // `x_ex` is now implicitly zero (or signals a carry that we
                // will clear in the next step)

                // Because `q_hat` may be too high by 1, we have to detect
                // underflow from the previous step and correct it. This is the
                // "Add back" (D6) step of Algorithm D
                if (neg) {
                    (x_hi, x_lo) = _add(x_hi, x_lo, y_hi, y_lo);
                }
            }
        } else {
            // y is 3 limbs

            // Normalize. Ensure the most significant limb of y ≥ 2¹²⁷ (step D1)
            // See above comment about the use of a shift instead of division.
            s = _clzLower(y_hi);
            (y_hi, y_lo) = _shl(y_hi, y_lo, s);
            // `y_next` is the second-most-significant, nonzero, normalized limb
            // of y
            uint256 y_next = y_lo >> 128; // TODO: this can probably be optimized (combined with `_shl`)
            // `y_whole` is the 2 most-significant, nonzero, normalized limbs of
            // y
            uint256 y_whole = (y_hi << 128) | y_next; // TODO: this can probably be optimized (combined with `_shl`)

            if (x_hi >> 128 != 0) {
                // x is 4 limbs; we have to run 2 iterations of Algorithm D to
                // fully divide out by y

                // Finish normalizing (step D1)
                uint256 x_ex;
                (x_ex, x_hi, x_lo) = _shl768(x_hi, x_lo, s);

                uint256 n_approx = (x_ex << 128) | (x_hi >> 128); // TODO: this can probably be optimized (combined with `_shl768`)
                // As before, `q_hat` is the most significant limb of the
                // quotient and too high by at most 3 (step D3)
                uint256 q_hat = n_approx.unsafeDiv(y_hi);
                uint256 r_hat = n_approx.unsafeMod(y_hi);

                // Subtract up to 2 from `q_hat`, improving our estimate (step
                // D3)
                q_hat = _correctQ(q_hat, r_hat, x_hi & type(uint128).max, y_next, y_whole);

                // Subtract up to 1 from q-hat to make it exactly the
                // most-significant limb of the quotient and subtract q-hat × y
                // from x to clear the most-significant limb of x.
                {
                    // "Multiply and subtract" (D4) step of Algorithm D
                    (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat);
                    uint256 tmp_ex = tmp_hi >> 128;
                    tmp_hi = (tmp_hi << 128) | (tmp_lo >> 128);
                    tmp_lo <<= 128;

                    // "Test remainder" (D5) step of Algorithm D
                    bool neg = _gt(tmp_ex, tmp_hi, tmp_lo, x_ex, x_hi, x_lo);
                    // Finish step D4
                    (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo);

                    // "Add back" (D6) step of Algorithm D. We implicitly
                    // subtract 1 from `q_hat`, but elide explicitly
                    // representing that because `q_hat` is no longer needed.
                    if (neg) {
                        // This branch is quite rare, so it's gas-advantageous
                        // to actually branch and usually skip the costly `_add`
                        (x_hi, x_lo) = _add(x_hi, x_lo, y_whole, y_lo << 128);
                    }
                }
                // `x_ex` is now zero (implicitly)
                // [x_hi x_lo] now represents the partial, normalized remainder.

                // Run another loop (steps D3 through D6) of Algorithm D to get
                // the lower limb of the quotient
                // Step D3
                q_hat = x_hi.unsafeDiv(y_hi);
                r_hat = x_hi.unsafeMod(y_hi);

                // Step D3
                q_hat = _correctQ(q_hat, r_hat, x_lo >> 128, y_next, y_whole);

                // Again, implicitly correct q-hat to make it exactly the
                // least-significant limb of the quotient. Subtract q-hat × y
                // from x to obtain the normalized remainder.
                {
                    // Steps D4 and D5
                    (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat);
                    bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo);
                    (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo);

                    // Step D6
                    if (neg) {
                        (x_hi, x_lo) = _add(x_hi, x_lo, y_hi, y_lo);
                    }
                }
            } else {
                // x is 3 limbs

                // Finish normalizing (step D1)
                (x_hi, x_lo) = _shl(x_hi, x_lo, s);

                // `q_hat` is the most significant (and only) limb of the
                // quotient and too high by at most 3 (step D3)
                uint256 q_hat = x_hi.unsafeDiv(y_hi);
                uint256 r_hat = x_hi.unsafeMod(y_hi);

                // Subtract up to 2 from `q_hat`, improving our estimate (step
                // D3)
                q_hat = _correctQ(q_hat, r_hat, x_lo >> 128, y_next, y_whole);

                // Make `q_hat` exact (implicitly) and subtract q-hat × y from x
                // to obtain the normalized remainder. (steps D4 through D6)
                {
                    (uint256 tmp_hi, uint256 tmp_lo) = _mul(y_hi, y_lo, q_hat);
                    bool neg = _gt(tmp_hi, tmp_lo, x_hi, x_lo);
                    (x_hi, x_lo) = _sub(x_hi, x_lo, tmp_hi, tmp_lo);
                    if (neg) {
                        (x_hi, x_lo) = _add(x_hi, x_lo, y_hi, y_lo);
                    }
                }
            }
        }
        // All other cases are handled by the checks that y ≥ 2²⁵⁶ (equivalently
        // y_hi != 0) and that x ≥ y

        // The second-most-significant limb of normalized x is now zero
        // (equivalently x_hi < 2**128), but because the entire machine is not
        // guaranteed to be cleared, we can't optimize any further.

        // [x_hi x_lo] now represents remainder × 2ˢ (the normalized remainder);
        // we shift right by `s` (un-normalize) to obtain the result.
        return _shr(x_hi, x_lo, s);
    }

    function odiv(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) {
        (uint256 y_hi, uint256 y_lo) = y.into();
        if (y_hi == 0) {
            // This is the only case where we can have a 2-word quotient
            return odiv(r, x, y_lo);
        }
        (uint256 x_hi, uint256 x_lo) = x.into();
        if (y_lo == 0) {
            uint256 r_lo = x_hi.unsafeDiv(y_hi);
            return r.from(0, r_lo);
        }
        if (_gt(y_hi, y_lo, x_hi, x_lo)) {
            return r.from(0, 0);
        }

        // At this point, we know that both `x` and `y` are fully represented by
        // 2 words. There is no simpler representation for the problem. We must
        // use Knuth's Algorithm D.
        {
            uint256 r_lo = _algorithmD(x_hi, x_lo, y_hi, y_lo);
            return r.from(0, r_lo);
        }
    }

    function idiv(uint512 r, uint512 y) internal pure returns (uint512) {
        return odiv(r, r, y);
    }

    function irdiv(uint512 r, uint512 y) internal pure returns (uint512) {
        return odiv(r, y, r);
    }

    function div(uint512 x, uint512 y) internal pure returns (uint256) {
        (uint256 y_hi, uint256 y_lo) = y.into();
        if (y_hi == 0) {
            return div(x, y_lo);
        }
        (uint256 x_hi, uint256 x_lo) = x.into();
        if (y_lo == 0) {
            return x_hi.unsafeDiv(y_hi);
        }
        if (_gt(y_hi, y_lo, x_hi, x_lo)) {
            return 0;
        }

        // At this point, we know that both `x` and `y` are fully represented by
        // 2 words. There is no simpler representation for the problem. We must
        // use Knuth's Algorithm D.
        return _algorithmD(x_hi, x_lo, y_hi, y_lo);
    }

    function omod(uint512 r, uint512 x, uint512 y) internal pure returns (uint512) {
        (uint256 y_hi, uint256 y_lo) = y.into();
        if (y_hi == 0) {
            uint256 r_lo = mod(x, y_lo);
            return r.from(0, r_lo);
        }
        (uint256 x_hi, uint256 x_lo) = x.into();
        if (y_lo == 0) {
            uint256 r_hi = x_hi.unsafeMod(y_hi);
            return r.from(r_hi, x_lo);
        }
        if (_gt(y_hi, y_lo, x_hi, x_lo)) {
            return r.from(x_hi, x_lo);
        }

        // At this point, we know that both `x` and `y` are fully represented by
        // 2 words. There is no simpler representation for the problem. We must
        // use Knuth's Algorithm D.
        {
            (uint256 r_hi, uint256 r_lo) = _algorithmDRemainder(x_hi, x_lo, y_hi, y_lo);
            return r.from(r_hi, r_lo);
        }
    }

    function imod(uint512 r, uint512 y) internal pure returns (uint512) {
        return omod(r, r, y);
    }

    function irmod(uint512 r, uint512 y) internal pure returns (uint512) {
        return omod(r, y, r);
    }
}

using Lib512MathArithmetic for uint512 global;

library Lib512MathUserDefinedHelpers {
    function checkNull(uint512 x, uint512 y) internal pure {
        unchecked {
            if (uint256(uint512.unwrap(x)) * uint256(uint512.unwrap(y)) == 0) {
                Panic.panic(Panic.ASSERT_FAIL);
            }
        }
    }
}

function __add(uint512 x, uint512 y) pure returns (uint512 r) {
    Lib512MathUserDefinedHelpers.checkNull(x, y);
    r.oadd(x, y);
}

function __sub(uint512 x, uint512 y) pure returns (uint512 r) {
    Lib512MathUserDefinedHelpers.checkNull(x, y);
    r.osub(x, y);
}

function __mul(uint512 x, uint512 y) pure returns (uint512 r) {
    Lib512MathUserDefinedHelpers.checkNull(x, y);
    r.omul(x, y);
}

function __mod(uint512 x, uint512 y) pure returns (uint512 r) {
    Lib512MathUserDefinedHelpers.checkNull(x, y);
    r.omod(x, y);
}

function __div(uint512 x, uint512 y) pure returns (uint512 r) {
    Lib512MathUserDefinedHelpers.checkNull(x, y);
    r.odiv(x, y);
}

using {__add as +, __sub as -, __mul as *, __mod as %, __div as / } for uint512 global;

struct uint512_external {
    uint256 hi;
    uint256 lo;
}

library Lib512MathExternal {
    function from(uint512 r, uint512_external memory x) internal pure returns (uint512) {
        assembly ("memory-safe") {
            mstore(r, mload(x))
            mstore(add(0x20, r), mload(add(0x20, x)))
        }
        return r;
    }

    function into(uint512_external memory x) internal pure returns (uint512 r) {
        assembly ("memory-safe") {
            r := x
        }
    }

    function toExternal(uint512 x) internal pure returns (uint512_external memory r) {
        assembly ("memory-safe") {
            if iszero(eq(mload(0x40), add(0x40, r))) { revert(0x00, 0x00) }
            mstore(0x40, r)
            r := x
        }
    }
}

using Lib512MathExternal for uint512 global;
using Lib512MathExternal for uint512_external global;
合同源代码
文件 2 的 46:BasisPoints.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {UnsafeMath} from "../lib/UnsafeMath.sol";

/// This type is given as `uint256` for efficiency, but it is capped at 10_000
/// (14 bits).
type BasisPoints is uint256;

BasisPoints constant ZERO = BasisPoints.wrap(0);
BasisPoints constant BASIS = BasisPoints.wrap(10_000);

library BasisPointsArithmetic {
    using UnsafeMath for uint256;

    function mul(BasisPoints x, uint256 y) internal pure returns (BasisPoints) {
        unchecked {
            return BasisPoints.wrap(BasisPoints.unwrap(x) * y);
        }
    }

    function div(BasisPoints n, uint256 d) internal pure returns (BasisPoints) {
        return BasisPoints.wrap(BasisPoints.unwrap(n).unsafeDiv(d));
    }
}

using BasisPointsArithmetic for BasisPoints global;

function __sub(BasisPoints a, BasisPoints b) pure returns (BasisPoints) {
    unchecked {
        return BasisPoints.wrap(BasisPoints.unwrap(a) - BasisPoints.unwrap(b));
    }
}

using {__sub as -} for BasisPoints global;

function __eq(BasisPoints a, BasisPoints b) pure returns (bool) {
    return BasisPoints.unwrap(a) == BasisPoints.unwrap(b);
}

function __lt(BasisPoints a, BasisPoints b) pure returns (bool) {
    return BasisPoints.unwrap(a) < BasisPoints.unwrap(b);
}

function __gt(BasisPoints a, BasisPoints b) pure returns (bool) {
    return BasisPoints.unwrap(a) > BasisPoints.unwrap(b);
}

function __ne(BasisPoints a, BasisPoints b) pure returns (bool) {
    return BasisPoints.unwrap(a) != BasisPoints.unwrap(b);
}

function __le(BasisPoints a, BasisPoints b) pure returns (bool) {
    return BasisPoints.unwrap(a) <= BasisPoints.unwrap(b);
}

function __ge(BasisPoints a, BasisPoints b) pure returns (bool) {
    return BasisPoints.unwrap(a) >= BasisPoints.unwrap(b);
}

using {__eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __gt as >=} for BasisPoints global;

function scale(uint256 x, BasisPoints bp) pure returns (uint256) {
    unchecked {
        return x * BasisPoints.unwrap(bp) / BasisPoints.unwrap(BASIS);
    }
}

function scaleUp(uint256 x, BasisPoints bp) pure returns (uint256) {
    unchecked {
        return UnsafeMath.unsafeDivUp(x * BasisPoints.unwrap(bp), BasisPoints.unwrap(BASIS));
    }
}
合同源代码
文件 3 的 46:Checkpoints.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC5805} from "../interfaces/IERC5805.sol";

import {Settings} from "./Settings.sol";

import {Votes, ZERO as ZERO_VOTES} from "../types/Votes.sol";

struct Checkpoint {
    uint48 key;
    uint56 _pad;
    uint152 value;
}

struct Checkpoints {
    mapping(address => Checkpoint[]) each;
    Checkpoint[] total;
}

library LibCheckpoints {
    function transfer(Checkpoints storage checkpoints, address from, address to, Votes incr, Votes decr, uint48 clock)
        internal
    {
        if (from == address(0)) {
            if (to == address(0)) {
                return;
            }
            return _mint(checkpoints, to, incr, clock);
        }
        if (to == address(0)) {
            return _burn(checkpoints, from, decr, clock);
        }
        if (from == to) {
            if (incr > decr) {
                _mint(checkpoints, from, incr - decr, clock);
            } else if (incr < decr) {
                _burn(checkpoints, to, decr - incr, clock);
            }
            return;
        }
        if (incr > decr) {
            _mint(checkpoints, incr - decr, clock);
        } else if (incr < decr) {
            _burn(checkpoints, decr - incr, clock);
        }
        _burn(checkpoints.each[from], from, decr, clock);
        _mint(checkpoints.each[to], to, incr, clock);
    }

    function mint(Checkpoints storage checkpoints, address to, Votes incr, uint48 clock) internal {
        if (to == address(0)) {
            return;
        }
        return _mint(checkpoints, to, incr, clock);
    }

    function burn(Checkpoints storage checkpoints, address from, Votes decr, uint48 clock) internal {
        if (from == address(0)) {
            return;
        }
        return _burn(checkpoints, from, decr, clock);
    }

    function burn(Checkpoints storage checkpoints, address from0, Votes decr0, address from1, Votes decr1, uint48 clock)
        internal
    {
        if (from0 == address(0)) {
            return burn(checkpoints, from1, decr1, clock);
        }
        if (from1 == address(0)) {
            return _burn(checkpoints, from0, decr0, clock);
        }
        return _burn(checkpoints, from0, decr0, from1, decr1, clock);
    }

    function _load(Checkpoint[] storage arr)
        private
        view
        returns (Votes value, uint256 len, uint256 key, bytes32 slotValue)
    {
        assembly ("memory-safe") {
            slotValue := sload(arr.slot)
            key := shr(0xd0, slotValue)
            len := and(0xffffffffffffff, shr(0x98, slotValue))
            value := and(0x1ffffffffffffffffffffffffffffffffffff, slotValue)
        }
    }

    function _get(Checkpoint[] storage arr, uint256 clock) private returns (Votes value, uint256 len) {
        uint256 key;
        bytes32 slotValue;
        (value, len, key, slotValue) = _load(arr);
        assembly ("memory-safe") {
            if mul(key, gt(clock, key)) {
                mstore(0x00, arr.slot)
                sstore(
                    add(keccak256(0x00, 0x20), len),
                    and(0xffffffffffff0000000000000001ffffffffffffffffffffffffffffffffffff, slotValue)
                )
                len := add(0x01, len)
            }
        }
    }

    function _set(Checkpoint[] storage arr, uint256 clock, Votes value, uint256 len) private {
        assembly ("memory-safe") {
            sstore(
                arr.slot, or(shl(0x98, len), or(shl(0xd0, clock), and(0x1ffffffffffffffffffffffffffffffffffff, value)))
            )
        }
    }

    function _mintUpdateState(Checkpoints storage checkpoints, Votes incr, uint256 clock) private {
        Checkpoint[] storage arr = checkpoints.total;
        (Votes oldValue, uint256 len) = _get(arr, clock);
        _set(arr, clock, oldValue + incr, len);
    }

    function _mint(Checkpoints storage checkpoints, Votes incr, uint256 clock) private {
        if (incr == ZERO_VOTES) {
            return;
        }
        _mintUpdateState(checkpoints, incr, clock);
    }

    function _mintUpdateState(Checkpoint[] storage array, address to, Votes incr, uint256 clock) private {
        (Votes oldValue, uint256 len) = _get(array, clock);
        Votes newValue = oldValue + incr;
        _set(array, clock, newValue, len);
        emit IERC5805.DelegateVotesChanged(to, oldValue.toExternal(), newValue.toExternal());
    }

    function _mint(Checkpoint[] storage array, address to, Votes incr, uint256 clock) private {
        if (incr == ZERO_VOTES) {
            return;
        }
        _mintUpdateState(array, to, incr, clock);
    }

    function _mint(Checkpoints storage checkpoints, address to, Votes incr, uint256 clock) private {
        if (incr == ZERO_VOTES) {
            return;
        }
        _mintUpdateState(checkpoints, incr, clock);
        _mintUpdateState(checkpoints.each[to], to, incr, clock);
    }

    function _burnUpdateState(Checkpoints storage checkpoints, Votes decr, uint256 clock) private {
        Checkpoint[] storage arr = checkpoints.total;
        (Votes oldValue, uint256 len) = _get(arr, clock);
        _set(arr, clock, oldValue - decr, len);
    }

    function _burn(Checkpoints storage checkpoints, Votes decr, uint256 clock) private {
        if (decr == ZERO_VOTES) {
            return;
        }
        _burnUpdateState(checkpoints, decr, clock);
    }

    function _burnUpdateState(Checkpoint[] storage array, address from, Votes decr, uint256 clock) private {
        (Votes oldValue, uint256 len) = _get(array, clock);
        Votes newValue = oldValue - decr;
        _set(array, clock, newValue, len);
        emit IERC5805.DelegateVotesChanged(from, oldValue.toExternal(), newValue.toExternal());
    }

    function _burn(Checkpoint[] storage array, address from, Votes decr, uint256 clock) private {
        if (decr == ZERO_VOTES) {
            return;
        }
        _burnUpdateState(array, from, decr, clock);
    }

    function _burn(Checkpoints storage checkpoints, address from, Votes decr, uint256 clock) private {
        if (decr == ZERO_VOTES) {
            return;
        }
        _burnUpdateState(checkpoints, decr, clock);
        _burnUpdateState(checkpoints.each[from], from, decr, clock);
    }

    function _burn(
        Checkpoints storage checkpoints,
        address from0,
        Votes decr0,
        address from1,
        Votes decr1,
        uint256 clock
    ) private {
        Votes decr = decr0 + decr1;
        if (decr == ZERO_VOTES) {
            return;
        }
        _burnUpdateState(checkpoints, decr, clock);
        _burn(checkpoints.each[from0], from0, decr0, clock);
        _burn(checkpoints.each[from1], from1, decr1, clock);
    }

    function current(Checkpoints storage checkpoints, address account) internal view returns (Votes value) {
        Checkpoint[] storage each = checkpoints.each[account];
        assembly ("memory-safe") {
            value := and(0x1ffffffffffffffffffffffffffffffffffff, sload(each.slot))
        }
    }

    function currentTotal(Checkpoints storage checkpoints) internal view returns (Votes value) {
        Checkpoint[] storage total = checkpoints.total;
        assembly ("memory-safe") {
            value := and(0x1ffffffffffffffffffffffffffffffffffff, sload(total.slot))
        }
    }

    function _bisect(Checkpoint[] storage arr, uint256 query) private view returns (Votes value) {
        uint256 len;
        {
            uint256 key;
            (value, len, key,) = _load(arr);
            if (key <= query) {
                return value;
            }
        }
        uint256 initialWindow = Settings.BISECT_WINDOW_DEFAULT;
        assembly ("memory-safe") {
            // A dynamic array's elements are encoded in storage beginning at
            // the slot named by the hash of the base slot
            mstore(0x00, arr.slot)
            let start := keccak256(0x00, 0x20)

            // Because we tend to query near the current time, we optimize by
            // bounding our search to progressively larger portions near the end
            // of the array, until we find one that contains the checkpoint of
            // interest
            let hi := add(start, len)
            let lo := sub(hi, initialWindow)
            for {} true {} {
                if lt(lo, start) {
                    lo := start
                    value := 0x00
                    break
                }
                value := sload(lo)
                if iszero(gt(shr(0xd0, value), query)) {
                    lo := add(0x01, lo)
                    break
                }
                let newLo := sub(lo, shl(0x01, sub(hi, lo)))
                hi := lo
                lo := newLo
            }

            // Apply normal binary search
            for {} xor(hi, lo) {} {
                let mid := add(shr(0x01, sub(hi, lo)), lo)
                let newValue := sload(mid)
                if gt(shr(0xd0, newValue), query) {
                    // down
                    hi := mid
                    continue
                }
                // up
                value := newValue
                lo := add(0x01, mid)
            }

            value := and(0x1ffffffffffffffffffffffffffffffffffff, value)
        }
    }

    function get(Checkpoints storage checkpoints, address account, uint48 timepoint) internal view returns (Votes) {
        return _bisect(checkpoints.each[account], timepoint);
    }

    function getTotal(Checkpoints storage checkpoints, uint48 timepoint) internal view returns (Votes) {
        return _bisect(checkpoints.total, timepoint);
    }
}
合同源代码
文件 4 的 46:ChecksumAddress.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library ChecksumAddress {
    /// Adapted from Solady https://github.com/Vectorized/solady/blob/1dd8967b93b379ca6cf384640e0715e55ef08e3d/src/utils/g/LibString.sol#L334
    function toChecksumAddress(address addr) internal pure returns (string memory r) {
        assembly ("memory-safe") {
            r := mload(0x40)
            mstore(0x40, add(0x60, r))
            mstore(0x0f, 0x30313233343536373839616263646566) // "0123456789abcdef" lookup table

            mstore(add(0x02, r), 0x3078) // "0x" prefix
            mstore(r, 0x2a) // length

            addr := shl(0x60, addr)
            let o := add(0x22, r)
            // Hexlify `addr` and write it into the output region. This is a do..while loop.
            for { let i } true {} {
                let p := add(o, add(i, i))
                let temp := byte(i, addr)
                // Split `temp` into nibbles and output the corresponding lookup table entries
                mstore8(add(0x01, p), mload(and(0x0f, temp)))
                mstore8(p, mload(shr(0x04, temp)))
                i := add(0x01, i)
                if eq(i, 0x14) { break }
            }

            // EIP-55 checksum is based on the keccak of the hexlified address. Hash it and extract
            // the hash bits that (might) form the checksum.
            let hash := and(0x8888888888888888888888888888888888888888000000000000000000000000, keccak256(o, 0x28))

            // Again, in a do..while, space the nibble-spaced bits of the hash into byte-spaced and
            // aligned as bit 6 of each byte
            for { let i } true {} {
                mstore(add(i, i), mul(0x88000000000000000000000000000000000000000000000000000000000000, byte(i, hash)))
                i := add(0x01, i)
                if eq(i, 0x14) { break }
            }

            let mask := 0x4040404040404040404040404040404040404040404040404040404040404040
            // Extract bit 6 of each byte of the hexlified output (indicates that the character is
            // a..f) and mask the hash with this. Shift those bits up to bit 7 (the case bit) and
            // flip it to zero (uppercase) wherever the hash is set
            mstore(o, xor(mload(o), shr(0x01, and(mload(0x00), and(mload(o), mask)))))
            o := add(0x20, o)
            // Do it again for the second word of the hexlified output
            mstore(o, xor(mload(o), shr(0x01, and(mload(0x20), and(mload(o), mask)))))
        }
    }
}
合同源代码
文件 5 的 46:Context.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

abstract contract AbstractContext {
    function _msgSender() internal view virtual returns (address);

    function _msgData() internal view virtual returns (bytes calldata);

    function _isForwarded() internal view virtual returns (bool);
}

abstract contract Context is AbstractContext {
    function _msgSender() internal view virtual override returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual override returns (bytes calldata) {
        return msg.data;
    }

    function _isForwarded() internal view virtual override returns (bool) {
        return false;
    }
}
合同源代码
文件 6 的 46:CrazyBalance.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Settings} from "../core/Settings.sol";

import {Math} from "../lib/Math.sol";

import {Shares} from "./Shares.sol";
import {Tokens} from "./Tokens.sol";
import {tmp, SharesToTokens} from "./TokensXShares.sol";

type CrazyBalance is uint256;

library CrazyBalanceAccessors {
    function toExternal(CrazyBalance x) internal pure returns (uint256) {
        return CrazyBalance.unwrap(x);
    }

    function isMax(CrazyBalance x) internal pure returns (bool) {
        return ~CrazyBalance.unwrap(x) == 0;
    }
}

using CrazyBalanceAccessors for CrazyBalance global;

function toCrazyBalance(uint256 x) pure returns (CrazyBalance) {
    return CrazyBalance.wrap(x);
}

CrazyBalance constant ZERO = CrazyBalance.wrap(0);
CrazyBalance constant MAX = CrazyBalance.wrap(type(uint256).max);

function __sub(CrazyBalance a, CrazyBalance b) pure returns (CrazyBalance) {
    unchecked {
        return CrazyBalance.wrap(CrazyBalance.unwrap(a) - CrazyBalance.unwrap(b));
    }
}

function __eq(CrazyBalance a, CrazyBalance b) pure returns (bool) {
    return CrazyBalance.unwrap(a) == CrazyBalance.unwrap(b);
}

function __lt(CrazyBalance a, CrazyBalance b) pure returns (bool) {
    return CrazyBalance.unwrap(a) < CrazyBalance.unwrap(b);
}

function __gt(CrazyBalance a, CrazyBalance b) pure returns (bool) {
    return CrazyBalance.unwrap(a) > CrazyBalance.unwrap(b);
}

function __ne(CrazyBalance a, CrazyBalance b) pure returns (bool) {
    return CrazyBalance.unwrap(a) != CrazyBalance.unwrap(b);
}

function __le(CrazyBalance a, CrazyBalance b) pure returns (bool) {
    return CrazyBalance.unwrap(a) <= CrazyBalance.unwrap(b);
}

function __ge(CrazyBalance a, CrazyBalance b) pure returns (bool) {
    return CrazyBalance.unwrap(a) >= CrazyBalance.unwrap(b);
}

using {__sub as -, __eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=} for CrazyBalance global;

library CrazyBalanceArithmetic {
    using SharesToTokens for Shares;

    function saturatingAdd(CrazyBalance x, CrazyBalance y) internal pure returns (CrazyBalance r) {
        return CrazyBalance.wrap(Math.saturatingAdd(CrazyBalance.unwrap(x), CrazyBalance.unwrap(y)));
    }

    function saturatingSub(CrazyBalance x, CrazyBalance y) internal pure returns (CrazyBalance r) {
        return CrazyBalance.wrap(Math.saturatingSub(CrazyBalance.unwrap(x), CrazyBalance.unwrap(y)));
    }

    function toCrazyBalance(Shares shares, address account, Tokens totalSupply, Shares totalShares)
        internal
        pure
        returns (CrazyBalance)
    {
        // slither-disable-next-line divide-before-multiply
        return CrazyBalance.wrap(
            Tokens.unwrap(
                tmp().omul(shares, totalSupply.mul(uint160(account) >> Settings.ADDRESS_SHIFT)).div(
                    totalShares.mul(Settings.CRAZY_BALANCE_BASIS)
                )
            )
        );
    }

    function toCrazyBalance(Tokens tokens, address account) internal pure returns (CrazyBalance) {
        unchecked {
            // slither-disable-next-line divide-before-multiply
            return CrazyBalance.wrap(
                Tokens.unwrap(tokens) * (uint160(account) >> Settings.ADDRESS_SHIFT) / Settings.CRAZY_BALANCE_BASIS
            );
        }
    }

    function toTokens(CrazyBalance balance, address account) internal pure returns (Tokens) {
        unchecked {
            // Checking for overflow in the multiplication is unnecessary. Checking for division by
            // zero is required.
            return Tokens.wrap(
                CrazyBalance.unwrap(balance) * Settings.CRAZY_BALANCE_BASIS
                    / (uint160(account) >> Settings.ADDRESS_SHIFT)
            );
        }
    }

    function toPairBalance(Tokens tokens) internal pure returns (CrazyBalance) {
        return CrazyBalance.wrap(Tokens.unwrap(tokens) / Settings.CRAZY_BALANCE_BASIS);
    }

    function toPairBalance(Shares shares, Tokens totalSupply, Shares totalShares)
        internal
        pure
        returns (CrazyBalance)
    {
        return CrazyBalance.wrap(
            Tokens.unwrap(shares.toTokens(totalSupply, totalShares.mul(Settings.CRAZY_BALANCE_BASIS)))
        );
    }

    function toPairTokens(CrazyBalance balance) internal pure returns (Tokens) {
        unchecked {
            return Tokens.wrap(CrazyBalance.unwrap(balance) * Settings.CRAZY_BALANCE_BASIS);
        }
    }
}

using CrazyBalanceArithmetic for CrazyBalance global;
合同源代码
文件 7 的 46:ERC20Base.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IFU} from "../interfaces/IFU.sol";
import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {IERC2612} from "../interfaces/IERC2612.sol";
import {IERC5267} from "../interfaces/IERC5267.sol";
import {IERC5805} from "../interfaces/IERC5805.sol";

import {FUStorage} from "../FUStorage.sol";
import {AbstractContext} from "../utils/Context.sol";

import {CrazyBalance, toCrazyBalance} from "../types/CrazyBalance.sol";

abstract contract ERC20Base is IFU, FUStorage, AbstractContext {
    using {toCrazyBalance} for uint256;

    constructor() {
        require(_DOMAIN_TYPEHASH == keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"));
        require(_NAME_HASH == keccak256(bytes(name)));
        require(
            _PERMIT_TYPEHASH
                == keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
        );
        require(_DELEGATION_TYPEHASH == keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"));

        require(block.chainid == _CHAIN_ID);
        _cachedDomainSeparator = _computeDomainSeparator();
    }

    function _success() internal view virtual returns (bool);

    function _transfer(Storage storage $, address from, address to, CrazyBalance amount)
        internal
        virtual
        returns (bool);
    function _burn(Storage storage $, address from, CrazyBalance amount) internal virtual returns (bool);
    function _deliver(Storage storage $, address from, CrazyBalance amount) internal virtual returns (bool);
    function _delegate(Storage storage $, address delegator, address delegatee) internal virtual;

    function _approve(Storage storage $, address owner, address spender, CrazyBalance amount)
        internal
        virtual
        returns (bool);
    function _checkAllowance(Storage storage $, address owner, address spender, CrazyBalance amount)
        internal
        view
        virtual
        returns (bool, CrazyBalance, CrazyBalance);
    function _spendAllowance(
        Storage storage $,
        address owner,
        address spender,
        CrazyBalance amount,
        CrazyBalance currentTempAllowance,
        CrazyBalance currentAllowance
    ) internal virtual returns (bool);

    function _consumeNonce(Storage storage $, address account) internal virtual returns (uint256);
    function clock() public view virtual override returns (uint48);

    /// @inheritdoc IERC20
    function transfer(address to, uint256 amount) external override returns (bool) {
        return _transfer(_$(), _msgSender(), to, amount.toCrazyBalance()) && _success();
    }

    /// @inheritdoc IERC20
    function approve(address spender, uint256 amount) external override returns (bool) {
        return _approve(_$(), _msgSender(), spender, amount.toCrazyBalance()) && _success();
    }

    /// @inheritdoc IERC20
    function transferFrom(address from, address to, uint256 amount) external override returns (bool) {
        Storage storage $ = _$();
        address operator = _msgSender();
        CrazyBalance amount_ = amount.toCrazyBalance();
        (bool success, CrazyBalance currentTempAllowance, CrazyBalance currentAllowance) =
            _checkAllowance($, from, operator, amount_);
        return success && _transfer($, from, to, amount_)
            && _spendAllowance($, from, operator, amount_, currentTempAllowance, currentAllowance) && _success();
    }

    /// @inheritdoc IERC5267
    function eip712Domain()
        external
        view
        override
        returns (
            bytes1 fields,
            string memory name_,
            string memory,
            uint256 chainId,
            address verifyingContract,
            bytes32,
            uint256[] memory
        )
    {
        fields = bytes1(0x0d);
        name_ = name;
        chainId = block.chainid;
        verifyingContract = address(this);
    }

    bytes32 private constant _DOMAIN_TYPEHASH = 0x8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866;
    // slither-disable-next-line naming-convention
    bytes32 private constant _NAME_HASH = 0xb614ddaf8c6c224524c95dbfcb82a82be086ec3a639808bbda893d5b4ac93694;
    uint256 private constant _CHAIN_ID = 1;
    bytes32 private immutable _cachedDomainSeparator;

    function _computeDomainSeparator() private view returns (bytes32 r) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x00, _DOMAIN_TYPEHASH)
            mstore(0x20, _NAME_HASH)
            mstore(0x40, chainid())
            mstore(0x60, address())
            r := keccak256(0x00, 0x80)
            mstore(0x40, ptr)
            mstore(0x60, 0x00)
        }
    }

    /// @inheritdoc IERC2612
    // slither-disable-next-line naming-convention
    function DOMAIN_SEPARATOR() public view override returns (bytes32) {
        return block.chainid == _CHAIN_ID ? _cachedDomainSeparator : _computeDomainSeparator();
    }

    bytes32 private constant _PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    uint256 private constant _ADDRESS_MASK = 0x00ffffffffffffffffffffffffffffffffffffffff;

    /// @inheritdoc IERC2612
    function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external
        override
    {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        // slither-disable-next-line timestamp
        if (~deadline != 0 && block.timestamp > deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        Storage storage $ = _$();

        uint256 nonce = _consumeNonce($, owner);
        bytes32 sep = DOMAIN_SEPARATOR();
        address signer;
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(ptr, _PERMIT_TYPEHASH)
            mstore(add(0x20, ptr), and(_ADDRESS_MASK, owner))
            mstore(add(0x40, ptr), and(_ADDRESS_MASK, spender))
            mstore(add(0x60, ptr), amount)
            mstore(add(0x80, ptr), nonce)
            mstore(add(0xa0, ptr), deadline)
            mstore(0x00, 0x1901)
            mstore(0x20, sep)
            mstore(0x40, keccak256(ptr, 0xc0))
            mstore(0x00, keccak256(0x1e, 0x42))
            mstore(0x20, and(0xff, v))
            mstore(0x40, r)
            mstore(0x60, s)
            pop(staticcall(gas(), 0x01, 0x00, 0x80, 0x00, 0x20))
            signer := mul(mload(0x00), eq(returndatasize(), 0x20))
            mstore(0x40, ptr)
            mstore(0x60, 0x00)
        }
        if (signer != owner) {
            revert ERC2612InvalidSigner(signer, owner);
        }
        require(_approve($, owner, spender, amount.toCrazyBalance()));
    }

    bytes32 private constant _DELEGATION_TYPEHASH = 0xe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf;

    /// @inheritdoc IERC5805
    function delegate(address delegatee) external override {
        return _delegate(_$(), _msgSender(), delegatee);
    }

    /// @inheritdoc IERC5805
    function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
        external
        override
    {
        // slither-disable-next-line timestamp
        if (~expiry != 0 && block.timestamp > expiry) {
            revert ERC5805ExpiredSignature(expiry);
        }
        bytes32 sep = DOMAIN_SEPARATOR();
        address signer;
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x00, _DELEGATION_TYPEHASH)
            mstore(0x20, and(_ADDRESS_MASK, delegatee))
            mstore(0x40, nonce)
            mstore(0x60, expiry)
            mstore(0x40, keccak256(0x00, 0x80))
            mstore(0x00, 0x1901)
            mstore(0x20, sep)
            mstore(0x00, keccak256(0x1e, 0x42))
            mstore(0x20, and(0xff, v))
            mstore(0x40, r)
            mstore(0x60, s)
            pop(staticcall(gas(), 0x01, 0x00, 0x80, 0x00, 0x20))
            signer := mul(mload(0x00), eq(returndatasize(), 0x20))
            mstore(0x40, ptr)
            mstore(0x60, 0x00)
        }
        if (signer == address(0)) {
            revert ERC5805InvalidSignature();
        }

        Storage storage $ = _$();

        uint256 expectedNonce = _consumeNonce($, signer);
        if (nonce != expectedNonce) {
            revert ERC5805InvalidNonce(nonce, expectedNonce);
        }
        return _delegate($, signer, delegatee);
    }

    /// @inheritdoc IFU
    function burn(uint256 amount) external override returns (bool) {
        return _burn(_$(), _msgSender(), amount.toCrazyBalance()) && _success();
    }

    /// @inheritdoc IFU
    function deliver(uint256 amount) external override returns (bool) {
        return _deliver(_$(), _msgSender(), amount.toCrazyBalance()) && _success();
    }

    /// @inheritdoc IFU
    function burnFrom(address from, uint256 amount) external override returns (bool) {
        Storage storage $ = _$();
        address operator = _msgSender();
        CrazyBalance amount_ = amount.toCrazyBalance();
        (bool success, CrazyBalance currentTempAllowance, CrazyBalance currentAllowance) =
            _checkAllowance($, from, operator, amount_);
        return success && _burn($, from, amount_)
            && _spendAllowance($, from, operator, amount_, currentTempAllowance, currentAllowance) && _success();
    }

    /// @inheritdoc IFU
    function deliverFrom(address from, uint256 amount) external override returns (bool) {
        Storage storage $ = _$();
        address operator = _msgSender();
        CrazyBalance amount_ = amount.toCrazyBalance();
        (bool success, CrazyBalance currentTempAllowance, CrazyBalance currentAllowance) =
            _checkAllowance($, from, operator, amount_);
        return success && _deliver($, from, amount_)
            && _spendAllowance($, from, operator, amount_, currentTempAllowance, currentAllowance) && _success();
    }
}
合同源代码
文件 8 的 46:FU.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ERC20Base} from "./core/ERC20Base.sol";
import {MultiCallContext} from "./utils/MultiCallContext.sol";

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {IFU} from "./interfaces/IFU.sol";
import {IERC1046} from "./interfaces/IERC1046.sol";
import {IERC5805} from "./interfaces/IERC5805.sol";
import {IERC6372} from "./interfaces/IERC6372.sol";
import {IERC7674} from "./interfaces/IERC7674.sol";

import {IUniswapV2Pair} from "./interfaces/IUniswapV2Pair.sol";
import {FACTORY, pairFor} from "./interfaces/IUniswapV2Factory.sol";

import {Settings} from "./core/Settings.sol";
import {ReflectMath} from "./core/ReflectMath.sol";
import {TransientStorageLayout} from "./core/TransientStorageLayout.sol";
import {Checkpoints, LibCheckpoints} from "./core/Checkpoints.sol";
import {RebaseQueue, LibRebaseQueue} from "./core/RebaseQueue.sol";
import {MoonPhase} from "./core/MoonPhase.sol";
import {whaleLimit as _whaleLimit, applyWhaleLimit as _applyWhaleLimit} from "./core/WhaleLimit.sol";

import {BasisPoints, BASIS} from "./types/BasisPoints.sol";
import {Shares, ZERO as ZERO_SHARES, SharesStorage} from "./types/Shares.sol";
import {Tokens} from "./types/Tokens.sol";
import {SharesToTokens} from "./types/TokensXShares.sol";
import {SharesToTokensProportional} from "./types/TokensXBasisPointsXShares.sol";
import {Votes, toVotes} from "./types/Votes.sol";
import {SharesXBasisPoints, scale, cast} from "./types/SharesXBasisPoints.sol";
import {
    CrazyBalance,
    toCrazyBalance,
    ZERO as ZERO_BALANCE,
    MAX as MAX_BALANCE,
    CrazyBalanceArithmetic
} from "./types/CrazyBalance.sol";

import {ChecksumAddress} from "./lib/ChecksumAddress.sol";
import {IPFS} from "./lib/IPFS.sol";
import {ItoA} from "./lib/ItoA.sol";
import {FastTransferLib} from "./lib/FastTransferLib.sol";
import {UnsafeMath} from "./lib/UnsafeMath.sol";
import {FastLogic} from "./lib/FastLogic.sol";

/// @custom:security non-reentrant
IERC20 constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
address constant DEAD = 0xdeaDDeADDEaDdeaDdEAddEADDEAdDeadDEADDEaD;
address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

library UnsafeArray {
    function unsafeGet(address[] memory a, uint256 i) internal pure returns (address r) {
        assembly ("memory-safe") {
            r := mload(add(a, add(0x20, shl(0x05, i))))
        }
    }
}

/// @custom:security-contact security@fuckyou.finance
contract FU is ERC20Base, TransientStorageLayout, MultiCallContext {
    using ChecksumAddress for address;
    using {toCrazyBalance} for uint256;
    using SharesToTokens for Shares;
    using SharesToTokensProportional for SharesXBasisPoints;
    using CrazyBalanceArithmetic for Shares;
    using CrazyBalanceArithmetic for Tokens;
    using {toVotes} for Shares;
    using LibCheckpoints for Checkpoints;
    using LibRebaseQueue for RebaseQueue;
    using IPFS for string;
    using IPFS for bytes32;
    using ItoA for uint256;
    using FastTransferLib for address payable;
    using FastTransferLib for IERC20;
    using UnsafeArray for address[];
    using UnsafeMath for uint256;
    using FastLogic for bool;

    /// @inheritdoc IERC20
    function totalSupply() external view override returns (uint256) {
        Storage storage $ = _$();
        return ($.totalSupply + $.pairTokens).toExternal();
    }

    /// @inheritdoc IFU
    /// @custom:security non-reentrant
    address public immutable override pair;

    bytes32 private immutable _imageHash;

    /// @inheritdoc IFU
    function image() external view override returns (string memory) {
        return _imageHash.CIDv0();
    }

    bytes32 private immutable _tokenUriHash;

    /// @inheritdoc IERC1046
    function tokenURI() external view override returns (string memory) {
        return _tokenUriHash.CIDv0();
    }

    constructor(bytes20 gitCommit, string memory image_, address[] memory initialHolders) payable {
        assert(Settings.SHARES_TO_VOTES_DIVISOR >= Settings.INITIAL_SHARES_RATIO);
        assert(
            Shares.unwrap(Settings.oneTokenInShares())
                > Settings.MIN_SHARES_RATIO * Tokens.unwrap(Settings.INITIAL_SUPPLY)
        );

        require(msg.sender == 0x4e59b44847b379578588920cA78FbF26c0B4956C);
        {
            bool isSimulation =
                (block.basefee < 7 wei).and(block.gaslimit > 1_000_000_000).and(block.number < 20_000_000);
            // slither-disable-next-line tx-origin
            require((tx.origin == 0x3D87e294ba9e29d2B5a557a45afCb0D052a13ea6).or(isSimulation));
        }
        require(address(this).balance >= 6 ether);
        uint256 length = initialHolders.length;
        require(length >= Settings.ANTI_WHALE_DIVISOR * 2);

        pair = address(pairFor(WETH, this));
        require(uint160(pair) >> Settings.ADDRESS_SHIFT == 1);

        assembly ("memory-safe") {
            log0(add(0x20, image_), mload(image_))
        }
        emit GitCommit(gitCommit);
        _imageHash = image_.dagPbUnixFsHash();
        string memory imageUri = _imageHash.CIDv0();
        _tokenUriHash = string.concat(
            "{\"interop\":{\"erc1046\":true},\"name\":\"",
            name,
            "\",\"symbol\":\"FU\",\"decimals\":",
            uint256(Settings.DECIMALS).itoa(),
            ",\"image\":\"",
            imageUri,
            "\",\"content\":{\"mime\":\"image/svg+xml\",\"uri\":\"",
            imageUri,
            "\"}}\n"
        ).dagPbUnixFsHash();

        payable(address(WETH)).fastSendEth(address(this).balance);
        WETH.fastTransfer(pair, WETH.fastBalanceOf(address(this)));

        Storage storage $ = _$();

        Tokens pairTokens = Settings.INITIAL_SUPPLY.div(Settings.INITIAL_LIQUIDITY_DIVISOR);
        pairTokens = pairTokens - Tokens.wrap(Tokens.unwrap(pairTokens) % Settings.CRAZY_BALANCE_BASIS);
        $.pairTokens = pairTokens;
        emit Transfer(address(0), pair, pairTokens.toExternal());

        Tokens totalSupply_ = Settings.INITIAL_SUPPLY - pairTokens;
        $.totalSupply = totalSupply_;
        Shares totalShares_ = Shares.wrap(Tokens.unwrap(totalSupply_) * Settings.INITIAL_SHARES_RATIO);
        $.totalShares = totalShares_;

        {
            // The queue is empty, so we have to special-case the first insertion. `DEAD` will
            // always hold a token balance, which makes many things simpler.
            $.sharesOf[DEAD] = Settings.oneTokenInShares().store();
            Tokens tokens = $.sharesOf[DEAD].load().toTokens(totalSupply_, totalShares_);
            emit Transfer(address(0), DEAD, tokens.toExternal());
            $.rebaseQueue.initialize(DEAD, tokens);
        }
        {
            Shares toMint = totalShares_ - $.sharesOf[DEAD].load();
            address prev = initialHolders.unsafeGet(0);
            require(uint160(prev) >> Settings.ADDRESS_SHIFT != 0);
            // slither-disable-next-line divide-before-multiply
            Shares sharesRest = toMint.div(length);
            {
                Shares sharesFirst = toMint - sharesRest.mul(length - 1);
                Tokens amount = sharesFirst.toTokens(totalSupply_, totalShares_);

                require(prev != DEAD);
                $.sharesOf[prev] = sharesFirst.store();
                emit Transfer(address(0), prev, amount.toExternal());
                $.rebaseQueue.enqueue(prev, amount);
            }
            {
                Tokens amount = sharesRest.toTokens(totalSupply_, totalShares_);
                SharesStorage sharesRestStorage = sharesRest.store();
                for (uint256 i = 1; i < length; i = i.unsafeInc()) {
                    address to = initialHolders.unsafeGet(i);
                    require(to != DEAD);
                    require(to > prev);
                    $.sharesOf[to] = sharesRestStorage;
                    emit Transfer(address(0), to, amount.toExternal());
                    $.rebaseQueue.enqueue(to, amount);
                    prev = to;
                }
            }
        }

        try FACTORY.createPair(WETH, this) returns (IUniswapV2Pair newPair) {
            require(pair == address(newPair));
        } catch {
            require(pair == address(FACTORY.getPair(WETH, this)));
        }

        // We can't call `pair.mint` from within the constructor because it wants to call back into
        // us with `balanceOf`. The call to `mint` and the check that liquidity isn't being stolen
        // is performed in the deployment script. Its atomicity is enforced by the check against
        // `tx.origin` above.
    }

    function _consumeNonce(Storage storage $, address account) internal override returns (uint256) {
        unchecked {
            return $.nonces[account]++;
        }
    }

    function _check() private view returns (bool r) {
        assembly ("memory-safe") {
            mstore(0x20, coinbase())
            mstore(0x0c, gasprice())
            mstore(0x00, prevrandao())
            r := shr(0xff, keccak256(0x00, 0x40))
        }
    }

    function _success() internal view override returns (bool) {
        if (_check()) {
            assembly ("memory-safe") {
                stop()
            }
        }
        return true;
    }

    function _loadAccount(Storage storage $, address account)
        private
        view
        returns (Shares originalShares, Shares cachedShares, Shares cachedTotalShares)
    {
        originalShares = $.sharesOf[account].load();
        (cachedShares, cachedTotalShares) = _applyWhaleLimit(originalShares, $.totalShares);
    }

    function _loadAccounts(Storage storage $, address account0, address account1)
        private
        view
        returns (
            Shares originalShares0,
            Shares cachedShares0,
            Shares originalShares1,
            Shares cachedShares1,
            Shares cachedTotalShares
        )
    {
        originalShares0 = $.sharesOf[account0].load();
        originalShares1 = $.sharesOf[account1].load();
        (cachedShares0, cachedShares1, cachedTotalShares) =
            _applyWhaleLimit(originalShares0, originalShares1, $.totalShares);
    }

    function _balanceOf(Storage storage $, address account)
        private
        view
        returns (
            CrazyBalance balance,
            Shares originalShares,
            Shares cachedShares,
            Tokens cachedTotalSupply,
            Shares cachedTotalShares
        )
    {
        (originalShares, cachedShares, cachedTotalShares) = _loadAccount($, account);
        cachedTotalSupply = $.totalSupply;
        balance = cachedShares.toCrazyBalance(account, cachedTotalSupply, cachedTotalShares);
    }

    /// @inheritdoc IERC20
    function balanceOf(address account) external view override returns (uint256) {
        Storage storage $ = _$();
        if (account == pair) {
            return $.pairTokens.toPairBalance().toExternal();
        }
        if (account == DEAD) {
            return $.sharesOf[DEAD].load().toCrazyBalance(account, $.totalSupply, $.totalShares).toExternal();
        }
        (CrazyBalance balance,,,,) = _balanceOf($, account);
        return balance.toExternal();
    }

    function _balanceOf(Storage storage $, address account0, address account1)
        private
        view
        returns (
            CrazyBalance balance0,
            Shares originalShares0,
            Shares cachedShares0,
            Shares originalShares1,
            Shares cachedShares1,
            Tokens cachedTotalSupply,
            Shares cachedTotalShares
        )
    {
        (originalShares0, cachedShares0, originalShares1, cachedShares1, cachedTotalShares) =
            _loadAccounts($, account0, account1);
        cachedTotalSupply = $.totalSupply;
        balance0 = cachedShares0.toCrazyBalance(account0, cachedTotalSupply, cachedTotalShares);
    }

    function _tax() private view returns (BasisPoints) {
        return MoonPhase.moonPhase(block.timestamp);
    }

    /// @inheritdoc IFU
    function tax() external view override returns (uint256) {
        return BasisPoints.unwrap(_tax());
    }

    /// @inheritdoc IFU
    function whaleLimit(address potentialWhale) external view override returns (uint256) {
        if ((potentialWhale == pair).or(potentialWhale == DEAD)) {
            return type(uint256).max;
        }
        // This looks gas-wasteful and baroque, but loading all this additional state is required for
        // exact correctness in the face of rounding error. This exactly replicates the rounding
        // behavior applied when calling `balanceOf(potentialWhale)`.
        Storage storage $ = _$();
        (Shares limit, Shares totalShares_) = _whaleLimit($.sharesOf[potentialWhale].load(), $.totalShares);
        return limit.toCrazyBalance(potentialWhale, $.totalSupply, totalShares_).toExternal();
    }

    function _pokeRebaseQueueFrom(
        Storage storage $,
        address from,
        Shares originalShares,
        Shares newShares,
        Tokens newTotalSupply,
        Shares newTotalShares
    ) private {
        if (newShares == ZERO_SHARES) {
            if (originalShares != ZERO_SHARES) {
                $.rebaseQueue.dequeue(from);
            }
        } else {
            $.rebaseQueue.moveToBack(from, newShares, newTotalSupply, newTotalShares);
        }
    }

    function _pokeRebaseQueueTo(
        Storage storage $,
        address to,
        Shares originalShares,
        Shares newShares,
        Tokens newTotalSupply,
        Shares newTotalShares
    ) private {
        if (originalShares == ZERO_SHARES) {
            if (newShares != ZERO_SHARES) {
                $.rebaseQueue.enqueue(to, newShares, newTotalSupply, newTotalShares);
            }
        } else {
            $.rebaseQueue.moveToBack(to, newShares, newTotalSupply, newTotalShares);
        }
    }

    function _transferFromPair(Storage storage $, address pair_, address to, CrazyBalance amount)
        private
        returns (bool)
    {
        // We don't need to check that `pair` is transferring less than its balance. The
        // `UniswapV2Pair` code does that for us. Additionally, `pair`'s balance can never reach
        // zero.

        (Shares originalShares, Shares cachedShares, Shares cachedTotalShares) = _loadAccount($, to);
        Tokens cachedTotalSupply = $.totalSupply;
        Tokens amountTokens = amount.toPairTokens();

        BasisPoints taxRate = _tax();
        (Shares newShares, Shares newTotalShares, Tokens newTotalSupply) = ReflectMath.getTransferSharesFromPair(
            taxRate, cachedTotalSupply, cachedTotalShares, amountTokens, cachedShares
        );
        {
            (Shares limit, Shares hypotheticalTotalShares) = _whaleLimit(newShares, newTotalShares);
            if (newShares >= limit) {
                newShares = limit;
                newTotalShares = hypotheticalTotalShares;

                // The quantity `cachedToShares` is counterfactual. We violate (temporarily) the
                // requirement that the sum of all accounts' shares equal the total shares.
                cachedShares = ReflectMath.getCounterfactualSharesFromPairToWhale(
                    taxRate, cachedTotalSupply, cachedTotalShares, amountTokens
                );
            }
        }

        // Take note of the mismatch between the holder/recipient of the tokens/shares (`to`) and
        // the account for whom we calculate the balance delta (`pair`). The `amount` field of the
        // `Transfer` event is relative to the sender of the tokens.
        CrazyBalance transferAmount = newShares.toPairBalance(newTotalSupply, newTotalShares)
            - cachedShares.toPairBalance(cachedTotalSupply, cachedTotalShares);
        CrazyBalance burnAmount = amount.saturatingSub(transferAmount);

        // State modification starts here. No more bailing out allowed.

        $.rebaseQueue.rebaseFor(to, cachedShares, cachedTotalSupply, cachedTotalShares);

        $.pairTokens = $.pairTokens - amountTokens;
        $.sharesOf[to] = newShares.store();
        $.totalSupply = newTotalSupply;
        $.totalShares = newTotalShares;

        emit Transfer(pair_, to, transferAmount.toExternal());
        emit Transfer(pair_, address(0), burnAmount.toExternal());

        if (newShares >= originalShares) {
            $.checkpoints.mint($.delegates[to], newShares.toVotes() - originalShares.toVotes(), clock());
        } else {
            $.checkpoints.burn($.delegates[to], originalShares.toVotes() - newShares.toVotes(), clock());
        }

        _pokeRebaseQueueTo($, to, originalShares, newShares, newTotalSupply, newTotalShares);

        $.rebaseQueue.processQueue($.sharesOf, newTotalSupply, newTotalShares);

        return true;
    }

    function _transferToPair(Storage storage $, address from, address pair_, CrazyBalance amount)
        private
        returns (bool)
    {
        (
            CrazyBalance balance,
            Shares originalShares,
            Shares cachedShares,
            Tokens cachedTotalSupply,
            Shares cachedTotalShares
        ) = _balanceOf($, from);
        if (amount > balance) {
            if (_check()) {
                revert ERC20InsufficientBalance(from, balance.toExternal(), amount.toExternal());
            }
            return false;
        }

        Tokens cachedPairTokens = $.pairTokens;
        BasisPoints taxRate = _tax();
        Shares newShares;
        Shares newTotalShares;
        Tokens transferTokens;
        Tokens newTotalSupply;
        if (amount == balance) {
            transferTokens = scale(cachedShares, BASIS - taxRate).toTokens(cachedTotalSupply, cachedTotalShares);
            newTotalSupply = cachedTotalSupply - transferTokens;
            newShares = ZERO_SHARES;
            newTotalShares = cachedTotalShares - cachedShares;
        } else {
            (newShares, newTotalShares, transferTokens, newTotalSupply) = ReflectMath.getTransferSharesToPair(
                taxRate, cachedTotalSupply, cachedTotalShares, amount.toTokens(from), cachedShares
            );
        }
        Tokens newPairTokens = cachedPairTokens + transferTokens;

        // Take note of the mismatch between who is holding the tokens (`pair`) and the address for
        // whom the `CrazyBalance` is being calculated (`from`). We're converting `pair`'s balance
        // delta into units as if it were held by `from`.
        CrazyBalance transferAmount = newPairTokens.toCrazyBalance(from) - cachedPairTokens.toCrazyBalance(from);
        CrazyBalance burnAmount = amount.saturatingSub(transferAmount);

        // There is no need to apply the whale limit. `pair` holds tokens directly (not shares) and
        // is allowed to go over the limit.

        // State modification starts here. No more bailing out allowed.

        $.rebaseQueue.rebaseFor(from, cachedShares, cachedTotalSupply, cachedTotalShares);

        $.sharesOf[from] = newShares.store();
        $.pairTokens = newPairTokens;
        $.totalSupply = newTotalSupply;
        $.totalShares = newTotalShares;

        emit Transfer(from, pair_, transferAmount.toExternal());
        emit Transfer(from, address(0), burnAmount.toExternal());

        $.checkpoints.burn($.delegates[from], originalShares.toVotes() - newShares.toVotes(), clock());

        _pokeRebaseQueueFrom($, from, originalShares, newShares, newTotalSupply, newTotalShares);

        $.rebaseQueue.processQueue($.sharesOf, newTotalSupply, newTotalShares);

        return true;
    }

    function _transfer(Storage storage $, address from, address to, CrazyBalance amount)
        internal
        override
        returns (bool)
    {
        if (from == DEAD) {
            if (_check()) {
                revert ERC20InvalidSender(from);
            }
            return false;
        }

        address pair_ = pair;
        if (to == pair_) {
            if (from == to) {
                if (_check()) {
                    revert ERC20InvalidReceiver(to);
                }
                return false;
            }
            return _transferToPair($, from, to, amount);
        }

        if ((to == DEAD).or(to == address(this)).or(uint160(to) >> Settings.ADDRESS_SHIFT == 0)) {
            if (_check()) {
                revert ERC20InvalidReceiver(to);
            }
            return false;
        }

        if (from == pair_) {
            return _transferFromPair($, from, to, amount);
        }

        if (from == to) {
            if (_check()) {
                revert ERC20InvalidReceiver(to);
            }
            return false;
        }

        (
            CrazyBalance fromBalance,
            Shares originalFromShares,
            Shares cachedFromShares,
            Shares originalToShares,
            Shares cachedToShares,
            Tokens cachedTotalSupply,
            Shares cachedTotalShares
        ) = _balanceOf($, from, to);

        if (amount > fromBalance) {
            if (_check()) {
                revert ERC20InsufficientBalance(from, fromBalance.toExternal(), amount.toExternal());
            }
            return false;
        }

        BasisPoints taxRate = _tax();
        Shares newFromShares;
        Shares newToShares;
        Shares newTotalShares;
        if (amount == fromBalance) {
            (newToShares, newTotalShares) =
                ReflectMath.getTransferAllShares(taxRate, cachedTotalShares, cachedFromShares, cachedToShares);
            newFromShares = ZERO_SHARES;
            if (newToShares >= (newTotalShares - newToShares).div(Settings.ANTI_WHALE_DIVISOR_MINUS_ONE)) {
                (cachedToShares, newToShares, newTotalShares) = ReflectMath.getTransferAllSharesToWhale(
                    taxRate, cachedTotalShares, cachedFromShares, cachedToShares
                );
                // The quantity `cachedToShares` is counterfactual. We violate (temporarily) the
                // requirement that the sum of all accounts' shares equal the total shares.
            }
        } else {
            Tokens amountTokens = amount.toTokens(from);
            (newFromShares, newToShares, newTotalShares) = ReflectMath.getTransferShares(
                amountTokens, taxRate, cachedTotalSupply, cachedTotalShares, cachedFromShares, cachedToShares
            );
            if (newToShares >= (newTotalShares - newToShares).div(Settings.ANTI_WHALE_DIVISOR_MINUS_ONE)) {
                (newFromShares, cachedToShares, newToShares, newTotalShares) = ReflectMath.getTransferSharesToWhale(
                    amountTokens, taxRate, cachedTotalSupply, cachedTotalShares, cachedFromShares, cachedToShares
                );
                // The quantity `cachedToShares` is counterfactual. We violate (temporarily) the
                // requirement that the sum of all accounts' shares equal the total shares.
            }
        }

        // Take note of the `to`/`from` mismatch here. We're converting `to`'s balance into
        // units as if it were held by `from`. Also note that when `to` is a whale, the `amount`
        // emitted in the event does not accurately reflect the change in balance.
        CrazyBalance transferAmount = newToShares.toCrazyBalance(from, cachedTotalSupply, newTotalShares)
            - cachedToShares.toCrazyBalance(from, cachedTotalSupply, cachedTotalShares);
        CrazyBalance burnAmount = amount.saturatingSub(transferAmount);

        // State modification starts here. No more bailing out allowed.

        $.rebaseQueue.rebaseFor(from, cachedFromShares, cachedTotalSupply, cachedTotalShares);
        $.rebaseQueue.rebaseFor(to, cachedToShares, cachedTotalSupply, cachedTotalShares);

        // The computation in `ReflectMath.getTransferShares` (whichever version we used) enforces
        // the postcondition that `from` and `to` come in under the whale limit. So we don't need to
        // check, we can just write the values to storage.
        $.sharesOf[from] = newFromShares.store();
        $.sharesOf[to] = newToShares.store();
        $.totalShares = newTotalShares;
        emit Transfer(from, to, transferAmount.toExternal());
        emit Transfer(from, address(0), burnAmount.toExternal());

        if (newToShares >= originalToShares) {
            $.checkpoints.transfer(
                $.delegates[from],
                $.delegates[to],
                newToShares.toVotes() - originalToShares.toVotes(),
                originalFromShares.toVotes() - newFromShares.toVotes(),
                clock()
            );
        } else {
            $.checkpoints.burn(
                $.delegates[from],
                originalFromShares.toVotes() - newFromShares.toVotes(),
                $.delegates[to],
                originalToShares.toVotes() - newToShares.toVotes(),
                clock()
            );
        }

        _pokeRebaseQueueFrom($, from, originalFromShares, newFromShares, cachedTotalSupply, newTotalShares);
        _pokeRebaseQueueTo($, to, originalToShares, newToShares, cachedTotalSupply, newTotalShares);

        $.rebaseQueue.processQueue($.sharesOf, cachedTotalSupply, newTotalShares);

        return true;
    }

    function _approve(Storage storage $, address owner, address spender, CrazyBalance amount)
        internal
        override
        returns (bool)
    {
        if (spender == PERMIT2) {
            return true;
        }
        $.allowance[owner][spender] = amount;
        emit Approval(owner, spender, amount.toExternal());
        return true;
    }

    /// @inheritdoc IERC7674
    function temporaryApprove(address spender, uint256 amount) external override returns (bool) {
        if (spender == PERMIT2) {
            return _success();
        }
        _setTemporaryAllowance(_msgSender(), spender, amount.toCrazyBalance());
        return _success();
    }

    /// @inheritdoc IERC20
    function allowance(address owner, address spender) external view override returns (uint256) {
        if (owner == pair) {
            return 0;
        }
        if (spender == PERMIT2) {
            return type(uint256).max;
        }
        CrazyBalance temporaryAllowance = _getTemporaryAllowance(owner, spender);
        if (temporaryAllowance.isMax()) {
            return temporaryAllowance.toExternal();
        }
        return _$().allowance[owner][spender].saturatingAdd(temporaryAllowance).toExternal();
    }

    function _checkAllowance(Storage storage $, address owner, address spender, CrazyBalance amount)
        internal
        view
        override
        returns (bool, CrazyBalance, CrazyBalance)
    {
        if (owner == pair) {
            if (amount == ZERO_BALANCE) {
                return (true, ZERO_BALANCE, ZERO_BALANCE);
            }
            if (_check()) {
                revert ERC20InsufficientAllowance(spender, 0, amount.toExternal());
            }
            return (false, ZERO_BALANCE, ZERO_BALANCE);
        }
        if (spender == PERMIT2) {
            return (true, MAX_BALANCE, ZERO_BALANCE);
        }
        CrazyBalance currentTempAllowance = _getTemporaryAllowance(owner, spender);
        if (currentTempAllowance >= amount) {
            return (true, currentTempAllowance, ZERO_BALANCE);
        }
        CrazyBalance currentAllowance = $.allowance[owner][spender];
        if (currentAllowance >= amount - currentTempAllowance) {
            return (true, currentTempAllowance, currentAllowance);
        }
        if (_check()) {
            revert ERC20InsufficientAllowance(spender, currentAllowance.toExternal(), amount.toExternal());
        }
        return (false, ZERO_BALANCE, ZERO_BALANCE);
    }

    function _spendAllowance(
        Storage storage $,
        address owner,
        address spender,
        CrazyBalance amount,
        CrazyBalance currentTempAllowance,
        CrazyBalance currentAllowance
    ) internal override returns (bool) {
        if (currentAllowance == ZERO_BALANCE) {
            if (currentTempAllowance.isMax()) {
                return true;
            } else {
                _setTemporaryAllowance(owner, spender, currentTempAllowance - amount);
                return true;
            }
        }
        if (currentTempAllowance != ZERO_BALANCE) {
            amount = amount - currentTempAllowance;
            _setTemporaryAllowance(owner, spender, ZERO_BALANCE);
        }
        if (currentAllowance.isMax()) {
            return true;
        }
        return _approve($, owner, spender, currentAllowance - amount);
    }

    /// @inheritdoc IERC20
    function symbol() external view override returns (string memory r) {
        // slither-disable-next-line tx-origin
        if (tx.origin == address(0)) {
            return "FU";
        }
        assembly ("memory-safe") {
            r := mload(0x40)
            mstore(0x40, add(0x0a, r))
        }
        // slither-disable-next-line unused-return
        msg.sender.toChecksumAddress();
        assembly ("memory-safe") {
            mstore(add(0x0a, r), 0x4675636b20796f752c20)
            mstore(r, 0x35)
            mstore8(add(0x54, r), 0x21)
            mstore(0x40, add(0x60, r))
        }
    }

    /// @inheritdoc IERC20
    uint8 public constant override decimals = Settings.DECIMALS;

    /// @inheritdoc IERC6372
    function clock() public view override returns (uint48) {
        unchecked {
            // slither-disable-next-line divide-before-multiply
            return uint48(block.timestamp / 1 days * 1 days);
        }
    }

    // slither-disable-next-line naming-convention
    /// @inheritdoc IERC6372
    string public constant override CLOCK_MODE = "mode=timestamp&epoch=1970-01-01T00%3A00%3A00Z&quantum=86400";

    /// @inheritdoc IERC5805
    function getVotes(address account) external view override returns (uint256) {
        return _$().checkpoints.current(account).toExternal();
    }

    /// @inheritdoc IERC5805
    function getPastVotes(address account, uint256 timepoint) external view override returns (uint256) {
        // slither-disable-next-line timestamp
        if (timepoint >= clock()) {
            revert ERC5805TimepointNotPast(timepoint, clock());
        }
        return _$().checkpoints.get(account, uint48(timepoint)).toExternal();
    }

    /// @inheritdoc IFU
    function getTotalVotes() external view override returns (uint256) {
        return _$().checkpoints.currentTotal().toExternal();
    }

    /// @inheritdoc IFU
    function getPastTotalVotes(uint256 timepoint) external view override returns (uint256) {
        // slither-disable-next-line timestamp
        if (timepoint >= clock()) {
            revert ERC5805TimepointNotPast(timepoint, clock());
        }
        return _$().checkpoints.getTotal(uint48(timepoint)).toExternal();
    }

    function _delegate(Storage storage $, address delegator, address delegatee) internal override {
        Shares shares = $.sharesOf[delegator].load();
        address oldDelegatee = $.delegates[delegator];
        emit DelegateChanged(delegator, oldDelegatee, delegatee);
        $.delegates[delegator] = delegatee;
        Votes votes = shares.toVotes();
        $.checkpoints.transfer(oldDelegatee, delegatee, votes, votes, clock());
    }

    function _burn(Storage storage $, address from, CrazyBalance amount) internal override returns (bool) {
        if (from == DEAD) {
            if (_check()) {
                revert ERC20InvalidSender(from);
            }
            return false;
        }
        if (from == pair) {
            // `amount` is zero or we would not have passed `_checkAllowance`
            emit Transfer(from, address(0), 0);
            $.rebaseQueue.processQueue($.sharesOf, $.totalSupply, $.totalShares);
            return true;
        }

        (
            CrazyBalance balance,
            Shares originalShares,
            Shares cachedShares,
            Tokens cachedTotalSupply,
            Shares cachedTotalShares
        ) = _balanceOf($, from);
        if (amount > balance) {
            if (_check()) {
                revert ERC20InsufficientBalance(from, balance.toExternal(), amount.toExternal());
            }
            return false;
        }

        Shares newShares;
        Shares newTotalShares;
        Tokens newTotalSupply;
        if (amount == balance) {
            // The amount to be deducted from `_totalSupply` is *NOT* the same as
            // `amount.toTokens(from)`. That would not correctly account for dust that is below the
            // "crazy balance" scaling factor for `from`. We have to explicitly recompute the
            // un-crazy balance of `from` and deduct *THAT* instead.
            newTotalSupply = cachedTotalSupply - cachedShares.toTokens(cachedTotalSupply, cachedTotalShares);
            newTotalShares = cachedTotalShares - cachedShares;
            newShares = ZERO_SHARES;
        } else {
            (newShares, newTotalShares, newTotalSupply) =
                ReflectMath.getBurnShares(amount.toTokens(from), cachedTotalSupply, cachedTotalShares, cachedShares);
        }

        $.rebaseQueue.rebaseFor(from, cachedShares, cachedTotalSupply, cachedTotalShares);

        $.sharesOf[from] = newShares.store();
        $.totalShares = newTotalShares;
        $.totalSupply = newTotalSupply;
        emit Transfer(from, address(0), amount.toExternal());

        $.checkpoints.burn($.delegates[from], originalShares.toVotes() - newShares.toVotes(), clock());

        _pokeRebaseQueueFrom($, from, originalShares, newShares, newTotalSupply, newTotalShares);

        $.rebaseQueue.processQueue($.sharesOf, newTotalSupply, newTotalShares);

        return true;
    }

    function _deliver(Storage storage $, address from, CrazyBalance amount) internal override returns (bool) {
        if (from == DEAD) {
            if (_check()) {
                revert ERC20InvalidSender(from);
            }
            return false;
        }
        if (from == pair) {
            // `amount` is zero or we would not have passed `_checkAllowance`
            emit Transfer(from, address(0), 0);
            $.rebaseQueue.processQueue($.sharesOf, $.totalSupply, $.totalShares);
            return true;
        }

        (
            CrazyBalance balance,
            Shares originalShares,
            Shares cachedShares,
            Tokens cachedTotalSupply,
            Shares cachedTotalShares
        ) = _balanceOf($, from);
        if (amount > balance) {
            if (_check()) {
                revert ERC20InsufficientBalance(from, balance.toExternal(), amount.toExternal());
            }
            return false;
        }

        Shares newShares;
        Shares newTotalShares;
        if (amount == balance) {
            newTotalShares = cachedTotalShares - cachedShares;
            newShares = ZERO_SHARES;
        } else {
            (newShares, newTotalShares) =
                ReflectMath.getDeliverShares(amount.toTokens(from), cachedTotalSupply, cachedTotalShares, cachedShares);
        }

        $.rebaseQueue.rebaseFor(from, cachedShares, cachedTotalSupply, cachedTotalShares);

        $.sharesOf[from] = newShares.store();
        $.totalShares = newTotalShares;
        emit Transfer(from, address(0), amount.toExternal());

        $.checkpoints.burn($.delegates[from], originalShares.toVotes() - newShares.toVotes(), clock());

        _pokeRebaseQueueFrom($, from, originalShares, newShares, cachedTotalSupply, newTotalShares);

        $.rebaseQueue.processQueue($.sharesOf, cachedTotalSupply, newTotalShares);

        return true;
    }
}
合同源代码
文件 9 的 46:FUStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {INonces} from "./interfaces/INonces.sol";
import {IERC5805} from "./interfaces/IERC5805.sol";

import {Tokens} from "./types/Tokens.sol";
import {Shares, SharesStorage} from "./types/Shares.sol";
import {CrazyBalance} from "./types/CrazyBalance.sol";

import {Checkpoints} from "./core/Checkpoints.sol";
import {RebaseQueue} from "./core/RebaseQueue.sol";

abstract contract FUStorage is IERC20, INonces, IERC5805 {
    struct Storage {
        Tokens totalSupply;
        Tokens pairTokens;
        Shares totalShares;
        RebaseQueue rebaseQueue;
        Checkpoints checkpoints;
        mapping(address account => SharesStorage shares) sharesOf;
        mapping(address owner => mapping(address spender => CrazyBalance allowed)) allowance;
        mapping(address account => address delegatee) delegates;
        mapping(address account => uint256 nonce) nonces;
    }

    /// @inheritdoc IERC5805
    function delegates(address account) external view override returns (address delegatee) {
        return _$().delegates[account];
    }

    /// @inheritdoc INonces
    function nonces(address account) external view override returns (uint256 nonce) {
        return _$().nonces[account];
    }

    /// @inheritdoc IERC20
    string public constant override name = "Fuck You!";

    constructor() {
        Storage storage $ = _$();
        uint256 $int;
        assembly ("memory-safe") {
            $int := $.slot
        }
        assert($int == uint128(uint256(keccak256(bytes(name))) - 1) & ~uint256(0xff));
    }

    // slither-disable-next-line naming-convention
    function _$() internal pure returns (Storage storage $) {
        assembly ("memory-safe") {
            $.slot := 0xe086ec3a639808bbda893d5b4ac93600
        }
    }
}
合同源代码
文件 10 的 46:FastLogic.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library FastLogic {
    function or(bool a, bool b) internal pure returns (bool r) {
        assembly ("memory-safe") {
            r := or(a, b)
        }
    }

    function and(bool a, bool b) internal pure returns (bool r) {
        assembly ("memory-safe") {
            r := and(a, b)
        }
    }
}
合同源代码
文件 11 的 46:FastTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@forge-std/interfaces/IERC20.sol";

library FastTransferLib {
    function fastSendEth(address payable to, uint256 value) internal {
        assembly ("memory-safe") {
            if iszero(call(gas(), to, value, 0x00, 0x00, 0x00, 0x00)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }
        }
    }

    function fastBalanceOf(IERC20 token, address acct) internal view returns (uint256 r) {
        assembly ("memory-safe") {
            mstore(0x14, acct) // Store the `acct` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // Selector for `balanceOf(address)`, with `acct`'s padding.

            // Call and check for revert. Storing the selector with padding in memory at 0 results
            // in a start of calldata at offset 16. Calldata is 36 bytes long (4 bytes selector, 32
            // bytes argument).
            if iszero(staticcall(gas(), token, 0x10, 0x24, 0x00, 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }
            // We assume that `token`'s code exists and that it conforms to ERC20 (won't return
            // short calldata). We do not bother to check for either of these conditions.

            r := mload(0x00)
        }
    }

    function fastTransfer(IERC20 token, address to, uint256 amount) internal {
        assembly ("memory-safe") {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            // Storing `amount` clobbers the upper bits of the free memory pointer, but those bits
            // can never be set without running into an OOG, so it's safe. We'll restore them to
            // zero at the end.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // Selector for `transfer(address,uint256)`, with `to`'s padding.

            // Calldata starts at offset 16 and is 68 bytes long (2 * 32 + 4). We're not checking
            // the return value, so we don't bother to copy the returndata into memory.
            if iszero(call(gas(), token, 0x00, 0x10, 0x44, 0x00, 0x00)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }
            // We assume that the token we're calling is well-behaved. We don't check that it
            // might've returned `false`.

            mstore(0x34, 0x00) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    function fastTotalSupply(IERC20 token) internal view returns (uint256 r) {
        assembly ("memory-safe") {
            mstore(0x00, 0x18160ddd) // selector for `totalSupply()`

            // Call and check for revert. Storing the misaligned selector in memory at 0 results in
            // a start of calldata at offset 28. Calldata is 4 bytes long.
            if iszero(staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }
            // We assume that `token`'s code exists and that it conforms to ERC20 (won't return
            // short calldata). We do not bother to check for either of these conditions.

            r := mload(0x00)
        }
    }
}
合同源代码
文件 12 的 46:IERC1046.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IERC1046 {
    /// @notice Gets an ERC-721-like token URI.
    /// @dev The resolved data MUST be in JSON format and support ERC-1046's ERC-20 Token Metadata Schema.
    function tokenURI() external view returns (string memory);
}
合同源代码
文件 13 的 46:IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
    /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
    event Transfer(address indexed from, address indexed to, uint256 value);

    /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
    /// is the new allowance.
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /// @notice Returns the amount of tokens in existence.
    function totalSupply() external view returns (uint256);

    /// @notice Returns the amount of tokens owned by `account`.
    function balanceOf(address account) external view returns (uint256);

    /// @notice Moves `amount` tokens from the caller's account to `to`.
    function transfer(address to, uint256 amount) external returns (bool);

    /// @notice Returns the remaining number of tokens that `spender` is allowed
    /// to spend on behalf of `owner`
    function allowance(address owner, address spender) external view returns (uint256);

    /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
    /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    function approve(address spender, uint256 amount) external returns (bool);

    /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
    /// `amount` is then deducted from the caller's allowance.
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    /// @notice Returns the name of the token.
    function name() external view returns (string memory);

    /// @notice Returns the symbol of the token.
    function symbol() external view returns (string memory);

    /// @notice Returns the decimals places of the token.
    function decimals() external view returns (uint8);
}
合同源代码
文件 14 的 46:IERC2612.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {INonces} from "./INonces.sol";

interface IERC2612 is IERC20, INonces {
    /// @notice Approves `spender` to spend `value` tokens on behalf of `owner` via an off-chain
    /// signature.
    /// @param owner The holder of the tokens and the signer of the EIP-712 object. Must not be the
    /// zero address.
    /// @param spender The account for which to create the allowance. `permit` causes `spender` to
    /// be able to move `owner`'s tokens.
    /// @param value The token amount of the allowance to be created.
    /// @param deadline The current blocktime must be less than or equal to `deadline`.
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;

    /// @notice Returns the EIP-712 domain separator used for signature verification.
    // slither-disable-next-line naming-convention
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
合同源代码
文件 15 的 46:IERC5267.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IERC5267 {
    /// @notice Returns the un-hashed fields that comprise the EIP-712 domain.
    /// @return fields A bitmask indicating which domain fields are used.
    /// @return name The human-readable name of the domain.
    /// @return chainId The chain ID of the network.
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory,
            uint256 chainId,
            address verifyingContract,
            bytes32,
            uint256[] memory
        );
}
合同源代码
文件 16 的 46:IERC5805.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {INonces} from "./INonces.sol";
import {IERC6372} from "./IERC6372.sol";

interface IERC5805 is INonces, IERC6372 {
    /// @notice Returns the current voting weight of an account. 
    /// @notice This is the sum of the voting power delegated of each account delegating to it at
    /// this moment.
    function getVotes(address account) external view returns (uint256 votingWeight);

    /// @notice Returns the historical voting weight of an account. 
    /// @notice This is the sum of the voting power delegated of each account delegating to it at a
    /// specific timepoint. 
    /// @notice If this function does not revert, this is a constant value.
    function getPastVotes(address account, uint256 timepoint) external view returns (uint256 votingWeight);

    /// @notice Returns the address to which the voting power of `account` is currently delegated.
    function delegates(address account) external view returns (address delegatee);

    /// @notice Changes the caller’s delegate, updating the vote delegation in the meantime.
    function delegate(address delegatee) external;

    /// @notice Changes an account's delegate using an off-chain signature, updating the vote
    /// delegation in the meantime.
    /// @param nonce Must be equal to the current value of `nonces(...)` for the signer.
    /// @param expiry The current blocktime must be less than or equal to `expiry`.
    function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;

    /// @notice Emitted when the delegate for an account is modified by `delegate` or
    /// `delegateBySig`.
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /// @notice Emitted when `delegate`'s available voting power changes from `previousBalance` to
    /// `newBalance`.
    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
}
合同源代码
文件 17 的 46:IERC6093.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IERC6093 {
    /// @notice Indicates an error related to the current `balance` of a `sender`.
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /// @notice Indicates a failure with the token `sender`.
    error ERC20InvalidSender(address sender);

    /// @notice Indicates a failure with the token `receiver`.
    error ERC20InvalidReceiver(address receiver);

    /// @notice Indicates a failure with the `spender`’s `allowance`.
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /// @notice Indicates a failure with the `approver` of a token to be approved.
    error ERC20InvalidApprover(address approver);

    /// @notice Indicates that the `deadline` of the `permit` has passed.
    error ERC2612ExpiredSignature(uint256 deadline);

    /// @notice Indicates a mismatch between the `owner` of a permit and the signer of the EIP-712
    /// object.
    error ERC2612InvalidSigner(address signer, address owner);

    /// @notice Indicates that the `expiry` of the `delegateBySig` has passed.
    error ERC5805ExpiredSignature(uint256 expiry);

    /// @notice Indicates that the signature of the `delegateBySig` is malformed.
    error ERC5805InvalidSignature();

    /// @notice Indicates that the current `nonces(...)` of the signer does not match the given
    /// `nonce` value.
    error ERC5805InvalidNonce(uint256 actual, uint256 expected);

    /// @notice Indicates that the queried `timepoint` is equal to or greater than the current value
    /// `clock`.
    error ERC5805TimepointNotPast(uint256 timepoint, uint256 clock);
}
合同源代码
文件 18 的 46:IERC6372.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IERC6372 {
    /// @notice Returns the current timepoint according to the mode the contract is operating on. 
    /// @notice This is non-decreasing.
    function clock() external view returns (uint48);

    /// @notice Returns a machine-readable string description of the clock.
    // slither-disable-next-line naming-convention
    function CLOCK_MODE() external view returns (string memory);
}
合同源代码
文件 19 的 46:IERC7674.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@forge-std/interfaces/IERC20.sol";

interface IERC7674 is IERC20 {
    /// @notice Allows `spender` to withdraw *within the same transaction*, from the caller,
    /// multiple times, up to `amount`.
    function temporaryApprove(address spender, uint256 amount) external returns (bool);
}
合同源代码
文件 20 的 46:IFU.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC1046} from "./IERC1046.sol";
import {IERC2612} from "./IERC2612.sol";
import {IERC5267} from "./IERC5267.sol";
import {IERC5805} from "./IERC5805.sol";
import {IERC6093} from "./IERC6093.sol";
import {IERC7674} from "./IERC7674.sol";

interface IFU is IERC1046, IERC2612, IERC5267, IERC5805, IERC6093, IERC7674 {
    /// @dev Emitted only once, on deployment, indicating the git commit hash from which this
    /// contract was built.
    event GitCommit(bytes20 indexed gitCommit);

    /// @notice Returns the UniswapV2 pair address where this token is paired with WETH. 
    /// @notice The UniswapV2 pair address is the only address that does not participate in the
    /// "reflection".
    function pair() external view returns (address uniV2Pair);

    /// @notice Returns the URI of the image/icon representing this token.
    function image() external view returns (string memory URI);

    /// @notice Returns the tax rate (in basis points) applied to *ALL* transfers. 
    /// @notice This is not a constant value.
    function tax() external view returns (uint256 basisPoints);

    /// @notice Returns the maximum possible balance of the account. 
    /// @notice Any action that would result in the account going over this balance causes the
    /// excess tokens to be implicitly `deliver()`'d. 
    /// @notice This is not a constant value.
    function whaleLimit(address account) external view returns (uint256 maxBalance);

    /// @notice Returns the sum of the current voting weight of all accounts.
    function getTotalVotes() external view returns (uint256);

    /// @notice Returns the sum of the historical voting weight of all accounts. 
    /// @notice If this function does not revert, this is a constant value.
    function getPastTotalVotes(uint256 timepoint) external view returns (uint256);

    /// @notice Destroys `amount` tokens from the caller's account. 
    /// @notice These tokens are removed from circulation, reducing `totalSupply()`.
    function burn(uint256 amount) external returns (bool);

    /// @notice Destroys `amount` tokens from `from` using the allowance mechanism. `amount` is
    /// then deducted from the caller's allowance. 
    /// @notice These tokens are removed from circulation, reducing `totalSupply()`.
    function burnFrom(address from, uint256 amount) external returns (bool);

    /// @notice Deducts `amount` tokens from the caller's account. 
    /// @notice These tokens are "reflected" or minted back to other tokens holders, proportionately. 
    /// @notice `totalSupply()` remains unchanged.
    function deliver(uint256 amount) external returns (bool);

    /// @notice Deducts `amount` tokens from `from` using the allowance mechanism. `amount` is then
    /// deducted from the caller's allowance. 
    /// @notice These tokens are "reflected" or minted back to other tokens holders, proportionately. 
    /// @notice `totalSupply()` remains unchanged.
    function deliverFrom(address from, uint256 amount) external returns (bool);
}
合同源代码
文件 21 的 46:INonces.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface INonces {
    /// @notice Returns the current nonce for `account` to be used for off-chain signatures.
    function nonces(address account) external view returns (uint256 nonce);
}
合同源代码
文件 22 的 46:IPFS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Panic} from "./Panic.sol";

library IPFS {
    /// @return r SHA256(Protobuf({1: Protobuf({1: 2, 2: contentString, 3: contentString.length})}))
    /// @param contentString File contents to be encoded and hashed
    /// @dev if `contentString` is empty, field 2 is omitted, but field 3 is retained as zero
    /// @dev if `contentString` is longer than 256kiB, it exceeds an IPFS chunk and cannot be handled by this function (reverts)
    function dagPbUnixFsHash(string memory contentString) internal view returns (bytes32 r) {
        unchecked {
            uint256 contentLength = bytes(contentString).length;
            if (contentLength >= 0x40001) {
                Panic.panic(Panic.OUT_OF_MEMORY);
            }
            bytes memory len = _protobufVarint(contentLength);
            bytes memory len2 = _protobufVarint(contentLength == 0 ? 4 : contentLength + 4 + 2 * len.length);
            assembly ("memory-safe") {
                let ptr := mload(0x40)
                let dst := ptr
                mstore8(ptr, 0x0a)
                dst := add(dst, 0x01)
                mcopy(dst, add(len2, 0x20), mload(len2))
                dst := add(dst, mload(len2))
                mstore(dst, hex"080212") // TODO: remove padding
                switch contentLength
                case 0 { dst := add(dst, 0x02) }
                default {
                    dst := add(dst, 0x03)
                    mcopy(dst, add(len, 0x20), mload(len))
                    dst := add(dst, mload(len))
                    mcopy(dst, add(contentString, 0x20), contentLength)
                    dst := add(dst, contentLength)
                }
                mstore8(dst, 0x18)
                dst := add(dst, 0x01)
                mcopy(dst, add(len, 0x20), mload(len))
                dst := add(dst, mload(len))
                if or(xor(returndatasize(), 0x20), iszero(staticcall(gas(), 0x02, ptr, sub(dst, ptr), ptr, 0x20))) {
                    invalid()
                }
                r := mload(ptr)
            }
        }
    }

    /// @return r string.concat("ipfs://", Base58(bytes.concat(hex"1220", h)))
    /// @param h The SHA256 hash value to be encoded. Must be the output of `ipfsDagPbUnixFsHash`
    // slither-disable-next-line naming-convention
    function CIDv0(bytes32 h) internal pure returns (string memory r) {
        assembly ("memory-safe") {
            // we're going to take total control of the first 4 words of
            // memory. we will restore the free memory pointer and the zero word
            // at the end
            r := mload(0x40)
            let ptr := add(r, 0x54)

            // store the base58 alphabet lookup table
            mstore(0x19, 0x31323334353637383941424344454647484a4b4c4d4e50515253)
            mstore(0x39, 0x5455565758595a6162636465666768696a6b6d6e6f707172737475767778797a)

            // the first 3 iterations are special because we're actually encoding 34 bytes
            mstore8(ptr, mload(mod(h, 0x3a)))
            ptr := sub(ptr, 0x01)
            h := add(0x04, div(h, 0x3a)) // 0x04 is the residue of prepending `hex"1220"`
            mstore8(ptr, mload(mod(h, 0x3a)))
            ptr := sub(ptr, 0x01)
            h := add(0x28, div(h, 0x3a)) // 0x28 is the residue of prepending `hex"1220"`
            mstore8(ptr, mload(mod(h, 0x3a)))
            ptr := sub(ptr, 0x01)
            h := div(h, 0x3a)
            // this absurd constant prepends `hex"1220"` to `h`
            h := add(h, 0x616868b6a3c45673102217be3fec84b7db78d8bb82965f94d9f33718a8074e3)

            // the rest is "normal"
            for { let end := sub(ptr, 0x2b) } gt(ptr, end) { ptr := sub(ptr, 0x01) } {
                mstore8(ptr, mload(mod(h, 0x3a)))
                h := div(h, 0x3a)
            }

            mstore(r, 0x00)
            // length plus "ipfs://"
            mstore(add(r, 0x07), 0x35697066733a2f2f)
            mstore(0x40, add(r, 0x55))
            mstore(0x60, 0x00)
        }
    }

    function _protobufVarint(uint256 x) private pure returns (bytes memory r) {
        if (x >= 0x200000) {
            Panic.panic(Panic.ARITHMETIC_OVERFLOW);
        }
        assembly ("memory-safe") {
            r := mload(0x40)
            let length := 0x01
            mstore8(add(r, 0x20), or(0x80, and(0x7f, x)))
            x := shr(0x07, x)
            if x {
                mstore8(add(r, 0x21), or(0x80, and(0x7f, x)))
                x := shr(0x07, x)
                switch x
                case 0 { length := 0x02 }
                default {
                    mstore8(add(r, 0x22), and(0x7f, x))
                    length := 0x03
                }
            }

            mstore(r, length)
            let last := add(r, length)
            mstore(last, and(0xffffff7f, mload(last)))
            mstore(0x40, add(last, 0x20))
        }
    }
}
合同源代码
文件 23 的 46:IUniswapV2Factory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {IUniswapV2Pair, INIT_HASH} from "./IUniswapV2Pair.sol";

interface IUniswapV2Factory {
    function createPair(IERC20 tokenA, IERC20 tokenB) external returns (IUniswapV2Pair pair);
    function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Pair pair);
    function feeTo() external view returns (address);
}

library FastUniswapV2FactoryLib {
    function fastFeeTo(IUniswapV2Factory factory) internal view returns (address r) {
        assembly ("memory-safe") {
            mstore(0x00, 0x017e7e58) // selector for `feeTo()`

            if iszero(staticcall(gas(), factory, 0x1c, 0x04, 0x00, 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }

            r := mload(0x00)
            if shr(0xa0, r) { revert(0x00, 0x00) }
        }
    }
}

IUniswapV2Factory constant FACTORY = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);

function pairFor(IERC20 tokenA, IERC20 tokenB) pure returns (IUniswapV2Pair) {
    (tokenA, tokenB) = tokenB < tokenA ? (tokenB, tokenA) : (tokenA, tokenB);
    bytes32 salt = keccak256(abi.encodePacked(tokenA, tokenB));
    bytes32 result = keccak256(abi.encodePacked(bytes1(0xff), FACTORY, salt, INIT_HASH));
    return IUniswapV2Pair(address(uint160(uint256(result))));
}
合同源代码
文件 24 的 46:IUniswapV2Pair.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC2612} from "./IERC2612.sol";

interface IUniswapV2Pair is IERC2612 {
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint256);
    function price1CumulativeLast() external view returns (uint256);
    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);
    function burn(address to) external returns (uint256 amount0, uint256 amount1);
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
    function sync() external;
}

library FastUniswapV2PairLib {
    function fastGetReserves(IUniswapV2Pair pair)
        internal
        view
        returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)
    {
        assembly ("memory-safe") {
            let ptr := mload(0x40)

            mstore(0x00, 0x0902f1ac)

            if iszero(staticcall(gas(), pair, 0x1c, 0x04, 0x00, 0x60)) {
                let ptr_ := mload(0x40)
                returndatacopy(ptr_, 0x00, returndatasize())
                revert(ptr_, returndatasize())
            }

            reserve0 := mload(0x00)
            reserve1 := mload(0x20)
            blockTimestampLast := mload(0x40)

            mstore(0x40, ptr)
        }
    }

    function fastPriceCumulativeLast(IUniswapV2Pair pair, bool which) internal view returns (uint256 r) {
        assembly ("memory-safe") {
            // selector for `price0CumulativeLast()` if `which` is false, otherwise selector for `price1CumulativeLast()`
            mstore(0x00, xor(0x5909c0d5, mul(0x03349446, which)))

            if iszero(staticcall(gas(), pair, 0x1c, 0x04, 0x00, 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }

            r := mload(0x00)
        }
    }

    function fastKLast(IUniswapV2Pair pair) internal view returns (uint256 r) {
        assembly ("memory-safe") {
            mstore(0x00, 0x7464fc3d) // selector for `kLast()`

            if iszero(staticcall(gas(), pair, 0x1c, 0x04, 0x00, 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }

            r := mload(0x00)
        }
    }

    function fastBurn(IUniswapV2Pair pair, address to) internal returns (uint256 amount0, uint256 amount1) {
        assembly ("memory-safe") {
            mstore(0x14, to)
            mstore(0x00, 0x89afcb44000000000000000000000000) // selector for `burn(address)` with `to`'s padding
            if iszero(call(gas(), pair, 0x00, 0x10, 0x24, 0x00, 0x40)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0x00, returndatasize())
                revert(ptr, returndatasize())
            }
            amount0 := mload(0x00)
            amount1 := mload(0x20)
        }
    }

    function fastSwap(IUniswapV2Pair pair, uint256 amount0, uint256 amount1, address to) internal {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(ptr, 0x022c0d9f) // selector for `swap(uint256,uint256,address,bytes)`
            mstore(add(0x20, ptr), amount0)
            mstore(add(0x40, ptr), amount1)
            mstore(add(0x60, ptr), and(0xffffffffffffffffffffffffffffffffffffffff, to))
            mstore(add(0x80, ptr), 0x80)
            mstore(add(0xa0, ptr), 0x00)

            if iszero(call(gas(), pair, 0x00, add(0x1c, ptr), 0xa4, 0x00, 0x00)) {
                let ptr_ := mload(0x40)
                returndatacopy(ptr_, 0x00, returndatasize())
                revert(ptr_, returndatasize())
            }
        }
    }
}

bytes32 constant INIT_HASH = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;
合同源代码
文件 25 的 46:ItoA.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library ItoA {
    function itoa(uint256 x) internal pure returns (string memory r) {
        assembly ("memory-safe") {
            mstore(9, 0x30313233343536373839) // lookup table [0..9]

            // we over-allocate memory here because that's cheaper than
            // computing the correct length and allocating exactly that much
            let end := add(mload(0x40), 0x6e)
            mstore(0x40, end)

            for {
                r := sub(end, 0x01)
                mstore8(r, mload(mod(x, 0x0a)))
                x := div(x, 0x0a)
            } x {} {
                r := sub(r, 0x01)
                mstore8(r, mload(mod(x, 0x0a)))
                x := div(x, 0x0a)
            }
            let length := sub(end, r)
            r := sub(r, 0x20)
            mstore(r, length)
        }
    }

    function itoa(int256 value) internal pure returns (string memory) {
        if (value < 0) {
            return string.concat("-", itoa(uint256(-value)));
        } else {
            return itoa(uint256(value));
        }
    }
}
合同源代码
文件 26 的 46:Math.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library Math {
    function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := add(x, y)
            r := or(r, sub(0x00, lt(r, y)))
        }
    }

    function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := mul(sub(x, y), gt(x, y))
        }
    }

    /// Copied from Solmate (https://github.com/transmissions11/solmate/blob/eaa7041378f9a6c12f943de08a6c41b31a9870fc/src/utils/FixedPointMathLib.sol#L288)
    /// The original code was released under the MIT license.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly ("memory-safe") {
            let y := x // We start y at x, which will help us make our initial estimate.

            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.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, 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(y, 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)). Therefore, we may rarely return ceil(sqrt(x)) instead of the expected value.
            // This error is not corrected because in our practical usage it doesn't matter and it saves some gas.
        }
    }
}
合同源代码
文件 27 的 46:MoonPhase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {BasisPoints} from "../types/BasisPoints.sol";

import {Ternary} from "../lib/Ternary.sol";
import {UnsafeMath} from "../lib/UnsafeMath.sol";

library MoonPhase {
    using Ternary for bool;
    using UnsafeMath for int256;

    uint256 private constant _EPOCH = 1740721485; // 2025-02-28T00:44:45Z, the last new moon of February 2025
    // This is the AVERAGE length of the synodic month at the epoch. The duration between actual new
    // moons varies significantly over short periods of time. Over long periods of time, the average
    // length of the synodic month increases slightly.
    uint256 private constant _SYNODIC_MONTH = 0x17348a775920; // 29.530588907 * 10 ** 7 * 1 days
    uint256 private constant _SCALE = 0x9896800000000000000000; // 2 ** 64 * 10 ** 7

    int256 private constant _ONE_HALF = 0x8000000000000000; // 0.5 * 2 ** 64
    int256 private constant _ONE_QUARTER = 0x4000000000000000; // 0.25 * 2 ** 64
    int256 private constant _THREE_QUARTERS = 0xc000000000000000; // 0.75 * 2 ** 64

    function moonPhase(uint256 timestamp) internal pure returns (BasisPoints) {
        // This is performed outside the `unchecked` block because we want underflow checking
        uint256 reEpoch = timestamp - _EPOCH;
        unchecked {
            // `monthElapsed` represents the position of the current moment within the current lunar
            // month. It's a linear value, even though the illumination of the moon is nonlinear in
            // time. The basis, `2 ** 64`, is chosen so that when we compute `sin` below, we can
            // avoid some extraneous bit shifts. The author considered a higher-order polynomial
            // approximation of the length of the synodic month, but concluded that it was excessive
            // given the relatively small second and third moments (compared to "reasonable"
            // timescales) as well as the significant additional complexity in taking the integral
            // of that approximation from the epoch to the present.
            int256 monthElapsed = int256((reEpoch * _SCALE / _SYNODIC_MONTH) & type(uint64).max);

            // Now that we have the sawtooth function `monthElapsed` that ranges from 0 at the new
            // moon to 0.5 at the full moon to 1 at the next new moon, we want to convert that into
            // a smooth function representing the (un)illuminated portion of the moon's face. We
            // must take the cosine of `monthElapsed`.

            // For convenience, rather than represent the input to `cos` in radians, we represent it
            // in turns (with a full circle represented by 1 instead of 2π). We first reduce the
            // range of `x` from 0 to 1 to 0 to 0.25 and reflect it so that we can compute `sign *
            // sin(x)` instead.
            int256 x;
            {
                int256 thresh = (monthElapsed < _ONE_HALF).ternary(_ONE_QUARTER, _THREE_QUARTERS);
                x = (monthElapsed < thresh).ternary(thresh - monthElapsed, monthElapsed - thresh);
            }
            int256 sign = (uint256(monthElapsed) - uint256(_ONE_QUARTER) < uint256(_ONE_HALF)).ternary(-1, 1); // underflow is desired

            // Now we approximate `sign * sin(x)` via a (4, 3)-term monic-numerator rational
            // polynomial. This technique was popularized by Remco Bloemen
            // (https://2π.com/22/approximation/). The basis `2 ** 64` was chosen to give enough
            // extra precision to avoid significant rounding error in the coefficients, but not so
            // much that we have to perform wasteful right shifts between each term. We use Horner's
            // rule to evaluate each polynomial because Knuth's and Winograd's algorithms give worse
            // rounding error. This relatively small rational polynomial is only accurate to ~1e-5,
            // but that is more than sufficient for our purposes.

            int256 p = x; // `p` is monic; the leading coefficient is 1
            p += 0x152c603e02fe2031; // ~0.0827
            p *= x;
            p -= 0x462df383df0568550000000000000000; // ~0.274
            p *= x;
            // The constant coefficient of `p` is so small (~3.98e-7) that it does not affect
            // accuracy if it is elided
            p *= sign;

            int256 q = -0x1d98428cf2b72221; // ~-0.116
            q *= x;
            q += 0x032c1ccefcbad6dd0000000000000000; // ~0.0124
            q *= x;
            q -= 0x0b2a3a89efcf885e00000000000000000000000000000000; // ~0.0436

            // Now `p/q` if computed exactly represents `cos(monthElapsed)`. What we actually want,
            // though, is `(1 + cos(monthElapsed)) / 2`. We also want to represent the output as a
            // value from 1 to 5000 inclusive; this gives rise to the awkward `2500` as well as the
            // `+ 1`. `q` has no zeroes in the domain, so we don't need to worry about
            // divide-by-zero.
            return BasisPoints.wrap(uint256(((p + q) * 2500).unsafeDiv(q)) + 1);
        }
    }
}
合同源代码
文件 28 的 46:MultiCallContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Context} from "./Context.sol";

interface IMultiCall {
    enum RevertPolicy {
        REVERT,
        HALT,
        CONTINUE
    }

    struct Call {
        address target;
        RevertPolicy revertPolicy;
        uint256 value;
        bytes data;
    }

    struct Result {
        bool success;
        bytes data;
    }

    function multicall(Call[] calldata calls, uint256 contextdepth) external payable returns (Result[] memory);

    receive() external payable;
}

abstract contract MultiCallContext is Context {
    address private constant _MULTICALL_ADDRESS = 0x00000000000000CF9E3c5A26621af382fA17f24f;

    IMultiCall internal constant MULTICALL = IMultiCall(payable(_MULTICALL_ADDRESS));

    function _isForwarded() internal view virtual override returns (bool) {
        return super._isForwarded() || super._msgSender() == address(MULTICALL);
    }

    function _msgData() internal view virtual override returns (bytes calldata r) {
        address sender = super._msgSender();
        r = super._msgData();
        assembly ("memory-safe") {
            r.length :=
                sub(r.length, mul(0x14, eq(_MULTICALL_ADDRESS, and(0xffffffffffffffffffffffffffffffffffffffff, sender))))
        }
    }

    function _msgSender() internal view virtual override returns (address sender) {
        sender = super._msgSender();
        if (sender == address(MULTICALL)) {
            bytes calldata data = super._msgData();
            assembly ("memory-safe") {
                sender := shr(0x60, calldataload(add(data.offset, sub(data.length, 0x14))))
            }
        }
    }
}
合同源代码
文件 29 的 46:Panic.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library Panic {
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)`
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }

    // https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require
    uint8 internal constant GENERIC = 0x00;
    uint8 internal constant ASSERT_FAIL = 0x01;
    uint8 internal constant ARITHMETIC_OVERFLOW = 0x11;
    uint8 internal constant DIVISION_BY_ZERO = 0x12;
    uint8 internal constant ENUM_CAST = 0x21;
    uint8 internal constant CORRUPT_STORAGE_ARRAY = 0x22;
    uint8 internal constant POP_EMPTY_ARRAY = 0x31;
    uint8 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    uint8 internal constant OUT_OF_MEMORY = 0x41;
    uint8 internal constant ZERO_FUNCTION_POINTER = 0x51;
}
合同源代码
文件 30 的 46:RebaseQueue.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IERC20} from "@forge-std/interfaces/IERC20.sol";

import {Settings} from "./Settings.sol";
import {applyWhaleLimit} from "./WhaleLimit.sol";

import {Tokens, ZERO as ZERO_TOKENS} from "../types/Tokens.sol";
import {Shares, SharesStorage, ONE as ONE_SHARE} from "../types/Shares.sol";
import {SharesToTokens} from "../types/TokensXShares.sol";
import {Tokens} from "../types/Tokens.sol";
import {UnsafeMath} from "../lib/UnsafeMath.sol";

struct RebaseQueueElem {
    address prev;
    address next;
    Tokens lastTokens;
}

struct RebaseQueue {
    mapping(address => RebaseQueueElem) queue;
    address head;
}

library LibRebaseQueue {
    using UnsafeMath for uint256;
    using SharesToTokens for Shares;

    function initialize(RebaseQueue storage self, address account, Tokens tokens) internal {
        self.head = account;
        RebaseQueueElem storage elem = self.queue[account];
        elem.prev = account;
        elem.next = account;
        elem.lastTokens = tokens;
    }

    function enqueue(RebaseQueue storage self, address account, Tokens balance) internal {
        RebaseQueueElem storage elem = self.queue[account];
        address head = self.head;
        RebaseQueueElem storage headElem = self.queue[head];
        address tail = headElem.prev;

        elem.prev = tail;
        elem.next = head;
        elem.lastTokens = balance;

        self.queue[tail].next = account;
        headElem.prev = account;
    }

    function enqueue(RebaseQueue storage self, address account, Shares shares, Tokens totalSupply, Shares totalShares)
        internal
    {
        return enqueue(self, account, shares.toTokens(totalSupply, totalShares));
    }

    function dequeue(RebaseQueue storage self, address account) internal {
        RebaseQueueElem storage elem = self.queue[account];
        elem.lastTokens = ZERO_TOKENS;
        address prev = elem.prev;
        address next = elem.next;

        elem.prev = address(0);
        elem.next = address(0);

        self.queue[prev].next = next;
        self.queue[next].prev = prev;

        if (self.head == account) {
            self.head = next;
        }
    }

    function moveToBack(
        RebaseQueue storage self,
        address account,
        Shares shares,
        Tokens totalSupply,
        Shares totalShares
    ) internal {
        RebaseQueueElem storage elem = self.queue[account];
        elem.lastTokens = shares.toTokens(totalSupply, totalShares);

        if (self.head == account) {
            self.head = elem.next;
            return;
        }

        address next = elem.next;
        address head = self.head;
        if (next == head) {
            return;
        }
        address prev = elem.prev;
        RebaseQueueElem storage headElem = self.queue[head];
        address tail = headElem.prev;

        elem.prev = tail;
        elem.next = head;

        self.queue[prev].next = next;
        self.queue[next].prev = prev;

        self.queue[tail].next = account;
        headElem.prev = account;
    }

    function _rebaseFor(
        RebaseQueueElem storage elem,
        address account,
        Shares shares,
        Tokens totalSupply,
        Shares totalShares
    ) private returns (Tokens newTokens) {
        Tokens oldTokens = elem.lastTokens;
        newTokens = shares.toTokens(totalSupply, totalShares);
        if (newTokens > oldTokens) {
            emit IERC20.Transfer(address(0), account, (newTokens - oldTokens).toExternal());
        } else {
            newTokens = oldTokens;
        }
    }

    function rebaseFor(RebaseQueue storage self, address account, Shares shares, Tokens totalSupply, Shares totalShares)
        internal
    {
        _rebaseFor(self.queue[account], account, shares, totalSupply, totalShares);
    }

    function processQueue(
        RebaseQueue storage self,
        mapping(address => SharesStorage) storage sharesOf,
        Tokens totalSupply,
        Shares totalShares
    ) internal {
        address cursor = self.head;
        RebaseQueueElem storage elem = self.queue[cursor];
        uint256 i;
        assembly ("memory-safe") {
            mstore(0x00, gas())
            i := shr(0xfd, keccak256(0x00, 0x20))
        }
        for (;; i = i.unsafeDec()) {
            (Shares shares, Shares totalSharesLimited) = applyWhaleLimit(sharesOf[cursor].load(), totalShares);
            elem.lastTokens = _rebaseFor(elem, cursor, shares, totalSupply, totalSharesLimited);
            cursor = elem.next;
            if (i == 0) {
                break;
            }
            elem = self.queue[cursor];
        }
        self.head = cursor;
    }
}
合同源代码
文件 31 的 46:ReflectMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Settings} from "../core/Settings.sol";
import {whaleLimit} from "../core/WhaleLimit.sol";

import {BasisPoints, BASIS} from "../types/BasisPoints.sol";
import {Shares, ONE as ONE_SHARE} from "../types/Shares.sol";
import {Tokens} from "../types/Tokens.sol";
import {TokensXBasisPoints, scale, cast} from "../types/TokensXBasisPoints.sol";
import {TokensXShares, tmp as tmpTS, alloc as allocTS} from "../types/TokensXShares.sol";
import {TokensXShares2} from "../types/TokensXShares2.sol";
import {TokensXBasisPointsXShares, tmp as tmpTBpS, alloc as allocTBpS} from "../types/TokensXBasisPointsXShares.sol";
import {TokensXBasisPointsXShares2} from "../types/TokensXBasisPointsXShares2.sol";
import {SharesXBasisPoints, scale, cast} from "../types/SharesXBasisPoints.sol";
import {Shares2XBasisPoints, alloc as allocS2Bp} from "../types/Shares2XBasisPoints.sol";

/*

WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING
  ***                                                                     ***
WARNING                     This code is unaudited                      WARNING
  ***                                                                     ***
WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING

*/

library ReflectMath {
    modifier freeMemory() {
        uint256 freePtr;
        assembly ("memory-safe") {
            freePtr := mload(0x40)
        }
        _;
        assembly ("memory-safe") {
            mstore(0x40, freePtr)
        }
    }

    // TODO: reorder arguments for clarity/consistency
    function getTransferShares(
        Tokens amount,
        BasisPoints taxRate,
        Tokens totalSupply,
        Shares totalShares,
        Shares fromShares,
        Shares toShares
    ) internal pure freeMemory returns (Shares newFromShares, Shares newToShares, Shares newTotalShares) {
        Shares uninvolvedShares = totalShares - fromShares - toShares;
        TokensXBasisPointsXShares2 n0 = allocTS().omul(fromShares, totalSupply).isub(tmpTS().omul(amount, totalShares))
            .imul(scale(uninvolvedShares, BASIS));
        TokensXBasisPointsXShares d = allocTBpS().omul(totalSupply, scale(uninvolvedShares, BASIS)).iadd(
            tmpTBpS().omul(amount, scale(totalShares, taxRate))
        );
        TokensXBasisPointsXShares2 n1 = allocTBpS().omul(amount, scale(totalShares, BASIS - taxRate)).iadd(
            tmpTBpS().omul(scale(toShares, BASIS), totalSupply)
        ).imul(uninvolvedShares);

        (newFromShares, newToShares) = (n0.div(d), n1.div(d));
        newTotalShares = totalShares + (newToShares - toShares) - (fromShares - newFromShares);
    }

    function getTransferAllShares(BasisPoints taxRate, Shares totalShares, Shares fromShares, Shares toShares)
        internal
        pure
        freeMemory
        returns (Shares newToShares, Shares newTotalShares)
    {
        Shares uninvolvedShares = totalShares - fromShares - toShares;
        Shares2XBasisPoints n = allocS2Bp().omul(scale(uninvolvedShares, BASIS), totalShares);
        SharesXBasisPoints d = scale(uninvolvedShares, BASIS) + scale(fromShares, taxRate);

        newTotalShares = n.div(d);
        newToShares = toShares + fromShares - (totalShares - newTotalShares);
    }

    function getTransferSharesToWhale(
        Tokens amount,
        BasisPoints taxRate,
        Tokens totalSupply,
        Shares totalShares,
        Shares fromShares,
        Shares toShares
    )
        internal
        pure
        freeMemory
        returns (Shares newFromShares, Shares counterfactualToShares, Shares newToShares, Shares newTotalShares)
    {
        TokensXShares d = allocTS().omul(totalShares.mul(Settings.ANTI_WHALE_DIVISOR), totalSupply + amount).isub(
            tmpTS().omul(fromShares.mul(Settings.ANTI_WHALE_DIVISOR) + totalShares, totalSupply)
        );
        Shares uninvolvedShares = totalShares - fromShares - toShares;
        TokensXShares2 n0 =
            allocTS().omul(totalShares.mul(Settings.ANTI_WHALE_DIVISOR), totalSupply).imul(uninvolvedShares);
        TokensXShares2 n1 = allocTS().omul(fromShares, totalSupply).isub(tmpTS().omul(totalShares, amount)).imul(
            uninvolvedShares.mul(Settings.ANTI_WHALE_DIVISOR)
        );

        (newToShares, newFromShares) = (n0.div(d), n1.div(d));
        newToShares = newToShares.div(Settings.ANTI_WHALE_DIVISOR) - ONE_SHARE;
        newTotalShares = totalShares - (fromShares + toShares - newFromShares - newToShares);
        counterfactualToShares = tmpTBpS().omul(
            scale(totalSupply, BASIS.div(Settings.ANTI_WHALE_DIVISOR)) - scale(amount, BASIS - taxRate), totalShares
        ).div(scale(totalSupply, BASIS));
    }

    function getTransferAllSharesToWhale(BasisPoints taxRate, Shares totalShares, Shares fromShares, Shares toShares)
        internal
        pure
        returns (Shares counterfactualToShares, Shares newToShares, Shares newTotalShares)
    {
        (newToShares, newTotalShares) = whaleLimit(toShares, totalShares - fromShares);
        counterfactualToShares =
            cast(scale(totalShares, BASIS.div(Settings.ANTI_WHALE_DIVISOR)) - scale(fromShares, BASIS - taxRate));
    }

    function getTransferSharesFromPair(
        BasisPoints taxRate,
        Tokens totalSupply,
        Shares totalShares,
        Tokens amount,
        Shares toShares
    ) internal pure freeMemory returns (Shares newToShares, Shares newTotalShares, Tokens newTotalSupply) {
        TokensXBasisPointsXShares d = allocTBpS().omul(scale(totalSupply, BASIS), totalShares).iadd(
            tmpTBpS().omul(scale(amount, taxRate), totalShares)
        );
        TokensXBasisPointsXShares t = tmpTBpS().omul(scale(totalSupply, BASIS), toShares);
        // slither-disable-next-line unused-return
        d.isub(t);
        TokensXBasisPointsXShares2 n =
            allocTBpS().omul(scale(amount, BASIS - taxRate), totalShares).iadd(t).imul(totalShares - toShares);

        newToShares = n.div(d);
        newTotalShares = totalShares + newToShares - toShares;
        newTotalSupply = totalSupply + amount;
    }

    function getCounterfactualSharesFromPairToWhale(
        BasisPoints taxRate,
        Tokens totalSupply,
        Shares totalShares,
        Tokens amount
    ) internal pure returns (Shares counterfactualToShares) {
        TokensXBasisPoints left = scale(totalSupply + amount, BASIS);
        TokensXBasisPoints right = scale(amount.mul(Settings.ANTI_WHALE_DIVISOR), BASIS - taxRate);
        counterfactualToShares = tmpTBpS().omul(left.saturatingSub(right), totalShares).div(
            scale(totalSupply.mul(Settings.ANTI_WHALE_DIVISOR), BASIS)
        );
    }

    function getTransferSharesToPair(
        BasisPoints taxRate,
        Tokens totalSupply,
        Shares totalShares,
        Tokens amount,
        Shares fromShares
    )
        internal
        pure
        freeMemory
        returns (Shares newFromShares, Shares newTotalShares, Tokens transferTokens, Tokens newTotalSupply)
    {
        TokensXBasisPointsXShares2 n = allocTBpS().omul(scale(fromShares, BASIS), totalSupply).isub(
            tmpTBpS().omul(scale(totalShares, BASIS), amount)
        ).imul(totalShares - fromShares);

        TokensXBasisPointsXShares d = allocTBpS().omul(scale(totalShares, taxRate), amount).iadd(
            tmpTBpS().omul(scale(totalShares - fromShares, BASIS), totalSupply)
        );

        newFromShares = n.div(d);
        newTotalShares = totalShares - (fromShares - newFromShares);
        transferTokens = cast(scale(amount, BASIS - taxRate));
        newTotalSupply = totalSupply - transferTokens;
    }

    function getDeliverShares(Tokens amount, Tokens totalSupply, Shares totalShares, Shares fromShares)
        internal
        pure
        freeMemory
        returns (Shares newFromShares, Shares newTotalShares)
    {
        TokensXShares d = allocTS().omul(totalSupply, totalShares - fromShares);
        TokensXShares t = tmpTS().omul(amount, totalShares);
        // slither-disable-next-line unused-return
        d.iadd(t);
        TokensXShares2 n = allocTS().omul(fromShares, totalSupply).isub(t).imul(totalShares - fromShares);

        newFromShares = n.div(d);
        newTotalShares = totalShares + newFromShares - fromShares;
    }

    // getDeliverShares(Tokens,Shares,Shares) is not provided because it's extremely straightforward

    function getBurnShares(Tokens amount, Tokens totalSupply, Shares totalShares, Shares fromShares)
        internal
        pure
        freeMemory
        returns (Shares newFromShares, Shares newTotalShares, Tokens newTotalSupply)
    {
        TokensXShares n = allocTS().omul(fromShares, totalSupply).isub(tmpTS().omul(totalShares, amount));
        newFromShares = n.div(totalSupply);
        newTotalShares = totalShares + newFromShares - fromShares;
        newTotalSupply = totalSupply - amount;
    }

    // getBurnShares(Tokens,Shares,Shares) is not provided because it's extremely straightforward
}
合同源代码
文件 32 的 46:Settings.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ReflectMath} from "./ReflectMath.sol";

import {BasisPoints, BASIS} from "../types/BasisPoints.sol";
import {Shares} from "../types/Shares.sol";
import {Tokens} from "../types/Tokens.sol";
import {TokensXShares, alloc, tmp} from "../types/TokensXShares.sol";

import {UnsafeMath} from "../lib/UnsafeMath.sol";

library Settings {
    using UnsafeMath for uint256;

    uint256 internal constant INITIAL_LIQUIDITY_DIVISOR = 5;
    // An amount of shares above `totalShares / 4` makes `ReflectMath` break down. Also setting it
    // near to `INITIAL_LIQUIDITY_DIVISOR` will cause unexpected reverts. This must also evenly
    // divide `BASIS` (10_000).
    uint256 internal constant ANTI_WHALE_DIVISOR = 40;
    uint256 internal constant ANTI_WHALE_DIVISOR_MINUS_ONE = 39;
    uint256 internal constant ANTI_WHALE_DIVISOR_MINUS_TWO = 38;

    BasisPoints internal constant MIN_TAX = BasisPoints.wrap(1);
    // A tax above `BASIS / 2` makes `ReflectMath` break down
    BasisPoints internal constant MAX_TAX = BasisPoints.wrap(5_000); // BasisPoints.unwrap(BASIS) / 2

    uint256 private constant _UNISWAPV2_MAX_BALANCE = 0xffffffffffffffffffffffffffff; // 2 ** 112 - 1

    uint8 internal constant DECIMALS = 35;
    uint256 internal constant PAIR_LEADING_ZEROES = 32;
    uint256 internal constant CRAZY_BALANCE_BASIS = 0x1ffffffff; // 2 ** (PAIR_LEADING_ZEROES + 1) - 1;
    Tokens internal constant INITIAL_SUPPLY = Tokens.wrap(0x1fffffffefffffffffffffffffffe00000001); // _UNISWAPV2_MAX_BALANCE * CRAZY_BALANCE_BASIS
    Shares internal constant INITIAL_SHARES = Shares.wrap(0x1fffffffefffffffffffffffffffe0000000100000000); // Tokens.unwrap(INITIAL_SUPPLY) << 32

    uint256 internal constant INITIAL_SHARES_RATIO = 0x100000000; // Shares.unwrap(INITIAL_SHARES) / Tokens.unwrap(INITIAL_SUPPLY)
    uint256 internal constant MIN_SHARES_RATIO = 5; // below this, `ReflectMath` breaks down
    // It is not possible for the shares ratio to get as low as `MIN_SHARES_RATIO`. 1 whole token is
    // sent to the `DEAD` address on construction (effectively locked forever). Therefore, the
    // maximum possible relative decrease of the shares ratio is the number of tokens, approximately
    // 446 million. This is considerably smaller than the ratio between the initial shares ratio
    // and the minimum shares ratio, approximately 859 million.

    uint256 internal constant ADDRESS_DIVISOR = 0x80000000000000000000000000000000; // 2 ** 160 / (CRAZY_BALANCE_BASIS + 1)
    uint256 internal constant ADDRESS_SHIFT = 127; // log_2(ADDRESS_DIVISOR)

    // This constant is intertwined with a bunch of hex literals in `Checkpoints.sol`, because
    // Solidity has poor support for introspecting the range of user-defined types and for defining
    // constants dependant on values in other translation units. If you change this, make
    // appropriate changes over there, and be sure to run the invariant/property tests.
    uint256 internal constant SHARES_TO_VOTES_DIVISOR = 0x100000000; // 2 ** 32
    uint256 internal constant SHARES_TO_VOTES_SHIFT = 32; // log_2(SHARES_TO_VOTES_DIVISOR)
    // Where there are no *wrong* values for this constant, setting it to the ratio between the
    // voting period and the clock quantum optimizes gas.
    uint256 internal constant BISECT_WINDOW_DEFAULT = 7;

    function oneTokenInShares() internal pure returns (Shares) {
        TokensXShares initialSharesTimesOneToken = alloc().omul(INITIAL_SHARES, Tokens.wrap(10 ** DECIMALS));
        Shares result = initialSharesTimesOneToken.div(INITIAL_SUPPLY);
        result = result.inc(tmp().omul(result, INITIAL_SUPPLY) < initialSharesTimesOneToken);
        return result;
    }
}
合同源代码
文件 33 的 46:Shares.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {UnsafeMath} from "../lib/UnsafeMath.sol";
import {Ternary} from "../lib/Ternary.sol";

/// This type is given as `uint256` for efficiency, but it is capped at `2 ** 177 - 1`.
type Shares is uint256;

Shares constant ZERO = Shares.wrap(0);
Shares constant ONE = Shares.wrap(1);

library SharesUnsafeMathAdapter {
    using UnsafeMath for uint256;

    function inc(Shares x, bool c) internal pure returns (Shares) {
        return Shares.wrap(Shares.unwrap(x).unsafeInc(c));
    }

    function dec(Shares x, bool c) internal pure returns (Shares) {
        return Shares.wrap(Shares.unwrap(x).unsafeDec(c));
    }
}

using SharesUnsafeMathAdapter for Shares global;

library SharesArithmetic {
    using UnsafeMath for uint256;

    function mul(Shares x, uint256 y) internal pure returns (Shares) {
        unchecked {
            return Shares.wrap(Shares.unwrap(x) * y);
        }
    }

    function div(Shares n, uint256 d) internal pure returns (Shares) {
        return Shares.wrap(Shares.unwrap(n).unsafeDiv(d));
    }
}

using SharesArithmetic for Shares global;

function __add(Shares a, Shares b) pure returns (Shares) {
    unchecked {
        return Shares.wrap(Shares.unwrap(a) + Shares.unwrap(b));
    }
}

function __sub(Shares a, Shares b) pure returns (Shares) {
    unchecked {
        return Shares.wrap(Shares.unwrap(a) - Shares.unwrap(b));
    }
}

function __eq(Shares a, Shares b) pure returns (bool) {
    return Shares.unwrap(a) == Shares.unwrap(b);
}

function __lt(Shares a, Shares b) pure returns (bool) {
    return Shares.unwrap(a) < Shares.unwrap(b);
}

function __gt(Shares a, Shares b) pure returns (bool) {
    return Shares.unwrap(a) > Shares.unwrap(b);
}

function __ne(Shares a, Shares b) pure returns (bool) {
    return Shares.unwrap(a) != Shares.unwrap(b);
}

function __le(Shares a, Shares b) pure returns (bool) {
    return Shares.unwrap(a) <= Shares.unwrap(b);
}

function __ge(Shares a, Shares b) pure returns (bool) {
    return Shares.unwrap(a) >= Shares.unwrap(b);
}

using {
    __add as +, __sub as -, __eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __gt as >=
} for Shares global;

function ternary(bool c, Shares x, Shares y) pure returns (Shares) {
    return Shares.wrap(Ternary.ternary(c, Shares.unwrap(x), Shares.unwrap(y)));
}

function maybeSwap(bool c, Shares x, Shares y) pure returns (Shares, Shares) {
    (uint256 a, uint256 b) = Ternary.maybeSwap(c, Shares.unwrap(x), Shares.unwrap(y));
    return (Shares.wrap(a), Shares.wrap(b));
}

// This is the same as `Shares`, except it has padding on both ends, just to make life harder for
// people who do state overrides. Also, unlike "normal" Solidity behavior, dirty padding is not
// cleaned, but instead results in the entire slot being implicitly cleared.
type SharesStorage is uint256;

function load(SharesStorage x) pure returns (Shares r) {
    assembly ("memory-safe") {
        r := mul(shr(0x28, x), iszero(and(0xffffffffff00000000000000000000000000000000000000000000ffffffffff, x)))
    }
}

function store(Shares x) pure returns (SharesStorage r) {
    assembly ("memory-safe") {
        r := shl(0x28, x)
    }
}

using {load} for SharesStorage global;
using {store} for Shares global;
合同源代码
文件 34 的 46:Shares2XBasisPoints.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Shares} from "./Shares.sol";
import {SharesXBasisPoints} from "./SharesXBasisPoints.sol";

import {uint512, alloc as baseAlloc} from "../lib/512Math.sol";

type Shares2XBasisPoints is bytes32;

function cast(Shares2XBasisPoints x) pure returns (uint512) {
    return uint512.wrap(Shares2XBasisPoints.unwrap(x));
}

function cast(uint512 x) pure returns (Shares2XBasisPoints) {
    return Shares2XBasisPoints.wrap(uint512.unwrap(x));
}

function alloc() pure returns (Shares2XBasisPoints) {
    return cast(baseAlloc());
}

library Shares2XBasisPointsArithmetic {
    function omul(Shares2XBasisPoints r, SharesXBasisPoints sbp, Shares s)
        internal
        pure
        returns (Shares2XBasisPoints)
    {
        return cast(cast(r).omul(SharesXBasisPoints.unwrap(sbp), Shares.unwrap(s)));
    }

    function omul(Shares2XBasisPoints r, Shares s, SharesXBasisPoints sbp)
        internal
        pure
        returns (Shares2XBasisPoints)
    {
        return cast(cast(r).omul(Shares.unwrap(s), SharesXBasisPoints.unwrap(sbp)));
    }

    function div(Shares2XBasisPoints n, SharesXBasisPoints d) internal pure returns (Shares) {
        return Shares.wrap(cast(n).div(SharesXBasisPoints.unwrap(d)));
    }

    function div(Shares2XBasisPoints n, Shares d) internal pure returns (SharesXBasisPoints) {
        return SharesXBasisPoints.wrap(cast(n).div(Shares.unwrap(d)));
    }
}

using Shares2XBasisPointsArithmetic for Shares2XBasisPoints global;

function __eq(Shares2XBasisPoints a, Shares2XBasisPoints b) pure returns (bool) {
    return cast(a) == cast(b);
}

function __lt(Shares2XBasisPoints a, Shares2XBasisPoints b) pure returns (bool) {
    return cast(a) < cast(b);
}

function __gt(Shares2XBasisPoints a, Shares2XBasisPoints b) pure returns (bool) {
    return cast(a) > cast(b);
}

function __ne(Shares2XBasisPoints a, Shares2XBasisPoints b) pure returns (bool) {
    return cast(a) != cast(b);
}

function __le(Shares2XBasisPoints a, Shares2XBasisPoints b) pure returns (bool) {
    return cast(a) <= cast(b);
}

function __ge(Shares2XBasisPoints a, Shares2XBasisPoints b) pure returns (bool) {
    return cast(a) >= cast(b);
}

using {__eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=} for Shares2XBasisPoints global;
合同源代码
文件 35 的 46:SharesXBasisPoints.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {BasisPoints, BASIS} from "./BasisPoints.sol";
import {Shares} from "./Shares.sol";

import {UnsafeMath} from "../lib/UnsafeMath.sol";

/// This type is given as `uint256` for efficiency, but it is actually only 191 bits.
type SharesXBasisPoints is uint256;

function scale(Shares s, BasisPoints bp) pure returns (SharesXBasisPoints) {
    unchecked {
        return SharesXBasisPoints.wrap(Shares.unwrap(s) * BasisPoints.unwrap(bp));
    }
}

function cast(SharesXBasisPoints tbp) pure returns (Shares) {
    return Shares.wrap(UnsafeMath.unsafeDiv(SharesXBasisPoints.unwrap(tbp), BasisPoints.unwrap(BASIS)));
}

function __add(SharesXBasisPoints a, SharesXBasisPoints b) pure returns (SharesXBasisPoints) {
    unchecked {
        return SharesXBasisPoints.wrap(SharesXBasisPoints.unwrap(a) + SharesXBasisPoints.unwrap(b));
    }
}

function __sub(SharesXBasisPoints a, SharesXBasisPoints b) pure returns (SharesXBasisPoints) {
    unchecked {
        return SharesXBasisPoints.wrap(SharesXBasisPoints.unwrap(a) - SharesXBasisPoints.unwrap(b));
    }
}

using {__add as +, __sub as -} for SharesXBasisPoints global;
合同源代码
文件 36 的 46:Ternary.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library Ternary {
    function ternary(bool c, uint256 x, uint256 y) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := xor(y, mul(xor(x, y), c))
        }
    }

    function ternary(bool c, int256 x, int256 y) internal pure returns (int256 r) {
        assembly ("memory-safe") {
            r := xor(y, mul(xor(x, y), c))
        }
    }

    function maybeSwap(bool c, uint256 x, uint256 y) internal pure returns (uint256 a, uint256 b) {
        assembly ("memory-safe") {
            let t := mul(xor(x, y), c)
            a := xor(x, t)
            b := xor(y, t)
        }
    }
}
合同源代码
文件 37 的 46:Tokens.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {UnsafeMath} from "../lib/UnsafeMath.sol";

/// This type is given as `uint256` for efficiency, but it is capped at `2 ** 145 - 1`.
type Tokens is uint256;

library TokensAccessors {
    function toExternal(Tokens x) internal pure returns (uint256) {
        return Tokens.unwrap(x);
    }
}

using TokensAccessors for Tokens global;

Tokens constant ZERO = Tokens.wrap(0);
Tokens constant ONE = Tokens.wrap(1);

library TokensUnsafeMathAdapter {
    using UnsafeMath for uint256;

    function inc(Tokens x, bool c) internal pure returns (Tokens) {
        return Tokens.wrap(Tokens.unwrap(x).unsafeInc(c));
    }

    function dec(Tokens x, bool c) internal pure returns (Tokens) {
        return Tokens.wrap(Tokens.unwrap(x).unsafeDec(c));
    }
}

using TokensUnsafeMathAdapter for Tokens global;

library TokensArithmetic {
    using UnsafeMath for uint256;

    function mul(Tokens x, uint256 y) internal pure returns (Tokens) {
        unchecked {
            return Tokens.wrap(Tokens.unwrap(x) * y);
        }
    }

    function div(Tokens n, uint256 d) internal pure returns (Tokens) {
        return Tokens.wrap(Tokens.unwrap(n).unsafeDiv(d));
    }
}

using TokensArithmetic for Tokens global;

function __add(Tokens a, Tokens b) pure returns (Tokens) {
    unchecked {
        return Tokens.wrap(Tokens.unwrap(a) + Tokens.unwrap(b));
    }
}

function __sub(Tokens a, Tokens b) pure returns (Tokens) {
    unchecked {
        return Tokens.wrap(Tokens.unwrap(a) - Tokens.unwrap(b));
    }
}

function __eq(Tokens a, Tokens b) pure returns (bool) {
    return Tokens.unwrap(a) == Tokens.unwrap(b);
}

function __lt(Tokens a, Tokens b) pure returns (bool) {
    return Tokens.unwrap(a) < Tokens.unwrap(b);
}

function __gt(Tokens a, Tokens b) pure returns (bool) {
    return Tokens.unwrap(a) > Tokens.unwrap(b);
}

function __ne(Tokens a, Tokens b) pure returns (bool) {
    return Tokens.unwrap(a) != Tokens.unwrap(b);
}

function __le(Tokens a, Tokens b) pure returns (bool) {
    return Tokens.unwrap(a) <= Tokens.unwrap(b);
}

function __ge(Tokens a, Tokens b) pure returns (bool) {
    return Tokens.unwrap(a) >= Tokens.unwrap(b);
}

using {
    __add as +, __sub as -, __eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=
} for Tokens global;
合同源代码
文件 38 的 46:TokensXBasisPoints.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {BasisPoints, BASIS} from "./BasisPoints.sol";
import {Tokens} from "./Tokens.sol";

import {Math} from "../lib/Math.sol";
import {UnsafeMath} from "../lib/UnsafeMath.sol";

/// This type is given as `uint256` for efficiency, but it is actually only 159 bits.
type TokensXBasisPoints is uint256;

library TokensXBasisPointsArithmetic {
    function saturatingAdd(TokensXBasisPoints x, TokensXBasisPoints y) internal pure returns (TokensXBasisPoints r) {
        return TokensXBasisPoints.wrap(Math.saturatingAdd(TokensXBasisPoints.unwrap(x), TokensXBasisPoints.unwrap(y)));
    }

    function saturatingSub(TokensXBasisPoints x, TokensXBasisPoints y) internal pure returns (TokensXBasisPoints r) {
        return TokensXBasisPoints.wrap(Math.saturatingSub(TokensXBasisPoints.unwrap(x), TokensXBasisPoints.unwrap(y)));
    }
}

using TokensXBasisPointsArithmetic for TokensXBasisPoints global;

function scale(Tokens s, BasisPoints bp) pure returns (TokensXBasisPoints) {
    unchecked {
        return TokensXBasisPoints.wrap(Tokens.unwrap(s) * BasisPoints.unwrap(bp));
    }
}

function cast(TokensXBasisPoints tbp) pure returns (Tokens) {
    return Tokens.wrap(UnsafeMath.unsafeDiv(TokensXBasisPoints.unwrap(tbp), BasisPoints.unwrap(BASIS)));
}

function castUp(TokensXBasisPoints tbp) pure returns (Tokens) {
    return Tokens.wrap(UnsafeMath.unsafeDivUp(TokensXBasisPoints.unwrap(tbp), BasisPoints.unwrap(BASIS)));
}

function __sub(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (TokensXBasisPoints) {
    unchecked {
        return TokensXBasisPoints.wrap(TokensXBasisPoints.unwrap(a) - TokensXBasisPoints.unwrap(b));
    }
}

function __eq(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (bool) {
    return TokensXBasisPoints.unwrap(a) == TokensXBasisPoints.unwrap(b);
}

function __lt(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (bool) {
    return TokensXBasisPoints.unwrap(a) < TokensXBasisPoints.unwrap(b);
}

function __gt(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (bool) {
    return TokensXBasisPoints.unwrap(a) > TokensXBasisPoints.unwrap(b);
}

function __ne(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (bool) {
    return TokensXBasisPoints.unwrap(a) != TokensXBasisPoints.unwrap(b);
}

function __le(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (bool) {
    return TokensXBasisPoints.unwrap(a) <= TokensXBasisPoints.unwrap(b);
}

function __ge(TokensXBasisPoints a, TokensXBasisPoints b) pure returns (bool) {
    return TokensXBasisPoints.unwrap(a) >= TokensXBasisPoints.unwrap(b);
}

using {
    __sub as -, __eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=
} for TokensXBasisPoints global;
合同源代码
文件 39 的 46:TokensXBasisPointsXShares.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {BASIS} from "./BasisPoints.sol";
import {Shares} from "./Shares.sol";
import {Tokens} from "./Tokens.sol";
import {SharesXBasisPoints, scale} from "./SharesXBasisPoints.sol";
import {TokensXBasisPoints} from "./TokensXBasisPoints.sol";

import {TokensXBasisPointsXShares2, cast as cast2} from "./TokensXBasisPointsXShares2.sol";

import {uint512, tmp as baseTmp, alloc as baseAlloc} from "../lib/512Math.sol";

type TokensXBasisPointsXShares is bytes32;

function cast(TokensXBasisPointsXShares x) pure returns (uint512) {
    return uint512.wrap(TokensXBasisPointsXShares.unwrap(x));
}

function cast(uint512 x) pure returns (TokensXBasisPointsXShares) {
    return TokensXBasisPointsXShares.wrap(uint512.unwrap(x));
}

function alloc() pure returns (TokensXBasisPointsXShares) {
    return cast(baseAlloc());
}

function tmp() pure returns (TokensXBasisPointsXShares) {
    return cast(baseTmp());
}

library TokensXBasisPointsXSharesArithmetic {
    function iadd(TokensXBasisPointsXShares r, TokensXBasisPointsXShares x)
        internal
        pure
        returns (TokensXBasisPointsXShares)
    {
        return cast(cast(r).iadd(cast(x)));
    }

    function isub(TokensXBasisPointsXShares r, TokensXBasisPointsXShares x)
        internal
        pure
        returns (TokensXBasisPointsXShares)
    {
        return cast(cast(r).isub(cast(x)));
    }

    function omul(TokensXBasisPointsXShares r, Tokens b, SharesXBasisPoints s)
        internal
        pure
        returns (TokensXBasisPointsXShares)
    {
        return cast(cast(r).omul(Tokens.unwrap(b), SharesXBasisPoints.unwrap(s)));
    }

    function omul(TokensXBasisPointsXShares r, SharesXBasisPoints s, Tokens b)
        internal
        pure
        returns (TokensXBasisPointsXShares)
    {
        return cast(cast(r).omul(SharesXBasisPoints.unwrap(s), Tokens.unwrap(b)));
    }

    function omul(TokensXBasisPointsXShares r, Shares s, TokensXBasisPoints b)
        internal
        pure
        returns (TokensXBasisPointsXShares)
    {
        return cast(cast(r).omul(Shares.unwrap(s), TokensXBasisPoints.unwrap(b)));
    }

    function omul(TokensXBasisPointsXShares r, TokensXBasisPoints b, Shares s)
        internal
        pure
        returns (TokensXBasisPointsXShares)
    {
        return cast(cast(r).omul(TokensXBasisPoints.unwrap(b), Shares.unwrap(s)));
    }

    function imul(TokensXBasisPointsXShares r, Shares s) internal pure returns (TokensXBasisPointsXShares2) {
        return cast2(cast(r).imul(Shares.unwrap(s)));
    }

    function div(TokensXBasisPointsXShares n, SharesXBasisPoints d) internal pure returns (Tokens) {
        return Tokens.wrap(cast(n).div(SharesXBasisPoints.unwrap(d)));
    }

    function div(TokensXBasisPointsXShares n, TokensXBasisPoints d) internal pure returns (Shares) {
        return Shares.wrap(cast(n).div(TokensXBasisPoints.unwrap(d)));
    }
}

using TokensXBasisPointsXSharesArithmetic for TokensXBasisPointsXShares global;

library SharesToTokensProportional {
    function toTokens(SharesXBasisPoints sharesBp, Tokens totalSupply, Shares totalShares)
        internal
        pure
        returns (Tokens)
    {
        return tmp().omul(sharesBp, totalSupply).div(scale(totalShares, BASIS));
    }
}
合同源代码
文件 40 的 46:TokensXBasisPointsXShares2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Shares} from "./Shares.sol";
import {TokensXBasisPointsXShares, cast as cast1} from "./TokensXBasisPointsXShares.sol";

import {uint512} from "../lib/512Math.sol";

type TokensXBasisPointsXShares2 is bytes32;

function cast(TokensXBasisPointsXShares2 x) pure returns (uint512) {
    return uint512.wrap(TokensXBasisPointsXShares2.unwrap(x));
}

function cast(uint512 x) pure returns (TokensXBasisPointsXShares2) {
    return TokensXBasisPointsXShares2.wrap(uint512.unwrap(x));
}

library TokensXBasisPointsXShares2Arithmetic {
    function div(TokensXBasisPointsXShares2 n, TokensXBasisPointsXShares d) internal pure returns (Shares) {
        return Shares.wrap(cast(n).div(cast1(d)));
    }
}

using TokensXBasisPointsXShares2Arithmetic for TokensXBasisPointsXShares2 global;
合同源代码
文件 41 的 46:TokensXShares.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Shares} from "./Shares.sol";
import {Tokens} from "./Tokens.sol";
import {BasisPoints} from "./BasisPoints.sol";
import {SharesXBasisPoints} from "./SharesXBasisPoints.sol";

import {TokensXShares2, cast2} from "./TokensXShares2.sol";
import {TokensXBasisPointsXShares, cast as cast3} from "./TokensXBasisPointsXShares.sol";
import {TokensXBasisPointsXShares2, cast as cast4} from "./TokensXBasisPointsXShares2.sol";

import {uint512, tmp as baseTmp, alloc as baseAlloc} from "../lib/512Math.sol";

type TokensXShares is bytes32;

function cast(TokensXShares x) pure returns (uint512) {
    return uint512.wrap(TokensXShares.unwrap(x));
}

function cast(uint512 x) pure returns (TokensXShares) {
    return TokensXShares.wrap(uint512.unwrap(x));
}

function alloc() pure returns (TokensXShares) {
    return cast(baseAlloc());
}

function tmp() pure returns (TokensXShares) {
    return cast(baseTmp());
}

library TokensXSharesArithmetic {
    function iadd(TokensXShares r, TokensXShares x) internal pure returns (TokensXShares) {
        return cast(cast(r).iadd(cast(x)));
    }

    function isub(TokensXShares r, TokensXShares x) internal pure returns (TokensXShares) {
        return cast(cast(r).isub(cast(x)));
    }

    function omul(TokensXShares r, Tokens b, Shares s) internal pure returns (TokensXShares) {
        return cast(cast(r).omul(Tokens.unwrap(b), Shares.unwrap(s)));
    }

    function omul(TokensXShares r, Shares s, Tokens b) internal pure returns (TokensXShares) {
        return cast(cast(r).omul(Shares.unwrap(s), Tokens.unwrap(b)));
    }

    function imul(TokensXShares r, Shares s) internal pure returns (TokensXShares2) {
        return cast2(cast(r).imul(Shares.unwrap(s)));
    }

    function imul(TokensXShares r, BasisPoints bp) internal pure returns (TokensXBasisPointsXShares) {
        return cast3(cast(r).imul(BasisPoints.unwrap(bp)));
    }

    function imul(TokensXShares r, SharesXBasisPoints s) internal pure returns (TokensXBasisPointsXShares2) {
        return cast4(cast(r).imul(SharesXBasisPoints.unwrap(s)));
    }

    function div(TokensXShares n, Tokens d) internal pure returns (Shares) {
        return Shares.wrap(cast(n).div(Tokens.unwrap(d)));
    }

    function div(TokensXShares n, Shares d) internal pure returns (Tokens) {
        return Tokens.wrap(cast(n).div(Shares.unwrap(d)));
    }

    function divMulti(TokensXShares n0, TokensXShares n1, Tokens d) internal pure returns (Shares, Shares) {
        (uint256 r0, uint256 r1) = cast(n0).divMulti(cast(n1), Tokens.unwrap(d));
        return (Shares.wrap(r0), Shares.wrap(r1));
    }

    function divMulti(TokensXShares n0, TokensXShares n1, Shares d) internal pure returns (Tokens, Tokens) {
        (uint256 r0, uint256 r1) = cast(n0).divMulti(cast(n1), Shares.unwrap(d));
        return (Tokens.wrap(r0), Tokens.wrap(r1));
    }
}

using TokensXSharesArithmetic for TokensXShares global;

function __eq(TokensXShares a, TokensXShares b) pure returns (bool) {
    return cast(a) == cast(b);
}

function __lt(TokensXShares a, TokensXShares b) pure returns (bool) {
    return cast(a) < cast(b);
}

function __gt(TokensXShares a, TokensXShares b) pure returns (bool) {
    return cast(a) > cast(b);
}

function __ne(TokensXShares a, TokensXShares b) pure returns (bool) {
    return cast(a) != cast(b);
}

function __le(TokensXShares a, TokensXShares b) pure returns (bool) {
    return cast(a) <= cast(b);
}

function __ge(TokensXShares a, TokensXShares b) pure returns (bool) {
    return cast(a) >= cast(b);
}

using {__eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=} for TokensXShares global;

library SharesToTokens {
    function toTokens(Shares shares, Tokens totalSupply, Shares totalShares) internal pure returns (Tokens) {
        return tmp().omul(shares, totalSupply).div(totalShares);
    }

    modifier freeMemory() {
        uint256 freePtr;
        assembly ("memory-safe") {
            freePtr := mload(0x40)
        }
        _;
        assembly ("memory-safe") {
            mstore(0x40, freePtr)
        }
    }

    function toTokensMulti(Shares shares0, Shares shares1, Tokens totalSupply, Shares totalShares)
        internal
        pure
        freeMemory
        returns (Tokens r0, Tokens r1)
    {
        TokensXShares n0 = alloc().omul(shares0, totalSupply);
        TokensXShares n1 = tmp().omul(shares1, totalSupply);
        (r0, r1) = n0.divMulti(n1, totalShares);
    }
}
合同源代码
文件 42 的 46:TokensXShares2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Shares} from "./Shares.sol";
import {TokensXShares, cast} from "./TokensXShares.sol";

import {uint512} from "../lib/512Math.sol";

type TokensXShares2 is bytes32;

function cast(TokensXShares2 x) pure returns (uint512) {
    return uint512.wrap(TokensXShares2.unwrap(x));
}

function cast2(uint512 x) pure returns (TokensXShares2) {
    return TokensXShares2.wrap(uint512.unwrap(x));
}

library TokensXShares2Arithmetic {
    function div(TokensXShares2 n, TokensXShares d) internal pure returns (Shares) {
        return Shares.wrap(cast(n).div(cast(d)));
    }
}

using TokensXShares2Arithmetic for TokensXShares2 global;

function __eq(TokensXShares2 a, TokensXShares2 b) pure returns (bool) {
    return cast(a) == cast(b);
}

function __lt(TokensXShares2 a, TokensXShares2 b) pure returns (bool) {
    return cast(a) < cast(b);
}

function __gt(TokensXShares2 a, TokensXShares2 b) pure returns (bool) {
    return cast(a) > cast(b);
}

function __ne(TokensXShares2 a, TokensXShares2 b) pure returns (bool) {
    return cast(a) != cast(b);
}

function __le(TokensXShares2 a, TokensXShares2 b) pure returns (bool) {
    return cast(a) <= cast(b);
}

function __ge(TokensXShares2 a, TokensXShares2 b) pure returns (bool) {
    return cast(a) >= cast(b);
}

using {__eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=} for TokensXShares2 global;
合同源代码
文件 43 的 46:TransientStorageLayout.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {CrazyBalance} from "../types/CrazyBalance.sol";

abstract contract TransientStorageLayout {
    function _setTemporaryAllowance(address owner, address spender, CrazyBalance amount) internal {
        assembly ("memory-safe") {
            mstore(0x14, spender)
            mstore(0x00, owner)
            tstore(keccak256(0x0c, 0x28), amount)
        }
    }

    function _getTemporaryAllowance(address owner, address spender) internal view returns (CrazyBalance r) {
        assembly ("memory-safe") {
            mstore(0x14, spender)
            mstore(0x00, owner)
            r := tload(keccak256(0x0c, 0x28))
        }
    }
}
合同源代码
文件 44 的 46:UnsafeMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library UnsafeMath {
    function unsafeInc(uint256 x) internal pure returns (uint256) {
        unchecked {
            return x + 1;
        }
    }

    function unsafeInc(uint256 x, bool b) internal pure returns (uint256) {
        assembly ("memory-safe") {
            x := add(x, b)
        }
        return x;
    }

    function unsafeInc(int256 x) internal pure returns (int256) {
        unchecked {
            return x + 1;
        }
    }

    function unsafeInc(int256 x, bool b) internal pure returns (int256) {
        assembly ("memory-safe") {
            x := add(x, b)
        }
        return x;
    }

    function unsafeDec(uint256 x) internal pure returns (uint256) {
        unchecked {
            return x - 1;
        }
    }

    function unsafeDec(uint256 x, bool b) internal pure returns (uint256) {
        assembly ("memory-safe") {
            x := sub(x, b)
        }
        return x;
    }

    function unsafeDec(int256 x) internal pure returns (int256) {
        unchecked {
            return x - 1;
        }
    }

    function unsafeDec(int256 x, bool b) internal pure returns (int256) {
        assembly ("memory-safe") {
            x := sub(x, b)
        }
        return x;
    }

    function unsafeNeg(int256 x) internal pure returns (int256) {
        unchecked {
            return -x;
        }
    }

    function unsafeDiv(uint256 numerator, uint256 denominator) internal pure returns (uint256 quotient) {
        assembly ("memory-safe") {
            quotient := div(numerator, denominator)
        }
    }

    function unsafeDiv(int256 numerator, int256 denominator) internal pure returns (int256 quotient) {
        assembly ("memory-safe") {
            quotient := sdiv(numerator, denominator)
        }
    }

    function unsafeMod(uint256 numerator, uint256 denominator) internal pure returns (uint256 remainder) {
        assembly ("memory-safe") {
            remainder := mod(numerator, denominator)
        }
    }

    function unsafeMod(int256 numerator, int256 denominator) internal pure returns (int256 remainder) {
        assembly ("memory-safe") {
            remainder := smod(numerator, denominator)
        }
    }

    function unsafeMulMod(uint256 a, uint256 b, uint256 m) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := mulmod(a, b, m)
        }
    }

    function unsafeAddMod(uint256 a, uint256 b, uint256 m) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := addmod(a, b, m)
        }
    }

    function unsafeDivUp(uint256 n, uint256 d) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := add(gt(mod(n, d), 0x00), div(n, d))
        }
    }
}
合同源代码
文件 45 的 46:Votes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Settings} from "../core/Settings.sol";

import {Shares} from "./Shares.sol";

// This is actually only 145 bits, but we set it to 256 bits here to convince the compiler we don't
// need to do as much masking.
type Votes is uint256;

Votes constant ZERO = Votes.wrap(0);

function toVotes(Shares s) pure returns (Votes) {
    return Votes.wrap(Shares.unwrap(s) >> Settings.SHARES_TO_VOTES_SHIFT);
}

function toExternal(Votes v) pure returns (uint256) {
    return Votes.unwrap(v);
}

using {toExternal} for Votes global;

function __add(Votes a, Votes b) pure returns (Votes) {
    unchecked {
        return Votes.wrap(Votes.unwrap(a) + Votes.unwrap(b));
    }
}

function __sub(Votes a, Votes b) pure returns (Votes) {
    unchecked {
        return Votes.wrap(Votes.unwrap(a) - Votes.unwrap(b));
    }
}

function __eq(Votes a, Votes b) pure returns (bool) {
    return Votes.unwrap(a) == Votes.unwrap(b);
}

function __lt(Votes a, Votes b) pure returns (bool) {
    return Votes.unwrap(a) < Votes.unwrap(b);
}

function __gt(Votes a, Votes b) pure returns (bool) {
    return Votes.unwrap(a) > Votes.unwrap(b);
}

function __ne(Votes a, Votes b) pure returns (bool) {
    return Votes.unwrap(a) != Votes.unwrap(b);
}

function __le(Votes a, Votes b) pure returns (bool) {
    return Votes.unwrap(a) <= Votes.unwrap(b);
}

function __ge(Votes a, Votes b) pure returns (bool) {
    return Votes.unwrap(a) >= Votes.unwrap(b);
}

using {
    __add as +, __sub as -, __eq as ==, __lt as <, __gt as >, __ne as !=, __le as <=, __ge as >=
} for Votes global;
合同源代码
文件 46 的 46:WhaleLimit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Shares, ONE as ONE_SHARE, ternary, maybeSwap} from "../types/Shares.sol";
import {Settings} from "./Settings.sol";

function whaleLimit(Shares shares, Shares totalShares) pure returns (Shares limit, Shares newTotalShares) {
    Shares uninvolved = totalShares - shares;
    limit = uninvolved.div(Settings.ANTI_WHALE_DIVISOR_MINUS_ONE) - ONE_SHARE;
    newTotalShares = uninvolved + limit;
}

function applyWhaleLimit(Shares shares, Shares totalShares) pure returns (Shares, Shares) {
    (Shares limit, Shares newTotalShares) = whaleLimit(shares, totalShares);
    bool condition = shares > limit;
    return (ternary(condition, limit, shares), ternary(condition, newTotalShares, totalShares));
}

function applyWhaleLimit(Shares shares0, Shares shares1, Shares totalShares) pure returns (Shares, Shares, Shares) {
    bool condition = shares0 > shares1;
    (Shares sharesLo, Shares sharesHi) = maybeSwap(condition, shares0, shares1);
    (Shares firstLimit, Shares newTotalShares) = whaleLimit(sharesHi, totalShares);
    if (sharesHi > firstLimit) {
        Shares uninvolved = totalShares - sharesHi - sharesLo;
        Shares secondLimit = uninvolved.div(Settings.ANTI_WHALE_DIVISOR_MINUS_TWO) - ONE_SHARE;
        if (sharesLo > secondLimit) {
            totalShares = uninvolved + secondLimit.mul(2);
            sharesHi = secondLimit;
            sharesLo = secondLimit;
        } else {
            totalShares = newTotalShares;
            sharesHi = firstLimit;
        }
    }
    (shares0, shares1) = maybeSwap(condition, sharesLo, sharesHi);
    return (shares0, shares1, totalShares);
}
设置
{
  "compilationTarget": {
    "src/FU.sol": "FU"
  },
  "evmVersion": "cancun",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "remappings": [
    ":@forge-std/=lib/forge-std/src/"
  ],
  "viaIR": true
}
ABI
[{"inputs":[{"internalType":"bytes20","name":"gitCommit","type":"bytes20"},{"internalType":"string","name":"image_","type":"string"},{"internalType":"address[]","name":"initialHolders","type":"address[]"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"ERC5805ExpiredSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"ERC5805InvalidNonce","type":"error"},{"inputs":[],"name":"ERC5805InvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"timepoint","type":"uint256"},{"internalType":"uint256","name":"clock","type":"uint256"}],"name":"ERC5805TimepointNotPast","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes20","name":"gitCommit","type":"bytes20"}],"name":"GitCommit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"CLOCK_MODE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"delegatee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deliver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deliverFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastTotalVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"image","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"r","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"temporaryApprove","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"potentialWhale","type":"address"}],"name":"whaleLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]