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