No wins yet. Buy a ticket to show up here.

Roboomhood

A token with a built-in buy/sell lottery: every trade takes a 10% fee, feeding an LP vault that backs the payouts, a ticket system that draws with verifiable randomness (VRF-style), and a dividend paid straight to holders.

🎟️ 8% of the fee funds the Vault, which pays out winning tickets
💰 1% of the fee is split among token holders
💧 LPs can freely deposit and withdraw ETH from the vault, earning from trading fees
🔁 1% of the fee goes to the team wallet, used for buybacks
🔒 A max-buy cap scales with pool size to resist price manipulation
✅ The random outcome can't be predicted or exploited in advance

Mechanics

Trading fee

Every buy or sell takes a 10% fee, split three ways: the Vault (funds the lottery), token holders (dividend), and the team wallet (used for buybacks).

Ticket on every buy

Every buy earns one ticket for a random draw, with a jackpot worth up to 50x the ETH spent.

Max buy cap

Every buy is capped relative to the current pool size, to stop a whale from swinging the price or draining the pool with an oversized win.

LP Vault

Anyone can deposit ETH into the Vault to become a liquidity provider, earn a share of the trading fees, and withdraw it back at any time in proportion to their contribution.

Holder dividend

Just holding the token earns a share of the dividend from trading fees, claimable any time, no action required.

Refunds on failure

If the randomness system fails or takes too long to resolve, buyers never lose their fee unfairly. It either gets refunded, or was simply never taken in the first place.

Provable fairness

No one, including the team running the project, can predict or manipulate a draw's outcome.

Full mechanics

1. Trading fee

Every buy or sell takes a 10% fee, split three ways according to fixed ratios in the contract:

uint256 public constant FEE_BPS = 1_000;                    // 10% of every trade
uint256 public constant VAULT_SHARE_OF_FEE_BPS = 8_000;      // 80% of the fee -> 8% of volume
uint256 public constant DIVIDEND_SHARE_OF_FEE_BPS = 1_000;   // 10% of the fee -> 1% of volume
                                                              // the remainder (1% of volume) goes to the team wallet

function _split(uint256 fee) internal pure returns (uint256 vaultShare, uint256 dividendShare, uint256 devShare) {
    vaultShare = (fee * VAULT_SHARE_OF_FEE_BPS) / 10_000;
    dividendShare = (fee * DIVIDEND_SHARE_OF_FEE_BPS) / 10_000;
    devShare = fee - vaultShare - dividendShare;
}

Selling takes the exact same 10% fee, split the same 8/1/1 way, just without earning a ticket.

2. Ticket on every buy

Every BUY (not sells) earns one ticket for a random draw, landing in exactly one of 7 fixed reward tiers:

// tierMultiplier[i] / MULT_SCALE(100) = payout multiplier
uint256[7] public tierMultiplier = [uint256(5), 10, 50, 100, 500, 2500, 5000];
//                                     0.05x  0.1x  0.5x   1x    5x   25x   50x

A ticket is always attributed to whichever wallet actually receives the tokens, whether the trade goes through directly or via a bot or router. The system listens for the real token transfer event to determine the buyer, rather than relying on the transaction'smsg.sender.

3. Max buy cap

To stop a single oversized buy from manipulating the price or draining the pool on a big win, every buy is capped by a percentage of the Vault's current ETH balance. The bigger the pool, the higher the cap. Exceeding it reverts the trade entirely, right at the moment of the transaction:

function rawPoolValue() public view returns (uint256) {
    return address(this).balance;
}

function maxBuyVolume() external view returns (uint256) {
    uint256 poolValue = rawPoolValue();
    if (poolValue == 0) return 0;
    (uint256 capBps,) = _tierParams(poolValue);
    return (poolValue * capBps) / 10_000;
}

This is a hard cap, distinct from buying too little or too much for a ticket to make sense: in that case the trade still succeeds normally, only the ticket gets skipped instead of reverting:

if (volume < MIN_TICKET_VOLUME || poolValueBefore == 0) {
    emit TicketSkipped(volume, true);
    return 0;               // the trade still succeeds, it just gets no ticket
}
...
if (volume > maxVolume) {
    emit TicketSkipped(volume, false);
    return 0;               // above the ticket's own cap -- still no revert
}

The team's own initial buy at token launch, used to seed a starting position, is exempt from the hard cap above, since it's a one-time action at launch rather than an ordinary buyer's trade:

if (sender != launcher) {
    uint256 maxAllowed = vault.maxBuyVolume();
    if (ethIn > maxAllowed) revert BuyExceedsMaxCap(ethIn, maxAllowed);
}

4. Timeouts, refunds & forgotten payouts

If a ticket has no result after 15 minutes, a rare case, it automatically expires and the fee taken for that buy is refunded to the buyer in full. Separately, if the randomness system can't take the request at all, say because of a temporary outage, the buy still succeeds as normal. That trade alone just doesn't take a fee, gets no ticket, and there's nothing to refund because nothing was ever taken. If a winner or a refund recipient forgets to claim for too long, the project owner can sweep that amount back into the shared pool for LPs, so no ETH is ever lost for good.

5. Holder dividend

1% of every trade's fee accrues into a dividend pool, split in proportion to token balance, claimable at any time. The project's own wallets (the liquidity pool, the hook, the vault, and the launcher) are excluded from the dividend split, so this share goes entirely to real holders:

function _isProjectWallet(address account) internal view returns (bool) {
    return account == poolManager || account == hook || account == vault || account == launcher;
}

function circulatingSupply() public view returns (uint256) {
    return totalSupply() - balanceOf(poolManager) - balanceOf(hook) - balanceOf(vault) - balanceOf(launcher);
}

6. LP Vault

Anyone can deposit ETH into the Vault to become an LP, receiving shares in proportion to their contribution (with protection against share-price manipulation on the very first deposit). This is the pool that backs the lottery's payouts. LPs earn from the 8% fee flowing in, but also carry the risk of a large win, and can't withdraw funds already confirmed owed to a winner who hasn't claimed yet.

7. Provable fairness of the draw

Draw results use a commit-reveal scheme: a secret hash chain is generated in advance, and only the hash of its very tip is made public. Each draw has to "unlock" the correct next secret value, mixed with a delayed blockhash, meaning a block that doesn't exist yet at the time of purchase. That combination means no one, not even the team running the keeper, can predict or manipulate a result:

function reveal(bytes32 preimage) external returns (uint256 requestId, uint256 randomWord) {
    if (msg.sender != server) revert OnlyServer();
    if (pendingCount() == 0) revert NoPendingRequest();
    if (keccak256(abi.encodePacked(preimage)) != headCommitment) revert BadReveal();

    requestId = _queue[_queueHead];
    uint256 seedBlock = seedBlockOf[requestId];
    if (block.number <= seedBlock) revert SeedNotReady();     // the seed didn't exist yet at purchase time
    bytes32 blockSeed = blockhash(seedBlock);
    if (blockSeed == bytes32(0)) revert SeedUnavailable();
    ...
}

If a ticket's reveal window is ever missed, a rare occurrence, the system has a way to safely skip it so it doesn't wedge the entire queue behind it. A skipped ticket still gets refunded normally through the timeout mechanism in section 4:

function skipStalled(uint256 requestId) external {
    if (pendingCount() == 0) revert NoPendingRequest();
    if (_queue[_queueHead] != requestId) revert NotHead();
    uint256 seedBlock = seedBlockOf[requestId];
    if (block.number <= seedBlock) revert SeedNotReady();
    if (blockhash(seedBlock) != bytes32(0)) revert SeedStillRecoverable();  // still recoverable, not eligible to skip yet
    ...
}

8. Pausing & abuse prevention

The project owner can pause new tickets in an emergency. This never blocks LP deposits/withdrawals or pending reward/refund claims. Separately, each transaction may trigger at most one ticket; if multiple buys are bundled into the same transaction, a technique commonly used to game reward systems, the whole transaction reverts instead of silently ignoring the extras.

9. Pool creation

Only the project team is allowed to create the token's initial trading pool, which blocks a third party from creating it first at an unfavorable starting price for holders:

function beforeInitialize(address sender, PoolKey calldata key, uint160)
    external override onlyPoolManager returns (bytes4)
{
    if (sender != launcher) revert NotLauncher();
    ...
}

There is no admin function anywhere in the Vault or Hook that lets the owner withdraw LP funds directly. Any ETH sitting in either contract only ever moves through the paths described above: LP withdrawals, ticket payouts, refunds, and dividend claims.