Source Code
Latest 25 from a total of 204 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Stake | 410706084 | 2 hrs ago | IN | 0 ETH | 0.0000096 | ||||
| Stake | 410343369 | 27 hrs ago | IN | 0 ETH | 0.00000119 | ||||
| Stake | 410338412 | 28 hrs ago | IN | 0 ETH | 0.00000119 | ||||
| Claim | 410013774 | 2 days ago | IN | 0 ETH | 0.00000074 | ||||
| Claim | 409931607 | 2 days ago | IN | 0 ETH | 0.0000011 | ||||
| Claim | 409862850 | 2 days ago | IN | 0 ETH | 0.00000085 | ||||
| Stake | 409859549 | 2 days ago | IN | 0 ETH | 0.00000076 | ||||
| Claim | 409858587 | 2 days ago | IN | 0 ETH | 0.00000083 | ||||
| Stake | 409858012 | 2 days ago | IN | 0 ETH | 0.00000081 | ||||
| Claim | 409856812 | 2 days ago | IN | 0 ETH | 0.00000046 | ||||
| Stake | 409650628 | 3 days ago | IN | 0 ETH | 0.00000093 | ||||
| Claim | 409649136 | 3 days ago | IN | 0 ETH | 0.0000007 | ||||
| Claim | 409582800 | 3 days ago | IN | 0 ETH | 0.00000083 | ||||
| Claim | 409580113 | 3 days ago | IN | 0 ETH | 0.00000065 | ||||
| Stake | 409268304 | 4 days ago | IN | 0 ETH | 0.00000382 | ||||
| Unstake | 409267034 | 4 days ago | IN | 0 ETH | 0.00000936 | ||||
| Claim | 409266834 | 4 days ago | IN | 0 ETH | 0.00001327 | ||||
| Stake | 408906092 | 5 days ago | IN | 0 ETH | 0.00000103 | ||||
| Unstake | 408905953 | 5 days ago | IN | 0 ETH | 0.00000101 | ||||
| Claim | 408905779 | 5 days ago | IN | 0 ETH | 0.0000009 | ||||
| Stake | 408739124 | 5 days ago | IN | 0 ETH | 0.00000104 | ||||
| Claim | 408738848 | 5 days ago | IN | 0 ETH | 0.00000088 | ||||
| Stake | 408500777 | 6 days ago | IN | 0 ETH | 0.00001003 | ||||
| Claim | 408500410 | 6 days ago | IN | 0 ETH | 0.00000627 | ||||
| Stake | 408476147 | 6 days ago | IN | 0 ETH | 0.00000119 |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
XPlutusStaking
Compiler Version
v0.8.29+commit.ab55807c
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IXPlutusStaking } from "./interfaces/IPlutusCommon.sol";
import { IXPlutusToken } from "./interfaces/IXPlutusToken.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// @title XPlutus Staking Contract
/// @notice Enables staking of a specific token and distribution of rewards over a fixed duration.
/// @dev This contract manages the staking of tokens and calculation and distribution of rewards based on staked amounts.
contract XPlutusStaking is IXPlutusStaking, AccessControl {
using SafeERC20 for IERC20;
/// @notice Token that users stake in this contract.
IERC20 public immutable stakingToken;
/// @notice Token distributed as rewards to stakers.
IERC20 public immutable rewardsToken;
/// @notice xPlutus Token
IXPlutusToken public immutable xPlutus;
/// @notice xPlutus reward conversion percentage.
uint256 public xPlutusRewardPercentage;
/// @notice Duration over which the rewards are distributed.
uint256 public duration;
/// @notice Time when the reward distribution finishes.
uint256 public finishAt;
/// @notice Last time rewards were updated or reward distribution finished, whichever is earlier.
uint256 public updatedAt;
/// @notice Rate at which rewards are distributed per second.
uint256 public rewardRate;
/// @notice Accumulated reward per token staked, scaled by 1e18.
uint256 public rewardPerTokenStored;
/// @notice Total amount of the staking token staked in the contract.
uint256 public totalSupply;
/// @notice Tracks which addresses are authorized as bridge adapters.
mapping(address => bool) public bridgeAdapters;
/// @notice Stores the rewardPerToken value at which each user's rewards were last calculated.
mapping(bytes32 => uint256) public userRewardPerTokenPaid;
/// @notice Stores the rewards that are yet to be claimed by each user.
mapping(bytes32 => uint256) public rewards;
/// @notice Amount of the staking token staked by each user.
mapping(bytes32 => uint256) public balanceOf;
/// @notice Initializes the staking and rewards tokens, along with the initial authority for access management.
/// @param _stakingToken Address of the staking token.
/// @param _rewardToken Address of the rewards token.
/// @param _initialAuthority Address with initial administrative authority.
constructor(address _stakingToken, address _rewardToken, address _xPlutus, address _initialAuthority) {
stakingToken = IERC20(_stakingToken);
rewardsToken = IERC20(_rewardToken);
xPlutus = IXPlutusToken(_xPlutus);
_grantRole(DEFAULT_ADMIN_ROLE, _initialAuthority);
}
/// @dev Updates reward calculation for a user before executing function logic.
/// @param _accountId Address of the user for whom rewards are updated.
function updateReward(bytes32 _accountId) private {
rewardPerTokenStored = rewardPerToken();
updatedAt = lastTimeRewardApplicable();
if (_accountId != 0) {
rewards[_accountId] = earned(_accountId);
userRewardPerTokenPaid[_accountId] = rewardPerTokenStored;
}
}
/// @notice Updates the authorization status of a bridge adapter.
/// @dev Restricted to contract administrators.
/// @param _bridgeAdapter Address of the bridge adapter.
/// @param _add True to authorize, false to revoke authorization.
function updateBridgeAdapter(address _bridgeAdapter, bool _add) external onlyRole(DEFAULT_ADMIN_ROLE) {
bridgeAdapters[_bridgeAdapter] = _add;
emit BridgeAdapterUpdated(_bridgeAdapter, _add);
}
/// @notice Updates xPlutus reward conversion percentage.
/// @dev Restricted to contract administrators.
/// @param _xPlutusRewardPercentage The percentage of PLUTUS rewards to be sent in xPlutus
function updateXPlutusRewardPercentage(uint256 _xPlutusRewardPercentage) external onlyRole(DEFAULT_ADMIN_ROLE) {
xPlutusRewardPercentage = _xPlutusRewardPercentage;
emit XPlutusRewardPercentageUpdated(_xPlutusRewardPercentage);
}
/// @notice Calculates the last time rewards are applicable.
function lastTimeRewardApplicable() public view returns (uint256) {
return _min(finishAt, block.timestamp);
}
/// @notice Calculates the accumulated amount of reward per token staked.
function rewardPerToken() public view returns (uint256) {
if (totalSupply == 0) {
return rewardPerTokenStored;
}
return rewardPerTokenStored + (rewardRate * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalSupply;
}
function stake(uint256 _amount, uint256 _chainId, address _account) external {
if (_amount == 0) revert XPlutusStaking_AmountZero();
bytes32 accountId;
uint256 chainId = _chainId;
if (!bridgeAdapters[msg.sender]) {
if (_account != msg.sender) revert XPlutusStaking_AccountNotSender();
stakingToken.safeTransferFrom(_account, address(this), _amount);
chainId = block.chainid;
accountId = keccak256(abi.encode(chainId, msg.sender));
} else {
accountId = keccak256(abi.encode(chainId, _account));
}
updateReward(accountId);
balanceOf[accountId] += _amount;
totalSupply += _amount;
emit Staked(_account, _amount, chainId);
}
function unstake(uint256 _amount, uint256 _chainId, address _account) public {
if (_amount == 0) revert XPlutusStaking_AmountZero();
bytes32 accountId;
uint256 chainId = _chainId;
if (!bridgeAdapters[msg.sender]) {
if (_account != msg.sender) revert XPlutusStaking_AccountNotSender();
stakingToken.safeTransfer(_account, _amount);
chainId = block.chainid;
accountId = keccak256(abi.encode(chainId, msg.sender));
} else {
accountId = keccak256(abi.encode(chainId, _account));
}
updateReward(accountId);
balanceOf[accountId] -= _amount;
totalSupply -= _amount;
emit Unstaked(_account, _amount, chainId);
}
function earned(bytes32 _accountId) public view returns (uint256) {
return ((balanceOf[_accountId] * (rewardPerToken() - userRewardPerTokenPaid[_accountId])) / 1e18) + rewards[_accountId];
}
function claim(uint256 _chainId, address _account) public returns (uint256 reward) {
bytes32 accountId;
uint256 chainId = _chainId;
if (!bridgeAdapters[msg.sender]) {
if (_account != msg.sender) revert XPlutusStaking_AccountNotSender();
chainId = block.chainid;
accountId = keccak256(abi.encode(chainId, msg.sender));
} else {
accountId = keccak256(abi.encode(chainId, _account));
}
updateReward(accountId);
reward = rewards[accountId];
if (reward > 0) {
rewards[accountId] = 0;
if (!bridgeAdapters[msg.sender]) {
uint256 xPlutusReward = (reward * xPlutusRewardPercentage) / 100;
if (xPlutusReward > 0) {
rewardsToken.approve(address(xPlutus), xPlutusReward);
xPlutus.convert(xPlutusReward, _account);
}
rewardsToken.safeTransfer(_account, reward - xPlutusReward);
} else {
// The transfer needs to happen to msg.sender since the reward is transferred to the bridge adapter which is bridged back for the account
rewardsToken.safeTransfer(msg.sender, reward);
}
}
emit Claimed(_account, reward, chainId);
}
function exit(uint256 _chainId, address _account) external returns (uint256 balance, uint256 reward) {
bytes32 accountId;
uint256 chainId = _chainId;
if (!bridgeAdapters[msg.sender]) {
chainId = block.chainid;
accountId = keccak256(abi.encode(chainId, msg.sender));
} else {
accountId = keccak256(abi.encode(chainId, _account));
}
balance = balanceOf[accountId];
unstake(balance, chainId, _account);
reward = claim(chainId, _account);
}
/// @notice Sets the duration over which rewards are distributed.
/// @dev Restricted to contract administrators.
/// @param _duration The new rewards duration.
function setRewardsDuration(uint256 _duration) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (finishAt >= block.timestamp) revert XPlutusStaking_RewardsDurationActive();
duration = _duration;
emit RewardsDurationSet(_duration);
}
/// @notice Notifies the contract of the amount of rewards to be distributed over the set duration.
/// @dev Restricted to contract administrators.
/// @param _amount The amount of rewards to distribute.
function notifyRewardAmount(uint256 _amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
updateReward(0);
if (block.timestamp >= finishAt) {
rewardRate = _amount / duration;
} else {
uint256 remainingRewards = (finishAt - block.timestamp) * rewardRate;
rewardRate = (_amount + remainingRewards) / duration;
}
if (rewardRate == 0) revert XPlutusStaking_RewardRateZero();
if (rewardRate * duration > rewardsToken.balanceOf(address(this))) {
revert XPlutusStaking_NotEnoughRewardBalance();
}
finishAt = block.timestamp + duration;
updatedAt = block.timestamp;
emit Notified(_amount, finishAt);
}
/// @notice Performs an emergency withdraw of all tokens from the contract.
/// @param token The address of the token to withdraw.
/// @dev Only the owner can call this function.
function recoverERC20(address token) external onlyRole(DEFAULT_ADMIN_ROLE) {
IERC20(token).safeTransfer(msg.sender, IERC20(token).balanceOf(address(this)));
}
/// @dev Returns the minimum of 2 values. Private function.
/// @param x uint256
/// @param y uint256
function _min(uint256 x, uint256 y) private pure returns (uint256) {
return x <= y ? x : y;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {IERC165, ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IXPlutusStaking {
/// @notice Emitted when a bridge adapter is added or removed.
/// @param bridgeAdapter Address of the bridge adapter.
/// @param add Indicates whether the bridge adapter was added (true) or removed (false).
event BridgeAdapterUpdated(address bridgeAdapter, bool add);
/// @notice Emitted when the xSYK reward conversion percentage is updated.
/// @param xPlutusRewardPercentage The percentage of SYK rewards to be sent in xSYK
event XPlutusRewardPercentageUpdated(uint256 xPlutusRewardPercentage);
/// @dev Emitted when tokens are staked in the contract.
/// @notice This event is fired whenever a user stakes tokens, indicating the amount staked.
/// @param account The address of the account that staked tokens.
/// @param amount The amount of tokens that were staked by the account.
/// @param chainId The Chain ID of source network from where the user is staking.
event Staked(address indexed account, uint256 amount, uint256 chainId);
/// @dev Emitted when staked tokens are withdrawn (unstaked) from the contract.
/// @notice This event is fired whenever a user unstakes tokens, indicating the amount unstaked.
/// @param account The address of the account that unstaked tokens.
/// @param amount The amount of tokens that were unstaked by the account.\
/// @param chainId The Chain ID of source network from where the user is unstaking.
event Unstaked(address indexed account, uint256 amount, uint256 chainId);
/// @dev Emitted when rewards are claimed by a staker.
/// @notice This event is fired whenever a user claims their staking rewards, indicating the amount claimed.
/// @param account The address of the account that claimed rewards.
/// @param amount The amount of rewards that were claimed by the account.
/// @param chainId The Chain ID of source network from where the user is claiming.
event Claimed(address indexed account, uint256 amount, uint256 chainId);
/// @dev Emitted when a new reward amount is notified to the contract.
/// @notice This event signals the notification of a new reward amount and the time when the rewards distribution will finish.
/// @param amount The amount of rewards that will be distributed.
/// @param finishAt The timestamp when the reward distribution is scheduled to finish.
event Notified(uint256 amount, uint256 finishAt);
/// @dev Emitted when the rewards distribution duration is set or updated.
/// @notice This event is fired whenever the duration for rewards distribution is set or changed, indicating the new duration period.
/// @param duration The new duration (in seconds) over which rewards will be distributed.
event RewardsDurationSet(uint256 duration);
/// @dev Error thrown when an operation that requires a non-zero amount is attempted with a zero value.
/// @notice Indicates that the operation cannot proceed because the amount specified is zero.
error XPlutusStaking_AmountZero();
/// @dev Error thrown when an operation requires the caller to be the same as a specified account, but it is not.
/// @notice Indicates that the caller of the function must be the same as the account specified for the operation.
error XPlutusStaking_AccountNotSender();
/// @dev Error thrown when an attempt is made to set or change the rewards duration while a previous rewards duration is still active.
/// @notice Indicates that the rewards duration cannot be modified while the current rewards period has not yet concluded.
error XPlutusStaking_RewardsDurationActive();
/// @dev Error thrown when an operation that requires a non-zero reward rate is attempted with a zero value.
/// @notice Indicates that the reward rate for distributing rewards cannot be zero.
error XPlutusStaking_RewardRateZero();
/// @dev Error thrown when there are not enough rewards in the contract to cover a distribution or operation.
/// @notice Indicates that the operation cannot proceed because the contract does not hold enough rewards to fulfill the request.
error XPlutusStaking_NotEnoughRewardBalance();
/// @notice Returns the saked balance of an account.
/// @param _accountId ID of the account.
function balanceOf(bytes32 _accountId) external returns (uint256);
/// @notice Returns the xSYK Reward Percentage.
function xPlutusRewardPercentage() external returns (uint256);
/// @notice Allows a user or a bridge adapter to stake tokens on behalf of a user.
/// @param _amount Amount of tokens to stake.
/// @param _chainId Chain ID from where the user is staking.
/// @param _account Address of the user on whose behalf tokens are staked.
function stake(uint256 _amount, uint256 _chainId, address _account) external;
/// @notice Unstakes staked tokens for a user.
/// @param _amount Amount of tokens to withdraw.
/// @param _chainId Chain ID from where the user is unstaking.
/// @param _account Address of the user withdrawing tokens.
function unstake(uint256 _amount, uint256 _chainId, address _account) external;
/// @notice Calculates the total rewards earned by a user.
/// @param _accountId ID of the user (keccak256(abi.encode(chainId, userAddress))).
/// @return The total rewards earned.
function earned(bytes32 _accountId) external view returns (uint256);
/// @notice Claims earned rewards for a user.
/// @param _account Address of the user claiming rewards.
/// @param _chainId Chain ID from where the user is claiming.
/// @return reward The amount of rewards claimed.
function claim(uint256 _chainId, address _account) external returns (uint256 reward);
/// @notice Withdraws staked tokens and claims rewards for a user.
/// @param _account Address of the user exiting the staking contract.
/// @return balance The staked token balance returned.
/// @return reward The rewards claimed.
function exit(uint256 _chainId, address _account) external returns (uint256 balance, uint256 reward);
function rewardsToken() external view returns (IERC20);
}
/// @dev Struct to hold information about each gauge.
struct GaugeInfo {
uint256 chainId;
uint256 baseReward;
uint8 gaugeType;
address gaugeAddress;
}
/// @dev Struct for the parameters to pass to vote().
struct VoteParams {
uint256 power;
uint256 totalPower;
uint256 epoch;
bytes32 gaugeId; // keccak256(abi.encode(chainId, gauge address))
bytes32 accountId; // keccak256(abi.encode(chainId, account address))
}
/// @dev Struct for the parameters to pass to pull().
struct PullParams {
uint256 epoch;
bytes32 gaugeId;
address gaugeAddress;
}
interface IGaugeController {
/// @dev Error thrown when trying to pull rewards for a gauge in the current epoch.
error GaugeController_EpochActive();
/// @dev Error thrown when the total reward available is insufficient to cover the base rewards.
error GaugeController_NotEnoughRewardAvailable();
/// @dev Error thrown when an account does not have enough power to vote as requested.
error GaugeController_NotEnoughPowerAvailable();
/// @dev Error thrown when an invalid gauge address is provided.
error GaugeController_InvalidGauge();
/// @dev Error thrown when a gauge is already added.
error GaugeController_GaugeAlreadyAdded();
/// @dev Error thrown when an action is attempted on a gauge that does not exist.
error GaugeController_GaugeNotFound();
/// @dev Error thrown when the msg.sender for pull() is not a gauge or a approved bridge adapter.
error GaugeController_NotGauge();
/// @dev Error thrown when a gauge tries to pull rewards for an epoch which already had its rewards pulled.
error GaugeController_RewardAlreadyPulled();
error GaugeController_IncorrectEpoch();
error GaugeController_EpochNotFinalized();
/// @notice Emitted when a vote is cast.
/// @param voteParams The parameters for the vote.
event Voted(VoteParams voteParams);
/// @notice Emitted when a gauge pulls its reward for the epoch.
/// @param pullParams The parameters for the pull.
/// @param reward Amount of reward.
event RewardPulled(PullParams pullParams, uint256 reward);
/// @notice Emitted when a bridge adapter's status is updated.
/// @param bridgeAdapter The address of the bridge adapter.
/// @param add True if the adapter is added, false if removed.
event BridgeAdapterUpdated(address bridgeAdapter, bool add);
/// @notice Emitted when the total rewards per epoch is changed
/// @param totalRewardsPerEpoch uint256 amount for total reward per epoch
event SetTotalRewardsPerEpoch(uint256 totalRewardsPerEpoch);
/// @notice Emitted when a new gauge is added
/// @param gaugeInfo The GaugeInfo struct
event GaugeAdded(GaugeInfo gaugeInfo);
/// @notice Emitted when a gauge is removed
/// @param gaugeInfo The GaugeInfo struct
event GaugeRemoved(GaugeInfo gaugeInfo);
/// @notice Calculates the current epoch based on the genesis time and epoch length.
/// @return _epoch current epoch number.
function epoch() external view returns (uint256 _epoch);
/// @notice Computes the rewards for a gauge based on votes in a given epoch.
/// @param _id The unique identifier of the gauge.
/// @param _epoch The epoch for which to compute rewards.
/// @return reward The amount of reward computed.
function computeRewards(bytes32 _id, uint256 _epoch) external view returns (uint256 reward);
/// @notice Allows an account to vote on a gauge with its voting power.
/// @param _voteParams Parameters including the gauge ID, power to allocate, and total power.
function vote(VoteParams calldata _voteParams) external;
/// @notice Pulls computed rewards for a gauge for a given epoch.
/// @param _pullParams Parameters including the gauge ID and the epoch.
/// @return reward The amount of reward pulled.
function pull(PullParams calldata _pullParams) external returns (uint256 reward);
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.29;
/* ========== STRUCTS ========== */
/*
* @notice Status of a vesting entry
*/
enum VestStatus {
INACTIVE,
ACTIVE,
REDEEMED,
CANCELLED
}
/*
* @notice Data structure for vesting entries
* @param account The account participating in the vesting (Owner of the vest)
* @param plutusAmount PLUTUS amount to be received upon vesting completion
* @param xPlutusAmount xPLUTUS amount being redeemed for PLUTUS
* @param maturity Timestamp when the vesting period ends
* @param status Current status of the vesting process
*/
struct VestData {
address account;
uint256 plutusAmount;
uint256 xPlutusAmount;
uint256 maturity;
VestStatus status;
}
/*
* @notice Settings for redeeming xPLUTUS for PLUTUS
* @param minRatio Minimum conversion ratio from xPLUTUS to PLUTUS
* @param maxRatio Maximum conversion ratio from xPLUTUS to PLUTUS
* @param minDuration Minimum duration for vesting
* @param maxDuration Maximum duration for vesting
*/
struct RedeemSettings {
uint256 minRatio;
uint256 maxRatio;
uint256 minDuration;
uint256 maxDuration;
}
/*
* @title IXPlutusToken
* @notice Interface for XPlutusToken contract
*/
interface IXPlutusToken {
/* ========== ERRORS ========== */
/*
* @notice Emitted when index out of bounds
*/
error XPlutusToken_IndexOutOfBounds();
/*
* @notice Emitted when Incorrect Ratio Range
*/
error XPlutusToken_InsufficientRatioRange();
/*
* @notice Emitted when incorrect ratio values are provided for redeem settings
*/
error XPlutusToken_WrongRatioValues();
/*
* @notice Emitted when incorrect duration values are provided for redeem settings
*/
error XPlutusToken_WrongDurationValues();
/*
* @notice Emitted when the provided amount for a transaction is zero
*/
error XPlutusToken_AmountZero();
/*
* @notice Emitted when the provided duration for vesting is below the minimum allowed
*/
error XPlutusToken_DurationTooLow();
/*
* @notice Emitted when an invalid address is provided
*/
error XPlutusToken_InvalidAddress();
/*
* @notice Emitted when the provided address for whitelist is the xPLUTUS address itself
*/
error XPlutusToken_InvalidWhitelistAddress();
/*
* @notice Emitted when someone tries to redeem before their vesting is completed
*/
error XPlutusToken_VestingHasNotMatured();
/*
* @notice Emitted when someone tries to redeem a non-active vesting
*/
error XPlutusToken_VestingNotActive();
/*
* @notice Emitted when a transfer of xPLUTUS is happening between non-whitelisted accounts
*/
error XPlutusToken_TransferNotAllowed();
/*
* @notice Emitted when msg.sender is not the account owner of the vest
*/
error XPlutusToken_SenderNotOwner();
/* ========== EVENTS ========== */
/*
* @notice Emitted when the excess receiver is updated
* @param excessReceiver The new excess receiver address
*/
event ExcessReceiverUpdated(address excessReceiver);
/*
* @notice Emitted when redeem settings are updated
* @param redeemSettings The new redeem settings applied
*/
event RedeemSettingsUpdated(RedeemSettings redeemSettings);
/*
* @notice Emitted when an account's whitelist status is updated
* @param account The account whose whitelist status is updated
* @param add Boolean indicating whether the account was added to (true) or removed from (false) the whitelist
*/
event WhitelistUpdated(address account, bool add);
/*
* @notice Emitted when PLUTUS tokens are converted to xPLUTUS tokens
* @param from The address of the account converting PLUTUS to xPLUTUS
* @param to The address of the account receiving the xPLUTUS tokens
* @param amount The amount of PLUTUS tokens being converted
*/
event Converted(address indexed from, address to, uint256 amount);
/*
* @notice Emitted when xPLUTUS tokens are vested for PLUTUS redemption
* @param account The account initiating the vest
* @param xPlutusAmount The amount of xPLUTUS tokens vested
* @param plutusAmount The amount of PLUTUS tokens to be received upon vest completion
* @param duration The duration of the vest in seconds
* @param vestIndex The vest index
*/
event Vested(address indexed account, uint256 xPlutusAmount, uint256 plutusAmount, uint256 duration, uint256 vestIndex);
/*
* @notice Emitted when vested xPLUTUS tokens are redeemed for PLUTUS
* @param account The account redeeming the vested xPLUTUS
* @param xPlutusAmount The amount of xPLUTUS tokens redeemed
* @param plutusAmount The amount of PLUTUS tokens received in exchange
*/
event Redeemed(address indexed account, uint256 xPlutusAmount, uint256 plutusAmount);
/*
* @notice Emitted when a vesting operation is cancelled
* @param account The account cancelling the vest
* @param vestIndex The index of the vesting operation being cancelled
* @param xPlutusAmount The amount of xPLUTUS associated with the cancelled vest
*/
event VestCancelled(address indexed account, uint256 vestIndex, uint256 xPlutusAmount);
/* ========== FUNCTIONS ========== */
/*
* @notice Converts PLUTUS to xPLUTUS 1:1
* @param _amount amount of PLUTUS to convert to xPLUTUS
* @param _to address of the receiving account
*/
function convert(uint256 _amount, address _to) external;
/*
* @notice Vest xPLUTUS to get back PLUTUS
* @param _amount amount of xPLUTUS to vest for getting back PLUTUS
* @param _duration duration of the vesting
*/
function vest(uint256 _amount, uint256 _duration) external;
/*
* @notice Redeem vested xPLUTUS
* @param _vestIndex Index of the vest
*/
function redeem(uint256 _vestIndex) external;
/*
* @notice Cancel a redeem vested xPLUTUS
* @param _vestIndex Index of the vest
*/
function cancelVest(uint256 _vestIndex) external;
/*
* @notice Get all active vesting entries for an account
* @param _account The account to query
* @return Array of vesting indices and their data
*/
function getAccountVests(address _account) external view returns (uint256[] memory, VestData[] memory);
/*
* @notice Computes the redeemable PLUTUS for xPLUTUS vested for duration
* @param _xPlutusAmount amount of xPLUTUS
* @param _duration the duration of the vesting
* @return plutusAmount
*/
function getPlutusByVestingDuration(uint256 _xPlutusAmount, uint256 _duration) external view returns (uint256);
/*
* @notice Get vesting data by index
* @param index The vesting index to query
* @return VestData struct
*/
function vests(uint256 index) external view returns (VestData memory);
/*
* @notice Get the number of vests owned by an address
* @param user The address to query
* @return The number of vests owned by the address
*/
function vestCount(address user) external view returns (uint256);
/*
* @notice Get the vest ID owned by an address at a specific index
* @param owner The address to query
* @param index The index of the vest in the owner's list
* @return The vest ID at the given index
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/*
* @notice Get the total number of vests in the contract
* @return The total number of vests
*/
function totalVests() external view returns (uint256);
/*
* @notice Get the vest ID at a specific index in the global list
* @param index The index to query
* @return The vest ID at the given index
*/
function vestByIndex(uint256 index) external view returns (uint256);
/*
* @notice Get the current redeem settings
* @return RedeemSettings struct containing current configuration
*/
function redeemSettings() external view returns (RedeemSettings memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)
pragma solidity >=0.8.4;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_xPlutus","type":"address"},{"internalType":"address","name":"_initialAuthority","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"XPlutusStaking_AccountNotSender","type":"error"},{"inputs":[],"name":"XPlutusStaking_AmountZero","type":"error"},{"inputs":[],"name":"XPlutusStaking_NotEnoughRewardBalance","type":"error"},{"inputs":[],"name":"XPlutusStaking_RewardRateZero","type":"error"},{"inputs":[],"name":"XPlutusStaking_RewardsDurationActive","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bridgeAdapter","type":"address"},{"indexed":false,"internalType":"bool","name":"add","type":"bool"}],"name":"BridgeAdapterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finishAt","type":"uint256"}],"name":"Notified","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"RewardsDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"xPlutusRewardPercentage","type":"uint256"}],"name":"XPlutusRewardPercentageUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridgeAdapters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"claim","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_accountId","type":"bytes32"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"exit","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setRewardsDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeAdapter","type":"address"},{"internalType":"bool","name":"_add","type":"bool"}],"name":"updateBridgeAdapter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_xPlutusRewardPercentage","type":"uint256"}],"name":"updateXPlutusRewardPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xPlutus","outputs":[{"internalType":"contract IXPlutusToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xPlutusRewardPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60e060405234801561000f575f5ffd5b5060405161170a38038061170a83398101604081905261002e9161011f565b6001600160a01b0380851660805283811660a052821660c0526100515f8261005b565b5050505050610170565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166100fb575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556100b33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016100fe565b505f5b92915050565b80516001600160a01b038116811461011a575f5ffd5b919050565b5f5f5f5f60808587031215610132575f5ffd5b61013b85610104565b935061014960208601610104565b925061015760408601610104565b915061016560608601610104565b905092959194509250565b60805160a05160c0516115386101d25f395f818161022301528181610e6d0152610f2d01525f818161046d0152818161060c01528181610e9c01528181610f9d0152610fd701525f81816103260152818161076f01526109ae01526115385ff3fe608060405234801561000f575f5ffd5b50600436106101f2575f3560e01c80638169709d11610114578063bdfe35b5116100a9578063d1af0c7d11610079578063d1af0c7d14610468578063d547741f1461048f578063ddd5e1b2146104a2578063df136d65146104b5578063e270b52c146104be575f5ffd5b8063bdfe35b514610412578063cc1a378f14610425578063cd3daf9d14610438578063cff4075914610440575f5ffd5b80639880c5a3116100e45780639880c5a3146103cd5780639e8c708e146103ef578063a217fddf14610402578063b6a827b214610409575f5ffd5b80638169709d1461037557806391d1485414610388578063938d967a1461039b57806393d4f2c9146103ba575f5ffd5b80635df012f61161018a5780637519ab501161015a5780637519ab50146103485780637628a37d146103515780637b0a47ee1461036457806380faa57d1461036d575f5ffd5b80635df012f6146102da57806367d3b488146102f95780636c7f15421461030257806372f702f314610321575f5ffd5b8063248a9ca3116101c5578063248a9ca31461027d5780632f2ff15d1461029f57806336568abe146102b45780633c6b16ab146102c7575f5ffd5b806301ffc9a7146101f657806306377ae11461021e5780630fb5a6b41461025d57806318160ddd14610274575b5f5ffd5b610209610204366004611350565b6104d1565b60405190151581526020015b60405180910390f35b6102457f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610215565b61026660025481565b604051908152602001610215565b61026660075481565b61026661028b366004611377565b5f9081526020819052604090206001015490565b6102b26102ad3660046113a9565b610507565b005b6102b26102c23660046113a9565b610531565b6102b26102d5366004611377565b610569565b6102666102e8366004611377565b60096020525f908152604090205481565b61026660035481565b610266610310366004611377565b600b6020525f908152604090205481565b6102457f000000000000000000000000000000000000000000000000000000000000000081565b61026660045481565b6102b261035f3660046113d3565b610701565b61026660055481565b610266610899565b6102b2610383366004611412565b6108ab565b6102096103963660046113a9565b610918565b6102666103a9366004611377565b600a6020525f908152604090205481565b6102b26103c83660046113d3565b610940565b6102096103db366004611447565b60086020525f908152604090205460ff1681565b6102b26103fd366004611447565b610acc565b6102665f81565b61026660015481565b6102b2610420366004611377565b610b57565b6102b2610433366004611377565b610b96565b610266610bf7565b61045361044e3660046113a9565b610c56565b60408051928352602083019190915201610215565b6102457f000000000000000000000000000000000000000000000000000000000000000081565b6102b261049d3660046113a9565b610d15565b6102666104b03660046113a9565b610d39565b61026660065481565b6102666104cc366004611377565b61104a565b5f6001600160e01b03198216637965db0b60e01b148061050157506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f82815260208190526040902060010154610521816110ab565b61052b83836110b8565b50505050565b6001600160a01b038116331461055a5760405163334bd91960e11b815260040160405180910390fd5b6105648282611147565b505050565b5f610573816110ab565b61057c5f6111b0565b600354421061059a576002546105929083611474565b6005556105d5565b5f600554426003546105ac9190611493565b6105b691906114a6565b6002549091506105c682856114bd565b6105d09190611474565b600555505b6005545f036105f757604051631b8dcd5560e21b815260040160405180910390fd5b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610659573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061067d91906114d0565b60025460055461068d91906114a6565b11156106ac5760405163161d88c760e21b815260040160405180910390fd5b6002546106b990426114bd565b6003819055426004556040805184815260208101929092527f0fd7bb2818b0aaa42a4064edb68964c3e29810804cf8cce3060a3bac23fb9d7991015b60405180910390a15050565b825f0361072157604051631043897760e01b815260040160405180910390fd5b335f90815260086020526040812054839060ff166107cc576001600160a01b038316331461076257604051630c06be4360e01b815260040160405180910390fd5b6107976001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168430886111f6565b50604080514660208201819052339282019290925260600160405160208183030381529060405280519060200120915061080a565b80836040516020016107f19291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b610813826111b0565b5f828152600b6020526040812080548792906108309084906114bd565b925050819055508460075f82825461084891906114bd565b909155505060408051868152602081018390526001600160a01b038516917f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee9091015b60405180910390a25050505050565b5f6108a66003544261125d565b905090565b5f6108b5816110ab565b6001600160a01b0383165f81815260086020908152604091829020805460ff19168615159081179091558251938452908301527f71012a5f9a4037fc79d666d18e9a92bac2889659098f5c98132fc11302bcf363910160405180910390a1505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b825f0361096057604051631043897760e01b815260040160405180910390fd5b335f90815260086020526040812054839060ff16610a0a576001600160a01b03831633146109a157604051630c06be4360e01b815260040160405180910390fd5b6109d56001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168487611275565b506040805146602082018190523392820192909252606001604051602081830303815290604052805190602001209150610a48565b8083604051602001610a2f9291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b610a51826111b0565b5f828152600b602052604081208054879290610a6e908490611493565b925050819055508460075f828254610a869190611493565b909155505060408051868152602081018390526001600160a01b038516917f7fc4727e062e336010f2c282598ef5f14facb3de68cf8195c2f23e1454b2b74e910161088a565b5f610ad6816110ab565b6040516370a0823160e01b8152306004820152610b539033906001600160a01b038516906370a0823190602401602060405180830381865afa158015610b1e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b4291906114d0565b6001600160a01b0385169190611275565b5050565b5f610b61816110ab565b60018290556040518281527fa2a4eef109d5c72572e2f255e4ae514871cd090da1e7e3b38e33b3b77eb5c21d906020016106f5565b5f610ba0816110ab565b4260035410610bc25760405163fdee9adf60e01b815260040160405180910390fd5b60028290556040518281527f47744a1ac202df7b343bfda5f2866a65a670c3817fd5b93f61d76ba1fdde953c906020016106f5565b5f6007545f03610c08575060065490565b600754600454610c16610899565b610c209190611493565b600554610c2d91906114a6565b610c3f90670de0b6b3a76400006114a6565b610c499190611474565b6006546108a691906114bd565b335f9081526008602052604081205481908190859060ff16610ca757506040805146602082018190523392820192909252606001604051602081830303815290604052805190602001209150610ce5565b8085604051602001610ccc9291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b5f828152600b60205260409020549350610d00848287610940565b610d0a8186610d39565b925050509250929050565b5f82815260208190526040902060010154610d2f816110ab565b61052b8383611147565b335f908152600860205260408120548190849060ff16610db1576001600160a01b0384163314610d7c57604051630c06be4360e01b815260040160405180910390fd5b506040805146602082018190523392820192909252606001604051602081830303815290604052805190602001209150610def565b8084604051602001610dd69291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b610df8826111b0565b5f828152600a602052604090205492508215610ffe575f828152600a60209081526040808320839055338352600890915290205460ff16610fca575f606460015485610e4491906114a6565b610e4e9190611474565b90508015610f855760405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303815f875af1158015610ee2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0691906114e7565b50604051631d17712960e11b8152600481018290526001600160a01b0386811660248301527f00000000000000000000000000000000000000000000000000000000000000001690633a2ee252906044015f604051808303815f87803b158015610f6e575f5ffd5b505af1158015610f80573d5f5f3e3d5ffd5b505050505b610fc485610f938387611493565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190611275565b50610ffe565b610ffe6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385611275565b60408051848152602081018390526001600160a01b038616917f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a910160405180910390a2505092915050565b5f818152600a60209081526040808320546009909252822054670de0b6b3a764000090611075610bf7565b61107f9190611493565b5f858152600b602052604090205461109791906114a6565b6110a19190611474565b61050191906114bd565b6110b581336112a6565b50565b5f6110c38383610918565b611140575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556110f83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610501565b505f610501565b5f6111528383610918565b15611140575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610501565b6111b8610bf7565b6006556111c3610899565b60045580156110b5576111d58161104a565b5f918252600a60209081526040808420929092556006546009909152912055565b6040516001600160a01b03848116602483015283811660448301526064820183905261052b9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506112e4565b5f8183111561126c578161126e565b825b9392505050565b6040516001600160a01b0383811660248301526044820183905261056491859182169063a9059cbb9060640161122b565b6112b08282610918565b610b535760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b5f5f60205f8451602086015f885af180611303576040513d5f823e3d81fd5b50505f513d9150811561131a578060011415611327565b6001600160a01b0384163b155b1561052b57604051635274afe760e01b81526001600160a01b03851660048201526024016112db565b5f60208284031215611360575f5ffd5b81356001600160e01b03198116811461126e575f5ffd5b5f60208284031215611387575f5ffd5b5035919050565b80356001600160a01b03811681146113a4575f5ffd5b919050565b5f5f604083850312156113ba575f5ffd5b823591506113ca6020840161138e565b90509250929050565b5f5f5f606084860312156113e5575f5ffd5b83359250602084013591506113fc6040850161138e565b90509250925092565b80151581146110b5575f5ffd5b5f5f60408385031215611423575f5ffd5b61142c8361138e565b9150602083013561143c81611405565b809150509250929050565b5f60208284031215611457575f5ffd5b61126e8261138e565b634e487b7160e01b5f52601160045260245ffd5b5f8261148e57634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561050157610501611460565b808202811582820484141761050157610501611460565b8082018082111561050157610501611460565b5f602082840312156114e0575f5ffd5b5051919050565b5f602082840312156114f7575f5ffd5b815161126e8161140556fea26469706673582212200bb069f8f4284e7857d3fff2d5a0a6b8c06a3d2785823558432c41a89b826f4364736f6c634300081d00330000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca70000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a20000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca7000000000000000000000000e46dc65869a31fd76affdf047d07a3ebc4ce1e13
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106101f2575f3560e01c80638169709d11610114578063bdfe35b5116100a9578063d1af0c7d11610079578063d1af0c7d14610468578063d547741f1461048f578063ddd5e1b2146104a2578063df136d65146104b5578063e270b52c146104be575f5ffd5b8063bdfe35b514610412578063cc1a378f14610425578063cd3daf9d14610438578063cff4075914610440575f5ffd5b80639880c5a3116100e45780639880c5a3146103cd5780639e8c708e146103ef578063a217fddf14610402578063b6a827b214610409575f5ffd5b80638169709d1461037557806391d1485414610388578063938d967a1461039b57806393d4f2c9146103ba575f5ffd5b80635df012f61161018a5780637519ab501161015a5780637519ab50146103485780637628a37d146103515780637b0a47ee1461036457806380faa57d1461036d575f5ffd5b80635df012f6146102da57806367d3b488146102f95780636c7f15421461030257806372f702f314610321575f5ffd5b8063248a9ca3116101c5578063248a9ca31461027d5780632f2ff15d1461029f57806336568abe146102b45780633c6b16ab146102c7575f5ffd5b806301ffc9a7146101f657806306377ae11461021e5780630fb5a6b41461025d57806318160ddd14610274575b5f5ffd5b610209610204366004611350565b6104d1565b60405190151581526020015b60405180910390f35b6102457f0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca781565b6040516001600160a01b039091168152602001610215565b61026660025481565b604051908152602001610215565b61026660075481565b61026661028b366004611377565b5f9081526020819052604090206001015490565b6102b26102ad3660046113a9565b610507565b005b6102b26102c23660046113a9565b610531565b6102b26102d5366004611377565b610569565b6102666102e8366004611377565b60096020525f908152604090205481565b61026660035481565b610266610310366004611377565b600b6020525f908152604090205481565b6102457f0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca781565b61026660045481565b6102b261035f3660046113d3565b610701565b61026660055481565b610266610899565b6102b2610383366004611412565b6108ab565b6102096103963660046113a9565b610918565b6102666103a9366004611377565b600a6020525f908152604090205481565b6102b26103c83660046113d3565b610940565b6102096103db366004611447565b60086020525f908152604090205460ff1681565b6102b26103fd366004611447565b610acc565b6102665f81565b61026660015481565b6102b2610420366004611377565b610b57565b6102b2610433366004611377565b610b96565b610266610bf7565b61045361044e3660046113a9565b610c56565b60408051928352602083019190915201610215565b6102457f0000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a281565b6102b261049d3660046113a9565b610d15565b6102666104b03660046113a9565b610d39565b61026660065481565b6102666104cc366004611377565b61104a565b5f6001600160e01b03198216637965db0b60e01b148061050157506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f82815260208190526040902060010154610521816110ab565b61052b83836110b8565b50505050565b6001600160a01b038116331461055a5760405163334bd91960e11b815260040160405180910390fd5b6105648282611147565b505050565b5f610573816110ab565b61057c5f6111b0565b600354421061059a576002546105929083611474565b6005556105d5565b5f600554426003546105ac9190611493565b6105b691906114a6565b6002549091506105c682856114bd565b6105d09190611474565b600555505b6005545f036105f757604051631b8dcd5560e21b815260040160405180910390fd5b6040516370a0823160e01b81523060048201527f0000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a26001600160a01b0316906370a0823190602401602060405180830381865afa158015610659573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061067d91906114d0565b60025460055461068d91906114a6565b11156106ac5760405163161d88c760e21b815260040160405180910390fd5b6002546106b990426114bd565b6003819055426004556040805184815260208101929092527f0fd7bb2818b0aaa42a4064edb68964c3e29810804cf8cce3060a3bac23fb9d7991015b60405180910390a15050565b825f0361072157604051631043897760e01b815260040160405180910390fd5b335f90815260086020526040812054839060ff166107cc576001600160a01b038316331461076257604051630c06be4360e01b815260040160405180910390fd5b6107976001600160a01b037f0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca7168430886111f6565b50604080514660208201819052339282019290925260600160405160208183030381529060405280519060200120915061080a565b80836040516020016107f19291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b610813826111b0565b5f828152600b6020526040812080548792906108309084906114bd565b925050819055508460075f82825461084891906114bd565b909155505060408051868152602081018390526001600160a01b038516917f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee9091015b60405180910390a25050505050565b5f6108a66003544261125d565b905090565b5f6108b5816110ab565b6001600160a01b0383165f81815260086020908152604091829020805460ff19168615159081179091558251938452908301527f71012a5f9a4037fc79d666d18e9a92bac2889659098f5c98132fc11302bcf363910160405180910390a1505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b825f0361096057604051631043897760e01b815260040160405180910390fd5b335f90815260086020526040812054839060ff16610a0a576001600160a01b03831633146109a157604051630c06be4360e01b815260040160405180910390fd5b6109d56001600160a01b037f0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca7168487611275565b506040805146602082018190523392820192909252606001604051602081830303815290604052805190602001209150610a48565b8083604051602001610a2f9291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b610a51826111b0565b5f828152600b602052604081208054879290610a6e908490611493565b925050819055508460075f828254610a869190611493565b909155505060408051868152602081018390526001600160a01b038516917f7fc4727e062e336010f2c282598ef5f14facb3de68cf8195c2f23e1454b2b74e910161088a565b5f610ad6816110ab565b6040516370a0823160e01b8152306004820152610b539033906001600160a01b038516906370a0823190602401602060405180830381865afa158015610b1e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b4291906114d0565b6001600160a01b0385169190611275565b5050565b5f610b61816110ab565b60018290556040518281527fa2a4eef109d5c72572e2f255e4ae514871cd090da1e7e3b38e33b3b77eb5c21d906020016106f5565b5f610ba0816110ab565b4260035410610bc25760405163fdee9adf60e01b815260040160405180910390fd5b60028290556040518281527f47744a1ac202df7b343bfda5f2866a65a670c3817fd5b93f61d76ba1fdde953c906020016106f5565b5f6007545f03610c08575060065490565b600754600454610c16610899565b610c209190611493565b600554610c2d91906114a6565b610c3f90670de0b6b3a76400006114a6565b610c499190611474565b6006546108a691906114bd565b335f9081526008602052604081205481908190859060ff16610ca757506040805146602082018190523392820192909252606001604051602081830303815290604052805190602001209150610ce5565b8085604051602001610ccc9291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b5f828152600b60205260409020549350610d00848287610940565b610d0a8186610d39565b925050509250929050565b5f82815260208190526040902060010154610d2f816110ab565b61052b8383611147565b335f908152600860205260408120548190849060ff16610db1576001600160a01b0384163314610d7c57604051630c06be4360e01b815260040160405180910390fd5b506040805146602082018190523392820192909252606001604051602081830303815290604052805190602001209150610def565b8084604051602001610dd69291909182526001600160a01b0316602082015260400190565b6040516020818303038152906040528051906020012091505b610df8826111b0565b5f828152600a602052604090205492508215610ffe575f828152600a60209081526040808320839055338352600890915290205460ff16610fca575f606460015485610e4491906114a6565b610e4e9190611474565b90508015610f855760405163095ea7b360e01b81526001600160a01b037f0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca781166004830152602482018390527f0000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a2169063095ea7b3906044016020604051808303815f875af1158015610ee2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0691906114e7565b50604051631d17712960e11b8152600481018290526001600160a01b0386811660248301527f0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca71690633a2ee252906044015f604051808303815f87803b158015610f6e575f5ffd5b505af1158015610f80573d5f5f3e3d5ffd5b505050505b610fc485610f938387611493565b6001600160a01b037f0000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a2169190611275565b50610ffe565b610ffe6001600160a01b037f0000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a2163385611275565b60408051848152602081018390526001600160a01b038616917f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a910160405180910390a2505092915050565b5f818152600a60209081526040808320546009909252822054670de0b6b3a764000090611075610bf7565b61107f9190611493565b5f858152600b602052604090205461109791906114a6565b6110a19190611474565b61050191906114bd565b6110b581336112a6565b50565b5f6110c38383610918565b611140575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556110f83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610501565b505f610501565b5f6111528383610918565b15611140575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610501565b6111b8610bf7565b6006556111c3610899565b60045580156110b5576111d58161104a565b5f918252600a60209081526040808420929092556006546009909152912055565b6040516001600160a01b03848116602483015283811660448301526064820183905261052b9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506112e4565b5f8183111561126c578161126e565b825b9392505050565b6040516001600160a01b0383811660248301526044820183905261056491859182169063a9059cbb9060640161122b565b6112b08282610918565b610b535760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b5f5f60205f8451602086015f885af180611303576040513d5f823e3d81fd5b50505f513d9150811561131a578060011415611327565b6001600160a01b0384163b155b1561052b57604051635274afe760e01b81526001600160a01b03851660048201526024016112db565b5f60208284031215611360575f5ffd5b81356001600160e01b03198116811461126e575f5ffd5b5f60208284031215611387575f5ffd5b5035919050565b80356001600160a01b03811681146113a4575f5ffd5b919050565b5f5f604083850312156113ba575f5ffd5b823591506113ca6020840161138e565b90509250929050565b5f5f5f606084860312156113e5575f5ffd5b83359250602084013591506113fc6040850161138e565b90509250925092565b80151581146110b5575f5ffd5b5f5f60408385031215611423575f5ffd5b61142c8361138e565b9150602083013561143c81611405565b809150509250929050565b5f60208284031215611457575f5ffd5b61126e8261138e565b634e487b7160e01b5f52601160045260245ffd5b5f8261148e57634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561050157610501611460565b808202811582820484141761050157610501611460565b8082018082111561050157610501611460565b5f602082840312156114e0575f5ffd5b5051919050565b5f602082840312156114f7575f5ffd5b815161126e8161140556fea26469706673582212200bb069f8f4284e7857d3fff2d5a0a6b8c06a3d2785823558432c41a89b826f4364736f6c634300081d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca70000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a20000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca7000000000000000000000000e46dc65869a31fd76affdf047d07a3ebc4ce1e13
-----Decoded View---------------
Arg [0] : _stakingToken (address): 0x7f89c81561C1A56d983cc5682348310cC330bca7
Arg [1] : _rewardToken (address): 0x8C1eA32448E09a59f36595abEC6207C9Ebd590A2
Arg [2] : _xPlutus (address): 0x7f89c81561C1A56d983cc5682348310cC330bca7
Arg [3] : _initialAuthority (address): 0xE46DC65869A31Fd76affdf047D07a3eBC4cE1e13
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca7
Arg [1] : 0000000000000000000000008c1ea32448e09a59f36595abec6207c9ebd590a2
Arg [2] : 0000000000000000000000007f89c81561c1a56d983cc5682348310cc330bca7
Arg [3] : 000000000000000000000000e46dc65869a31fd76affdf047d07a3ebc4ce1e13
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.