> For the complete documentation index, see [llms.txt](https://docs.owy.wtf/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.owy.wtf/contracts/source-codes/owy-token-contract.md).

# Owy Token Contract

### File Directory Tree

```
.
└── src/
    ├── abstracts/
    │   └── ReentrancyGuard.sol
    ├── interfaces/
    │   └── IERC20.sol
    ├── libraries/
    │   └── Math.sol
    └── Owy.sol
```

***

## Download Source Code

Click the zip file below to download the code.

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

***

{% code title="Owy.sol" %}

```solidity
// SPDX-License-Identifier: MIT
// ACKNOWLEDMENT: The code is modified from OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
// ACKNOWLEDMENT: Abstarcts and Libraries are derived from Solady and Soledge.
// ACKNOWLEDGEMENT: EIP-2612 logics are derived from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
pragma solidity 0.8.25;

import {ReentrancyGuard} from "./abstracts/ReentrancyGuard.sol";
import {IERC20} from "./interfaces/IERC20.sol";
import {FixedPointMathLib} from "./libraries/Math.sol";
contract Owy is IERC20, ReentrancyGuard {
    struct Balance {
        uint256 balance;
        uint256 blockNumber;
    }

    struct Momentum {
        uint256 accumulatedReserve;
        uint256 accumulatedCirculating;
    }

    Momentum private momentum;
    address private _deployer;
    uint256 private _finalSupply = 69000000000000000000; // 69 tokens * 18 decimals
    uint256 private _totalSupply = 69000000000000000000000000; // 69M tokens * 18 decimals
    uint256 internal immutable INITIAL_CHAIN_ID;
    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) private nonces;
    mapping(address account => Balance) private _balances;
    mapping(address account => mapping(address spender => uint256))
        private _allowances;

    constructor() {
        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
        _deployer = msg.sender;
        _balances[msg.sender].balance = 69000000000000000000000000;
        // do this only on Testnet because 100% allocation will be used to LPing.
    }

    function name() public pure virtual override returns (string memory) {
        return "Owy Token";
    }

    function symbol() public pure virtual override returns (string memory) {
        return "OWY";
    }

    function decimals() public pure virtual override returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(
        address account
    ) public view virtual override returns (uint256) {
        return _balances[account].balance;
    }

    function blockOf(
        address account
    ) public view virtual override returns (uint256) {
        return _balances[account].blockNumber;
    }

    function getMomentum()
        public
        view
        returns (uint256 accumulatedReserve, uint256 accumulatedCircultating)
    {
        accumulatedReserve = momentum.accumulatedReserve;
        accumulatedCircultating = momentum.accumulatedCirculating;
    }

    function allowance(
        address owner,
        address spender
    ) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 value) public returns (bool) {
        address owner = msg.sender;
        _approve(owner, spender, value);
        return true;
    }
    function getTransferAmount(
        address from,
        uint256 value
    ) public view returns (uint256 tax, uint256 output) {
        (tax, output) = _getTransferOutPut(from, value);
    }

    function transfer(
        address to,
        uint256 value
    ) public virtual override returns (bool) {
        address owner = msg.sender;
        _transfer(owner, to, value, 0);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) public virtual override returns (bool) {
        address spender = msg.sender;
        _spendAllowance(from, spender, value);
        if (from == _deployer && from != address(0)) {
            require(_initTransfer(from, to));
            _deployer = address(0);
        } else {
            _transfer(from, to, value, 0);
        }
        return true;
    }

    function _initTransfer(address from, address to) private returns (bool) {
        uint256 amount = _balances[from].balance;
        _balances[from].balance = 0;
        _balances[to].balance = amount;
        _balances[to].blockNumber = block.number;
        return true;
    }

    function transferWithSlippage(
        address to,
        uint256 value,
        uint256 maxTax
    ) public virtual override returns (bool) {
        address owner = msg.sender;
        (uint256 tax, ) = _getTransferOutPut(owner, value);

        if (tax > maxTax) {
            revert ERC20SlippageExceed(tax, maxTax);
        }
        /// Note: maxTax input can be > value because the actual tax charged is calculated in `_update`.
        _transfer(owner, to, value, 0);
        return true;
    }

    function transferFromWithSlippage(
        address from,
        address to,
        uint256 value,
        uint256 maxTax
    ) public virtual override returns (bool) {
        address spender = msg.sender;
        (uint256 tax, ) = _getTransferOutPut(from, value);
        if (tax > maxTax) {
            revert ERC20SlippageExceed(tax, maxTax);
        }
        /// Note: maxTax input can be > value because the actual tax charged is calculated in `_update`.
        _spendAllowance(from, spender, value);
        _transfer(from, to, value, 0);
        return true;
    }

    function transferFixedAmount(
        address to,
        uint256 value,
        uint256 taxOffer
    ) public virtual override returns (bool, uint256) {
        address owner = msg.sender;
        (uint256 tax, ) = _getTransferOutPut(owner, value);

        if (taxOffer < tax) {
            revert ERC20InsufficientTaxOffer(tax, taxOffer);
        }
        uint256 maxTax = value / 5;
        // maximum tax is capped at 1/5 of transfer value
        if (taxOffer > maxTax) {
            taxOffer = maxTax;
        }
        _transfer(owner, to, value, taxOffer);
        return (true, taxOffer); // return transfer status and ACTUAL tax
    }

    function transferFromFixedAmouunt(
        address from,
        address to,
        uint256 value,
        uint256 taxOffer
    ) public virtual override returns (bool, uint256) {
        address spender = msg.sender;
        (uint256 tax, ) = _getTransferOutPut(from, value);

        if (taxOffer < tax) {
            revert ERC20InsufficientTaxOffer(tax, taxOffer);
        }
        uint256 maxTax = value / 5;
        // maximum tax is capped at 1/5 of transfer value
        if (taxOffer > maxTax) {
            taxOffer = maxTax;
        }
        _spendAllowance(from, spender, value);
        _transfer(from, to, value, taxOffer);
        return (true, taxOffer); // return transfer status and ACTUAL tax
    }

    function _transfer(
        address from,
        address to,
        uint256 value,
        uint256 tax
    ) private nonReentrant {
        if (from == address(0)) {
            revert ERC20InvalidSender();
        }
        if (from == to) {
            revert ERC20InvalidReceiver();
        }
        if (value == 0) {
            revert ERC20InvalidAmount();
        }
        _update(from, to, value, tax);
    }

    function _getTransferOutPut(
        address from,
        uint256 value
    ) private view nonReadReentrant returns (uint256 tax, uint256 output) {
        Balance memory _balSender = _balances[from];
        uint256 cTSupply = _totalSupply;

        if (_balSender.balance < value) {
            revert ERC20InsufficientBalance(from, _balSender.balance, value);
        }
        if (cTSupply > _finalSupply) {
            _balSender.balance -= value;
            uint256 cBlock = block.number;
            tax = FixedPointMathLib.fullMulDiv(
                value,
                type(uint256).max,
                cTSupply
            );
            tax = FixedPointMathLib.fullMulDiv(
                tax,
                _balSender.blockNumber ** 2,
                cBlock ** 2
            );
            uint256 accReserve = momentum.accumulatedReserve +
                _balSender.balance;
            uint256 accCirculate = momentum.accumulatedCirculating + value;
            if (accCirculate > accReserve) {
                tax = FixedPointMathLib.fullMulDiv(
                    tax,
                    accReserve,
                    accCirculate
                );
            }
            tax = FixedPointMathLib.fullMulDiv(
                tax,
                value * 169, // no overflow
                type(uint256).max
            );
            tax = tax / 100;

            uint256 oneThird = value / 5;
            if (tax > oneThird) {
                tax = oneThird;
                // maximum tax is capped at 1/5 of transfer value
            }
            output = value - tax;
        } else {
            tax = 0;
            output = value;
        }
    }

    function _update(
        address from,
        address to,
        uint256 value,
        uint256 tax
    ) private {
        Balance memory _balSender = _balances[from];
        Balance memory _balReceiver = _balances[to];
        uint256 cTSupply = _totalSupply;
        //-----------sender-----------------------
        if (_balSender.balance < value) {
            revert ERC20InsufficientBalance(from, _balSender.balance, value);
        }
        unchecked {
            // Overflow not possible: value <= _balSender.balance <= totalSupply.
            _balSender.balance = _balSender.balance - value;
            _balances[from].balance = _balSender.balance;

            //-----------receiver-----------------------
            uint256 realValue;
            if (to == address(0)) {
                _totalSupply = cTSupply - value; // even supply is <= 69, you still can burn OWY to address(0).
            } else if (cTSupply > _finalSupply) {
                uint256 accReserve = momentum.accumulatedReserve +
                    _balSender.balance;
                uint256 accCirculate = momentum.accumulatedCirculating + value;
                uint256 currentBlock = block.number;
                if (tax == 0) {
                    tax = FixedPointMathLib.fullMulDiv(
                        value,
                        type(uint256).max,
                        cTSupply
                        // wll not overflow because the worst case for this mulDiv is equal to 1,
                        // when value == cTSupply.
                    );
                    tax = FixedPointMathLib.fullMulDiv(
                        tax,
                        _balSender.blockNumber ** 2,
                        currentBlock ** 2
                        // wll not overflow because the worst case for this mulDiv is equal to 1,
                        // when blockNumber == currentBlock.
                    );

                    if (accCirculate > accReserve) {
                        tax = FixedPointMathLib.fullMulDiv(
                            tax,
                            accReserve,
                            accCirculate
                            // wll not overflow because: accCirculate > accReserve
                        );
                    }
                    tax = FixedPointMathLib.fullMulDiv(
                        tax,
                        value * 169, // no overflow
                        type(uint256).max
                    );

                    tax = tax / 100;
                    uint256 oneThird = value / 5;
                    if (tax > oneThird) {
                        tax = oneThird;
                        // maximum tax is capped at 1/5 of transfer value
                    }
                }

                /// @dev Since we don't know exactly when the tax system will stop (when cTsupply <= finalSupply)
                /// `momentum.accumulatedCirculating` and `momentum.accumulatedReserve` can be overflow,
                /// so we deal with it by division of 2.
                uint256 ctSupplySqr = cTSupply ** 2;
                if (accCirculate > ctSupplySqr || accReserve > ctSupplySqr) {
                    accCirculate = accCirculate >> 1;
                    accReserve = accReserve >> 1;
                    /// @dev We assume that any of `momentum.accumulatedCirculating` and `momentum.accumulatedReserve` is always > 1
                    /// because it is hardly possible for an account or everyone to transfer 100% of their fund every time
                    /// at the begining to the end of (one round) this update.
                }
                momentum.accumulatedCirculating = accCirculate;
                momentum.accumulatedReserve = accReserve;

                _totalSupply = cTSupply - tax;
                realValue = value - tax;

                // -------------- Reciever's balance --------------
                if (_balReceiver.blockNumber != currentBlock) {
                    if (_balReceiver.balance == 0) {
                        _balances[to].blockNumber = currentBlock;
                    } else {
                        _balances[to].blockNumber =
                            ((_balReceiver.blockNumber * _balReceiver.balance) +
                                (realValue * currentBlock)) /
                            (_balReceiver.balance + realValue); // no need for fixpoint scaling here
                        // you will find its extremely unlikely to overfow, even though the BPS of Ethereum is 100x.
                    }
                }
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to].balance = _balReceiver.balance + realValue;
            } else {
                realValue = value;
                _balances[to].balance = _balReceiver.balance + value;
                // `_balances[to].blockNumber` and  `_balances[from].blockNumber` are no longer used.
            }
            emit Transfer(from, to, value, realValue);
        }
    }

    function _approve(address owner, address spender, uint256 value) private {
        if (owner == address(0) || spender == address(0)) {
            revert ERC20InvalidApprove(owner, spender);
        }
        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _spendAllowance(
        address owner,
        address spender,
        uint256 value
    ) private {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(
                    spender,
                    currentAllowance,
                    value
                );
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value); // will not overflow
            }
        }
    }

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable override {
        if (block.timestamp < deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address signer = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            if (signer != owner) {
                revert ERC2612InvalidSigner(signer, owner);
            }

            _approve(signer, spender, value);
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view override returns (bytes32) {
        return
            block.chainid == INITIAL_CHAIN_ID
                ? INITIAL_DOMAIN_SEPARATOR
                : computeDomainSeparator();
    }

    function computeDomainSeparator() private view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256(
                        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                    ),
                    keccak256(bytes(name())),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }
}
```

{% endcode %}

### IERC20.sol

{% code title="IERC20.sol" %}

```solidity
// SPDX-License-Identifier: MIT
// ACKNOWLEDGEMENT: modified from OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity 0.8.25;

interface IERC20 {
    error ERC20InsufficientBalance(
        address sender,
        uint256 balance,
        uint256 needed
    );

    error ERC20InvalidSender();

    error ERC20InvalidReceiver();

    error ERC20InvalidAmount();

    error ERC20InsufficientAllowance(
        address spender,
        uint256 allowance,
        uint256 needed
    );

    error ERC20InvalidApprove(address approver, address spender);

    error ERC20SlippageExceed(uint256 tax, uint256 maxTax);

    error ERC20InsufficientTaxOffer(uint256 tax, uint256 taxOffer);

    error ERC2612ExpiredSignature(uint256 deadline);

    error ERC2612InvalidSigner(address signer, address owner);

    event Transfer(
        address indexed from,
        address indexed to,
        uint256 value,
        uint256 realValue
    );

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function blockOf(address account) external view returns (uint256);

    function getMomentum()
        external
        view
        returns (uint256 accumulatedReserve, uint256 accumulatedCircultating);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function getTransferAmount(
        address from,
        uint256 value
    ) external view returns (uint256 tax, uint256 output);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function transferWithSlippage(
        address to,
        uint256 value,
        uint256 maxTax
    ) external returns (bool);

    function transferFromWithSlippage(
        address from,
        address to,
        uint256 value,
        uint256 maxTax
    ) external returns (bool);

    function transferFixedAmount(
        address to,
        uint256 value,
        uint256 taxOffer
    ) external returns (bool, uint256);

    function transferFromFixedAmouunt(
        address from,
        address to,
        uint256 value,
        uint256 taxOffer
    ) external returns (bool, uint256);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable;
}
```

{% endcode %}

### Math.sol

{% code title="Math.sol" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
/// @dev Acknowledgement: all codes below are retrieved from Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(
        uint256 x,
        uint256 y,
        uint256 d
    ) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {

            } 1 {

            } {
                // 512-bit multiply `[p1 p0] = x * y`.
                // Compute the product mod `2**256` and mod `2**256 - 1`
                // then use the Chinese Remainder Theorem to reconstruct
                // the 512 bit result. The result is stored in two 256
                // variables such that `product = p1 * 2**256 + p0`.

                // Least significant 256 bits of the product.
                result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
                let mm := mulmod(x, y, not(0))
                // Most significant 256 bits of the product.
                let p1 := sub(mm, add(result, lt(mm, result)))

                // Handle non-overflow cases, 256 by 256 division.
                if iszero(p1) {
                    if iszero(d) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    result := div(result, d)
                    break
                }

                // Make sure the result is less than `2**256`. Also prevents `d == 0`.
                if iszero(gt(d, p1)) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }

                /*------------------- 512 by 256 division --------------------*/

                // Make division exact by subtracting the remainder from `[p1 p0]`.
                // Compute remainder using mulmod.
                let r := mulmod(x, y, d)
                // `t` is the least significant bit of `d`.
                // Always greater or equal to 1.
                let t := and(d, sub(0, d))
                // Divide `d` by `t`, which is a power of two.
                d := div(d, t)
                // Invert `d mod 2**256`
                // Now that `d` is an odd number, it has an inverse
                // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                // Compute the inverse by starting with a seed that is correct
                // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                let inv := xor(2, mul(3, d))
                // Now use Newton-Raphson iteration to improve the precision.
                // Thanks to Hensel's lifting lemma, this also works in modular
                // arithmetic, doubling the correct bits in each step.
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                result := mul(
                    // Divide [p1 p0] by the factors of two.
                    // Shift in bits from `p1` into `p0`. For this we need
                    // to flip `t` such that it is `2**256 / t`.
                    or(
                        mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
                        div(sub(result, r), t)
                    ),
                    // inverse mod 2**256
                    mul(inv, sub(2, mul(d, inv)))
                )
                break
            }
        }
    }
}
```

{% endcode %}

### ReentracyGuard.sol

{% code title="ReentrancyGuard.sol" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

/// @notice Reentrancy guard mixin.
/// @author Soledge (https://github.com/vectorized/soledge/blob/main/src/utils/ReentrancyGuard.sol)
///
/// @dev Note: This implementation utilizes the `TSTORE` and `TLOAD` opcodes.
/// Please ensure that the chain you are deploying on supports them.
abstract contract ReentrancyGuard {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CUSTOM ERRORS                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
    /// 9 bytes is large enough to avoid collisions in practice,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      REENTRANCY GUARD                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            tstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            tstore(_REENTRANCY_GUARD_SLOT, 0)
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}
```

{% endcode %}
