PonstrategyFeeMachine

0x6a37f7191f5023fc780be59c688ddd495ea8545b

Verification
Verified
0.8.30+commit.73712a01
Type
Contract
11,495 bytes
ABI entries
73
32 read · 13 write
License
none

Contract information

Address
0x6a37f7191f5023fc780be59c688ddd495ea8545b
Chain
Robinhood Chain (4663)
Compiler
0.8.30+commit.73712a01
Optimization
Enabled
Creation tx
0x6a3e1a130f…d7a0a278fc

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (32)

DEAD_ADDRESS()address
MAX_CREATOR_SHARE_BPS()uint16
buyIncrement()uint256
creatorPayout()address
creatorShareBps()uint16
currentDropInterval()uint32
dropBudget()uint256
dropCount()uint256
dropIntervalOverride()uint32
dropShareBps()uint16
keeper()address
lastBuyBlock()uint256
lastDropAt()uint256
maxSlippageBps()uint16
maxSpend()uint256
owner()address
pendingOwner()address
pons()address
ponsIsToken0()bool
ponsLocker()address
ponsPool()address
ponsPoolFee()uint24
ponstrategy()address
quotePonsOut(uint256)uint256
quoteWethValue(uint256)uint256
router()address
totalBurned()uint256
totalDropValueWeth()uint256
totalPonsBought()uint256
totalPonsDropped()uint256
twapWindow()uint32
weth()address

Events (11)

CreatorShareUpdatedDividendDroppedDropPolicyUpdatedDropStartedFeesBurnedFeesCollectedKeeperUpdatedOwnershipTransferStartedOwnershipTransferredParamsUpdatedPonsBought

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "initialOwner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "ponstrategy_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pons_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "weth_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "router_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "v3Factory_",
        "type": "address"
      },
      {
        "internalType": "uint24",
        "name": "ponsPoolFee_",
        "type": "uint24"
      },
      {
        "internalType": "address",
        "name": "ponsLocker_",
        "type": "address"
      },
      {
        "internalType": "uint16",
        "name": "creatorShareBps_",
        "type": "uint16"
      },
      {
        "internalType": "address",
        "name": "creatorPayout_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "BadParams",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "DropAboveBudget",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "DropTooSoon",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTick",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LengthMismatch",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NoLocker",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotKeeper",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NothingToBurn",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NothingToBuy",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NothingToDrop",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SpendAboveRatchet",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "creatorShareBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "creatorPayout",
        "type": "address"
      }
    ],
    "name": "CreatorShareUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "dropId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalPons",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "valueWethAtDrop",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "holderCount",
        "type": "uint256"
      }
    ],
    "name": "DividendDropped",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "dropShareBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint32",
        "name": "dropInterval",
        "type": "uint32"
      }
    ],
    "name": "DropPolicyUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "dropId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "budget",
        "type": "uint256"
      }
    ],
    "name": "DropStarted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalBurned",
        "type": "uint256"
      }
    ],
    "name": "FeesBurned",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wethAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      }
    ],
    "name": "FeesCollected",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "keeper",
        "type": "address"
      }
    ],
    "name": "KeeperUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferStarted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint32",
        "name": "twapWindow",
        "type": "uint32"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "maxSlippageBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "buyIncrement",
        "type": "uint256"
      }
    ],
    "name": "ParamsUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wethIn",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ponsOut",
        "type": "uint256"
      }
    ],
    "name": "PonsBought",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "DEAD_ADDRESS",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_CREATOR_SHARE_BPS",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "acceptOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "burnFees",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "buyIncrement",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amountIn",
        "type": "uint256"
      }
    ],
    "name": "buyPons",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "collectFromLocker",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "wethAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "creatorPayout",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "creatorShareBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "currentDropInterval",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "dropBudget",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "dropCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "holders",
        "type": "address[]"
      },
      {
        "internalType": "uint256[]",
        "name": "amounts",
        "type": "uint256[]"
      }
    ],
    "name": "dropDividend",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "dropIntervalOverride",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "dropShareBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "keeper",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastBuyBlock",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastDropAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxSlippageBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxSpend",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingOwner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pons",
    "outputs": [
      {
        "internalType": "contract IERC20",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ponsIsToken0",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ponsLocker",
    "outputs": [
      {
        "internalType": "contract IPonsLockerLike",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ponsPool",
    "outputs": [
      {
        "internalType": "contract IUniswapV3PoolTwapLike",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ponsPoolFee",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ponstrategy",
    "outputs": [
      {
        "internalType": "contract IERC20",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "wethIn",
        "type": "uint256"
      }
    ],
    "name": "quotePonsOut",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "ponsAmount",
        "type": "uint256"
      }
    ],
    "name": "quoteWethValue",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "router",
    "outputs": [
      {
        "internalType": "contract ISwapRouterLike",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint16",
        "name": "creatorShareBps_",
        "type": "uint16"
      },
      {
        "internalType": "address",
        "name": "creatorPayout_",
        "type": "address"
      }
    ],
    "name": "setCreatorShare",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint16",
        "name": "dropShareBps_",
        "type": "uint16"
      },
      {
        "internalType": "uint32",
        "name": "dropInterval_",
        "type": "uint32"
      }
    ],
    "name": "setDropPolicy",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "keeper_",
        "type": "address"
      }
    ],
    "name": "setKeeper",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint32",
        "name": "twapWindow_",
        "type": "uint32"
      },
      {
        "internalType": "uint16",
        "name": "maxSlippageBps_",
        "type": "uint16"
      },
      {
        "internalType": "uint256",
        "name": "buyIncrement_",
        "type": "uint256"
      }
    ],
    "name": "setParams",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "startDrop",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "budget",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalBurned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalDropValueWeth",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalPonsBought",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalPonsDropped",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "twapWindow",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "contract IERC20",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "wrapEth",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ISwapRouterLike, IWETHLike} from "../interfaces/IExternal.sol";
import {TickMathLib} from "../libraries/TickMathLib.sol";

interface IPonsLockerLike {
    function collectFees(address token) external returns (uint256 amount0, uint256 amount1);
}

interface IUniswapV3FactoryLike {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}

interface IUniswapV3PoolTwapLike {
    function token0() external view returns (address);
    function observe(uint32[] calldata secondsAgos)
        external
        view
        returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
}

/**
 * @title PonstrategyFeeMachine
 * @notice $PONSTRATEGY launches as a regular token on the Pons launchpad and
 * this contract is set as its creator fee recipient (via the launcher's fee
 * redirect). From then on the loop runs with almost no trust:
 *
 *  - `collectFromLocker()` — PERMISSIONLESS. Pulls accrued creator fees from
 *    the Pons locker (the machine is the authorized recipient).
 *  - `buyPons()`           — PERMISSIONLESS. Swaps accrued WETH into $PONS.
 *    Slippage is bounded on-chain by the PONS pool's TWAP; a per-block spend
 *    ratchet TWAPs entries and blocks single-shot drains into a manipulated
 *    pool.
 *  - `burnFees()`          — PERMISSIONLESS. Sends every $PONSTRATEGY token
 *    accrued as fees to the dead address.
 *  - `dropDividend()`      — KEEPER. Pushes $PONS to holders pro-rata; the
 *    holder snapshot comes from off-chain Transfer logs (the launcher token is
 *    a vanilla ERC-20). The drop's WETH value is computed on-chain from TWAP.
 *
 * There is NO withdraw function: funds can only ever move into $PONS buys,
 * holder wallets, or the burn address. Owner (a multisig, eventually) only
 * tunes parameters and rotates the keeper.
 */
contract PonstrategyFeeMachine is Ownable2Step, ReentrancyGuard {
    using SafeERC20 for IERC20;

    error NotKeeper();
    error NoLocker();
    error LengthMismatch();
    error NothingToBurn();
    error NothingToDrop();
    error NothingToBuy();
    error SpendAboveRatchet();
    error BadParams();
    error DropTooSoon();
    error DropAboveBudget();

    event FeesCollected(uint256 wethAmount, uint256 tokenAmount);
    event PonsBought(uint256 wethIn, uint256 ponsOut);
    event FeesBurned(uint256 amount, uint256 totalBurned);
    event DividendDropped(
        uint256 indexed dropId, uint256 totalPons, uint256 valueWethAtDrop, uint256 holderCount
    );
    event KeeperUpdated(address indexed keeper);
    event ParamsUpdated(uint32 twapWindow, uint16 maxSlippageBps, uint256 buyIncrement);
    event DropPolicyUpdated(uint16 dropShareBps, uint32 dropInterval);
    event DropStarted(uint256 indexed dropId, uint256 budget);
    event CreatorShareUpdated(uint16 creatorShareBps, address creatorPayout);

    address public constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;
    uint256 private constant BPS = 10_000;
    uint256 private constant Q96 = 2 ** 96;
    /// @notice Hard ceiling on the creator share — immutable, guarantees at
    /// least half of every collection always buys $PONS, no matter what the
    /// owner sets. This is the trust floor holders can verify once and forever.
    uint16 public constant MAX_CREATOR_SHARE_BPS = 5_000; // 50%

    IERC20 public immutable ponstrategy;
    IERC20 public immutable pons;
    IERC20 public immutable weth;
    ISwapRouterLike public immutable router;
    IPonsLockerLike public immutable ponsLocker;
    IUniswapV3PoolTwapLike public immutable ponsPool;
    uint24 public immutable ponsPoolFee;
    bool public immutable ponsIsToken0;

    /// @notice Creator's share of collected WETH fees (e.g. 1000 = 10% to the
    /// creator wallet at every collection). Owner-tunable via setCreatorShare,
    /// but hard-capped at MAX_CREATOR_SHARE_BPS. The remainder stays in the
    /// machine and buys $PONS. Token-side fees are always burned.
    uint16 public creatorShareBps;
    /// @notice Where the creator share is forwarded. Owner-tunable.
    address public creatorPayout;

    /// @notice Low-privilege role that may execute dividend drops.
    address public keeper;

    /// @notice TWAP lookback for the buy guard (seconds).
    uint32 public twapWindow = 30 minutes;
    /// @notice Max shortfall vs TWAP quote a buy will accept.
    uint16 public maxSlippageBps = 300; // 3%
    /// @notice WETH-per-block spend ratchet for permissionless buys.
    uint256 public buyIncrement = 0.05e18;
    uint256 public lastBuyBlock;

    /// @notice Drop policy — enforced ON-CHAIN and owner-modifiable: each drop
    /// round may distribute at most `dropShareBps` of the machine's PONS
    /// treasury, and rounds must be `currentDropInterval()` apart. Even a
    /// compromised keeper cannot move more than one round's share.
    uint16 public dropShareBps = 1_000; // 10% of the PONS treasury per round
    /// @notice Manual interval override; 0 means the graduated schedule below
    /// applies (8h for drops 1-10, 12h for drops 11-20, 24h thereafter).
    uint32 public dropIntervalOverride;
    uint256 public lastDropAt;
    /// @notice Remaining PONS budget of the active drop round.
    uint256 public dropBudget;

    uint256 public totalPonsBought;
    uint256 public totalPonsDropped;
    uint256 public totalBurned;
    uint256 public totalDropValueWeth;
    uint256 public dropCount;

    modifier onlyKeeperOrOwner() {
        if (msg.sender != keeper && msg.sender != owner()) revert NotKeeper();
        _;
    }

    constructor(
        address initialOwner,
        address ponstrategy_,
        address pons_,
        address weth_,
        address router_,
        address v3Factory_,
        uint24 ponsPoolFee_,
        address ponsLocker_,
        uint16 creatorShareBps_,
        address creatorPayout_
    ) Ownable(initialOwner) {
        if (creatorShareBps_ > MAX_CREATOR_SHARE_BPS || (creatorShareBps_ > 0 && creatorPayout_ == address(0))) {
            revert BadParams();
        }
        creatorShareBps = creatorShareBps_;
        creatorPayout = creatorPayout_;
        ponstrategy = IERC20(ponstrategy_);
        pons = IERC20(pons_);
        weth = IERC20(weth_);
        router = ISwapRouterLike(router_);
        ponsPoolFee = ponsPoolFee_;
        ponsLocker = IPonsLockerLike(ponsLocker_);
        keeper = initialOwner;
        lastBuyBlock = block.number;

        address pool = IUniswapV3FactoryLike(v3Factory_).getPool(pons_, weth_, ponsPoolFee_);
        if (pool == address(0)) revert BadParams();
        ponsPool = IUniswapV3PoolTwapLike(pool);
        ponsIsToken0 = IUniswapV3PoolTwapLike(pool).token0() == pons_;
    }

    /* ------------------------------------------------------------------ */
    /*                        Admin (parameters only)                     */
    /* ------------------------------------------------------------------ */

    function setKeeper(address keeper_) external onlyOwner {
        keeper = keeper_;
        emit KeeperUpdated(keeper_);
    }

    function setParams(uint32 twapWindow_, uint16 maxSlippageBps_, uint256 buyIncrement_)
        external
        onlyOwner
    {
        if (twapWindow_ < 5 minutes || maxSlippageBps_ > 2_000 || buyIncrement_ == 0) {
            revert BadParams();
        }
        twapWindow = twapWindow_;
        maxSlippageBps = maxSlippageBps_;
        buyIncrement = buyIncrement_;
        emit ParamsUpdated(twapWindow_, maxSlippageBps_, buyIncrement_);
    }

    /// @notice Updates the drop policy (share of treasury per round, minimum
    /// spacing between rounds). This is the intended lever for evolving the
    /// dividend TIMING and size over time. Pass `dropInterval_ = 0` to follow
    /// the graduated schedule (8h -> 12h -> 24h by drop count); any non-zero
    /// value (min 1h) overrides it.
    function setDropPolicy(uint16 dropShareBps_, uint32 dropInterval_) external onlyOwner {
        if (dropShareBps_ == 0 || dropShareBps_ > BPS || (dropInterval_ != 0 && dropInterval_ < 1 hours)) {
            revert BadParams();
        }
        dropShareBps = dropShareBps_;
        dropIntervalOverride = dropInterval_;
        emit DropPolicyUpdated(dropShareBps_, dropInterval_);
    }

    /// @notice Updates the ETH-side FEE SPLIT: the creator's share of each
    /// collection and where it goes. Capped at MAX_CREATOR_SHARE_BPS so the
    /// buy-side can never be starved. Set share to 0 to route 100% into buys.
    function setCreatorShare(uint16 creatorShareBps_, address creatorPayout_) external onlyOwner {
        if (creatorShareBps_ > MAX_CREATOR_SHARE_BPS) revert BadParams();
        if (creatorShareBps_ > 0 && creatorPayout_ == address(0)) revert BadParams();
        creatorShareBps = creatorShareBps_;
        creatorPayout = creatorPayout_;
        emit CreatorShareUpdated(creatorShareBps_, creatorPayout_);
    }


    /* ------------------------------------------------------------------ */
    /*                      Permissionless mechanism                      */
    /* ------------------------------------------------------------------ */

    /// @notice Accept native ETH and wrap on demand.
    receive() external payable {}

    function wrapEth() external {
        uint256 balance = address(this).balance;
        if (balance > 0) IWETHLike(address(weth)).deposit{value: balance}();
    }

    /// @notice Pulls accrued creator fees (both assets) from the Pons locker.
    /// If a creator share was frozen in at deploy, that slice of the received
    /// WETH is forwarded to the creator payout address; the rest stays in the
    /// machine for the loop.
    function collectFromLocker() external nonReentrant returns (uint256 wethAmount, uint256 tokenAmount) {
        if (address(ponsLocker) == address(0)) revert NoLocker();
        uint256 wethBefore = weth.balanceOf(address(this));
        (uint256 amount0, uint256 amount1) = ponsLocker.collectFees(address(ponstrategy));

        if (creatorShareBps > 0) {
            uint256 received = weth.balanceOf(address(this)) - wethBefore;
            uint256 creatorCut = (received * creatorShareBps) / BPS;
            if (creatorCut > 0) weth.safeTransfer(creatorPayout, creatorCut);
        }

        // Orientation of the locker's return values is pool-specific; report
        // both raw amounts and let indexers attribute them.
        emit FeesCollected(amount0, amount1);
        return (amount0, amount1);
    }

    /// @notice Maximum WETH a single buy may spend, growing per block.
    function maxSpend() public view returns (uint256) {
        return (block.number - lastBuyBlock + 1) * buyIncrement;
    }

    /// @notice TWAP quote: expected PONS out for `wethIn`.
    function quotePonsOut(uint256 wethIn) public view returns (uint256) {
        uint32[] memory secondsAgos = new uint32[](2);
        secondsAgos[0] = twapWindow;
        secondsAgos[1] = 0;
        (int56[] memory tickCumulatives,) = ponsPool.observe(secondsAgos);
        int56 delta = tickCumulatives[1] - tickCumulatives[0];
        int24 avgTick = int24(delta / int56(uint56(twapWindow)));
        // Round toward negative infinity like the canonical OracleLibrary.
        if (delta < 0 && (delta % int56(uint56(twapWindow)) != 0)) avgTick--;

        uint160 sqrtP = TickMathLib.getSqrtRatioAtTick(avgTick);
        if (ponsIsToken0) {
            // price token1/token0 = (sqrtP/Q96)^2 -> WETH per PONS; invert.
            uint256 intermediate = Math.mulDiv(wethIn, Q96, sqrtP);
            return Math.mulDiv(intermediate, Q96, sqrtP);
        } else {
            uint256 intermediate = Math.mulDiv(wethIn, sqrtP, Q96);
            return Math.mulDiv(intermediate, sqrtP, Q96);
        }
    }

    /// @notice TWAP value in WETH of a PONS amount (for drop bookkeeping).
    function quoteWethValue(uint256 ponsAmount) public view returns (uint256) {
        uint256 ponsPerWeth = quotePonsOut(1e18);
        if (ponsPerWeth == 0) return 0;
        return Math.mulDiv(ponsAmount, 1e18, ponsPerWeth);
    }

    /// @notice Swaps accrued WETH into $PONS. Permissionless: slippage is
    /// bounded by TWAP and spend is bounded by the per-block ratchet.
    function buyPons(uint256 amountIn) external nonReentrant {
        uint256 balance = weth.balanceOf(address(this));
        if (amountIn == 0 || amountIn > balance) revert NothingToBuy();
        if (amountIn > maxSpend()) revert SpendAboveRatchet();
        lastBuyBlock = block.number;

        uint256 minOut = (quotePonsOut(amountIn) * (BPS - maxSlippageBps)) / BPS;

        weth.forceApprove(address(router), amountIn);
        uint256 out = router.exactInputSingle(
            ISwapRouterLike.ExactInputSingleParams({
                tokenIn: address(weth),
                tokenOut: address(pons),
                fee: ponsPoolFee,
                recipient: address(this),
                amountIn: amountIn,
                amountOutMinimum: minOut,
                sqrtPriceLimitX96: 0
            })
        );
        totalPonsBought += out;
        emit PonsBought(amountIn, out);
    }

    /// @notice Burns every $PONSTRATEGY token accrued as fees.
    function burnFees() external nonReentrant {
        uint256 balance = ponstrategy.balanceOf(address(this));
        if (balance == 0) revert NothingToBurn();
        totalBurned += balance;
        ponstrategy.safeTransfer(DEAD_ADDRESS, balance);
        emit FeesBurned(balance, totalBurned);
    }

    /* ------------------------------------------------------------------ */
    /*                          Keeper mechanism                          */
    /* ------------------------------------------------------------------ */

    /// @notice Minimum spacing before the next drop round may open. Follows a
    /// graduated on-chain schedule — 8h between the first 10 drops, 12h
    /// through drop 20, 24h thereafter — unless the owner has set a manual
    /// override via `setDropPolicy`. The very first drop has no wait
    /// (`lastDropAt` starts at 0).
    function currentDropInterval() public view returns (uint32) {
        if (dropIntervalOverride != 0) return dropIntervalOverride;
        if (dropCount < 10) return 8 hours;
        if (dropCount < 20) return 12 hours;
        return 24 hours;
    }

    /// @notice Opens a drop round: budgets `dropShareBps` of the current PONS
    /// treasury and starts the interval clock. Reverts if called before
    /// `currentDropInterval()` has elapsed since the previous round.
    function startDrop() external onlyKeeperOrOwner returns (uint256 budget) {
        if (block.timestamp < lastDropAt + currentDropInterval()) revert DropTooSoon();
        lastDropAt = block.timestamp;
        budget = (pons.balanceOf(address(this)) * dropShareBps) / BPS;
        dropBudget = budget;
        dropCount += 1;
        emit DropStarted(dropCount, budget);
    }

    /// @notice Pushes a batch of the active drop round to holders, pro-rata
    /// amounts computed off-chain from Transfer-log snapshots. Batches may not
    /// exceed the round's on-chain budget; the WETH value is computed on-chain
    /// from TWAP — nothing about the drop's reported value is keeper-supplied.
    function dropDividend(address[] calldata holders, uint256[] calldata amounts)
        external
        onlyKeeperOrOwner
        nonReentrant
    {
        if (holders.length == 0) revert NothingToDrop();
        if (holders.length != amounts.length) revert LengthMismatch();

        uint256 total;
        for (uint256 i; i < holders.length; i++) {
            total += amounts[i];
        }
        if (total > dropBudget) revert DropAboveBudget();
        dropBudget -= total;

        for (uint256 i; i < holders.length; i++) {
            pons.safeTransfer(holders[i], amounts[i]);
        }

        uint256 valueWeth = quoteWethValue(total);
        totalPonsDropped += total;
        totalDropValueWeth += valueWeth;
        emit DividendDropped(dropCount, total, valueWeth, holders.length);
    }
}
Chain explorer2493msChain node81ms