CreatorFeeShare
0x10e88fc30e5abbb1d6dc4a648e1679dc2c826e43
Verification
Unverified
v0.8.26+commit.8a97fa7a
Type
Contract
4,329 bytes
ABI entries
36
17 read · 5 write
License
none
Contract information
- Address
- 0x10e88fc30e5abbb1d6dc4a648e1679dc2c826e43
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x519fd71F5d…20c336273e
- Creation tx
- 0x6cbd55a063…fa8a879c34
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (17)
BPS_DENOMINATOR() → uint256
CREATOR_BPS() → uint256
claimBalance() → uint256
creator() → address
creatorClaimable() → uint256
excessWeth() → uint256
factory() → address
hook() → address
isSolvent() → bool
outstanding() → uint256
poolManager() → address
protocolClaimable() → uint256
totalAssets() → uint256
totalCreatorClaimed() → uint256
totalDeposited() → uint256
totalProtocolClaimed() → uint256
weth() → address
Events (3)
CreatorClaimedDepositedProtocolClaimed
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "factory_",
"type": "address"
},
{
"internalType": "address",
"name": "creator_",
"type": "address"
},
{
"internalType": "address",
"name": "hook_",
"type": "address"
},
{
"internalType": "address",
"name": "weth_",
"type": "address"
},
{
"internalType": "contract IPoolManager",
"name": "poolManager_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "Insolvent",
"type": "error"
},
{
"inputs": [],
"name": "NothingToClaim",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "UnauthorizedDepositor",
"type": "error"
},
{
"inputs": [],
"name": "UnauthorizedUnlockCallback",
"type": "error"
},
{
"inputs": [],
"name": "UnexpectedClaimRedemption",
"type": "error"
},
{
"inputs": [],
"name": "UnsupportedTransferBehavior",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddressNotAllowed",
"type": "error"
},
{
"inputs": [],
"name": "ZeroValueNotAllowed",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "CreatorClaimed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "creatorAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "protocolAmount",
"type": "uint256"
}
],
"name": "Deposited",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ProtocolClaimed",
"type": "event"
},
{
"inputs": [],
"name": "BPS_DENOMINATOR",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "CREATOR_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "claim",
"outputs": [
{
"internalType": "uint256",
"name": "creatorAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "protocolAmount",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "claimBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "claimCreator",
"outputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "claimProtocol",
"outputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "creator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "creatorClaimable",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "depositClaim",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "excessWeth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hook",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "isSolvent",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "outstanding",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poolManager",
"outputs": [
{
"internalType": "contract IPoolManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "protocolClaimable",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalAssets",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalCreatorClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalDeposited",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalProtocolClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "unlockCallback",
"outputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol";
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {IFactoryFeeSource} from "./interfaces/IPumpV4.sol";
/**
* @title CreatorFeeShare
* @notice Immutable per-token PoolManager-claim custody with a fixed 50/50 split.
* @dev The hook is the only depositor. Anyone may trigger claims, but creator
* funds always go to the constructor-fixed creator and protocol funds
* always go to the factory's current feeCollector.
*/
contract CreatorFeeShare is ReentrancyGuard, IUnlockCallback {
using SafeERC20 for IERC20;
uint256 public constant CREATOR_BPS = 5_000;
uint256 public constant BPS_DENOMINATOR = 10_000;
address public immutable factory;
address public immutable creator;
address public immutable hook;
address public immutable weth;
IPoolManager public immutable poolManager;
uint256 public creatorClaimable;
uint256 public protocolClaimable;
uint256 public totalDeposited;
uint256 public totalCreatorClaimed;
uint256 public totalProtocolClaimed;
uint256 private redeemingClaimAmount;
event Deposited(uint256 amount, uint256 creatorAmount, uint256 protocolAmount);
event CreatorClaimed(address indexed caller, address indexed creator, uint256 amount);
event ProtocolClaimed(address indexed caller, address indexed recipient, uint256 amount);
error ZeroAddressNotAllowed();
error ZeroValueNotAllowed();
error UnauthorizedDepositor();
error UnsupportedTransferBehavior();
error Insolvent();
error NothingToClaim();
error UnauthorizedUnlockCallback();
error UnexpectedClaimRedemption();
constructor(address factory_, address creator_, address hook_, address weth_, IPoolManager poolManager_) {
if (
factory_ == address(0) || creator_ == address(0) || hook_ == address(0) || weth_ == address(0)
|| address(poolManager_) == address(0)
) {
revert ZeroAddressNotAllowed();
}
factory = factory_;
creator = creator_;
hook = hook_;
weth = weth_;
poolManager = poolManager_;
}
function depositClaim(uint256 amount) external nonReentrant {
if (msg.sender != hook) revert UnauthorizedDepositor();
if (amount == 0) revert ZeroValueNotAllowed();
_recordDeposit(amount);
}
function unlockCallback(bytes calldata data) external returns (bytes memory) {
if (msg.sender != address(poolManager)) revert UnauthorizedUnlockCallback();
uint256 amount = abi.decode(data, (uint256));
if (amount == 0 || amount != redeemingClaimAmount) revert UnexpectedClaimRedemption();
redeemingClaimAmount = 0;
uint256 claimId = uint256(uint160(weth));
poolManager.burn(address(this), claimId, amount);
poolManager.take(Currency.wrap(weth), address(this), amount);
return abi.encode(amount);
}
function totalAssets() public view returns (uint256) {
return IERC20(weth).balanceOf(address(this)) + claimBalance();
}
function claimBalance() public view returns (uint256) {
return poolManager.balanceOf(address(this), uint256(uint160(weth)));
}
function _recordDeposit(uint256 amount) private {
uint256 creatorAmount = amount / 2;
uint256 protocolAmount = amount - creatorAmount;
creatorClaimable += creatorAmount;
protocolClaimable += protocolAmount;
totalDeposited += amount;
_assertClaimBacked();
emit Deposited(amount, creatorAmount, protocolAmount);
}
function claimCreator() external nonReentrant returns (uint256 amount) {
amount = _claimCreator(msg.sender);
}
function claimProtocol() external nonReentrant returns (uint256 amount) {
amount = _claimProtocol(msg.sender);
}
function claim() external nonReentrant returns (uint256 creatorAmount, uint256 protocolAmount) {
creatorAmount = creatorClaimable;
protocolAmount = protocolClaimable;
if (creatorAmount == 0 && protocolAmount == 0) revert NothingToClaim();
address recipient = IFactoryFeeSource(factory).feeCollector();
if (protocolAmount != 0 && recipient == address(0)) revert ZeroAddressNotAllowed();
creatorClaimable = 0;
protocolClaimable = 0;
totalCreatorClaimed += creatorAmount;
totalProtocolClaimed += protocolAmount;
_redeemClaims(creatorAmount + protocolAmount);
IERC20 token = IERC20(weth);
if (creatorAmount != 0) {
token.safeTransfer(creator, creatorAmount);
emit CreatorClaimed(msg.sender, creator, creatorAmount);
}
if (protocolAmount != 0) {
token.safeTransfer(recipient, protocolAmount);
emit ProtocolClaimed(msg.sender, recipient, protocolAmount);
}
_assertClaimBacked();
}
function outstanding() public view returns (uint256) {
return creatorClaimable + protocolClaimable;
}
function isSolvent() external view returns (bool) {
return claimBalance() >= outstanding();
}
function excessWeth() external view returns (uint256) {
return IERC20(weth).balanceOf(address(this));
}
function _claimCreator(address caller) private returns (uint256 amount) {
amount = creatorClaimable;
if (amount == 0) revert NothingToClaim();
creatorClaimable = 0;
totalCreatorClaimed += amount;
_payout(creator, amount);
_assertClaimBacked();
emit CreatorClaimed(caller, creator, amount);
}
function _claimProtocol(address caller) private returns (uint256 amount) {
amount = protocolClaimable;
if (amount == 0) revert NothingToClaim();
address recipient = IFactoryFeeSource(factory).feeCollector();
if (recipient == address(0)) revert ZeroAddressNotAllowed();
protocolClaimable = 0;
totalProtocolClaimed += amount;
_payout(recipient, amount);
_assertClaimBacked();
emit ProtocolClaimed(caller, recipient, amount);
}
function _payout(address recipient, uint256 amount) private {
_redeemClaims(amount);
IERC20(weth).safeTransfer(recipient, amount);
}
function _redeemClaims(uint256 amount) private {
if (redeemingClaimAmount != 0) revert UnexpectedClaimRedemption();
IERC20 token = IERC20(weth);
uint256 beforeBalance = token.balanceOf(address(this));
redeemingClaimAmount = amount;
bytes memory result = poolManager.unlock(abi.encode(amount));
if (redeemingClaimAmount != 0 || abi.decode(result, (uint256)) != amount) {
revert UnexpectedClaimRedemption();
}
if (token.balanceOf(address(this)) - beforeBalance != amount) revert UnsupportedTransferBehavior();
}
function _assertClaimBacked() private view {
if (claimBalance() < outstanding()) revert Insolvent();
}
}
Chain explorer6006msChain node84ms