{"file_path":"contracts/core/StakingRewardsDistributor.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts/access/Ownable2Step.sol\";\n\nimport \"../interfaces/IStakedTrUSD.sol\";\n\n/**\n * @title StakingRewardsDistributor\n * @notice This helper contract allows us to distribute staking rewards without the need of multisig transactions.\n * It increases the distribution frequency and automates almost the whole process, we also mitigate some arbitrage\n * opportunities with this approach.\n * @dev We have two roles:\n *      - The owner of this helper will be the multisig, only used for configuration calls.\n *      - The operator will be the delegated signer and is only allowed to call transferInRewards to send\n *        TrUSD rewards to the staking contract. The operator can be replaced by the owner at any time with\n *        a single transaction.\n */\ncontract StakingRewardsDistributor is Ownable2Step, ReentrancyGuard {\n    using SafeERC20 for IERC20;\n\n    // ---------------------- Constants -----------------------\n    /// @notice placeholder address for ETH\n    address internal constant _ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n    // ---------------------- Immutables -----------------------\n    /// @notice Tori staking contract\n    IStakedTrUSD public immutable STAKING_VAULT;\n    /// @notice Tori TrUSD stablecoin\n    IERC20 public immutable TRUSD_TOKEN;\n\n    // ---------------------- Storage --------------------------\n    /// @notice only address authorized to invoke transferInRewards\n    address public operator;\n\n    // ---------------------- Events ---------------------------\n    event TokensRescued(address indexed token, address indexed to, uint256 amount);\n    event OperatorUpdated(address indexed newOperator, address indexed oldOperator);\n    event RewardsDistributed(uint256 indexed amount, address indexed operator, uint256 timestamp);\n    event LossReported(uint256 indexed amount, address indexed operator, uint256 timestamp);\n    event ApprovalUpdated(address indexed spender, uint256 amount);\n    event ApprovalRevoked(address indexed spender);\n\n    // ---------------------- Errors ---------------------------\n    error InvalidZeroAddress();\n    error OnlyOperator();\n    error InsufficientFunds();\n    error InvalidAmount();\n    error TransferFailed();\n    error CantRenounceOwnership();\n    error CannotRescueRewardToken();\n    error NotAContract();\n    error InvalidStakingVault();\n    error OperatorUnchanged();\n\n    constructor(IStakedTrUSD _staking_vault, IERC20 _trusd, address _admin, address _operator) Ownable(_admin) {\n        if (address(_staking_vault) == address(0)) revert InvalidZeroAddress();\n        if (address(_trusd) == address(0)) revert InvalidZeroAddress();\n        if (address(_admin) == address(0)) revert InvalidZeroAddress();\n        if (address(_operator) == address(0)) revert InvalidZeroAddress();\n\n        if (address(_staking_vault).code.length == 0) revert NotAContract();\n\n        try _staking_vault.getUnvestedAmount() returns (uint256) {\n        } catch {\n            revert InvalidStakingVault();\n        }\n\n        STAKING_VAULT = _staking_vault;\n        TRUSD_TOKEN = _trusd;\n\n        operator = _operator;\n        emit OperatorUpdated(_operator, address(0));\n\n        IERC20(address(TRUSD_TOKEN)).safeIncreaseAllowance(address(STAKING_VAULT), type(uint256).max);\n\n        if (msg.sender != _admin) {\n            _transferOwnership(_admin);\n        }\n    }\n\n    /**\n     * @notice only the operator can call transferInRewards in order to transfer TrUSD to the staking contract\n     * @param _rewardsAmount the amount of TrUSD to send\n     * @dev In order to use this function, we need to set this contract as the REWARDER_ROLE in the staking contract\n     */\n    function transferInRewards(uint256 _rewardsAmount) external nonReentrant {\n        if (msg.sender != operator) revert OnlyOperator();\n        if (_rewardsAmount == 0) revert InvalidAmount();\n        if (TRUSD_TOKEN.balanceOf(address(this)) < _rewardsAmount) revert InsufficientFunds();\n\n        STAKING_VAULT.transferInRewards(_rewardsAmount);\n\n        emit RewardsDistributed(_rewardsAmount, msg.sender, block.timestamp);\n    }\n\n    /**\n     * @notice only the operator can call reportLoss to report a loss to the staking contract\n     * @param _lossAmount the amount of TrUSD loss to report\n     * @dev In order to use this function, we need to set this contract as the REWARDER_ROLE in the staking contract\n     */\n    function reportLoss(uint256 _lossAmount) external nonReentrant {\n        if (msg.sender != operator) revert OnlyOperator();\n        if (_lossAmount == 0) revert InvalidAmount();\n\n        STAKING_VAULT.reportLoss(_lossAmount);\n\n        emit LossReported(_lossAmount, msg.sender, block.timestamp);\n    }\n\n    /**\n     * @notice owner can rescue tokens that were accidentally sent to the contract\n     * @param _token the token to transfer\n     * @param _to the address to send the tokens to\n     * @param _amount the amount of tokens to send\n     * @dev only available for the owner\n     */\n    function rescueTokens(address _token, address _to, uint256 _amount) external nonReentrant onlyOwner {\n        if (_token == address(0)) revert InvalidZeroAddress();\n        if (_token == address(TRUSD_TOKEN)) revert CannotRescueRewardToken();\n        if (_to == address(0)) revert InvalidZeroAddress();\n        if (_amount == 0) revert InvalidAmount();\n\n        // Contract can only receive ETH via selfdestruct, allow rescuing it\n        if (_token == _ETH_ADDRESS) {\n            (bool success,) = _to.call{value: _amount}(\"\");\n            if (!success) revert TransferFailed();\n        } else {\n            IERC20(_token).safeTransfer(_to, _amount);\n        }\n        emit TokensRescued(_token, _to, _amount);\n    }\n\n    /**\n     * @notice sets a new operator\n     * @param _newOperator new operator address\n     * @dev only available for the owner. We allow the address(0) as a new operator\n     * in case that the key is exposed and we just want to remove the current operator\n     * as soon as possible being able to set to 0\n     */\n    function setOperator(address _newOperator) public onlyOwner {\n        if (_newOperator == operator) revert OperatorUnchanged();\n\n        address oldOperator = operator;\n        operator = _newOperator;\n\n        emit OperatorUpdated(_newOperator, oldOperator);\n    }\n\n    /**\n     * @notice allows owner to update TrUSD approval to staking vault\n     * @param amount the new approval amount\n     * @dev only available for the owner, useful if staking vault is compromised or needs updating\n     */\n    function updateStakingVaultApproval(uint256 amount) external onlyOwner {\n        TRUSD_TOKEN.forceApprove(address(STAKING_VAULT), amount);\n        emit ApprovalUpdated(address(STAKING_VAULT), amount);\n    }\n\n    /**\n     * @notice emergency function to revoke all TrUSD approvals to staking vault\n     * @dev only available for the owner, use if staking vault is compromised\n     */\n    function revokeStakingVaultApproval() external onlyOwner {\n        TRUSD_TOKEN.forceApprove(address(STAKING_VAULT), 0);\n        emit ApprovalRevoked(address(STAKING_VAULT));\n    }\n\n    /**\n     * @notice prevents the owner from renouncing the owner role\n     */\n    function renounceOwnership() public view override onlyOwner {\n        revert CantRenounceOwnership();\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f5ffd5b50600436106100e5575f3560e01c8063b3ab15fb11610088578063cea9d26f11610063578063cea9d26f146101c9578063ddd6d260146101dc578063e30c3978146101ef578063f2fde38b14610200575f5ffd5b8063b3ab15fb1461019b578063c80ef110146101ae578063c8bcc271146101c1575f5ffd5b806379ba5097116100c357806379ba5097146101495780638da5cb5b146101515780639416910014610161578063a4679c6314610174575f5ffd5b8063398387c1146100e9578063570ca7351461012c578063715018a61461013f575b5f5ffd5b6101107f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f581581565b6040516001600160a01b03909116815260200160405180910390f35b600354610110906001600160a01b031681565b610147610213565b005b610147610234565b5f546001600160a01b0316610110565b61014761016f366004610bd6565b61027d565b6101107f000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e2756091169781565b6101476101a9366004610c08565b61033f565b6101476101bc366004610bd6565b6103c6565b610147610577565b6101476101d7366004610c28565b610628565b6101476101ea366004610bd6565b610803565b6001546001600160a01b0316610110565b61014761020e366004610c08565b6108ff565b61021b61096f565b60405163185b73b160e01b815260040160405180910390fd5b60015433906001600160a01b031681146102715760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b61027a8161099d565b50565b61028561096f565b6102d96001600160a01b037f000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e27560911697167f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f5815836109b6565b7f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f58156001600160a01b03167f92bb139d32a500a24971eca3a43636fdf4608e854b533d1d27e468ba90f086608260405161033491815260200190565b60405180910390a250565b61034761096f565b6003546001600160a01b039081169082160361037657604051633626e1bf60e01b815260040160405180910390fd5b600380546001600160a01b038381166001600160a01b03198316811790935560405191169182917ffbe5b6cbafb274f445d7fed869dc77a838d8243a22c460de156560e8857cad03905f90a35050565b6103ce610a79565b6003546001600160a01b031633146103f9576040516327e1f1e560e01b815260040160405180910390fd5b805f036104195760405163162908e360e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015281907f000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e275609116976001600160a01b0316906370a0823190602401602060405180830381865afa15801561047d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a19190610c62565b10156104c05760405163356680b760e01b815260040160405180910390fd5b604051630c80ef1160e41b8152600481018290527f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f58156001600160a01b03169063c80ef110906024015f604051808303815f87803b15801561051f575f5ffd5b505af1158015610531573d5f5f3e3d5ffd5b50506040514281523392508391507f4cbfa67f54cf0255619787991cb52aa46c0d3ee5cfabb0abf659f2b310f47485906020015b60405180910390a361027a6001600255565b61057f61096f565b6105d36001600160a01b037f000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e27560911697167f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f58155f6109b6565b6040516001600160a01b037f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f581516907fb9d372ca98fcaccd93b1d0e8a23b184901314fb7f610fb82ba911d094c4c2e76905f90a2565b610630610a79565b61063861096f565b6001600160a01b03831661065f5760405163f6b2911f60e01b815260040160405180910390fd5b7f000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e275609116976001600160a01b0316836001600160a01b0316036106b157604051637d8969bd60e11b815260040160405180910390fd5b6001600160a01b0382166106d85760405163f6b2911f60e01b815260040160405180910390fd5b805f036106f85760405163162908e360e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610793575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610766576040519150601f19603f3d011682016040523d82523d5f602084013e61076b565b606091505b505090508061078d576040516312171d8360e31b815260040160405180910390fd5b506107a7565b6107a76001600160a01b0384168383610aa1565b816001600160a01b0316836001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c4836040516107ec91815260200190565b60405180910390a36107fe6001600255565b505050565b61080b610a79565b6003546001600160a01b03163314610836576040516327e1f1e560e01b815260040160405180910390fd5b805f036108565760405163162908e360e11b815260040160405180910390fd5b6040516306eeb69360e51b8152600481018290527f000000000000000000000000280839980a7ed0d7717f64125fe241012e5f58156001600160a01b03169063ddd6d260906024015f604051808303815f87803b1580156108b5575f5ffd5b505af11580156108c7573d5f5f3e3d5ffd5b50506040514281523392508391507f0b21957367904e69c5149e4fc624813d66f2f472ab75a14a62bf430297f5c28090602001610565565b61090761096f565b600180546001600160a01b0383166001600160a01b031990911681179091556109375f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f546001600160a01b0316331461099b5760405163118cdaa760e01b8152336004820152602401610268565b565b600180546001600160a01b031916905561027a81610ad2565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610a078482610b21565b610a73576040516001600160a01b0384811660248301525f6044830152610a6991869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610b6a565b610a738482610b6a565b50505050565b6002805403610a9b57604051633ee5aeb560e01b815260040160405180910390fd5b60028055565b6040516001600160a01b038381166024830152604482018390526107fe91859182169063a9059cbb90606401610a37565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610b6057508115610b525780600114610b60565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af180610b89576040513d5f823e3d81fd5b50505f513d91508115610ba0578060011415610bad565b6001600160a01b0384163b155b15610a7357604051635274afe760e01b81526001600160a01b0385166004820152602401610268565b5f60208284031215610be6575f5ffd5b5035919050565b80356001600160a01b0381168114610c03575f5ffd5b919050565b5f60208284031215610c18575f5ffd5b610c2182610bed565b9392505050565b5f5f5f60608486031215610c3a575f5ffd5b610c4384610bed565b9250610c5160208501610bed565b929592945050506040919091013590565b5f60208284031215610c72575f5ffd5b505191905056fea2646970667358221220ffcdad9955d48eb8ffb09c7f5dda212a6c234253b9aa52ad61c89657e6e81b9964736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0x280839980a7eD0D7717F64125fE241012E5F5815",{"internalType":"contract IStakedTrUSD","name":"_staking_vault","type":"address"}],["0xd0580192E98eA6CEB9c7b6191Ed2E27560911697",{"internalType":"contract IERC20","name":"_trusd","type":"address"}],["0x0C6Bbfd2d5666d44bf28580eDEec0263692C8316",{"internalType":"address","name":"_admin","type":"address"}],["0xA2ADCD948DCFB8AF6dB60c43C1c1B841e6d7F006",{"internalType":"address","name":"_operator","type":"address"}]],"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-06-11T13:05:17.952232Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60c060405234801561000f575f5ffd5b5060405161126538038061126583398101604081905261002e916104be565b816001600160a01b03811661005d57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6100668161023d565b5060016002556001600160a01b0384166100935760405163f6b2911f60e01b815260040160405180910390fd5b6001600160a01b0383166100ba5760405163f6b2911f60e01b815260040160405180910390fd5b6001600160a01b0382166100e15760405163f6b2911f60e01b815260040160405180910390fd5b6001600160a01b0381166101085760405163f6b2911f60e01b815260040160405180910390fd5b836001600160a01b03163b5f03610132576040516309ee12d560e01b815260040160405180910390fd5b836001600160a01b031663e7c2a6086040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561018c575060408051601f3d908101601f191682019092526101899181019061051a565b60015b6101a857604051627da0a960e91b815260040160405180910390fd5b506001600160a01b0384811660805283811660a052600380546001600160a01b03191691831691821790556040515f91907ffbe5b6cbafb274f445d7fed869dc77a838d8243a22c460de156560e8857cad03908390a360805160a05161021b916001600160a01b03909116905f19610259565b336001600160a01b03831614610234576102348261023d565b50505050610550565b600180546001600160a01b0319169055610256816102e6565b50565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa1580156102a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ca919061051a565b90506102e084846102db8585610531565b610335565b50505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b1790915261038d90859083906103f316565b6102e057604080516001600160a01b03851660248201525f6044808301919091528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526103e991869161043e16565b6102e0848261043e565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610432575081156104245780600114610432565b5f866001600160a01b03163b115b93505050505b92915050565b5f5f60205f8451602086015f885af18061045d576040513d5f823e3d81fd5b50505f513d91508115610474578060011415610481565b6001600160a01b0384163b155b156102e057604051635274afe760e01b81526001600160a01b0385166004820152602401610054565b6001600160a01b0381168114610256575f5ffd5b5f5f5f5f608085870312156104d1575f5ffd5b84516104dc816104aa565b60208601519094506104ed816104aa565b60408601519093506104fe816104aa565b606086015190925061050f816104aa565b939692955090935050565b5f6020828403121561052a575f5ffd5b5051919050565b8082018082111561043857634e487b7160e01b5f52601160045260245ffd5b60805160a051610caf6105b65f395f818161017901528181610292015281816104300152818161058c015261066101525f818160ee015281816102b4015281816102db015281816104d6015281816105ae015281816105e0015261086c0152610caf5ff3fe608060405234801561000f575f5ffd5b50600436106100e5575f3560e01c8063b3ab15fb11610088578063cea9d26f11610063578063cea9d26f146101c9578063ddd6d260146101dc578063e30c3978146101ef578063f2fde38b14610200575f5ffd5b8063b3ab15fb1461019b578063c80ef110146101ae578063c8bcc271146101c1575f5ffd5b806379ba5097116100c357806379ba5097146101495780638da5cb5b146101515780639416910014610161578063a4679c6314610174575f5ffd5b8063398387c1146100e9578063570ca7351461012c578063715018a61461013f575b5f5ffd5b6101107f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b600354610110906001600160a01b031681565b610147610213565b005b610147610234565b5f546001600160a01b0316610110565b61014761016f366004610bd6565b61027d565b6101107f000000000000000000000000000000000000000000000000000000000000000081565b6101476101a9366004610c08565b61033f565b6101476101bc366004610bd6565b6103c6565b610147610577565b6101476101d7366004610c28565b610628565b6101476101ea366004610bd6565b610803565b6001546001600160a01b0316610110565b61014761020e366004610c08565b6108ff565b61021b61096f565b60405163185b73b160e01b815260040160405180910390fd5b60015433906001600160a01b031681146102715760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b61027a8161099d565b50565b61028561096f565b6102d96001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000836109b6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f92bb139d32a500a24971eca3a43636fdf4608e854b533d1d27e468ba90f086608260405161033491815260200190565b60405180910390a250565b61034761096f565b6003546001600160a01b039081169082160361037657604051633626e1bf60e01b815260040160405180910390fd5b600380546001600160a01b038381166001600160a01b03198316811790935560405191169182917ffbe5b6cbafb274f445d7fed869dc77a838d8243a22c460de156560e8857cad03905f90a35050565b6103ce610a79565b6003546001600160a01b031633146103f9576040516327e1f1e560e01b815260040160405180910390fd5b805f036104195760405163162908e360e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561047d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a19190610c62565b10156104c05760405163356680b760e01b815260040160405180910390fd5b604051630c80ef1160e41b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c80ef110906024015f604051808303815f87803b15801561051f575f5ffd5b505af1158015610531573d5f5f3e3d5ffd5b50506040514281523392508391507f4cbfa67f54cf0255619787991cb52aa46c0d3ee5cfabb0abf659f2b310f47485906020015b60405180910390a361027a6001600255565b61057f61096f565b6105d36001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6109b6565b6040516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016907fb9d372ca98fcaccd93b1d0e8a23b184901314fb7f610fb82ba911d094c4c2e76905f90a2565b610630610a79565b61063861096f565b6001600160a01b03831661065f5760405163f6b2911f60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316036106b157604051637d8969bd60e11b815260040160405180910390fd5b6001600160a01b0382166106d85760405163f6b2911f60e01b815260040160405180910390fd5b805f036106f85760405163162908e360e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610793575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610766576040519150601f19603f3d011682016040523d82523d5f602084013e61076b565b606091505b505090508061078d576040516312171d8360e31b815260040160405180910390fd5b506107a7565b6107a76001600160a01b0384168383610aa1565b816001600160a01b0316836001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c4836040516107ec91815260200190565b60405180910390a36107fe6001600255565b505050565b61080b610a79565b6003546001600160a01b03163314610836576040516327e1f1e560e01b815260040160405180910390fd5b805f036108565760405163162908e360e11b815260040160405180910390fd5b6040516306eeb69360e51b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ddd6d260906024015f604051808303815f87803b1580156108b5575f5ffd5b505af11580156108c7573d5f5f3e3d5ffd5b50506040514281523392508391507f0b21957367904e69c5149e4fc624813d66f2f472ab75a14a62bf430297f5c28090602001610565565b61090761096f565b600180546001600160a01b0383166001600160a01b031990911681179091556109375f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f546001600160a01b0316331461099b5760405163118cdaa760e01b8152336004820152602401610268565b565b600180546001600160a01b031916905561027a81610ad2565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610a078482610b21565b610a73576040516001600160a01b0384811660248301525f6044830152610a6991869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610b6a565b610a738482610b6a565b50505050565b6002805403610a9b57604051633ee5aeb560e01b815260040160405180910390fd5b60028055565b6040516001600160a01b038381166024830152604482018390526107fe91859182169063a9059cbb90606401610a37565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610b6057508115610b525780600114610b60565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af180610b89576040513d5f823e3d81fd5b50505f513d91508115610ba0578060011415610bad565b6001600160a01b0384163b155b15610a7357604051635274afe760e01b81526001600160a01b0385166004820152602401610268565b5f60208284031215610be6575f5ffd5b5035919050565b80356001600160a01b0381168114610c03575f5ffd5b919050565b5f60208284031215610c18575f5ffd5b610c2182610bed565b9392505050565b5f5f5f60608486031215610c3a575f5ffd5b610c4384610bed565b9250610c5160208501610bed565b929592945050506040919091013590565b5f60208284031215610c72575f5ffd5b505191905056fea2646970667358221220ffcdad9955d48eb8ffb09c7f5dda212a6c234253b9aa52ad61c89657e6e81b9964736f6c634300081c0033000000000000000000000000280839980a7ed0d7717f64125fe241012e5f5815000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e275609116970000000000000000000000000c6bbfd2d5666d44bf28580edeec0263692c8316000000000000000000000000a2adcd948dcfb8af6db60c43c1c1b841e6d7f006","name":"StakingRewardsDistributor","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/ReentrancyGuard.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == ENTERED;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/access/Ownable2Step.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {Ownable} from \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This extension of the {Ownable} contract includes a two-step mechanism to transfer\n * ownership, where the new owner must call {acceptOwnership} in order to replace the\n * old one. This can help prevent common mistakes, such as transfers of ownership to\n * incorrect accounts, or to contracts that are unable to interact with the\n * permission system.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return _pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     *\n     * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        _pendingOwner = newOwner;\n        emit OwnershipTransferStarted(owner(), newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete _pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() public virtual {\n        address sender = _msgSender();\n        if (pendingOwner() != sender) {\n            revert OwnableUnauthorizedAccount(sender);\n        }\n        _transferOwnership(sender);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"contracts/interfaces/IStakedTrUSD.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IStakedTrUSD {\n    // Events //\n    /// @notice Event emitted when the rewards are received\n    event RewardsReceived(uint256 indexed amount);\n    /// @notice Event emitted when the balance from an FULL_RESTRICTED_STAKER_ROLE user are redistributed\n    event LockedAmountRedistributed(address indexed from, address indexed to, uint256 amount);\n    /// @notice Event emitted when admin seizes cooldown assets from a blacklisted user\n    event CooldownSeized(address indexed from, address indexed to, uint256 amount);\n\n    // Errors //\n    /// @notice Error emitted shares or assets equal zero.\n    error InvalidAmount();\n    /// @notice Error emitted when owner attempts to rescue TrUSD tokens.\n    error InvalidToken();\n    /// @notice Error emitted when slippage is exceeded on a deposit or withdrawal\n    error SlippageExceeded();\n    /// @notice Error emitted when a small non-zero share amount remains, which risks donations attack\n    error MinSharesViolation();\n    /// @notice Error emitted when owner is not allowed to perform an operation\n    error OperationNotAllowed();\n    /// @notice Error emitted when there is still unvested amount\n    error StillVesting();\n    /// @notice Error emitted when owner or blacklist manager attempts to blacklist owner\n    error CantBlacklistOwner();\n    /// @notice Error emitted when the zero address is given\n    error InvalidZeroAddress();\n    /// @notice Error emitted when there are no orphan funds to rescue\n    error NoOrphanFunds();\n    /// @notice Error emitted when attempting to use grantRole/revokeRole for TIMELOCK_ADMIN_ROLE\n    error UseSetTimelockAdmin();\n    /// @notice Error emitted when trying to initialize timelock admin more than once\n    error TimelockAdminAlreadyInitialized();\n\n    /// @notice Event emitted when orphan funds are rescued\n    event OrphanFundsRescued(address indexed to, uint256 amount);\n    /// @notice Event emitted when the timelock admin is updated\n    event TimelockAdminUpdated(address indexed oldTimelockAdmin, address indexed newTimelockAdmin);\n    /// @notice Event emitted when a loss is reported and assets are burned\n    event LossReported(uint256 indexed amount);\n\n    function transferInRewards(uint256 amount) external;\n\n    function reportLoss(uint256 amount) external;\n\n    function rescueTokens(address token, uint256 amount, address to) external;\n\n    function rescueOrphanFunds(address to) external;\n\n    function getUnvestedAmount() external view returns (uint256);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"contract IStakedTrUSD","name":"_staking_vault","type":"address"},{"internalType":"contract IERC20","name":"_trusd","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotRescueRewardToken","type":"error"},{"inputs":[],"name":"CantRenounceOwnership","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidStakingVault","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyOperator","type":"error"},{"inputs":[],"name":"OperatorUnchanged","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"}],"name":"ApprovalRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ApprovalUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"LossReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOperator","type":"address"},{"indexed":true,"internalType":"address","name":"oldOperator","type":"address"}],"name":"OperatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensRescued","type":"event"},{"inputs":[],"name":"STAKING_VAULT","outputs":[{"internalType":"contract IStakedTrUSD","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRUSD_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lossAmount","type":"uint256"}],"name":"reportLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeStakingVaultApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOperator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsAmount","type":"uint256"}],"name":"transferInRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"updateStakingVaultApproval","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000280839980a7ed0d7717f64125fe241012e5f5815000000000000000000000000d0580192e98ea6ceb9c7b6191ed2e275609116970000000000000000000000000c6bbfd2d5666d44bf28580edeec0263692c8316000000000000000000000000a2adcd948dcfb8af6db60c43c1c1b841e6d7f006"}