S Price: $0.462979 (+2.06%)

Contract Diff Checker

Contract Name:
SonicChainSafeLocker

Contract Source Code:

File 1 of 1 : SonicChainSafeLocker

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// IERC20 interface
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);
}

// ReentrancyGuard implementation
abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

// Ownable implementation
abstract contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor(address initialOwner) {
        _transferOwnership(initialOwner);
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// TokenLocker contract
contract SonicChainSafeLocker is ReentrancyGuard, Ownable {
    struct Lock {
        address token;
        uint256 amount;
        uint256 unlockTime;
        bool isUnlocked;
    }

    mapping(address => Lock[]) public userLocks;

    event TokensLocked(
        address indexed user,
        address indexed token,
        uint256 amount,
        uint256 unlockTime,
        uint256 lockId
    );

    event TokensUnlocked(
        address indexed user,
        address indexed token,
        uint256 amount,
        uint256 lockId
    );

    constructor() Ownable(msg.sender) {}

    function lockTokens(
        address _token,
        uint256 _amount,
        uint256 _duration
    ) external nonReentrant {
        require(_token != address(0), "Invalid token address");
        require(_amount > 0, "Amount must be greater than 0");
        require(_duration > 0, "Duration must be greater than 0");

        IERC20 token = IERC20(_token);
        require(
            token.balanceOf(msg.sender) >= _amount,
            "Insufficient token balance"
        );
        require(
            token.allowance(msg.sender, address(this)) >= _amount,
            "Insufficient allowance"
        );

        uint256 unlockTime = block.timestamp + _duration;

        // Transfer tokens to contract
        require(
            token.transferFrom(msg.sender, address(this), _amount),
            "Token transfer failed"
        );

        // Create new lock
        userLocks[msg.sender].push(Lock({
            token: _token,
            amount: _amount,
            unlockTime: unlockTime,
            isUnlocked: false
        }));

        emit TokensLocked(
            msg.sender,
            _token,
            _amount,
            unlockTime,
            userLocks[msg.sender].length - 1
        );
    }

    function unlockTokens(uint256 _lockId) external nonReentrant {
        require(_lockId < userLocks[msg.sender].length, "Invalid lock ID");
        Lock storage lock = userLocks[msg.sender][_lockId];

        require(!lock.isUnlocked, "Tokens already unlocked");
        require(block.timestamp >= lock.unlockTime, "Tokens are still locked");

        lock.isUnlocked = true;

        IERC20 token = IERC20(lock.token);
        require(
            token.transfer(msg.sender, lock.amount),
            "Token transfer failed"
        );

        emit TokensUnlocked(
            msg.sender,
            lock.token,
            lock.amount,
            _lockId
        );
    }

    function getUserLocks(address _user) external view returns (Lock[] memory) {
        return userLocks[_user];
    }

    function getLockInfo(address _user, uint256 _lockId) external view returns (
        address token,
        uint256 amount,
        uint256 unlockTime,
        bool isUnlocked
    ) {
        require(_lockId < userLocks[_user].length, "Invalid lock ID");
        Lock memory lock = userLocks[_user][_lockId];
        return (
            lock.token,
            lock.amount,
            lock.unlockTime,
            lock.isUnlocked
        );
    }

    // Emergency function to recover stuck tokens
    function emergencyWithdraw(address _token) external onlyOwner {
        IERC20 token = IERC20(_token);
        uint256 balance = token.balanceOf(address(this));
        require(balance > 0, "No tokens to withdraw");
        require(
            token.transfer(owner(), balance),
            "Token transfer failed"
        );
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):