Robinhood MainnetChain ID: 4663
Contract detail

FeeEscrow

Live Robinhood Chain account facts for 0x479b2997…1d7467af with at least 326 observed transactions. The history total is updating as indexing continues.

Address type
Smart contract
Transactions
326+ observed
First indexed block
#92651078
Latest indexed block
#112046324
History coverage
Recent activity available; total is catching up
Indexed token transfers
31573
ERC-20 transfers
31573
Emitted events
31579
Verification
Verified
Compiler
0.8.26+commit.8a97fa7a
Verification match
exact
Creation transaction
0x60524333…ff12df57
Created at block
#92651078
Language
Solidity
EVM version
cancun
License
MIT
Compiler optimization
Enabled · 500 runs
Deployed bytecode hash
0xc08c68400a65c7a7ad7509c3343b5abd76683e026887c16dad0569312db9205f
Related activity

Transactions

Verified contract

Contract source code

// SPDX-License-Identifier: MIT
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 {IBondingCurve, IFeeEscrow, ILaunchHook} from "./interfaces/ILaunchpad.sol";

/// @title FeeEscrow
/// @notice Holds creators' stock fees per curve until the curve's current fee
///         recipient claims. Credits are permissionless but must be backed by
///         stock already transferred in, accounted per stock so one curve is
///         never paid from another stock's backing. Curves are recognised by
///         the hook's authorization flag, so one escrow serves one hook.
contract FeeEscrow is IFeeEscrow {
    using SafeERC20 for IERC20;

    ILaunchHook public immutable hook;

    /// @notice Stock owed to each curve's fee recipient.
    mapping(address curve => uint256) public balanceOf;
    /// @notice Sum of `balanceOf` over the curves of each stock.
    mapping(address stock => uint256) public accounted;

    event Credited(address indexed curve, address indexed stock, uint256 amount);
    event Claimed(address indexed curve, address indexed recipient, uint256 amount);

    error Unbacked();
    error UnknownCurve();

    constructor(ILaunchHook hook_) {
        hook = hook_;
    }

    /// @notice Records `amount` of the curve's stock for its creator. The caller
    ///         transfers the stock first, same transaction.
    function credit(address curve, uint256 amount) external {
        if (!hook.curveAuthorized(curve)) revert UnknownCurve();
        address stock = IBondingCurve(curve).stock();
        if (IERC20(stock).balanceOf(address(this)) - accounted[stock] < amount) revert Unbacked();
        accounted[stock] += amount;
        balanceOf[curve] += amount;
        emit Credited(curve, stock, amount);
    }

    /// @notice Pays the curve's balance to its current fee recipient. Anyone may call.
    function claim(address curve) external returns (uint256 amount) {
        if (!hook.curveAuthorized(curve)) revert UnknownCurve();
        IBondingCurve c = IBondingCurve(curve);
        address stock = c.stock();
        address recipient = c.feeRecipient();

        amount = balanceOf[curve];
        balanceOf[curve] = 0;
        accounted[stock] -= amount;
        if (amount > 0) IERC20(stock).safeTransfer(recipient, amount);
        emit Claimed(curve, recipient, amount);
    }
}