# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.owy.wtf/contracts/source-codes/owy-token-contract.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
