编译器
0.8.13+commit.abaa5c0e
文件 1 的 10:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 10:BaseIncentivesController.sol
pragma solidity 0.8.13;
import {DistributionTypes} from "../../lib/DistributionTypes.sol";
import {DistributionManager} from "./DistributionManager.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IAaveIncentivesController} from "../../interfaces/IAaveIncentivesController.sol";
abstract contract BaseIncentivesController is IAaveIncentivesController, DistributionManager {
uint256 public constant REVISION = 1;
address public immutable override REWARD_TOKEN;
mapping(address => uint256) internal _usersUnclaimedRewards;
mapping(address => address) internal _authorizedClaimers;
modifier onlyAuthorizedClaimers(address claimer, address user) {
if (_authorizedClaimers[user] != claimer) revert ClaimerUnauthorized();
_;
}
error InvalidConfiguration();
error IndexOverflowAtEmissionsPerSecond();
error InvalidToAddress();
error InvalidUserAddress();
error ClaimerUnauthorized();
constructor(IERC20 rewardToken, address emissionManager) DistributionManager(emissionManager) {
REWARD_TOKEN = address(rewardToken);
}
function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond)
external
override
onlyEmissionManager
{
if (assets.length != emissionsPerSecond.length) revert InvalidConfiguration();
DistributionTypes.AssetConfigInput[] memory assetsConfig =
new DistributionTypes.AssetConfigInput[](assets.length);
for (uint256 i = 0; i < assets.length;) {
if (uint104(emissionsPerSecond[i]) != emissionsPerSecond[i]) revert IndexOverflowAtEmissionsPerSecond();
assetsConfig[i].underlyingAsset = assets[i];
assetsConfig[i].emissionPerSecond = uint104(emissionsPerSecond[i]);
assetsConfig[i].totalStaked = IERC20(assets[i]).totalSupply();
unchecked { i++; }
}
_configureAssets(assetsConfig);
}
function handleAction(
address user,
uint256 totalSupply,
uint256 userBalance
) public override {
uint256 accruedRewards = _updateUserAssetInternal(user, msg.sender, userBalance, totalSupply);
if (accruedRewards != 0) {
_usersUnclaimedRewards[user] = _usersUnclaimedRewards[user] + accruedRewards;
emit RewardsAccrued(user, accruedRewards);
}
}
function getRewardsBalance(address[] calldata assets, address user)
external
view
override
returns (uint256)
{
uint256 unclaimedRewards = _usersUnclaimedRewards[user];
DistributionTypes.UserStakeInput[] memory userState = new DistributionTypes.UserStakeInput[](assets.length);
for (uint256 i = 0; i < assets.length;) {
userState[i].underlyingAsset = assets[i];
(userState[i].stakedByUser, userState[i].totalStaked) = _getScaledUserBalanceAndSupply(assets[i], user);
unchecked { i++; }
}
unclaimedRewards = unclaimedRewards + _getUnclaimedRewards(user, userState);
return unclaimedRewards;
}
function claimRewards(
address[] calldata assets,
uint256 amount,
address to
) external override returns (uint256) {
if (to == address(0)) revert InvalidToAddress();
return _claimRewards(assets, amount, msg.sender, msg.sender, to);
}
function claimRewardsOnBehalf(
address[] calldata assets,
uint256 amount,
address user,
address to
) external override onlyAuthorizedClaimers(msg.sender, user) returns (uint256) {
if (user == address(0)) revert InvalidUserAddress();
if (to == address(0)) revert InvalidToAddress();
return _claimRewards(assets, amount, msg.sender, user, to);
}
function claimRewardsToSelf(address[] calldata assets, uint256 amount)
external
override
returns (uint256)
{
return _claimRewards(assets, amount, msg.sender, msg.sender, msg.sender);
}
function setClaimer(address user, address caller) external override onlyEmissionManager {
_authorizedClaimers[user] = caller;
emit ClaimerSet(user, caller);
}
function getClaimer(address user) external view override returns (address) {
return _authorizedClaimers[user];
}
function getUserUnclaimedRewards(address _user) external view override returns (uint256) {
return _usersUnclaimedRewards[_user];
}
function _claimRewards(
address[] calldata assets,
uint256 amount,
address claimer,
address user,
address to
) internal returns (uint256) {
if (amount == 0) {
return 0;
}
uint256 unclaimedRewards = _usersUnclaimedRewards[user];
if (amount > unclaimedRewards) {
DistributionTypes.UserStakeInput[] memory userState = new DistributionTypes.UserStakeInput[](assets.length);
for (uint256 i = 0; i < assets.length;) {
userState[i].underlyingAsset = assets[i];
(userState[i].stakedByUser, userState[i].totalStaked) = _getScaledUserBalanceAndSupply(assets[i], user);
unchecked { i++; }
}
uint256 accruedRewards = _claimRewards(user, userState);
if (accruedRewards != 0) {
unclaimedRewards = unclaimedRewards + accruedRewards;
emit RewardsAccrued(user, accruedRewards);
}
}
if (unclaimedRewards == 0) {
return 0;
}
uint256 amountToClaim = amount > unclaimedRewards ? unclaimedRewards : amount;
unchecked { _usersUnclaimedRewards[user] = unclaimedRewards - amountToClaim; }
_transferRewards(to, amountToClaim);
emit RewardsClaimed(user, to, claimer, amountToClaim);
return amountToClaim;
}
function _transferRewards(address to, uint256 amount) internal virtual;
function _getScaledUserBalanceAndSupply(address _asset, address _user)
internal
view
virtual
returns (uint256 userBalance, uint256 totalSupply);
}
文件 3 的 10:DistributionManager.sol
pragma solidity 0.8.13;
import {IAaveDistributionManager} from "../../interfaces/IAaveDistributionManager.sol";
import {DistributionTypes} from "../../lib/DistributionTypes.sol";
contract DistributionManager is IAaveDistributionManager {
struct AssetData {
uint104 emissionPerSecond;
uint104 index;
uint40 lastUpdateTimestamp;
mapping(address => uint256) users;
}
address public immutable EMISSION_MANAGER;
uint8 public constant PRECISION = 18;
uint256 public constant TEN_POW_PRECISION = 10 ** PRECISION;
mapping(address => AssetData) public assets;
uint256 internal _distributionEnd;
error OnlyEmissionManager();
error IndexOverflow();
modifier onlyEmissionManager() {
if (msg.sender != EMISSION_MANAGER) revert OnlyEmissionManager();
_;
}
constructor(address emissionManager) {
EMISSION_MANAGER = emissionManager;
}
function setDistributionEnd(uint256 distributionEnd) external override onlyEmissionManager {
_distributionEnd = distributionEnd;
emit DistributionEndUpdated(distributionEnd);
}
function getDistributionEnd() external view override returns (uint256) {
return _distributionEnd;
}
function DISTRIBUTION_END() external view override returns (uint256) {
return _distributionEnd;
}
function getUserAssetData(address user, address asset) public view override returns (uint256) {
return assets[asset].users[user];
}
function getAssetData(address asset) public view override returns (uint256, uint256, uint256) {
return (assets[asset].index, assets[asset].emissionPerSecond, assets[asset].lastUpdateTimestamp);
}
function _configureAssets(DistributionTypes.AssetConfigInput[] memory assetsConfigInput) internal {
for (uint256 i = 0; i < assetsConfigInput.length;) {
AssetData storage assetConfig = assets[assetsConfigInput[i].underlyingAsset];
_updateAssetStateInternal(
assetsConfigInput[i].underlyingAsset,
assetConfig,
assetsConfigInput[i].totalStaked
);
assetConfig.emissionPerSecond = assetsConfigInput[i].emissionPerSecond;
emit AssetConfigUpdated(
assetsConfigInput[i].underlyingAsset,
assetsConfigInput[i].emissionPerSecond
);
unchecked { i++; }
}
}
function _updateAssetStateInternal(
address asset,
AssetData storage assetConfig,
uint256 totalStaked
) internal returns (uint256) {
uint256 oldIndex = assetConfig.index;
uint256 emissionPerSecond = assetConfig.emissionPerSecond;
uint128 lastUpdateTimestamp = assetConfig.lastUpdateTimestamp;
if (block.timestamp == lastUpdateTimestamp) {
return oldIndex;
}
uint256 newIndex = _getAssetIndex(oldIndex, emissionPerSecond, lastUpdateTimestamp, totalStaked);
if (newIndex != oldIndex) {
if (uint104(newIndex) != newIndex) revert IndexOverflow();
assetConfig.index = uint104(newIndex);
assetConfig.lastUpdateTimestamp = uint40(block.timestamp);
emit AssetIndexUpdated(asset, newIndex);
} else {
assetConfig.lastUpdateTimestamp = uint40(block.timestamp);
}
return newIndex;
}
function _updateUserAssetInternal(
address user,
address asset,
uint256 stakedByUser,
uint256 totalStaked
) internal returns (uint256) {
AssetData storage assetData = assets[asset];
uint256 userIndex = assetData.users[user];
uint256 accruedRewards = 0;
uint256 newIndex = _updateAssetStateInternal(asset, assetData, totalStaked);
if (userIndex != newIndex) {
if (stakedByUser != 0) {
accruedRewards = _getRewards(stakedByUser, newIndex, userIndex);
}
assetData.users[user] = newIndex;
emit UserIndexUpdated(user, asset, newIndex);
}
return accruedRewards;
}
function _claimRewards(address user, DistributionTypes.UserStakeInput[] memory stakes)
internal
returns (uint256)
{
uint256 accruedRewards = 0;
for (uint256 i = 0; i < stakes.length;) {
accruedRewards = accruedRewards + _updateUserAssetInternal(
user,
stakes[i].underlyingAsset,
stakes[i].stakedByUser,
stakes[i].totalStaked
);
unchecked { i++; }
}
return accruedRewards;
}
function _getUnclaimedRewards(address user, DistributionTypes.UserStakeInput[] memory stakes)
internal
view
returns (uint256)
{
uint256 accruedRewards = 0;
for (uint256 i = 0; i < stakes.length;) {
AssetData storage assetConfig = assets[stakes[i].underlyingAsset];
uint256 assetIndex = _getAssetIndex(
assetConfig.index,
assetConfig.emissionPerSecond,
assetConfig.lastUpdateTimestamp,
stakes[i].totalStaked
);
accruedRewards = accruedRewards + _getRewards(stakes[i].stakedByUser, assetIndex, assetConfig.users[user]);
unchecked { i++; }
}
return accruedRewards;
}
function _getRewards(
uint256 principalUserBalance,
uint256 reserveIndex,
uint256 userIndex
) internal pure returns (uint256 rewards) {
rewards = principalUserBalance * (reserveIndex - userIndex);
unchecked { rewards /= TEN_POW_PRECISION; }
}
function _getAssetIndex(
uint256 currentIndex,
uint256 emissionPerSecond,
uint128 lastUpdateTimestamp,
uint256 totalBalance
) internal view returns (uint256 newIndex) {
uint256 distributionEnd = _distributionEnd;
if (
emissionPerSecond == 0 ||
totalBalance == 0 ||
lastUpdateTimestamp == block.timestamp ||
lastUpdateTimestamp >= distributionEnd
) {
return currentIndex;
}
uint256 currentTimestamp = block.timestamp > distributionEnd ? distributionEnd : block.timestamp;
uint256 timeDelta = currentTimestamp - lastUpdateTimestamp;
newIndex = emissionPerSecond * timeDelta * TEN_POW_PRECISION;
unchecked { newIndex /= totalBalance; }
newIndex += currentIndex;
}
}
文件 4 的 10:DistributionTypes.sol
pragma solidity 0.8.13;
library DistributionTypes {
struct AssetConfigInput {
uint104 emissionPerSecond;
uint256 totalStaked;
address underlyingAsset;
}
struct UserStakeInput {
address underlyingAsset;
uint256 stakedByUser;
uint256 totalStaked;
}
}
文件 5 的 10:IAaveDistributionManager.sol
pragma solidity 0.8.13;
import {DistributionTypes} from "../lib/DistributionTypes.sol";
interface IAaveDistributionManager {
event AssetConfigUpdated(address indexed asset, uint256 emission);
event AssetIndexUpdated(address indexed asset, uint256 index);
event UserIndexUpdated(address indexed user, address indexed asset, uint256 index);
event DistributionEndUpdated(uint256 newDistributionEnd);
function setDistributionEnd(uint256 distributionEnd) external;
function getDistributionEnd() external view returns (uint256);
function DISTRIBUTION_END() external view returns(uint256);
function getUserAssetData(address user, address asset) external view returns (uint256);
function getAssetData(address asset) external view returns (uint256, uint256, uint256);
}
文件 6 的 10:IAaveIncentivesController.sol
pragma solidity 0.8.13;
import {IAaveDistributionManager} from "../interfaces/IAaveDistributionManager.sol";
interface IAaveIncentivesController is IAaveDistributionManager {
event RewardsAccrued(address indexed user, uint256 amount);
event RewardsClaimed(
address indexed user,
address indexed to,
address indexed claimer,
uint256 amount
);
event ClaimerSet(address indexed user, address indexed claimer);
function setClaimer(address user, address claimer) external;
function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond) external;
function handleAction(
address asset,
uint256 userBalance,
uint256 totalSupply
) external;
function claimRewards(
address[] calldata assets,
uint256 amount,
address to
) external returns (uint256);
function claimRewardsOnBehalf(
address[] calldata assets,
uint256 amount,
address user,
address to
) external returns (uint256);
function claimRewardsToSelf(address[] calldata assets, uint256 amount) external returns (uint256);
function getClaimer(address user) external view returns (address);
function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256);
function getUserUnclaimedRewards(address user) external view returns (uint256);
function REWARD_TOKEN() external view returns (address);
}
文件 7 的 10:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 8 的 10:INotificationReceiver.sol
pragma solidity 0.8.13;
interface INotificationReceiver {
function onAfterTransfer(address _token, address _from, address _to, uint256 _amount) external;
function notificationReceiverPing() external pure returns (bytes4);
}
文件 9 的 10:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 10 的 10:SiloIncentivesController.sol
pragma solidity 0.8.13;
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {BaseIncentivesController} from "../external/aave/incentives/base/BaseIncentivesController.sol";
import "../interfaces/INotificationReceiver.sol";
contract SiloIncentivesController is BaseIncentivesController, INotificationReceiver {
using SafeERC20 for IERC20;
constructor(IERC20 rewardToken, address emissionManager) BaseIncentivesController(rewardToken, emissionManager) {}
function onAfterTransfer(address , address _from, address _to, uint256 _amount) external {
if (assets[msg.sender].lastUpdateTimestamp == 0) {
return;
}
uint256 totalSupplyBefore = IERC20(msg.sender).totalSupply();
if (_from == address(0x0)) {
unchecked { totalSupplyBefore -= _amount; }
} else if (_to == address(0x0)) {
unchecked { totalSupplyBefore += _amount; }
}
if (_from != address(0x0)) {
uint256 balanceBefore;
unchecked { balanceBefore = IERC20(msg.sender).balanceOf(_from) + _amount; }
handleAction(_from, totalSupplyBefore, balanceBefore);
}
if (_to != address(0x0)) {
uint256 balanceBefore;
unchecked { balanceBefore = IERC20(msg.sender).balanceOf(_to) - _amount; }
handleAction(_to, totalSupplyBefore, balanceBefore);
}
}
function rescueRewards() external onlyEmissionManager {
IERC20(REWARD_TOKEN).safeTransfer(msg.sender, IERC20(REWARD_TOKEN).balanceOf(address(this)));
}
function notificationReceiverPing() external pure returns (bytes4) {
return this.notificationReceiverPing.selector;
}
function _transferRewards(address to, uint256 amount) internal override {
IERC20(REWARD_TOKEN).safeTransfer(to, amount);
}
function _getScaledUserBalanceAndSupply(address _asset, address _user)
internal
virtual
view
override
returns (uint256 userBalance, uint256 totalSupply)
{
userBalance = IERC20(_asset).balanceOf(_user);
totalSupply = IERC20(_asset).totalSupply();
}
}
{
"compilationTarget": {
"contracts/incentives/SiloIncentivesController.sol": "SiloIncentivesController"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20","name":"rewardToken","type":"address"},{"internalType":"address","name":"emissionManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ClaimerUnauthorized","type":"error"},{"inputs":[],"name":"IndexOverflow","type":"error"},{"inputs":[],"name":"IndexOverflowAtEmissionsPerSecond","type":"error"},{"inputs":[],"name":"InvalidConfiguration","type":"error"},{"inputs":[],"name":"InvalidToAddress","type":"error"},{"inputs":[],"name":"InvalidUserAddress","type":"error"},{"inputs":[],"name":"OnlyEmissionManager","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"emission","type":"uint256"}],"name":"AssetConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"AssetIndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"claimer","type":"address"}],"name":"ClaimerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDistributionEnd","type":"uint256"}],"name":"DistributionEndUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"UserIndexUpdated","type":"event"},{"inputs":[],"name":"DISTRIBUTION_END","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TEN_POW_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assets","outputs":[{"internalType":"uint104","name":"emissionPerSecond","type":"uint104"},{"internalType":"uint104","name":"index","type":"uint104"},{"internalType":"uint40","name":"lastUpdateTimestamp","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"claimRewardsOnBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimRewardsToSelf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"emissionsPerSecond","type":"uint256[]"}],"name":"configureAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetData","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getClaimer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDistributionEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address","name":"user","type":"address"}],"name":"getRewardsBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"asset","type":"address"}],"name":"getUserAssetData","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserUnclaimedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"userBalance","type":"uint256"}],"name":"handleAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"notificationReceiverPing","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"onAfterTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"setClaimer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"distributionEnd","type":"uint256"}],"name":"setDistributionEnd","outputs":[],"stateMutability":"nonpayable","type":"function"}]