// SPDX-License-Identifier: MIT
pragma solidity 0.8.35;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./PCATCompanionNFT.sol";
import "./PCATRewardsPool.sol";
contract PCATNFTStaking is IERC721Receiver, ReentrancyGuard {
bytes32 public constant launchFingerprint = 0x064072855cef16f15e97223103f448dc406a937a3e8135d94029410f15a74a51;
error Unauthorized();
error AlreadyInitialized();
error InvalidAddress();
error InvalidSchedule();
error ScheduleActive();
error StakingPaused();
error NotTokenOwner();
error NotTokenStaker();
error InvalidReceipt();
error NothingToClaim();
IERC721 public immutable nftCollection;
PCATRewardsPool public immutable rewardsPool;
address public immutable initializer;
address public controller;
bool public paused;
uint256 public totalStaked;
uint256 public totalAccrued;
uint256 public totalClaimed;
uint256 public rewardRatePerNftPerSecond;
uint64 public periodStart;
uint64 public periodFinish;
uint64 public epochDuration;
uint64 public lastUpdateTime;
uint256 public rewardPerNftStored;
mapping(uint256 => address) public stakerOf;
mapping(address => uint256) public stakedBalance;
mapping(address => uint256) public userRewardPerNftPaid;
mapping(address => uint256) public rewards;
uint256 private receivingTokenIdPlusOne;
event ControllerInitialized(address indexed controller);
event ScheduleStarted(uint256 rewardRatePerNftPerSecond, uint64 periodStart, uint64 periodFinish, uint64 epochDuration);
event ScheduleEnded(uint64 endedAt);
event PauseChanged(bool paused);
event Staked(address indexed account, uint256 indexed tokenId);
event Unstaked(address indexed account, uint256 indexed tokenId);
event RewardClaimed(address indexed account, uint256 amount);
constructor(
address nftCollection_,
address rewardsPool_,
address initializer_
) {
if (nftCollection_ == address(0) || rewardsPool_ == address(0) || initializer_ == address(0)) {
revert InvalidAddress();
}
nftCollection = IERC721(nftCollection_);
rewardsPool = PCATRewardsPool(rewardsPool_);
initializer = initializer_;
}
modifier onlyController() {
if (msg.sender != controller) revert Unauthorized();
_;
}
function initializeController(address controller_) external {
if (msg.sender != initializer) revert Unauthorized();
if (controller != address(0)) revert AlreadyInitialized();
if (controller_ == address(0)) revert InvalidAddress();
controller = controller_;
emit ControllerInitialized(controller_);
}
function startSchedule(
uint256 rewardRate_,
uint64 duration_,
uint64 epochDuration_
) external onlyController {
_updateGlobal();
if (block.timestamp < periodFinish) revert ScheduleActive();
if (
rewardRate_ == 0 || duration_ == 0 || epochDuration_ == 0
|| duration_ % epochDuration_ != 0
) revert InvalidSchedule();
uint64 startedAt = uint64(block.timestamp);
rewardRatePerNftPerSecond = rewardRate_;
periodStart = startedAt;
periodFinish = startedAt + duration_;
epochDuration = epochDuration_;
lastUpdateTime = startedAt;
emit ScheduleStarted(rewardRate_, startedAt, periodFinish, epochDuration_);
}
function endSchedule() external onlyController {
_updateGlobal();
uint64 endedAt = uint64(block.timestamp);
if (endedAt < periodFinish) periodFinish = endedAt;
rewardRatePerNftPerSecond = 0;
lastUpdateTime = endedAt;
emit ScheduleEnded(endedAt);
}
function setPaused(bool paused_) external onlyController {
paused = paused_;
emit PauseChanged(paused_);
}
function stake(uint256 tokenId) external nonReentrant {
if (paused) revert StakingPaused();
if (nftCollection.ownerOf(tokenId) != msg.sender) revert NotTokenOwner();
_updateAccount(msg.sender);
stakerOf[tokenId] = msg.sender;
stakedBalance[msg.sender] += 1;
totalStaked += 1;
receivingTokenIdPlusOne = tokenId + 1;
nftCollection.safeTransferFrom(msg.sender, address(this), tokenId);
receivingTokenIdPlusOne = 0;
emit Staked(msg.sender, tokenId);
}
function unstake(uint256 tokenId) external nonReentrant {
if (stakerOf[tokenId] != msg.sender) revert NotTokenStaker();
_updateAccount(msg.sender);
delete stakerOf[tokenId];
stakedBalance[msg.sender] -= 1;
totalStaked -= 1;
nftCollection.safeTransferFrom(address(this), msg.sender, tokenId);
emit Unstaked(msg.sender, tokenId);
}
function claim() external nonReentrant returns (uint256 amount) {
_updateAccount(msg.sender);
amount = rewards[msg.sender];
if (amount == 0) revert NothingToClaim();
rewards[msg.sender] = 0;
totalClaimed += amount;
rewardsPool.payReward(msg.sender, amount);
emit RewardClaimed(msg.sender, amount);
}
function earned(address account) public view returns (uint256) {
return rewards[account]
+ stakedBalance[account] * (currentRewardPerNft() - userRewardPerNftPaid[account]);
}
function currentRewardPerNft() public view returns (uint256) {
uint64 applicable = lastTimeRewardApplicable();
if (applicable <= lastUpdateTime) return rewardPerNftStored;
return rewardPerNftStored
+ uint256(applicable - lastUpdateTime) * rewardRatePerNftPerSecond;
}
function lastTimeRewardApplicable() public view returns (uint64) {
return uint64(block.timestamp < periodFinish ? block.timestamp : periodFinish);
}
function currentEpoch() external view returns (uint256) {
if (epochDuration == 0 || block.timestamp <= periodStart) return 0;
uint256 elapsed = lastTimeRewardApplicable() - periodStart;
return elapsed / epochDuration;
}
function _updateGlobal() private {
uint64 applicable = lastTimeRewardApplicable();
if (applicable <= lastUpdateTime) return;
uint256 elapsed = applicable - lastUpdateTime;
uint256 perNft = elapsed * rewardRatePerNftPerSecond;
rewardPerNftStored += perNft;
lastUpdateTime = applicable;
uint256 accrued = perNft * totalStaked;
if (accrued > 0) {
totalAccrued += accrued;
rewardsPool.recognizeReward(accrued);
}
}
function _updateAccount(address account) private {
_updateGlobal();
rewards[account] += stakedBalance[account]
* (rewardPerNftStored - userRewardPerNftPaid[account]);
userRewardPerNftPaid[account] = rewardPerNftStored;
}
function onERC721Received(
address operator,
address,
uint256 tokenId,
bytes calldata
) external view returns (bytes4) {
if (
msg.sender != address(nftCollection)
|| operator != address(this)
|| receivingTokenIdPlusOne != tokenId + 1
) revert InvalidReceipt();
return IERC721Receiver.onERC721Received.selector;
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "nftCollection_",
"type": "address",
"internalType": "address"
},
{
"name": "rewardsPool_",
"type": "address",
"internalType": "address"
},
{
"name": "initializer_",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "AlreadyInitialized",
"type": "error",
"inputs": []
},
{
"name": "InvalidAddress",
"type": "error",
"inputs": []
},
{
"name": "InvalidReceipt",
"type": "error",
"inputs": []
},
{
"name": "InvalidSchedule",
"type": "error",
"inputs": []
},
{
"name": "NotTokenOwner",
"type": "error",
"inputs": []
},
{
"name": "NotTokenStaker",
"type": "error",
"inputs": []
},
{
"name": "NothingToClaim",
"type": "error",
"inputs": []
},
{
"name": "ReentrancyGuardReentrantCall",
"type": "error",
"inputs": []
},
{
"name": "ScheduleActive",
"type": "error",
"inputs": []
},
{
"name": "StakingPaused",
"type": "error",
"inputs": []
},
{
"name": "Unauthorized",
"type": "error",
"inputs": []
},
{
"name": "ControllerInitialized",
"type": "event",
"inputs": [
{
"name": "controller",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "PauseChanged",
"type": "event",
"inputs": [
{
"name": "paused",
"type": "bool",
"indexed": false,
"internalType": "bool"
}
],
"anonymous": false
},
{
"name": "RewardClaimed",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "ScheduleEnded",
"type": "event",
"inputs": [
{
"name": "endedAt",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
}
],
"anonymous": false
},
{
"name": "ScheduleStarted",
"type": "event",
"inputs": [
{
"name": "rewardRatePerNftPerSecond",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "periodStart",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "periodFinish",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "epochDuration",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
}
],
"anonymous": false
},
{
"name": "Staked",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "tokenId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Unstaked",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "tokenId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "claim",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "controller",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "currentEpoch",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "currentRewardPerNft",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "earned",
"type": "function",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "endSchedule",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "epochDuration",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"name": "initializeController",
"type": "function",
"inputs": [
{
"name": "controller_",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "initializer",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "lastTimeRewardApplicable",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"name": "lastUpdateTime",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"name": "launchFingerprint",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"name": "nftCollection",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IERC721"
}
],
"stateMutability": "view"
},
{
"name": "onERC721Received",
"type": "function",
"inputs": [
{
"name": "operator",
"type": "address",
"internalType": "address"
},
{
"name": "",
"type": "address",
"internalType": "address"
},
{
"name": "tokenId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
}
],
"stateMutability": "view"
},
{
"name": "paused",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"name": "periodFinish",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"name": "periodStart",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"name": "rewardPerNftStored",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "rewardRatePerNftPerSecond",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "rewards",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "rewardsPool",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract PCATRewardsPool"
}
],
"stateMutability": "view"
},
{
"name": "setPaused",
"type": "function",
"inputs": [
{
"name": "paused_",
"type": "bool",
"internalType": "bool"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "stake",
"type": "function",
"inputs": [
{
"name": "tokenId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "stakedBalance",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "stakerOf",
"type": "function",
"inputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "startSchedule",
"type": "function",
"inputs": [
{
"name": "rewardRate_",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "duration_",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "epochDuration_",
"type": "uint64",
"internalType": "uint64"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "totalAccrued",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "totalClaimed",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "totalStaked",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "unstake",
"type": "function",
"inputs": [
{
"name": "tokenId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "userRewardPerNftPaid",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
}
]0x60806040526004361015610011575f80fd5b5f5f3560e01c80628cc26214610ee55780630359fea914610ea15780630700037d14610e69578063150b7a0214610d7b57806316c38b3c14610cfa5780632aedc7b714610cc05780632e17de7814610b455780634ae8a5b714610b275780634e71d92d146109ff5780634ff0876a146109d557806359d94c16146109b75780635c975abb1461099257806360217267146109595780636588103b1461091457806376671808146108f95780637ca2e2331461082157806380faa57d146107f5578063817b1cd2146107d75780639ce110d714610792578063a694fc3a14610561578063ac86e1861461052e578063c726993c1461050b578063c83945f5146104ed578063c8f33c91146104cc578063d2b059b81461030a578063d54ad2a1146102ec578063e9f4aa40146102b3578063ebe2b12b14610289578063eda4e6d614610262578063f5276e4c146101975763f77c47911461016e575f80fd5b34610194578060031936011261019457546040516001600160a01b039091168152602090f35b80fd5b5034610194576020366003190112610194576101b1610f52565b7f000000000000000000000000057cfc81b0ee956c5bbb709ad80955628a7178416001600160a01b03163303610254578154906001600160a01b038216610246576001600160a01b0316908115610237576001600160a01b031916811782557faf6cb4b6bd854745d0a59a68dd9678894a2a8a403d922ed85763badb1548c7148280a280f35b63e6c4247b60e01b8352600483fd5b62dc149f60e41b8352600483fd5b6282b42960e81b8252600482fd5b503461019457806003193601126101945760206001600160401b0360055416604051908152f35b503461019457806003193601126101945760206001600160401b0360055460401c16604051908152f35b5034610194576020366003190112610194576020906040906001600160a01b036102db610f52565b168152600983522054604051908152f35b50346101945780600319360112610194576020600354604051908152f35b5034610194576060366003190112610194576004356024356001600160401b0381168091036104c857604435906001600160401b038216918281036104c45784546001600160a01b031633036104b657610362611193565b600554906001600160401b038260401c1642106104a7578415801561049f575b8015610497575b8015610469575b61045a576001600160401b034216928560045583016001600160401b03811161044657608091821b67ffffffffffffffff60801b16604091821b67ffffffffffffffff60401b166001600160c01b03861617174260c01b6001600160c01b0319161760058190558151968752602087019490945292831c6001600160401b0316928501929092525060608301919091527fbbd886b2c522b80f12cd382ae89a2b0c7f6d2c404ccc3929e68bac7e6792587a91a180f35b634e487b7160e01b87526011600452602487fd5b631b742d9d60e31b8652600486fd5b508315610483576001600160401b03848406161515610390565b634e487b7160e01b86526012600452602486fd5b508315610389565b508215610382565b63aa14e3f360e01b8652600486fd5b6282b42960e81b8552600485fd5b8480fd5b8280fd5b5034610194578060031936011261019457602060055460c01c604051908152f35b50346101945780600319360112610194576020600454604051908152f35b503461019457806003193601126101945760206105266110a7565b604051908152f35b503461019457602036600319011261019457602090600435815260078252604060018060a01b0391205416604051908152f35b50346101945760203660031901126101945760043561057e6110f7565b60ff825460a01c16610783576040516331a9108f60e11b8152600481018290527f0000000000000000000000003f04063203e34aa5277ec44b4c49b07b641668596001600160a01b031690602081602481855afa908115610778578491610732575b50336001600160a01b0390911603610723576105fb3361112f565b818352600760205260408320336bffffffffffffffffffffffff60a01b8254161790553383526008602052604083208054906001820180921161070f5755600154600181018091116106fb57600155600182018083116106fb57600b558290803b156106ec57604051632142170760e11b8152336004820152306024820152604481018490529082908290606490829084905af180156106f0576106d7575b50600b55337f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d8380a360015f51602061128c5f395f51905f525580f35b816106e191610fab565b6106ec57815f61069a565b5080fd5b6040513d84823e3d90fd5b634e487b7160e01b84526011600452602484fd5b634e487b7160e01b85526011600452602485fd5b6359dc379f60e01b8352600483fd5b90506020813d602011610770575b8161074d60209383610fab565b8101031261076c57516001600160a01b038116810361076c575f6105e0565b8380fd5b3d9150610740565b6040513d86823e3d90fd5b6326d1807b60e01b8252600482fd5b50346101945780600319360112610194576040517f000000000000000000000000057cfc81b0ee956c5bbb709ad80955628a7178416001600160a01b03168152602090f35b50346101945780600319360112610194576020600154604051908152f35b50346101945780600319360112610194576020610810611075565b6001600160401b0360405191168152f35b503461019457806003193601126101945780546001600160a01b031633036108eb5761084b611193565b7fe9ab78028e18e75e017a5e76cfe5c427690c4c1f59bdecf6d72e32082fd56ccd60206001600160401b0342166005546001600160401b038160401c1682106108bd575b506004849055600580546001600160c01b03164260c01b6001600160c01b031916179055604051908152a180f35b6fffffffffffffffff000000000000000019164260401b67ffffffffffffffff60401b16176005555f61088f565b6282b42960e81b8152600490fd5b50346101945780600319360112610194576020610526611000565b50346101945780600319360112610194576040517f0000000000000000000000003f04063203e34aa5277ec44b4c49b07b641668596001600160a01b03168152602090f35b5034610194576020366003190112610194576020906040906001600160a01b03610981610f52565b168152600883522054604051908152f35b503461019457806003193601126101945760ff6020915460a01c166040519015158152f35b50346101945780600319360112610194576020600654604051908152f35b503461019457806003193601126101945760206001600160401b0360055460801c16604051908152f35b5034610194578060031936011261019457610a186110f7565b610a213361112f565b338152600a60205260408120548015610b1857338252600a602052816040812055610a4e81600354610f9e565b600355817f000000000000000000000000e889e9a3f811214409624508b1506c3f3be1f06b6001600160a01b0316803b156106ec578190604460405180948193638b8afcd760e01b83523360048401528760248401525af18015610b0d57610af8575b6020826040518181527f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241833392a260015f51602061128c5f395f51905f5255604051908152f35b610b03838092610fab565b6106ec5781610ab1565b6040513d85823e3d90fd5b6312d37ee560e31b8252600482fd5b50346101945780600319360112610194576020600254604051908152f35b5034610c99576020366003190112610c9957600435610b626110f7565b5f818152600760205260409020546001600160a01b03163303610cb157610b883361112f565b805f52600760205260405f206bffffffffffffffffffffffff60a01b8154169055335f52600860205260405f208054905f198201918211610c9d57556001545f198101908111610c9d576001557f0000000000000000000000003f04063203e34aa5277ec44b4c49b07b641668596001600160a01b0316803b15610c9957604051632142170760e11b815230600482015233602482015260448101839052905f908290606490829084905af18015610c8e57610c79575b50337f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f758380a360015f51602061128c5f395f51905f525580f35b610c869192505f90610fab565b5f905f610c3f565b6040513d5f823e3d90fd5b5f80fd5b634e487b7160e01b5f52601160045260245ffd5b63a4d0594f60e01b5f5260045ffd5b34610c99575f366003190112610c995760206040517f064072855cef16f15e97223103f448dc406a937a3e8135d94029410f15a74a518152f35b34610c99576020366003190112610c9957600435801515809103610c99575f546001600160a01b0381163303610d6d5760ff60a01b191660a082901b60ff60a01b16175f556040519081527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec590602090a1005b6282b42960e81b5f5260045ffd5b34610c99576080366003190112610c9957610d94610f52565b610d9c610f68565b506044356064356001600160401b038111610c995736602382011215610c995780600401356001600160401b038111610c995736910160240111610c9957337f0000000000000000000000003f04063203e34aa5277ec44b4c49b07b641668596001600160a01b03161480159290610e55575b508115610e3d575b50610e2e57604051630a85bd0160e11b8152602090f35b63300262ab60e21b5f5260045ffd5b9050600b5460018201809211610c9d57141581610e17565b6001600160a01b0316301415915082610e0f565b34610c99576020366003190112610c99576001600160a01b03610e8a610f52565b165f52600a602052602060405f2054604051908152f35b34610c99575f366003190112610c99576040517f000000000000000000000000e889e9a3f811214409624508b1506c3f3be1f06b6001600160a01b03168152602090f35b34610c99576020366003190112610c995760206105266001600160a01b03610f0b610f52565b16805f52600a8352610f4c60405f205491805f5260088552610f4660405f205491610f346110a7565b905f526009875260405f205490610f7e565b90610f8b565b90610f9e565b600435906001600160a01b0382168203610c9957565b602435906001600160a01b0382168203610c9957565b91908203918211610c9d57565b81810292918115918404141715610c9d57565b91908201809211610c9d57565b90601f801991011681019081106001600160401b03821117610fcc57604052565b634e487b7160e01b5f52604160045260245ffd5b906001600160401b03809116911603906001600160401b038211610c9d57565b6005546001600160401b038160801c1690811590818015611062575b61105b5761103d6001600160401b039182611035611075565b911690610fe0565b1690611047570490565b634e487b7160e01b5f52601260045260245ffd5b5050505f90565b506001600160401b03811642111561101c565b6001600160401b0360055460401c168042105f1461109b57506001600160401b03421690565b6001600160401b031690565b6110af611075565b60055460c01c90816001600160401b03821611156110ef57610f4c6001600160401b036110e26110ec9460065494610fe0565b1660045490610f8b565b90565b505060065490565b60025f51602061128c5f395f51905f5254146111205760025f51602061128c5f395f51905f5255565b633ee5aeb560e01b5f5260045ffd5b611137611193565b60018060a01b0316805f52600860205261116860405f2054610f46600654845f52600960205260405f205490610f7e565b815f52600a60205261117f60405f20918254610f9e565b9055600654905f52600960205260405f2055565b61119b611075565b600554908160c01c91826001600160401b0383161115611286576111cd6001600160401b036110e26112059585610fe0565b916111da83600654610f9e565b6006556001600160c01b0390911660c09190911b6001600160c01b0319161760055560015490610f8b565b8061120d5750565b61121981600254610f9e565b6002557f000000000000000000000000e889e9a3f811214409624508b1506c3f3be1f06b6001600160a01b031690813b15610c99575f91602483926040519485938492635c6197af60e01b845260048401525af18015610c8e5761127a5750565b5f61128491610fab565b565b50505056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a264697066735822122097644b2421b0592c69bd6f28563b7e62d9ee04e2a357582789b2d3b5c9294d9064736f6c63430008230033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| no token holdings | ||||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| no token transfers for this address yet | |||||||||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| 0x5978d2…a44b08 | 22 days agoSun, 26 Jul 2026 13:23:03 UTC | 0xbbd886…587a | data: 0x000000000000000000…00015180 |
| 0x5978d2…a44b08 | 22 days agoSun, 26 Jul 2026 13:23:03 UTC | 0xaf6cb4…c714 | [0] 0x000000000000…919e6b1a |
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| No direct transactions — this address is only ever reached via internal calls (common for a contract only invoked through a router or proxy). View Internal Transactions → | |||||||||
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 19,903,323 | 22 days agoSun, 26 Jul 2026 13:23:03 UTC | 0x5978d2…a44b08 | CREATE | launch | 0x057c…7841 | IN | 0x1db0…e926 | 0 ETH |