Robinhood MainnetChain ID: 4663
Contract detail

ForkBurnEngine

Live Robinhood Chain account facts for 0x20c6d511…6f2dc876 with at least 25 observed transactions. The history total is updating as indexing continues.

Address type
Smart contract
Transactions
25+ observed
First indexed block
#73237022
Latest indexed block
#89683372
History coverage
Recent activity available; total is catching up
Indexed token transfers
22
ERC-20 transfers
22
Emitted events
21
Verification
Verified
Compiler
0.8.30+commit.73712a01
Verification match
exact
Creation transaction
0x32329b9c…e7ff78f7
Created at block
#73237022
Language
Solidity
EVM version
cancun
License
MIT
Compiler optimization
Enabled · 200 runs
Deployed bytecode hash
0x752a925ba7f9aa7dbbff0c58f0872ad8f9c5bc39d28d4b327b5db89361a8fd66
Related activity

Transactions

Verified contract

Contract source code

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

import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import {ForkSwapAdapter} from "./ForkSwapAdapter.sol";

interface IForkReferenceQuote {
    function quote(uint256 ethIn) external view returns (uint256 expectedTokenOut, uint256 updatedAt);
}

/// @notice User-triggered burn engine for real v3/v4 routes.
/// @dev Production candidate; quote integrity, liquidity, and security require final review.
contract ForkBurnEngine is ReentrancyGuard, Ownable {
    using SafeERC20 for IERC20;

    address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
    uint256 public immutable INTERVAL;
    uint256 public constant INTERVALS_PER_DAY = 144;
    uint256 public constant DENOMINATOR = 10_000;
    uint256 public constant CALLER_REWARD_BPS = 150;
    uint256 public constant DRIP_DENOMINATOR = INTERVALS_PER_DAY * DENOMINATOR;
    uint256 public constant MAX_QUOTE_AGE = 15 minutes;
    uint256 public constant MAX_SLIPPAGE_BPS = 1_000;

    IERC20 public immutable token;
    IForkReferenceQuote public immutable referenceQuote;
    uint256 public immutable launchTime;
    uint256 public maxSwapEth;
    ForkSwapAdapter public adapter;
    uint256 public dailyPoolBps = 100;
    uint256 public maxSlippageBps = MAX_SLIPPAGE_BPS;
    uint256 public lastExecutedInterval;
    uint256 public lastRateCheckpointInterval;
    uint256 public pendingDripWeight;
    uint256 public pendingExecutableEth;

    error InvalidConfiguration();
    error NotStarted();
    error NoElapsedIntervals();
    error AmountTooSmall();
    error StaleOrInvalidQuote();
    error TransferFailed();

    event Funded(address indexed sender, uint256 amount);
    event DailyPoolBpsUpdated(uint256 previousBps, uint256 newBps);
    event MaxSlippageBpsUpdated(uint256 previousBps, uint256 newBps);
    event MaxSwapEthUpdated(uint256 previousLimit, uint256 newLimit);
    event Executed(
        address indexed caller,
        uint256 intervals,
        uint256 grossEth,
        uint256 callerReward,
        uint256 swapEth,
        uint256 tokensBurned
    );

    constructor(
        IERC20 token_,
        IForkReferenceQuote referenceQuote_,
        uint256 launchTime_,
        uint256 maxSwapEth_,
        uint256 interval_,
        address owner_
    ) Ownable(owner_) {
        if (
            address(token_) == address(0) || address(referenceQuote_) == address(0) || launchTime_ == 0
                || maxSwapEth_ == 0 || (interval_ != 10 seconds && interval_ != 10 minutes)
        ) {
            revert InvalidConfiguration();
        }
        token = token_;
        referenceQuote = referenceQuote_;
        launchTime = launchTime_;
        maxSwapEth = maxSwapEth_;
        INTERVAL = interval_;
    }

    receive() external payable {
        if (msg.value == 0) revert AmountTooSmall();
        emit Funded(msg.sender, msg.value);
    }

    function configureAdapter(ForkSwapAdapter adapter_) external onlyOwner {
        if (
            address(adapter) != address(0) || address(adapter_) == address(0) || adapter_.controller() != address(this)
                || address(adapter_.outputToken()) != address(token)
        ) {
            revert InvalidConfiguration();
        }
        adapter = adapter_;
    }

    function setDailyPoolBps(uint256 newBps) external onlyOwner {
        if (newBps < 100 || newBps > 1_000) revert InvalidConfiguration();
        uint256 intervalNow = currentInterval();
        pendingDripWeight += (intervalNow - lastRateCheckpointInterval) * dailyPoolBps;
        lastRateCheckpointInterval = intervalNow;
        emit DailyPoolBpsUpdated(dailyPoolBps, newBps);
        dailyPoolBps = newBps;
    }

    function setMaxSlippageBps(uint256 newBps) external onlyOwner {
        if (newBps > MAX_SLIPPAGE_BPS) revert InvalidConfiguration();
        emit MaxSlippageBpsUpdated(maxSlippageBps, newBps);
        maxSlippageBps = newBps;
    }

    function setMaxSwapEth(uint256 newLimit) external onlyOwner {
        if (newLimit == 0) revert InvalidConfiguration();
        emit MaxSwapEthUpdated(maxSwapEth, newLimit);
        maxSwapEth = newLimit;
    }

    function currentInterval() public view returns (uint256) {
        if (block.timestamp < launchTime) return 0;
        return (block.timestamp - launchTime) / INTERVAL;
    }

    function executableAmount() public view returns (uint256) {
        uint256 intervalNow = currentInterval();
        if (intervalNow <= lastExecutedInterval) return 0;
        uint256 weight = pendingDripWeight + (intervalNow - lastRateCheckpointInterval) * dailyPoolBps;
        uint256 amount = pendingExecutableEth + Math.mulDiv(address(this).balance, weight, DRIP_DENOMINATOR);
        return Math.min(amount, address(this).balance);
    }

    function execute() external nonReentrant returns (uint256 tokensBurned) {
        if (block.timestamp < launchTime) revert NotStarted();
        uint256 intervalNow = currentInterval();
        if (intervalNow <= lastExecutedInterval) revert NoElapsedIntervals();
        uint256 elapsedIntervals = intervalNow - lastExecutedInterval;
        uint256 available = executableAmount();
        uint256 gross = Math.min(available, maxSwapEth);
        if (gross == 0) revert AmountTooSmall();
        uint256 callerReward = gross * CALLER_REWARD_BPS / DENOMINATOR;
        uint256 swapEth = gross - callerReward;
        if (swapEth == 0) revert AmountTooSmall();
        uint256 minimumOut = _minimumOut(swapEth);

        lastExecutedInterval = intervalNow;
        lastRateCheckpointInterval = intervalNow;
        pendingDripWeight = 0;
        pendingExecutableEth = available - gross;
        tokensBurned = adapter.swap{value: swapEth}(minimumOut, block.timestamp + 2 minutes);
        token.safeTransfer(BURN_ADDRESS, tokensBurned);
        (bool rewarded,) = payable(msg.sender).call{value: callerReward}("");
        if (!rewarded) revert TransferFailed();
        emit Executed(msg.sender, elapsedIntervals, gross, callerReward, swapEth, tokensBurned);
    }

    function _minimumOut(uint256 swapEth) private view returns (uint256 minimumOut) {
        (uint256 expectedOut, uint256 updatedAt) = referenceQuote.quote(swapEth);
        if (expectedOut == 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > MAX_QUOTE_AGE) {
            revert StaleOrInvalidQuote();
        }
        minimumOut = Math.mulDiv(expectedOut, DENOMINATOR - maxSlippageBps, DENOMINATOR);
        if (minimumOut == 0 || address(adapter) == address(0)) revert InvalidConfiguration();
    }
}