StockPayDistributor

0x43dc3ecfe02aa4192f41143fee9c0b6267424935

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
18,643 bytes
ABI entries
87
44 read · 23 write
License
none

Contract information

Address
0x43dc3ecfe02aa4192f41143fee9c0b6267424935
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xb3bddd063d…639731798f

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (44)

BASE_BPS()uint256
CARRY_CREATOR_BPS()uint256
CARRY_PLATFORM_BPS()uint256
ZEROX()address
active(address)bool
activeStrategies(uint256)uint256
activeStrategyCount()uint256
buyer()address
carryCredits(address, uint256)uint256
carryExempt(uint256)bool
claimable(address, address)uint256
cycler()address
defaultStock()address
defaultStrategyId()uint32
holderCount()uint256
holderList(uint256)address
holders(address)uint256, uint256, address, uint32, uint64, uint256, uint256, uint256, uint32
magBase(address)uint256
magMatch(address)uint256
magStratBase(uint256)uint256
magStratMatch(uint256)uint256
menu(uint256)address
menuLength()uint256
minBalanceForRewards()uint256
onMenu(address)bool
opsWallet()address
outstanding(uint256)uint256
owner()address
previewCycle(uint256)tuple[]
pushCursor()uint256
stratListed(uint256)bool
strategies()address
tierCutoffs(uint256)uint32
tierWeightOf(address)uint256
tierWeights(uint256)uint16
token()address
totalBaseShares(address)uint256
totalMatchShares(address)uint256
totalStratBaseShares(uint256)uint256
totalStratMatchShares(uint256)uint256
unallocated(address)uint256
vault(uint256, address)uint256
vetted(address)bool
withdrawable(address, address)uint256

Events (10)

BuyerSetCarryAccruedClaimedClockResetCycleBuyDefaultStrategySetMenuUpdatedOwnershipTransferredPreferenceSetStrategyAdopted

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "defaultStock_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "ops_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "BadStrategy",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NoBuyer",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotOnMenu",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OnlyToken",
    "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"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "buyer",
        "type": "address"
      }
    ],
    "name": "BuyerSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "strategyId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "credits",
        "type": "uint256"
      }
    ],
    "name": "CarryAccrued",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "holder",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "stock",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "Claimed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "holder",
        "type": "address"
      }
    ],
    "name": "ClockReset",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "bool",
        "name": "strat",
        "type": "bool"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "stock",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "sid",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethSpent",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "got",
        "type": "uint256"
      }
    ],
    "name": "CycleBuy",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "strategyId",
        "type": "uint256"
      }
    ],
    "name": "DefaultStrategySet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "stock",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "active",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "vetted",
        "type": "bool"
      }
    ],
    "name": "MenuUpdated",
    "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": true,
        "internalType": "address",
        "name": "holder",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "stock",
        "type": "address"
      }
    ],
    "name": "PreferenceSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "holder",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "strategyId",
        "type": "uint256"
      }
    ],
    "name": "StrategyAdopted",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BASE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "CARRY_CREATOR_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "CARRY_PLATFORM_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ZEROX",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "active",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "activeStrategies",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "activeStrategyCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "s",
        "type": "address"
      }
    ],
    "name": "addStock",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "name": "adoptStrategy",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "buyer",
    "outputs": [
      {
        "internalType": "contract IBuyer",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "carryCredits",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "carryExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "claim",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "sid",
        "type": "uint256"
      }
    ],
    "name": "claimCarry",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "claimForSelf",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "stock",
        "type": "address"
      }
    ],
    "name": "claimable",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "cycler",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "defaultStock",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "defaultStrategyId",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "holderCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "holderList",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "holders",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "shares",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "matchShares",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "pref",
        "type": "address"
      },
      {
        "internalType": "uint32",
        "name": "stratId",
        "type": "uint32"
      },
      {
        "internalType": "uint64",
        "name": "vestStart",
        "type": "uint64"
      },
      {
        "internalType": "uint256",
        "name": "idxBase",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "idxMatch",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "storedCredits",
        "type": "uint256"
      },
      {
        "internalType": "uint32",
        "name": "listPos",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "magBase",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "magMatch",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "magStratBase",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "magStratMatch",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "menu",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "menuLength",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "minBalanceForRewards",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "onMenu",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "opsWallet",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "outstanding",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "maxEthPerStock",
        "type": "uint256"
      }
    ],
    "name": "previewCycle",
    "outputs": [
      {
        "components": [
          {
            "internalType": "bool",
            "name": "strat",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "stock",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "sid",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "ethBase",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "ethMatch",
            "type": "uint256"
          }
        ],
        "internalType": "struct StockPayDistributor.Leg[]",
        "name": "",
        "type": "tuple[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "maxSteps",
        "type": "uint256"
      }
    ],
    "name": "pruneStrategies",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "count",
        "type": "uint256"
      }
    ],
    "name": "pushBatch",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pushCursor",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "refresh",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "maxEthPerStock",
        "type": "uint256"
      }
    ],
    "name": "runCycle",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "bool",
            "name": "strat",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "stock",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "sid",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "ethBase",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "ethMatch",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "minOut",
            "type": "uint256"
          },
          {
            "internalType": "bytes",
            "name": "data",
            "type": "bytes"
          }
        ],
        "internalType": "struct StockPayDistributor.ZBuy[]",
        "name": "buys",
        "type": "tuple[]"
      },
      {
        "internalType": "uint256",
        "name": "maxEthPerStock",
        "type": "uint256"
      }
    ],
    "name": "runCycleZeroX",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "s",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "a",
        "type": "bool"
      }
    ],
    "name": "setActive",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "b",
        "type": "address"
      }
    ],
    "name": "setBuyer",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "sid",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "exempt",
        "type": "bool"
      }
    ],
    "name": "setCarryExempt",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "c",
        "type": "address"
      }
    ],
    "name": "setCycler",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "name": "setDefaultStrategy",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "v",
        "type": "uint256"
      }
    ],
    "name": "setMinBalanceForRewards",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "o",
        "type": "address"
      }
    ],
    "name": "setOpsWallet",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "stock",
        "type": "address"
      }
    ],
    "name": "setPreference",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "s",
        "type": "address"
      }
    ],
    "name": "setStrategies",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "s",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "v",
        "type": "bool"
      }
    ],
    "name": "setVetted",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "stratListed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "strategies",
    "outputs": [
      {
        "internalType": "contract IStrategies",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "fromShares",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "toShares",
        "type": "uint256"
      }
    ],
    "name": "syncShares",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "tierCutoffs",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "tierWeightOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "tierWeights",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "token",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "totalBaseShares",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "totalMatchShares",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "totalStratBaseShares",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "totalStratMatchShares",
    "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": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "unallocated",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "vault",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "vetted",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "withdrawable",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

// SPDX-License-Identifier: MIT
//
//   QUANT
//   https://quantrh.com
//   https://x.com/Quantrhood
//
pragma solidity ^0.8.26;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

interface IBuyer {
    function buy(address stock, uint256 ethAmount, uint256 minOut, address recipient) external payable returns (uint256);
}
interface IStrategies {
    function creatorOf(uint256 id) external view returns (address);
    function entries(uint256 id) external view returns (address[] memory stocks, uint16[] memory weightsBps);
    function count() external view returns (uint256);
}

contract StockPayDistributor is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    uint256 private constant MAG = 2 ** 128;
    uint256 public constant BASE_BPS = 8000;
    uint256 public constant CARRY_CREATOR_BPS = 400;
    uint256 public constant CARRY_PLATFORM_BPS = 100;
    uint16[5] public tierWeights = [0, 100, 125, 150, 200];
    uint32[5] public tierCutoffs = [0, 3 days, 7 days, 14 days, 30 days];

    uint256 private constant RESET_SELL_BPS = 2500;

    address public constant ZEROX = 0x0000000000001fF3684f28c67538d4D072C22734;

    uint256 private constant ALLOC_TOL = 105;

    struct ZBuy { bool strat; address stock; uint256 sid; uint256 ethBase; uint256 ethMatch; uint256 minOut; bytes data; }

    struct Leg { bool strat; address stock; uint256 sid; uint256 ethBase; uint256 ethMatch; }

    address public immutable token;
    address public opsWallet;
    IBuyer public buyer;
    address public cycler;
    IStrategies public strategies;

    address[] public menu;
    mapping(address => bool) public onMenu;
    mapping(address => bool) public active;
    mapping(address => bool) public vetted;
    address public defaultStock;
    uint32 public defaultStrategyId;
    uint256 public minBalanceForRewards = 10_000 ether;

    mapping(address => uint256) public magBase;
    mapping(address => uint256) public magMatch;
    mapping(address => uint256) public totalBaseShares;
    mapping(address => uint256) public totalMatchShares;
    mapping(address => uint256) public unallocated;

    mapping(uint256 => uint256) public magStratBase;
    mapping(uint256 => uint256) public magStratMatch;
    mapping(uint256 => uint256) public totalStratBaseShares;
    mapping(uint256 => uint256) public totalStratMatchShares;
    mapping(uint256 => mapping(address => uint256)) public vault;
    mapping(uint256 => uint256) public outstanding;
    uint256[] public activeStrategies;
    mapping(uint256 => bool) public stratListed;
    mapping(address => mapping(uint256 => uint256)) public carryCredits;
    mapping(uint256 => bool) public carryExempt;

    struct Holder {
        uint256 shares;
        uint256 matchShares;
        address pref;
        uint32 stratId;
        uint64 vestStart;
        uint256 idxBase;
        uint256 idxMatch;
        uint256 storedCredits;
        uint32 listPos;
    }
    mapping(address => Holder) public holders;
    mapping(address => mapping(address => uint256)) public withdrawable;
    address[] public holderList;
    uint256 public pushCursor;

    event PreferenceSet(address indexed holder, address indexed stock);
    event StrategyAdopted(address indexed holder, uint256 indexed strategyId);
    event MenuUpdated(address indexed stock, bool active, bool vetted);
    event DefaultStrategySet(uint256 indexed strategyId);
    event Claimed(address indexed holder, address indexed stock, uint256 amount);
    event CarryAccrued(address indexed recipient, uint256 indexed strategyId, uint256 credits);
    event ClockReset(address indexed holder);
    event CycleBuy(bool strat, address indexed stock, uint256 indexed sid, uint256 ethSpent, uint256 got);
    event BuyerSet(address indexed buyer);

    error OnlyToken();
    error NotOnMenu();
    error NoBuyer();
    error BadStrategy();

    modifier onlyToken() { if (msg.sender != token) revert OnlyToken(); _; }

    constructor(address token_, address defaultStock_, address ops_) Ownable(msg.sender) {
        require(token_ != address(0) && defaultStock_ != address(0) && ops_ != address(0), "zero addr");
        token = token_;
        opsWallet = ops_;
        _addStock(defaultStock_);
        _addStock(token_);
        defaultStock = defaultStock_;
    }

    receive() external payable {}

    function _addStock(address s) internal {
        if (!onMenu[s]) { menu.push(s); onMenu[s] = true; }
        active[s] = true;
        vetted[s] = true;
        emit MenuUpdated(s, true, true);
    }
    function addStock(address s) external onlyOwner { _addStock(s); }
    function setActive(address s, bool a) external onlyOwner {
        if (!onMenu[s]) revert NotOnMenu();
        active[s] = a; emit MenuUpdated(s, a, vetted[s]);
    }
    function setVetted(address s, bool v) external onlyOwner {
        if (!onMenu[s]) revert NotOnMenu();
        vetted[s] = v; emit MenuUpdated(s, active[s], v);
    }

    function setBuyer(address b) external onlyOwner {
        require(address(buyer) == address(0) && b != address(0), "set once");
        buyer = IBuyer(b); emit BuyerSet(b);
    }
    function setCycler(address c) external onlyOwner { cycler = c; }
    function setOpsWallet(address o) external onlyOwner { opsWallet = o; }

    function setMinBalanceForRewards(uint256 v) external onlyOwner { minBalanceForRewards = v; }
    function setStrategies(address s) external onlyOwner {
        require(address(strategies) == address(0), "set once");
        strategies = IStrategies(s);
    }

    function setDefaultStrategy(uint256 id) external onlyOwner {
        require(id == 0 || (address(strategies) != address(0) && id > 0 && id < strategies.count()), "bad strategy");
        defaultStrategyId = uint32(id);
        if (id != 0) carryExempt[id] = true;
        emit DefaultStrategySet(id);
    }

    function setCarryExempt(uint256 sid, bool exempt) external onlyOwner { carryExempt[sid] = exempt; }
    function menuLength() external view returns (uint256) { return menu.length; }
    function holderCount() external view returns (uint256) { return holderList.length; }
    function activeStrategyCount() external view returns (uint256) { return activeStrategies.length; }

    function tierWeightOf(address h) public view returns (uint256) {
        Holder storage H = holders[h];
        if (H.shares == 0) return 0;
        uint256 e = block.timestamp - H.vestStart;
        for (uint256 i = tierCutoffs.length; i > 0; i--) if (e >= tierCutoffs[i - 1]) return tierWeights[i - 1];
        return 0;
    }

    function _settle(address h) internal {
        Holder storage H = holders[h];
        if (H.stratId != 0) {
            uint256 sid = H.stratId;
            uint256 pendBase = H.shares * (magStratBase[sid] - H.idxBase) / MAG;
            uint256 pendMatch = H.matchShares * (magStratMatch[sid] - H.idxMatch) / MAG;
            if (pendMatch > 0) {
                address creator = strategies.creatorOf(sid);

                if (creator != h && !carryExempt[sid]) {
                    uint256 cC = pendMatch * CARRY_CREATOR_BPS / 10_000;
                    uint256 cP = pendMatch * CARRY_PLATFORM_BPS / 10_000;
                    if (cC > 0) { carryCredits[creator][sid] += cC; emit CarryAccrued(creator, sid, cC); }
                    if (cP > 0) { carryCredits[opsWallet][sid] += cP; emit CarryAccrued(opsWallet, sid, cP); }
                    pendMatch -= cC + cP;
                }
            }
            H.storedCredits += pendBase + pendMatch;
            H.idxBase = magStratBase[sid];
            H.idxMatch = magStratMatch[sid];
        } else {
            address p = H.pref;
            if (p == address(0)) return;
            uint256 pb = H.shares * (magBase[p] - H.idxBase) / MAG;
            uint256 pm = H.matchShares * (magMatch[p] - H.idxMatch) / MAG;
            if (pb + pm > 0) withdrawable[h][p] += pb + pm;
            H.idxBase = magBase[p];
            H.idxMatch = magMatch[p];
        }
    }

    function _removeFromPools(address h) internal {
        Holder storage H = holders[h];
        if (H.stratId != 0) {
            totalStratBaseShares[H.stratId] -= H.shares;
            totalStratMatchShares[H.stratId] -= H.matchShares;
        } else if (H.pref != address(0)) {
            totalBaseShares[H.pref] -= H.shares;
            totalMatchShares[H.pref] -= H.matchShares;
        }
    }

    function _addToPools(address h) internal {
        Holder storage H = holders[h];
        if (H.stratId != 0) {
            uint256 sid = H.stratId;
            totalStratBaseShares[sid] += H.shares;
            totalStratMatchShares[sid] += H.matchShares;
            H.idxBase = magStratBase[sid];
            H.idxMatch = magStratMatch[sid];
            if (!stratListed[sid] && H.shares > 0) { stratListed[sid] = true; activeStrategies.push(sid); }
        } else {
            address p = H.pref;
            totalBaseShares[p] += H.shares;
            totalMatchShares[p] += H.matchShares;
            H.idxBase = magBase[p];
            H.idxMatch = magMatch[p];
        }
    }

    function syncShares(address from, address to, uint256 fromShares, uint256 toShares) external onlyToken {
        if (from != address(0)) _syncOne(from, fromShares, true);
        if (to != address(0) && to != from) _syncOne(to, toShares, false);
    }

    function _syncOne(address h, uint256 newShares, bool isSender) internal {

        if (newShares < minBalanceForRewards) newShares = 0;
        Holder storage H = holders[h];
        _settle(h);
        _removeFromPools(h);
        uint256 prev = H.shares;

        if (isSender && newShares < prev) {

            if (newShares == 0 || (prev - newShares) * 10_000 / prev > RESET_SELL_BPS) {
                H.vestStart = uint64(block.timestamp);
            } else {
                H.vestStart = uint64(block.timestamp - ((block.timestamp - H.vestStart) * newShares / prev));
            }
            emit ClockReset(h);
        } else if (newShares > prev) {
            if (prev == 0) H.vestStart = uint64(block.timestamp);
            else {
                uint256 e = block.timestamp - H.vestStart;
                H.vestStart = uint64(block.timestamp - (e * prev / newShares));
            }
        }

        if (H.pref == address(0) && H.stratId == 0) {
            if (defaultStrategyId != 0) H.stratId = defaultStrategyId;
            else H.pref = defaultStock;
        }

        uint256 w;
        if (newShares > 0) {
            uint256 e2 = block.timestamp - H.vestStart;
            for (uint256 i = tierCutoffs.length; i > 0; i--) if (e2 >= tierCutoffs[i - 1]) { w = tierWeights[i - 1]; break; }
        }
        H.shares = newShares;
        H.matchShares = newShares * w / 100;
        _addToPools(h);

        if (newShares > 0 && H.listPos == 0) { holderList.push(h); H.listPos = uint32(holderList.length); }
    }

    function refresh(address h) public {
        Holder storage H = holders[h];
        if (H.shares == 0) return;
        _settle(h);
        _removeFromPools(h);
        H.matchShares = H.shares * tierWeightOf(h) / 100;
        _addToPools(h);
    }

    function _flushStrategy(address h) internal {
        Holder storage H = holders[h];
        if (H.stratId != 0 && H.storedCredits > 0) {
            uint256 c = H.storedCredits;
            H.storedCredits = 0;

            _redeem(h, H.stratId, c, false);
        }
    }

    function setPreference(address stock) external nonReentrant {
        if (!onMenu[stock] || !active[stock]) revert NotOnMenu();
        _settle(msg.sender);
        _flushStrategy(msg.sender);
        _removeFromPools(msg.sender);
        Holder storage H = holders[msg.sender];
        H.stratId = 0;
        H.pref = stock;
        H.matchShares = H.shares * tierWeightOf(msg.sender) / 100;
        _addToPools(msg.sender);
        emit PreferenceSet(msg.sender, stock);
    }

    function adoptStrategy(uint256 id) external nonReentrant {
        if (address(strategies) == address(0) || id == 0 || id >= strategies.count()) revert BadStrategy();
        _settle(msg.sender);
        if (holders[msg.sender].stratId != uint32(id)) _flushStrategy(msg.sender);
        _removeFromPools(msg.sender);
        Holder storage H = holders[msg.sender];
        H.stratId = uint32(id);
        H.matchShares = H.shares * tierWeightOf(msg.sender) / 100;
        _addToPools(msg.sender);
        emit StrategyAdopted(msg.sender, id);
    }

    function _distributeSingle(address stock, uint256 baseGot, uint256 matchGot) internal {
        uint256 tb = totalBaseShares[stock];
        if (tb == 0) { unallocated[stock] += baseGot + matchGot; return; }
        baseGot += unallocated[stock];
        unallocated[stock] = 0;
        magBase[stock] += baseGot * MAG / tb;
        uint256 tm = totalMatchShares[stock];
        if (tm > 0 && matchGot > 0) magMatch[stock] += matchGot * MAG / tm;
        else if (matchGot > 0) magBase[stock] += matchGot * MAG / tb;
    }

    function _tryBuy(address s, uint256 eth, address to) internal returns (uint256 got) {
        try buyer.buy{value: eth}(s, eth, 0, to) returns (uint256 g) { return g; } catch { return 0; }
    }

    function runCycle(uint256 maxEthPerStock) external nonReentrant {
        require(msg.sender == cycler || msg.sender == owner(), "not cycler");
        if (address(buyer) == address(0)) revert NoBuyer();
        uint256 pot = address(this).balance;
        if (pot == 0) return;

        uint256 sumBase; uint256 sumMatch;
        for (uint256 i = 0; i < menu.length; i++) {
            if (!active[menu[i]]) continue;
            sumBase += totalBaseShares[menu[i]];
            sumMatch += totalMatchShares[menu[i]];
        }
        for (uint256 i = 0; i < activeStrategies.length; i++) {
            uint256 sid = activeStrategies[i];
            sumBase += totalStratBaseShares[sid];
            sumMatch += totalStratMatchShares[sid];
        }
        if (sumBase == 0) return;

        uint256 basePot = pot * BASE_BPS / 10_000;
        uint256 matchPot = pot - basePot;
        if (sumMatch == 0) { basePot = pot; matchPot = 0; }

        for (uint256 i = 0; i < menu.length; i++) {
            address s = menu[i];
            if (!active[s]) continue;
            uint256 ethBase = basePot * totalBaseShares[s] / sumBase;
            uint256 ethMatch = sumMatch > 0 ? matchPot * totalMatchShares[s] / sumMatch : 0;
            uint256 eth = ethBase + ethMatch;
            if (eth == 0) continue;
            if (eth > maxEthPerStock) { ethBase = ethBase * maxEthPerStock / eth; ethMatch = maxEthPerStock - ethBase; eth = maxEthPerStock; }
            uint256 got = _tryBuy(s, eth, address(this));
            if (got == 0) continue;
            _distributeSingle(s, got * ethBase / eth, got - (got * ethBase / eth));
            emit CycleBuy(false, s, 0, eth, got);
        }

        for (uint256 i = 0; i < activeStrategies.length; ) {
            uint256 sid = activeStrategies[i];
            uint256 tb = totalStratBaseShares[sid];
            if (tb == 0) {
                stratListed[sid] = false;
                activeStrategies[i] = activeStrategies[activeStrategies.length - 1];
                activeStrategies.pop();
                continue;
            }
            uint256 tm = totalStratMatchShares[sid];
            uint256 ethBase = basePot * tb / sumBase;
            uint256 ethMatch = sumMatch > 0 ? matchPot * tm / sumMatch : 0;
            uint256 ethTotal = ethBase + ethMatch;
            if (ethTotal == 0) { unchecked { ++i; } continue; }
            (address[] memory stk, uint16[] memory wt) = strategies.entries(sid);
            uint256 used;
            for (uint256 j = 0; j < stk.length; j++) {

                if (!active[stk[j]] || !vetted[stk[j]]) continue;
                uint256 legEth = ethTotal * wt[j] / 10_000;
                if (legEth == 0) continue;
                if (legEth > maxEthPerStock) legEth = maxEthPerStock;
                uint256 got = _tryBuy(stk[j], legEth, address(this));
                if (got > 0) { vault[sid][stk[j]] += got; used += legEth; emit CycleBuy(true, stk[j], sid, legEth, got); }
            }
            if (used == 0) { unchecked { ++i; } continue; }

            uint256 uBase = ethBase * used / ethTotal;
            uint256 uMatch = used - uBase;
            magStratBase[sid] += uBase * MAG / tb;
            if (tm > 0) magStratMatch[sid] += uMatch * MAG / tm;
            else magStratBase[sid] += uMatch * MAG / tb;
            outstanding[sid] += used;
            unchecked { ++i; }
        }
    }

    function _execZeroX(address stock, uint256 eth, uint256 minOut, bytes calldata data) internal returns (uint256 got) {
        if (eth == 0 || eth > address(this).balance) return 0;
        uint256 bal = IERC20(stock).balanceOf(address(this));
        (bool ok, ) = ZEROX.call{value: eth}(data);
        if (!ok) return 0;
        got = IERC20(stock).balanceOf(address(this)) - bal;

        require(minOut > 0 && got >= minOut, "0x: bad fill / misdeliver");
    }

    function runCycleZeroX(ZBuy[] calldata buys, uint256 maxEthPerStock) external nonReentrant {
        require(msg.sender == cycler || msg.sender == owner(), "not cycler");

        Leg[] memory canon = _computeLegs(maxEthPerStock);
        bool[] memory used = new bool[](canon.length);
        for (uint256 i = 0; i < buys.length; i++) {
            ZBuy calldata b = buys[i];
            if (!active[b.stock]) continue;
            if (b.strat && !vetted[b.stock]) continue;

            uint256 j = canon.length;
            for (uint256 c = 0; c < canon.length; c++) {
                if (!used[c] && canon[c].strat == b.strat && canon[c].stock == b.stock && canon[c].sid == b.sid) { j = c; break; }
            }
            if (j == canon.length) continue;
            used[j] = true;
            if (b.ethBase > canon[j].ethBase * ALLOC_TOL / 100) continue;
            if (b.ethMatch > canon[j].ethMatch * ALLOC_TOL / 100) continue;
            uint256 eth = b.ethBase + b.ethMatch;
            if (!b.strat) {
                uint256 got = _execZeroX(b.stock, eth, b.minOut, b.data);
                if (got == 0) continue;
                uint256 baseGot = got * b.ethBase / eth;
                _distributeSingle(b.stock, baseGot, got - baseGot);
                emit CycleBuy(false, b.stock, 0, eth, got);
            } else {
                uint256 sid = b.sid;
                uint256 tb = totalStratBaseShares[sid];
                if (tb == 0) continue;
                uint256 got = _execZeroX(b.stock, eth, b.minOut, b.data);
                if (got == 0) continue;
                vault[sid][b.stock] += got;
                uint256 tm = totalStratMatchShares[sid];
                magStratBase[sid] += b.ethBase * MAG / tb;
                if (tm > 0) magStratMatch[sid] += b.ethMatch * MAG / tm;
                else magStratBase[sid] += b.ethMatch * MAG / tb;
                outstanding[sid] += eth;
                emit CycleBuy(true, b.stock, sid, eth, got);
            }
        }
    }

    function pruneStrategies(uint256 maxSteps) external {
        uint256 i = 0; uint256 steps = 0;
        while (i < activeStrategies.length && steps < maxSteps) {
            uint256 sid = activeStrategies[i];
            if (totalStratBaseShares[sid] == 0) {
                stratListed[sid] = false;
                activeStrategies[i] = activeStrategies[activeStrategies.length - 1];
                activeStrategies.pop();
            } else { i++; }
            steps++;
        }
    }

    function previewCycle(uint256 maxEthPerStock) external view returns (Leg[] memory) {
        return _computeLegs(maxEthPerStock);
    }
    function _computeLegs(uint256 maxEthPerStock) internal view returns (Leg[] memory legs) {
        uint256 pot = address(this).balance;
        if (pot == 0) return new Leg[](0);
        uint256 sumBase; uint256 sumMatch;
        for (uint256 i = 0; i < menu.length; i++) {
            if (!active[menu[i]]) continue;
            sumBase += totalBaseShares[menu[i]];
            sumMatch += totalMatchShares[menu[i]];
        }
        for (uint256 i = 0; i < activeStrategies.length; i++) {
            sumBase += totalStratBaseShares[activeStrategies[i]];
            sumMatch += totalStratMatchShares[activeStrategies[i]];
        }
        if (sumBase == 0) return new Leg[](0);
        uint256 basePot = pot * BASE_BPS / 10_000;
        uint256 matchPot = pot - basePot;
        if (sumMatch == 0) { basePot = pot; matchPot = 0; }

        uint256 cnt;
        for (uint256 i = 0; i < menu.length; i++) {
            address s = menu[i];
            if (!active[s]) continue;
            uint256 eb = basePot * totalBaseShares[s] / sumBase;
            uint256 em = sumMatch > 0 ? matchPot * totalMatchShares[s] / sumMatch : 0;
            if (eb + em > 0) cnt++;
        }
        for (uint256 i = 0; i < activeStrategies.length; i++) {
            uint256 sid = activeStrategies[i];
            uint256 tb = totalStratBaseShares[sid];
            if (tb == 0) continue;
            uint256 eb = basePot * tb / sumBase;
            uint256 em = sumMatch > 0 ? matchPot * totalStratMatchShares[sid] / sumMatch : 0;
            uint256 tot = eb + em;
            if (tot == 0) continue;
            (address[] memory stk, uint16[] memory wt) = strategies.entries(sid);
            for (uint256 j = 0; j < stk.length; j++) {
                if (!active[stk[j]] || !vetted[stk[j]]) continue;

                if (eb * wt[j] / 10_000 + em * wt[j] / 10_000 > 0) cnt++;
            }
        }

        legs = new Leg[](cnt);
        uint256 k;
        for (uint256 i = 0; i < menu.length; i++) {
            address s = menu[i];
            if (!active[s]) continue;
            uint256 eb = basePot * totalBaseShares[s] / sumBase;
            uint256 em = sumMatch > 0 ? matchPot * totalMatchShares[s] / sumMatch : 0;
            uint256 eth = eb + em;
            if (eth == 0) continue;
            if (eth > maxEthPerStock) { eb = eb * maxEthPerStock / eth; em = maxEthPerStock - eb; }
            legs[k++] = Leg(false, s, 0, eb, em);
        }
        for (uint256 i = 0; i < activeStrategies.length; i++) {
            uint256 sid = activeStrategies[i];
            uint256 tb = totalStratBaseShares[sid];
            if (tb == 0) continue;
            uint256 eb = basePot * tb / sumBase;
            uint256 em = sumMatch > 0 ? matchPot * totalStratMatchShares[sid] / sumMatch : 0;
            uint256 tot = eb + em;
            if (tot == 0) continue;
            (address[] memory stk, uint16[] memory wt) = strategies.entries(sid);
            for (uint256 j = 0; j < stk.length; j++) {
                if (!active[stk[j]] || !vetted[stk[j]]) continue;
                uint256 lb = eb * wt[j] / 10_000;
                uint256 lm = em * wt[j] / 10_000;
                uint256 le = lb + lm;
                if (le == 0) continue;
                if (le > maxEthPerStock) { lb = lb * maxEthPerStock / le; lm = maxEthPerStock - lb; }
                legs[k++] = Leg(true, stk[j], sid, lb, lm);
            }
        }
    }

    function claim() external nonReentrant { _claimFor(msg.sender); }

    function _claimFor(address h) internal {
        _settle(h);
        Holder storage H = holders[h];

        for (uint256 i = 0; i < menu.length; i++) {
            address s = menu[i];
            uint256 amt = withdrawable[h][s];
            if (amt == 0) continue;
            withdrawable[h][s] = 0;
            IERC20(s).safeTransfer(h, amt);
            emit Claimed(h, s, amt);
        }

        if (H.stratId != 0 && H.storedCredits > 0) {
            uint256 c = H.storedCredits;
            H.storedCredits = 0;
            if (!_redeem(h, H.stratId, c, false)) H.storedCredits = c;
        }
    }

    function _redeem(address to, uint256 sid, uint256 credits, bool toWithdrawable) internal returns (bool paidAny) {
        uint256 out = outstanding[sid];
        if (out == 0 || credits == 0) return false;
        (address[] memory stk, ) = strategies.entries(sid);
        uint256 n = stk.length;
        uint256[] memory gives = new uint256[](n);
        for (uint256 j = 0; j < n; j++) {
            uint256 g = vault[sid][stk[j]] * credits / out;
            if (g > 0) { gives[j] = g; paidAny = true; }
        }
        if (!paidAny) return false;
        outstanding[sid] = out - credits;
        for (uint256 j = 0; j < n; j++) {
            if (gives[j] == 0) continue;
            vault[sid][stk[j]] -= gives[j];
            if (toWithdrawable) withdrawable[to][stk[j]] += gives[j];
            else { IERC20(stk[j]).safeTransfer(to, gives[j]); emit Claimed(to, stk[j], gives[j]); }
        }
        return true;
    }

    function claimCarry(uint256 sid) external nonReentrant {
        uint256 c = carryCredits[msg.sender][sid];
        if (c == 0) return;
        carryCredits[msg.sender][sid] = 0;
        if (!_redeem(msg.sender, sid, c, false)) carryCredits[msg.sender][sid] = c;
    }

    function claimForSelf(address h) external {
        require(msg.sender == address(this), "only self");
        _claimFor(h);
    }

    function pushBatch(uint256 count) external nonReentrant {
        uint256 n = holderList.length;
        if (n == 0) return;
        for (uint256 i = 0; i < count; i++) {
            if (pushCursor >= n) pushCursor = 0;

            try this.claimForSelf(holderList[pushCursor]) {} catch {}
            pushCursor++;
        }
    }

    function claimable(address h, address stock) external view returns (uint256 amount) {
        amount = withdrawable[h][stock];
        Holder storage H = holders[h];
        if (H.stratId == 0) {
            address p = H.pref;
            if (p == stock) {
                amount += H.shares * (magBase[stock] - H.idxBase) / MAG
                        + H.matchShares * (magMatch[stock] - H.idxMatch) / MAG;
            }
        } else {
            uint256 sid = H.stratId;

            uint256 pendBase = H.shares * (magStratBase[sid] - H.idxBase) / MAG;
            uint256 pendMatch = H.matchShares * (magStratMatch[sid] - H.idxMatch) / MAG;

            if (pendMatch > 0 && strategies.creatorOf(sid) != h && !carryExempt[sid]) {
                pendMatch -= pendMatch * (CARRY_CREATOR_BPS + CARRY_PLATFORM_BPS) / 10_000;
            }
            uint256 credits = H.storedCredits + pendBase + pendMatch;
            uint256 out = outstanding[sid];
            if (out > 0 && credits > 0) amount += vault[sid][stock] * credits / out;
        }
    }
}

Chain explorer4223msChain node73ms