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();
}
}