Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/governance/FluidRewardsClaimer.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {FarmRegistry} from "@integrations/FarmRegistry.sol";
import {CoreControlled} from "@core/CoreControlled.sol";
/// @title A contract to help claim Fluid rewards
/// This contract needs GOVERNOR role to act on behalf of protocol contracts
/// that have earned Fluid rewards.
contract FluidRewardsClaimer is CoreControlled {
error InvalidFarm(address _farm);
error NoRewardsToClaim(address _farm);
error InvalidRecipient(address _recipient);
event RecipientUpdated(uint256 indexed timestamp, address indexed recipient);
event Claimed(uint256 indexed timestamp, address indexed farm, uint256 amount);
/// @notice reference to the farm registry contract
address public immutable farmRegistry;
/// @notice recipient of the Fluid rewards
address public recipient;
/// @notice fluid rewards claimer contract
address public constant FLUID_REWARDS_CONTRACT = 0x7060FE0Dd3E31be01EFAc6B28C8D38018fD163B0;
/// @notice fluid reward token
address public constant FLUID_REWARD_TOKEN = 0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb;
constructor(address _core, address _farmRegistry, address _recipient) CoreControlled(_core) {
farmRegistry = _farmRegistry;
_setRecipient(_recipient);
}
/// @notice sets the recipient of the Fluid rewards
function setRecipient(address _recipient) external onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS) {
_setRecipient(_recipient);
}
function _setRecipient(address _recipient) internal {
require(_recipient != address(0), InvalidRecipient(_recipient));
recipient = _recipient;
emit RecipientUpdated(block.timestamp, _recipient);
}
/// @notice claims the Fluid rewards for the recipient
/// @dev note that this call is unprotected, anyone can make the farm claim its rewards.
function claimFluidRewards(
address _farm,
uint256 _cumulativeAmount,
uint8 _positionType,
bytes32 _positionId,
uint256 _cycle,
bytes32[] calldata _merkleProof,
bytes memory _metadata
) external whenNotPaused onlyCoreRole(CoreRoles.FARM_SWAP_CALLER) {
require(FarmRegistry(farmRegistry).isFarm(_farm), InvalidFarm(_farm));
CoreControlled.Call[] memory claimCalls = new CoreControlled.Call[](1);
claimCalls[0] = CoreControlled.Call({
target: FLUID_REWARDS_CONTRACT,
value: 0,
callData: abi.encodeWithSignature(
"claim(address,uint256,uint8,bytes32,uint256,bytes32[],bytes)",
_farm,
_cumulativeAmount,
_positionType,
_positionId,
_cycle,
_merkleProof,
_metadata
)
});
CoreControlled(_farm).emergencyAction(claimCalls);
uint256 rewardTokenBalance = IERC20(FLUID_REWARD_TOKEN).balanceOf(_farm);
require(rewardTokenBalance > 0, NoRewardsToClaim(_farm));
CoreControlled.Call[] memory transferCalls = new CoreControlled.Call[](1);
transferCalls[0] = CoreControlled.Call({
target: FLUID_REWARD_TOKEN,
value: 0,
callData: abi.encodeWithSignature("transfer(address,uint256)", recipient, rewardTokenBalance)
});
CoreControlled(_farm).emergencyAction(transferCalls);
emit Claimed(block.timestamp, _farm, rewardTokenBalance);
}
}
"
},
"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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);
}
"
},
"src/libraries/CoreRoles.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @notice Holds a complete list of all roles which can be held by contracts inside the InfiniFi protocol.
library CoreRoles {
/// ----------- Core roles for access control --------------
/// @notice the all-powerful role. Controls all other roles and protocol functionality.
bytes32 internal constant GOVERNOR = keccak256("GOVERNOR");
/// @notice Can pause contracts in an emergency.
bytes32 internal constant PAUSE = keccak256("PAUSE");
/// @notice Can unpause contracts after an emergency.
bytes32 internal constant UNPAUSE = keccak256("UNPAUSE");
/// @notice can tweak protocol parameters
bytes32 internal constant PROTOCOL_PARAMETERS = keccak256("PROTOCOL_PARAMETERS");
/// @notice can manage minor roles
bytes32 internal constant MINOR_ROLES_MANAGER = keccak256("MINOR_ROLES_MANAGER");
/// ----------- User Flow Management -----------------------
/// @notice Granted to the user entry point of the system
bytes32 internal constant ENTRY_POINT = keccak256("ENTRY_POINT");
/// ----------- Token Management ---------------------------
/// @notice can mint DebtToken arbitrarily
bytes32 internal constant RECEIPT_TOKEN_MINTER = keccak256("RECEIPT_TOKEN_MINTER");
/// @notice can burn DebtToken tokens
bytes32 internal constant RECEIPT_TOKEN_BURNER = keccak256("RECEIPT_TOKEN_BURNER");
/// @notice can mint arbitrarily & burn held LockedPositionToken
bytes32 internal constant LOCKED_TOKEN_MANAGER = keccak256("LOCKED_TOKEN_MANAGER");
/// @notice can prevent transfers of LockedPositionToken
bytes32 internal constant TRANSFER_RESTRICTOR = keccak256("TRANSFER_RESTRICTOR");
/// ----------- Funds Management & Accounting --------------
/// @notice contract that can allocate funds between farms
bytes32 internal constant FARM_MANAGER = keccak256("FARM_MANAGER");
/// @notice addresses who can use the manual rebalancer
bytes32 internal constant MANUAL_REBALANCER = keccak256("MANUAL_REBALANCER");
/// @notice addresses who can use the periodic rebalancer
bytes32 internal constant PERIODIC_REBALANCER = keccak256("PERIODIC_REBALANCER");
/// @notice addresses who can move funds from farms to a safe address
bytes32 internal constant EMERGENCY_WITHDRAWAL = keccak256("EMERGENCY_WITHDRAWAL");
/// @notice addresses who can trigger swaps in Farms
bytes32 internal constant FARM_SWAP_CALLER = keccak256("FARM_SWAP_CALLER");
/// @notice can set oracles references within the system
bytes32 internal constant ORACLE_MANAGER = keccak256("ORACLE_MANAGER");
/// @notice trusted to report profit and losses in the system.
/// This role can be used to slash depositors in case of losses, and
/// can also deposit profits for distribution to end users.
bytes32 internal constant FINANCE_MANAGER = keccak256("FINANCE_MANAGER");
/// ----------- Timelock management ------------------------
/// The hashes are the same as OpenZeppelins's roles in TimelockController
/// @notice can propose new actions in timelocks
bytes32 internal constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
/// @notice can execute actions in timelocks after their delay
bytes32 internal constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
/// @notice can cancel actions in timelocks
bytes32 internal constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE");
}
"
},
"src/integrations/FarmRegistry.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IFarm} from "@interfaces/IFarm.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {CoreControlled} from "@core/CoreControlled.sol";
/// @notice InfiniFi Farm registry
contract FarmRegistry is CoreControlled {
error FarmAlreadyAdded(address farm);
error FarmNotFound(address farm);
error AssetNotEnabled(address farm, address asset);
error AssetAlreadyEnabled(address asset);
error AssetNotFound(address asset);
event AssetEnabled(uint256 indexed timestamp, address asset);
event AssetDisabled(uint256 indexed timestamp, address asset);
event FarmsAdded(uint256 indexed timestamp, uint256 farmType, address[] indexed farms);
event FarmsRemoved(uint256 indexed timestamp, uint256 farmType, address[] indexed farms);
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet private assets;
EnumerableSet.AddressSet private farms;
mapping(uint256 _type => EnumerableSet.AddressSet _farms) private typeFarms;
mapping(address _asset => EnumerableSet.AddressSet _farms) private assetFarms;
mapping(address _asset => mapping(uint256 _type => EnumerableSet.AddressSet _farms)) private assetTypeFarms;
constructor(address _core) CoreControlled(_core) {}
/// ----------------------------------------------------------------------------
/// READ METHODS
/// ----------------------------------------------------------------------------
function getEnabledAssets() external view returns (address[] memory) {
return assets.values();
}
function isAssetEnabled(address _asset) external view returns (bool) {
return assets.contains(_asset);
}
function getFarms() external view returns (address[] memory) {
return farms.values();
}
function getTypeFarms(uint256 _type) external view returns (address[] memory) {
return typeFarms[_type].values();
}
function getAssetFarms(address _asset) external view returns (address[] memory) {
return assetFarms[_asset].values();
}
function getAssetTypeFarms(address _asset, uint256 _type) external view returns (address[] memory) {
return assetTypeFarms[_asset][_type].values();
}
function isFarm(address _farm) external view returns (bool) {
return farms.contains(_farm);
}
function isFarmOfAsset(address _farm, address _asset) external view returns (bool) {
return assetFarms[_asset].contains(_farm);
}
function isFarmOfType(address _farm, uint256 _type) external view returns (bool) {
return typeFarms[_type].contains(_farm);
}
/// ----------------------------------------------------------------------------
/// WRITE METHODS
/// ----------------------------------------------------------------------------
function enableAsset(address _asset) external onlyCoreRole(CoreRoles.GOVERNOR) {
require(assets.add(_asset), AssetAlreadyEnabled(_asset));
emit AssetEnabled(block.timestamp, _asset);
}
function disableAsset(address _asset) external onlyCoreRole(CoreRoles.GOVERNOR) {
require(assets.remove(_asset), AssetNotFound(_asset));
emit AssetDisabled(block.timestamp, _asset);
}
function addFarms(uint256 _type, address[] calldata _list) external onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS) {
_addFarms(_type, _list);
emit FarmsAdded(block.timestamp, _type, _list);
}
function removeFarms(uint256 _type, address[] calldata _list)
external
onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS)
{
_removeFarms(_type, _list);
emit FarmsRemoved(block.timestamp, _type, _list);
}
/// ----------------------------------------------------------------------------
/// INTERNAL METHODS
/// ----------------------------------------------------------------------------
function _addFarms(uint256 _type, address[] calldata _list) internal {
for (uint256 i = 0; i < _list.length; i++) {
address farmAsset = IFarm(_list[i]).assetToken();
require(assets.contains(farmAsset), AssetNotEnabled(_list[i], farmAsset));
require(farms.add(_list[i]), FarmAlreadyAdded(_list[i]));
require(typeFarms[_type].add(_list[i]), FarmAlreadyAdded(_list[i]));
require(assetFarms[farmAsset].add(_list[i]), FarmAlreadyAdded(_list[i]));
require(assetTypeFarms[farmAsset][_type].add(_list[i]), FarmAlreadyAdded(_list[i]));
}
}
function _removeFarms(uint256 _type, address[] calldata _list) internal {
for (uint256 i = 0; i < _list.length; i++) {
address farmAsset = IFarm(_list[i]).assetToken();
require(farms.remove(_list[i]), FarmNotFound(_list[i]));
require(typeFarms[_type].remove(_list[i]), FarmNotFound(_list[i]));
require(assetFarms[farmAsset].remove(_list[i]), FarmNotFound(_list[i]));
require(assetTypeFarms[farmAsset][_type].remove(_list[i]), FarmNotFound(_list[i]));
}
}
}
"
},
"src/core/CoreControlled.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {InfiniFiCore} from "@core/InfiniFiCore.sol";
/// @notice Defines some modifiers and utilities around interacting with Core
abstract contract CoreControlled is Pausable {
error UnderlyingCallReverted(bytes returnData);
/// @notice emitted when the reference to core is updated
event CoreUpdate(address indexed oldCore, address indexed newCore);
/// @notice reference to Core
InfiniFiCore private _core;
constructor(address coreAddress) {
_core = InfiniFiCore(coreAddress);
}
/// @notice named onlyCoreRole to prevent collision with OZ onlyRole modifier
modifier onlyCoreRole(bytes32 role) {
require(_core.hasRole(role, msg.sender), "UNAUTHORIZED");
_;
}
/// @notice address of the Core contract referenced
function core() public view returns (InfiniFiCore) {
return _core;
}
/// @notice WARNING CALLING THIS FUNCTION CAN POTENTIALLY
/// BRICK A CONTRACT IF CORE IS SET INCORRECTLY
/// @notice set new reference to core
/// only callable by governor
/// @param newCore to reference
function setCore(address newCore) external onlyCoreRole(CoreRoles.GOVERNOR) {
_setCore(newCore);
}
/// @notice WARNING CALLING THIS FUNCTION CAN POTENTIALLY
/// BRICK A CONTRACT IF CORE IS SET INCORRECTLY
/// @notice set new reference to core
/// @param newCore to reference
function _setCore(address newCore) internal {
address oldCore = address(_core);
_core = InfiniFiCore(newCore);
emit CoreUpdate(oldCore, newCore);
}
/// @notice set pausable methods to paused
function pause() public onlyCoreRole(CoreRoles.PAUSE) {
_pause();
}
/// @notice set pausable methods to unpaused
function unpause() public onlyCoreRole(CoreRoles.UNPAUSE) {
_unpause();
}
/// ------------------------------------------
/// ------------ Emergency Action ------------
/// ------------------------------------------
/// inspired by MakerDAO Multicall:
/// https://github.com/makerdao/multicall/blob/master/src/Multicall.sol
/// @notice struct to pack calldata and targets for an emergency action
struct Call {
/// @notice target address to call
address target;
/// @notice amount of eth to send with the call
uint256 value;
/// @notice payload to send to target
bytes callData;
}
/// @notice due to inflexibility of current smart contracts,
/// add this ability to be able to execute arbitrary calldata
/// against arbitrary addresses.
/// callable only by governor
function emergencyAction(Call[] calldata calls)
external
payable
virtual
onlyCoreRole(CoreRoles.GOVERNOR)
returns (bytes[] memory returnData)
{
returnData = new bytes[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
address payable target = payable(calls[i].target);
uint256 value = calls[i].value;
bytes calldata callData = calls[i].callData;
(bool success, bytes memory returned) = target.call{value: value}(callData);
require(success, UnderlyingCallReverted(returned));
returnData[i] = returned;
}
}
}
"
},
"src/interfaces/IFarm.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @notice Interface for an InfiniFi Farm contract
interface IFarm {
/// @notice emitted when there is a deposit of withdrawal from the farm
event AssetsUpdated(uint256 timestamp, uint256 assetsBefore, uint256 assetsAfter);
// --------------------------------------------------------------------
// Accounting
// --------------------------------------------------------------------
/// @notice the cap of the farm
function cap() external view returns (uint256);
/// @notice the asset used by deposits and withdrawals in the farm
function assetToken() external view returns (address);
/// @notice the total assets in the farm, reported as a balance of asset()
function assets() external view returns (uint256);
// --------------------------------------------------------------------
// Adapter logic
// --------------------------------------------------------------------
/// @notice deposit all asset() held by the contract into the farm
function deposit() external;
/// @notice Returns the max deposit amount for the underlying protocol
function maxDeposit() external view returns (uint256);
/// @notice withdraw an amount of the asset() from the farm
/// @param amount Amount of assets to withdraw
/// @param to Address to receive the withdrawn assets
function withdraw(uint256 amount, address to) external;
/// @notice available number of assetToken() withdrawable instantly from the farm
function liquidity() external view returns (uint256);
}
"
},
"lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
import {Arrays} from "../Arrays.sol";
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
* - Set can be cleared (all elements removed) in O(n).
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function _clear(Set storage set) private {
uint256 len = _length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(Bytes32Set storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(AddressSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(UintSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Pausable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
"
},
"src/core/InfiniFiCore.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {AccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
/// @notice Maintains roles and access control
contract InfiniFiCore is AccessControlEnumerable {
error RoleAlreadyExists(bytes32 role);
error RoleDoesNotExist(bytes32 role);
error LengthMismatch(uint256 expected, uint256 actual);
/// @notice construct Core
constructor() {
// For initial setup before going live, deployer can then call
// renounceRole(bytes32 role, address account)
_grantRole(CoreRoles.GOVERNOR, msg.sender);
// Initial roles setup: direct hierarchy, everything under governor
_setRoleAdmin(CoreRoles.GOVERNOR, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PAUSE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.UNPAUSE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PROTOCOL_PARAMETERS, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.MINOR_ROLES_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.ENTRY_POINT, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.RECEIPT_TOKEN_MINTER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.RECEIPT_TOKEN_BURNER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.LOCKED_TOKEN_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.TRANSFER_RESTRICTOR, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.FARM_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.MANUAL_REBALANCER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PERIODIC_REBALANCER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.EMERGENCY_WITHDRAWAL, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.FARM_SWAP_CALLER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.ORACLE_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.FINANCE_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PROPOSER_ROLE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.EXECUTOR_ROLE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.CANCELLER_ROLE, CoreRoles.GOVERNOR);
}
/// @notice creates a new role to be maintained
/// @param role the new role id
/// @param adminRole the admin role id for `role`
function createRole(bytes32 role, bytes32 adminRole) external onlyRole(CoreRoles.GOVERNOR) {
require(getRoleAdmin(role) == bytes32(0), RoleAlreadyExists(role));
_setRoleAdmin(role, adminRole);
}
/// @notice override admin role of an existing role
/// @param role the role id
/// @param adminRole the admin role id
function setRoleAdmin(bytes32 role, bytes32 adminRole) external onlyRole(CoreRoles.GOVERNOR) {
require(getRoleAdmin(role) != bytes32(0), RoleDoesNotExist(role));
_setRoleAdmin(role, adminRole);
}
/// @notice batch granting of roles to various addresses
/// @dev if msg.sender does not have admin role needed to grant any of the
/// granted roles, the whole transaction reverts.
function grantRoles(bytes32[] calldata roles, address[] calldata accounts) external {
require(roles.length == accounts.length, LengthMismatch(roles.length, accounts.length));
for (uint256 i = 0; i < roles.length; i++) {
_checkRole(getRoleAdmin(roles[i]));
_grantRole(roles[i], accounts[i]);
}
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Arrays.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
pragma solidity ^0.8.20;
import {Comparators} from "./Comparators.sol";
import {SlotDerivation} from "./SlotDerivation.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using SlotDerivation for bytes32;
using StorageSlot for bytes32;
/**
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
uint256[] memory array,
function(uint256, uint256) pure returns (bool) comp
) internal pure returns (uint256[] memory) {
_quickSort(_begin(array), _end(array), comp);
return array;
}
/**
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
*/
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
sort(array, Comparators.lt);
return array;
}
/**
* @dev Sort an array of address (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
address[] memory array,
function(address, address) pure returns (bool) comp
) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of address in increasing order.
*/
function sort(address[] memory array) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
bytes32[] memory array,
function(bytes32, bytes32) pure returns (bool) comp
) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
*/
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
* at end (exclusive). Sorting follows the `comp` comparator.
*
* Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
*
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
* be used only if the limits are within a memory array.
*/
function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
unchecked {
if (end - begin < 0x40) return;
// Use first element as pivot
uint256 pivot = _mload(begin);
// Position where the pivot should be at the end of the loop
uint256 pos = begin;
for (uint256 it = begin + 0x20; it < end; it += 0x20) {
if (comp(_mload(it), pivot)) {
// If the value stored at the iterator's position comes before the pivot, we increment the
// position of the pivot and move the value there.
pos += 0x20;
_swap(pos, it);
}
}
_swap(begin, pos); // Swap pivot into place
_quickSort(begin, pos, comp); // Sort the left side of the pivot
_quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
}
}
/**
* @dev Pointer to the memory location of the first element of `array`.
*/
function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
assembly ("memory-safe") {
ptr := add(array, 0x20)
}
}
/**
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
* that comes just after the last element of the array.
*/
function _end(uint256[] memory array) private pure returns (uint256 ptr) {
unchecked {
return _begin(array) + array.length * 0x20;
}
}
/**
* @dev Load memory word (as a uint256) at location `ptr`.
*/
function _mload(uint256 ptr) private pure returns (uint256 value) {
assembly {
value := mload(ptr)
}
}
/**
* @dev Swaps the elements memory location `ptr1` and `ptr2`.
*/
function _swap(uint256 ptr1, uint256 ptr2) private pure {
assembly {
let value1 := mload(ptr1)
let value2 := mload(ptr2)
mstore(ptr1, value2)
mstore(ptr2, value1)
}
}
/// @dev Helper: low level cast address memory array to uint256 memory array
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast address comp function to uint256 comp function
function _castToUint256Comp(
function(address, address) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
function _castToUint256Comp(
function(bytes32, bytes32) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* NOTE: The `array` is expected to be sorted in ascending order, and to
* contain no repeated elements.
*
* IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
* support for repeated elements in the array. The {lowerBound} function should
* be used instead.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value greater or equal than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
*/
function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value strictly greater than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
*/
function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Same as {lowerBound}, but with an array in memory.
*/
function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Same as {upperBound}, but with an array in memory.
*/
function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytesSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getStringSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(address[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(uint256[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(string[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Context.sol": {
"content": "// 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()
Submitted on: 2025-10-14 17:18:22
Comments
Log in to comment.
No comments yet.