Contract detail
HoodpegHook
HoodpegHook is a verified Robinhood Chain smart contract at 0xfeabcd62…e8f5cccd with 1 indexed transactions.
- Address type
- Smart contract
- Transactions
- 1
- First indexed block
- #922987
- Latest indexed block
- #922988
- ERC-20 transfers
- 1
- Emitted events
- 2
- Verification
- Verified
- Compiler
- v0.8.20+commit.a1b79de6
- Verification match
- full
- Creation transaction
- 0x6a3672e2…c9dbc2a8
- Created at block
- #922987
- Language
- solidity
- EVM version
- shanghai
- License
- none
- Compiler optimization
- Enabled · 200 runs
Related activity
Transactions
| Transaction | Block | From | To | Value (wei) |
|---|---|---|---|---|
| 0x03250cf4…6a185755 | #922988 | 0x6cff5939…37463154 | 0xfeabcd62…e8f5cccd | 0 |
Verified contract
Contract source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// ============================================================
// The first on-chain object built on @Uniswap V4 Hooks on @RobinhoodApp Chain.
// https://x.com/hoodpegv4
// https://www.hoodpeg.xyz/
// ============================================================
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface IRandomSeedProvider {
function randomSeed() external view returns (uint256);
}
interface IStartableToken {
function start(address newPool) external;
function isStarted() external view returns (bool);
}
abstract contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
constructor() {
_transferOwnership(msg.sender);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view returns (address) {
return _owner;
}
function _checkOwner() internal view {
if (owner() != msg.sender) revert OwnableUnauthorizedAccount(msg.sender);
}
function renounceOwnership() public onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public onlyOwner {
if (newOwner == address(0)) revert OwnableInvalidOwner(address(0));
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
abstract contract ERC20 is IERC20 {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public pure returns (uint8) {
return 18;
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function allowance(address owner_, address spender) public view returns (uint256) {
return _allowances[owner_][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
_spendAllowance(from, msg.sender, amount);
_transfer(from, to, amount);
return true;
}
function _transfer(address from, address to, uint256 amount) internal {
require(from != address(0), "ERC20: transfer from zero");
require(to != address(0), "ERC20: transfer to zero");
_update(from, to, amount);
}
function _update(address from, address to, uint256 amount) internal {
if (from == address(0)) {
_totalSupply += amount;
} else {
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: insufficient balance");
unchecked {
_balances[from] = fromBalance - amount;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= amount;
}
} else {
unchecked {
_balances[to] += amount;
}
}
emit Transfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal {
_update(address(0), account, amount);
}
function _approve(address owner_, address spender, uint256 amount) internal {
_allowances[owner_][spender] = amount;
emit Approval(owner_, spender, amount);
}
function _spendAllowance(address owner_, address spender, uint256 amount) internal {
uint256 currentAllowance = allowance(owner_, spender);
if (currentAllowance < type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner_, spender, currentAllowance - amount);
}
}
}
}
/// @title Hoodpeg
/// @dev Transfer logic is vanilla ERC-20. Hook/seed/SVG functions are decorative only.
contract Hoodpeg is ERC20, Ownable, IStartableToken, IRandomSeedProvider {
uint256 public constant TOTAL_SUPPLY = 10_000 * 1e18;
uint256 public constant UNIT_PER_ENTITY = 1e18;
address public hook;
address public pool;
address public seedProvider;
address public upegsRegistry;
address public nftWrapper;
bool public started;
uint256 internal _randomSeed;
uint256 internal _randomCount;
mapping(address => uint256) public userSeed;
mapping(address => uint256) public lockedTokens;
event HookSet(address indexed hook);
event PoolSet(address indexed pool);
event SeedProviderSet(address indexed provider);
event UpegsAddressSet(address indexed upegs);
event NFTWrapperSet(address indexed wrapper);
event SeedAssigned(address indexed user, uint256 seed);
event TokenStarted(address indexed pool);
event EntityLocked(address indexed user, uint256 lockedAmount);
event EntityUnlocked(address indexed user, uint256 lockedAmount);
constructor() ERC20("Hoodpeg", "hoodPEG") {
_randomSeed = block.timestamp;
_mint(msg.sender, TOTAL_SUPPLY);
}
function setHook(address hookAddress) external onlyOwner {
hook = hookAddress;
emit HookSet(hookAddress);
}
function setPool(address poolAddress) external onlyOwner {
pool = poolAddress;
emit PoolSet(poolAddress);
}
function setSeedProvider(address provider) external onlyOwner {
seedProvider = provider;
emit SeedProviderSet(provider);
}
function setUpegsAddress(address upegsAddress) external onlyOwner {
upegsRegistry = upegsAddress;
emit UpegsAddressSet(upegsAddress);
}
function setNFTWrapper(address wrapper) external onlyOwner {
nftWrapper = wrapper;
emit NFTWrapperSet(wrapper);
}
function start(address newPool) external onlyOwner {
pool = newPool;
started = true;
emit TokenStarted(newPool);
}
function isStarted() external view override returns (bool) {
return started;
}
function isTokenSetted() external view returns (bool) {
return pool != address(0);
}
function randomSeed() external view override returns (uint256) {
return _randomSeed;
}
function randomizeSeed() external onlyOwner {
_randomSeed = uint256(
keccak256(
abi.encodePacked(++_randomCount, _randomSeed, block.timestamp, block.prevrandao, block.number)
)
);
}
function entityCount(address user) external view returns (uint256) {
return balanceOf(user) / UNIT_PER_ENTITY;
}
function getEntityTraits(address user, uint256 index) external view returns (uint256) {
return _entityTraits(user, index);
}
function getSvg(address user, uint256 index) external view returns (string memory) {
return _buildartSvg(_entityTraits(user, index));
}
function tokenURI(address user, uint256 index) external view returns (string memory) {
return string.concat("data:image/svg+xml;utf8,", _buildartSvg(_entityTraits(user, index)));
}
function pokeSeed() external {
if (userSeed[msg.sender] != 0) return;
uint256 seed = uint256(
keccak256(abi.encodePacked(_randomSeed, msg.sender, block.timestamp, block.prevrandao))
);
userSeed[msg.sender] = seed;
emit SeedAssigned(msg.sender, seed);
}
function lockForNFT(address user) external {
lockedTokens[user] += UNIT_PER_ENTITY;
emit EntityLocked(user, lockedTokens[user]);
}
function unlockFromNFT(address user) external {
if (lockedTokens[user] >= UNIT_PER_ENTITY) {
lockedTokens[user] -= UNIT_PER_ENTITY;
}
emit EntityUnlocked(user, lockedTokens[user]);
}
function _entityTraits(address user, uint256 index) internal view returns (uint256) {
uint256 seed = userSeed[user];
if (seed == 0) {
seed = uint256(keccak256(abi.encodePacked(user, index, _randomSeed)));
}
return uint256(keccak256(abi.encodePacked(seed, index, "hoodpeg-traits")));
}
function _buildartSvg(uint256 traits) internal pure returns (string memory) {
string memory color = _traitColor(traits);
return string.concat(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">',
'<rect width="24" height="24" fill="#101820"/>',
'<path d="M6 16c2-4 4-6 6-6s4 2 6 6" stroke="',
color,
'" fill="none"/>',
'<circle cx="10" cy="11" r="1" fill="',
color,
'"/>',
'<path d="M14 8l3-2 1 3" stroke="',
color,
'" fill="none"/>',
'<text x="12" y="22" text-anchor="middle" font-size="2" fill="#8aa0b2">HOODPEG</text>',
"</svg>"
);
}
function _traitColor(uint256 traits) internal pure returns (string memory) {
uint256 palette = traits % 6;
if (palette == 0) return "#ff6b6b";
if (palette == 1) return "#4ecdc4";
if (palette == 2) return "#ffe66d";
if (palette == 3) return "#a78bfa";
if (palette == 4) return "#f472b6";
return "#60a5fa";
}
}
/// @title HoodpegHook
contract HoodpegHook is Ownable, IRandomSeedProvider {
struct HookPermissions {
bool beforeInitialize;
bool afterInitialize;
bool beforeAddLiquidity;
bool afterAddLiquidity;
bool beforeRemoveLiquidity;
bool afterRemoveLiquidity;
bool beforeSwap;
bool afterSwap;
bool beforeDonate;
bool afterDonate;
bool beforeSwapReturnDelta;
bool afterSwapReturnDelta;
bool afterAddLiquidityReturnDelta;
bool afterRemoveLiquidityReturnDelta;
}
address public upegs;
address public token;
address public poolManager;
uint256 internal _randomSeed;
uint256 internal _randomCount;
event UpegsAddressSet(address indexed upegs);
event TokenSet(address indexed token);
event RandomSeedUpdated(uint256 seed);
constructor() {
_randomSeed = block.timestamp;
}
function setUpegsAddress(address upegsAddress) external onlyOwner {
upegs = upegsAddress;
emit UpegsAddressSet(upegsAddress);
}
function setToken(address tokenAddress) external onlyOwner {
token = tokenAddress;
emit TokenSet(tokenAddress);
}
function setPoolManager(address poolManager_) external onlyOwner {
poolManager = poolManager_;
}
function isTokenSetted() public view returns (bool) {
return token != address(0);
}
function randomSeed() external view override returns (uint256) {
return _randomSeed;
}
function randomizeSeed() external onlyOwner {
_randomSeed = uint256(
keccak256(
abi.encodePacked(++_randomCount, _randomSeed, block.timestamp, block.prevrandao, block.number)
)
);
emit RandomSeedUpdated(_randomSeed);
}
function getHookPermissions() external pure returns (HookPermissions memory) {
return
HookPermissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: true,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: true,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
});
}
function afterAddLiquidity() external pure returns (bytes4) {
return bytes4(keccak256("afterAddLiquidity(address,address,uint160,int24)"));
}
function afterSwap() external pure returns (bytes4) {
return bytes4(keccak256("afterSwap(address,address,uint160,int24)"));
}
}