Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/query-router/CallbackExecutor.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {
AccessControlDefaultAdminRules
} from "@openzeppelin-contracts-5.2.0/access/extensions/AccessControlDefaultAdminRules.sol";
import {
CallWithExactGas
} from "smartcontractkit-chainlink-evm-1.5.0/contracts/src/v0.8/shared/call/CallWithExactGas.sol";
import {ICallbackExecutor} from "./interfaces/ICallbackExecutor.sol";
import {GasCost} from "./libraries/GasCost.sol";
/// @title CallbackExecutor
/// @author Placeholder
/// @notice Executes calls to other contracts for callbacks
contract CallbackExecutor is ICallbackExecutor, AccessControlDefaultAdminRules {
using GasCost for GasCost.GasCostConfig;
/// @notice Role for executor
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
/// @notice Gas cost configuration struct
GasCost.GasCostConfig public gasCostConfig;
/// @notice Maximum allowed gas limit for callback executions
uint256 public maxGasLimit;
/// @notice Initializes the contract, sets gas cost configuration and admin
/// @param _gasCostConfig Gas cost configuration struct
/// @param admin the admin address for access control
constructor(GasCost.GasCostConfig memory _gasCostConfig, address admin) AccessControlDefaultAdminRules(0, admin) {
_gasCostConfig.validateConfig();
gasCostConfig = _gasCostConfig;
maxGasLimit = type(uint256).max;
}
/// @inheritdoc ICallbackExecutor
function setGasCostConfig(GasCost.GasCostConfig calldata newConfig)
external
override
onlyRole(DEFAULT_ADMIN_ROLE) // aderyn-ignore(centralization-risk)
{
newConfig.validateConfig();
gasCostConfig = newConfig;
emit GasCostConfigUpdated(newConfig);
}
/// @notice Set the maximum gas limit that may be passed to `execute`
/// @param newMax The new maximum gas limit (0 disables callbacks with gas)
function setMaxGasLimit(uint256 newMax)
external
override
onlyRole(DEFAULT_ADMIN_ROLE) // aderyn-ignore(centralization-risk)
{
maxGasLimit = newMax;
emit MaxGasLimitUpdated(newMax);
}
/// @inheritdoc ICallbackExecutor
function execute(
address target,
bytes calldata data,
uint256 gasLimit,
uint256 maxGasPrice,
uint256 additionalGasUsed
)
external
override
onlyRole(EXECUTOR_ROLE) // aderyn-ignore(centralization-risk)
returns (uint256 gasCost)
{
if (target.code.length == 0) {
emit NoCallbackContract(target);
gasCost = 0;
} else {
uint256 effectiveGasLimit = gasLimit > maxGasLimit ? maxGasLimit : gasLimit;
(uint256 scaledGasCostInUsd, uint256 tokenUsdPrice) = gasCostConfig.gasCost(maxGasPrice);
(bool success, bytes memory retData, uint256 gasUsed) = CallWithExactGas._callWithExactGasSafeReturnData({
payload: data,
target: target,
gasLimit: effectiveGasLimit,
gasForCallExactCheck: 5000,
maxReturnBytes: 4
});
if (!success) emit CallbackFailed(target, retData);
gasCost = (gasUsed + additionalGasUsed) * scaledGasCostInUsd / tokenUsdPrice;
}
}
}
"
},
"dependencies/@openzeppelin-contracts-5.2.0/access/extensions/AccessControlDefaultAdminRules.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.20;
import {IAccessControlDefaultAdminRules} from "./IAccessControlDefaultAdminRules.sol";
import {AccessControl, IAccessControl} from "../AccessControl.sol";
import {SafeCast} from "../../utils/math/SafeCast.sol";
import {Math} from "../../utils/math/Math.sol";
import {IERC5313} from "../../interfaces/IERC5313.sol";
/**
* @dev Extension of {AccessControl} that allows specifying special rules to manage
* the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions
* over other roles that may potentially have privileged rights in the system.
*
* If a specific role doesn't have an admin role assigned, the holder of the
* `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.
*
* This contract implements the following risk mitigations on top of {AccessControl}:
*
* * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.
* * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
* * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.
* * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.
* * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.
*
* Example usage:
*
* ```solidity
* contract MyToken is AccessControlDefaultAdminRules {
* constructor() AccessControlDefaultAdminRules(
* 3 days,
* msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder
* ) {}
* }
* ```
*/
abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl {
// pending admin pair read/written together frequently
address private _pendingDefaultAdmin;
uint48 private _pendingDefaultAdminSchedule; // 0 == unset
uint48 private _currentDelay;
address private _currentDefaultAdmin;
// pending delay pair read/written together frequently
uint48 private _pendingDelay;
uint48 private _pendingDelaySchedule; // 0 == unset
/**
* @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
*/
constructor(uint48 initialDelay, address initialDefaultAdmin) {
if (initialDefaultAdmin == address(0)) {
revert AccessControlInvalidDefaultAdmin(address(0));
}
_currentDelay = initialDelay;
_grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC5313-owner}.
*/
function owner() public view virtual returns (address) {
return defaultAdmin();
}
///
/// Override AccessControl role management
///
/**
* @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super.grantRole(role, account);
}
/**
* @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super.revokeRole(role, account);
}
/**
* @dev See {AccessControl-renounceRole}.
*
* For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling
* {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule
* has also passed when calling this function.
*
* After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.
*
* NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},
* thereby disabling any functionality that is only available for it, and the possibility of reassigning a
* non-administrated role.
*/
function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
(address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
revert AccessControlEnforcedDefaultAdminDelay(schedule);
}
delete _pendingDefaultAdminSchedule;
}
super.renounceRole(role, account);
}
/**
* @dev See {AccessControl-_grantRole}.
*
* For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the
* role has been previously renounced.
*
* NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE`
* assignable again. Make sure to guarantee this is the expected behavior in your implementation.
*/
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
if (role == DEFAULT_ADMIN_ROLE) {
if (defaultAdmin() != address(0)) {
revert AccessControlEnforcedDefaultAdminRules();
}
_currentDefaultAdmin = account;
}
return super._grantRole(role, account);
}
/**
* @dev See {AccessControl-_revokeRole}.
*/
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
delete _currentDefaultAdmin;
}
return super._revokeRole(role, account);
}
/**
* @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super._setRoleAdmin(role, adminRole);
}
///
/// AccessControlDefaultAdminRules accessors
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdmin() public view virtual returns (address) {
return _currentDefaultAdmin;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelay() public view virtual returns (uint48) {
uint48 schedule = _pendingDelaySchedule;
return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
schedule = _pendingDelaySchedule;
return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
return 5 days;
}
///
/// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_beginDefaultAdminTransfer(newAdmin);
}
/**
* @dev See {beginDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
_setPendingDefaultAdmin(newAdmin, newSchedule);
emit DefaultAdminTransferScheduled(newAdmin, newSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_cancelDefaultAdminTransfer();
}
/**
* @dev See {cancelDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _cancelDefaultAdminTransfer() internal virtual {
_setPendingDefaultAdmin(address(0), 0);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function acceptDefaultAdminTransfer() public virtual {
(address newDefaultAdmin, ) = pendingDefaultAdmin();
if (_msgSender() != newDefaultAdmin) {
// Enforce newDefaultAdmin explicit acceptance.
revert AccessControlInvalidDefaultAdmin(_msgSender());
}
_acceptDefaultAdminTransfer();
}
/**
* @dev See {acceptDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _acceptDefaultAdminTransfer() internal virtual {
(address newAdmin, uint48 schedule) = pendingDefaultAdmin();
if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
revert AccessControlEnforcedDefaultAdminDelay(schedule);
}
_revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
_grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
delete _pendingDefaultAdmin;
delete _pendingDefaultAdminSchedule;
}
///
/// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_changeDefaultAdminDelay(newDelay);
}
/**
* @dev See {changeDefaultAdminDelay}.
*
* Internal function without access restriction.
*/
function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {
uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);
_setPendingDelay(newDelay, newSchedule);
emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_rollbackDefaultAdminDelay();
}
/**
* @dev See {rollbackDefaultAdminDelay}.
*
* Internal function without access restriction.
*/
function _rollbackDefaultAdminDelay() internal virtual {
_setPendingDelay(0, 0);
}
/**
* @dev Returns the amount of seconds to wait after the `newDelay` will
* become the new {defaultAdminDelay}.
*
* The value returned guarantees that if the delay is reduced, it will go into effect
* after a wait that honors the previously set delay.
*
* See {defaultAdminDelayIncreaseWait}.
*/
function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {
uint48 currentDelay = defaultAdminDelay();
// When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up
// to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day
// to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new
// delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like
// using milliseconds instead of seconds.
//
// When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees
// that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled.
// For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days.
return
newDelay > currentDelay
? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48
: currentDelay - newDelay;
}
///
/// Private setters
///
/**
* @dev Setter of the tuple for pending admin and its schedule.
*
* May emit a DefaultAdminTransferCanceled event.
*/
function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {
(, uint48 oldSchedule) = pendingDefaultAdmin();
_pendingDefaultAdmin = newAdmin;
_pendingDefaultAdminSchedule = newSchedule;
// An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.
if (_isScheduleSet(oldSchedule)) {
// Emit for implicit cancellations when another default admin was scheduled.
emit DefaultAdminTransferCanceled();
}
}
/**
* @dev Setter of the tuple for pending delay and its schedule.
*
* May emit a DefaultAdminDelayChangeCanceled event.
*/
function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {
uint48 oldSchedule = _pendingDelaySchedule;
if (_isScheduleSet(oldSchedule)) {
if (_hasSchedulePassed(oldSchedule)) {
// Materialize a virtual delay
_currentDelay = _pendingDelay;
} else {
// Emit for implicit cancellations when another delay was scheduled.
emit DefaultAdminDelayChangeCanceled();
}
}
_pendingDelay = newDelay;
_pendingDelaySchedule = newSchedule;
}
///
/// Private helpers
///
/**
* @dev Defines if an `schedule` is considered set. For consistency purposes.
*/
function _isScheduleSet(uint48 schedule) private pure returns (bool) {
return schedule != 0;
}
/**
* @dev Defines if an `schedule` is considered passed. For consistency purposes.
*/
function _hasSchedulePassed(uint48 schedule) private view returns (bool) {
return schedule < block.timestamp;
}
}
"
},
"dependencies/smartcontractkit-chainlink-evm-1.5.0/contracts/src/v0.8/shared/call/CallWithExactGas.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice This library contains various callWithExactGas functions. All of them are
/// safe from gas bomb attacks.
/// @dev There is code duplication in this library. This is done to not leave the assembly
/// the blocks.
library CallWithExactGas {
error NoContract();
error NoGasForCallExactCheck();
error NotEnoughGasForCall();
bytes4 internal constant NO_CONTRACT_SIG = 0x0c3b563c;
bytes4 internal constant NO_GAS_FOR_CALL_EXACT_CHECK_SIG = 0xafa32a2c;
bytes4 internal constant NOT_ENOUGH_GAS_FOR_CALL_SIG = 0x37c3be29;
/// @notice calls target address with exactly gasAmount gas and payload as calldata.
/// Accounts for gasForCallExactCheck gas that will be used by this function. Will revert
/// if the target is not a contact. Will revert when there is not enough gas to call the
/// target with gasAmount gas.
/// @dev Ignores the return data, which makes it immune to gas bomb attacks.
/// @return success whether the call succeeded
function _callWithExactGas(
bytes memory payload,
address target,
uint256 gasLimit,
uint16 gasForCallExactCheck
) internal returns (bool success) {
assembly {
// solidity calls check that a contract actually exists at the destination, so we do the same
// Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion")
// doesn't need to account for it.
if iszero(extcodesize(target)) {
mstore(0x0, NO_CONTRACT_SIG)
revert(0x0, 0x4)
}
let g := gas()
// Compute g -= gasForCallExactCheck and check for underflow
// The gas actually passed to the callee is _min(gasAmount, 63//64*gas available).
// We want to ensure that we revert if gasAmount > 63//64*gas available
// as we do not want to provide them with less, however that check itself costs
// gas. gasForCallExactCheck ensures we have at least enough gas to be able
// to revert if gasAmount > 63//64*gas available.
if lt(g, gasForCallExactCheck) {
mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG)
revert(0x0, 0x4)
}
g := sub(g, gasForCallExactCheck)
// if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150
if iszero(gt(sub(g, div(g, 64)), gasLimit)) {
mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG)
revert(0x0, 0x4)
}
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
}
return success;
}
/// @notice calls target address with exactly gasAmount gas and payload as calldata.
/// Account for gasForCallExactCheck gas that will be used by this function. Will revert
/// if the target is not a contact. Will revert when there is not enough gas to call the
/// target with gasAmount gas.
/// @dev Caps the return data length, which makes it immune to gas bomb attacks.
/// @dev Return data cap logic borrowed from
/// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
/// @return success whether the call succeeded
/// @return retData the return data from the call, capped at maxReturnBytes bytes
/// @return gasUsed the gas used by the external call. Does not include the overhead of this function.
function _callWithExactGasSafeReturnData(
bytes memory payload,
address target,
uint256 gasLimit,
uint16 gasForCallExactCheck,
uint16 maxReturnBytes
) internal returns (bool success, bytes memory retData, uint256 gasUsed) {
// allocate retData memory ahead of time
retData = new bytes(maxReturnBytes);
assembly {
// solidity calls check that a contract actually exists at the destination, so we do the same
// Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion")
// doesn't need to account for it.
if iszero(extcodesize(target)) {
mstore(0x0, NO_CONTRACT_SIG)
revert(0x0, 0x4)
}
let g := gas()
// Compute g -= gasForCallExactCheck and check for underflow
// The gas actually passed to the callee is _min(gasAmount, 63//64*gas available).
// We want to ensure that we revert if gasAmount > 63//64*gas available
// as we do not want to provide them with less, however that check itself costs
// gas. gasForCallExactCheck ensures we have at least enough gas to be able
// to revert if gasAmount > 63//64*gas available.
if lt(g, gasForCallExactCheck) {
mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG)
revert(0x0, 0x4)
}
g := sub(g, gasForCallExactCheck)
// if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150
if iszero(gt(sub(g, div(g, 64)), gasLimit)) {
mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG)
revert(0x0, 0x4)
}
// We save the gas before the call so we can calculate how much gas the call used
let gasBeforeCall := gas()
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
gasUsed := sub(gasBeforeCall, gas())
// limit our copy to maxReturnBytes bytes
let toCopy := returndatasize()
if gt(toCopy, maxReturnBytes) { toCopy := maxReturnBytes }
// Store the length of the copied bytes
mstore(retData, toCopy)
// copy the bytes from retData[0:_toCopy]
returndatacopy(add(retData, 0x20), 0x0, toCopy)
}
return (success, retData, gasUsed);
}
/// @notice Calls target address with exactly gasAmount gas and payload as calldata
/// or reverts if at least gasLimit gas is not available.
/// @dev Does not check if target is a contract. If it is not a contract, the low-level
/// call will still be made and it will succeed.
/// @dev Ignores the return data, which makes it immune to gas bomb attacks.
/// @return success whether the call succeeded
/// @return sufficientGas Whether there was enough gas to make the call
function _callWithExactGasEvenIfTargetIsNoContract(
bytes memory payload,
address target,
uint256 gasLimit,
uint16 gasForCallExactCheck
) internal returns (bool success, bool sufficientGas) {
assembly {
let g := gas()
// Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
// need the cushion since the logic following the above call to gas also
// costs gas which we cannot account for exactly. So cushion is a
// conservative upper bound for the cost of this logic.
if iszero(lt(g, gasForCallExactCheck)) {
g := sub(g, gasForCallExactCheck)
// If g - g//64 <= gasAmount, we don't have enough gas. We subtract g//64 because of EIP-150.
if gt(sub(g, div(g, 64)), gasLimit) {
// Call and ignore success/return data. Note that we did not check
// whether a contract actually exists at the target address.
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
sufficientGas := true
}
}
}
return (success, sufficientGas);
}
}
"
},
"src/query-router/interfaces/ICallbackExecutor.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {GasCost} from "../libraries/GasCost.sol";
/// @title ICallbackExecutor
/// @author Placeholder
/// @notice Interface for the CallbackExecutor contract
interface ICallbackExecutor {
/// @notice Emitted when gas cost config is updated
/// @param newConfig The new gas cost configuration
event GasCostConfigUpdated(GasCost.GasCostConfig newConfig);
/// @notice Emitted when a callback execution fails
/// @param target The address of the target contract
/// @param returnData First four bytes of return data from the failed call
event CallbackFailed(address indexed target, bytes returnData);
/// @notice Emitted when execute is called on an address without a contract
/// @param target The address that had no contract
event NoCallbackContract(address indexed target);
/// @notice Emitted when the max gas limit is updated
/// @param newMax The new max gas limit
event MaxGasLimitUpdated(uint256 indexed newMax);
/// @notice Allows admin to update the gas cost configuration
/// @param newConfig New gas cost configuration struct
function setGasCostConfig(GasCost.GasCostConfig calldata newConfig) external;
/// @notice Set the maximum gas limit that may be passed to `execute`
/// @param newMax The new maximum gas limit (0 disables callbacks with gas)
function setMaxGasLimit(uint256 newMax) external;
/// @notice Executes a call to the target contract with a gas limit and returns gas used
/// @param target The address of the target contract
/// @param data The data to send to the target contract
/// @param gasLimit The gas limit for the call
/// @param maxGasPrice The max gas price for the call
/// @param additionalGasUsed Additional gas used to account for overhead/external factors
/// @return gasUsed The amount of gas used for the call
function execute(
address target,
bytes calldata data,
uint256 gasLimit,
uint256 maxGasPrice,
uint256 additionalGasUsed
) external returns (uint256 gasUsed);
}
"
},
"src/query-router/libraries/GasCost.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {
AggregatorV3Interface
} from "smartcontractkit-chainlink-evm-1.5.0/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
/// @title GasCost
/// @author Placeholder
/// @notice Library for converting gas cost to token amount using Chainlink price feeds
library GasCost {
using GasCost for GasCost.GasCostConfig;
/// @notice Gas cost configuration
/// @param nativeUsdFeed Chainlink native token / USD feed address
/// @param nativeStaleThreshold Max seconds before native feed is stale
/// @param tokenUsdFeed Chainlink payment token / USD feed address
/// @param tokenStaleThreshold Max seconds before token feed is stale
/// @param scalingFactor Multiplier to scale USD value; 0 allows free gas
struct GasCostConfig {
address nativeUsdFeed;
uint64 nativeStaleThreshold;
address tokenUsdFeed;
uint64 tokenStaleThreshold;
uint256 scalingFactor;
}
/// @dev Constant for the zero address
address internal constant ZERO_ADDRESS = address(0);
/// @dev Constant for the smallest positive value for Chainlink price feeds
int256 internal constant SMALLEST_POSITIVE_VALUE = 1;
/// @notice Thrown when Chainlink price feed data is invalid
error InvalidPriceFeedData();
/// @notice Thrown when Chainlink price feed data is stale
error StalePriceFeedData();
/// @notice Thrown when GasCostConfig is invalid
error InvalidGasCostConfig();
/// @notice Validate and return the latest price from a Chainlink feed
/// @param feed Address of the Chainlink price feed
/// @param staleThreshold Threshold in seconds for staleness
/// @return price The validated price from the feed
function checkedPrice(address feed, uint256 staleThreshold) internal view returns (uint256 price) {
// slither-disable-next-line unused-return
(, int256 answer, uint256 startedAt, uint256 updatedAt,) = AggregatorV3Interface(feed).latestRoundData();
if (answer < SMALLEST_POSITIVE_VALUE || startedAt == 0) {
revert InvalidPriceFeedData();
}
// solhint-disable-next-line not-rely-on-time
if (updatedAt + staleThreshold < block.timestamp) {
revert StalePriceFeedData();
}
// forge-lint: disable-next-line(unsafe-typecast)
price = uint256(answer);
}
/// @notice Calculate scaled gas cost in USD and token USD price
/// @param config GasCostConfig with feed addresses and thresholds
/// @param maxGasPrice Maximum gas price to use for calculation
/// @return scaledGasCostInUsd Scaled gas cost in USD
/// @return tokenUsdPrice Token price in USD
function gasCost(GasCostConfig storage config, uint256 maxGasPrice)
internal
view
returns (uint256 scaledGasCostInUsd, uint256 tokenUsdPrice)
{
uint256 effectiveGasPrice = tx.gasprice < maxGasPrice ? tx.gasprice : maxGasPrice;
uint256 nativeUsdPrice = checkedPrice(config.nativeUsdFeed, config.nativeStaleThreshold);
scaledGasCostInUsd = effectiveGasPrice * nativeUsdPrice * config.scalingFactor;
tokenUsdPrice = checkedPrice(config.tokenUsdFeed, config.tokenStaleThreshold);
}
/// @notice Validate a GasCostConfig for contract use
/// @param config GasCostConfig to validate
/// @dev Reverts if any feed address or threshold is zero
function validateConfig(GasCostConfig memory config) internal pure {
if (config.nativeUsdFeed == ZERO_ADDRESS) revert InvalidGasCostConfig();
if (config.nativeStaleThreshold == 0) revert InvalidGasCostConfig();
if (config.tokenUsdFeed == ZERO_ADDRESS) revert InvalidGasCostConfig();
if (config.tokenStaleThreshold == 0) revert InvalidGasCostConfig();
}
}
"
},
"dependencies/@openzeppelin-contracts-5.2.0/access/extensions/IAccessControlDefaultAdminRules.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/IAccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlDefaultAdminRules declared to support ERC-165 detection.
*/
interface IAccessControlDefaultAdminRules is IAccessControl {
/**
* @dev The new default admin is not a valid default admin.
*/
error AccessControlInvalidDefaultAdmin(address defaultAdmin);
/**
* @dev At least one of the following rules was violated:
*
* - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.
* - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.
* - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.
*/
error AccessControlEnforcedDefaultAdminRules();
/**
* @dev The delay for transferring the default admin delay is enforced and
* the operation must wait until `schedule`.
*
* NOTE: `schedule` can be 0 indicating there's no transfer scheduled.
*/
error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);
/**
* @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next
* address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`
* passes.
*/
event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);
/**
* @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule.
*/
event DefaultAdminTransferCanceled();
/**
* @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next
* delay to be applied between default admin transfer after `effectSchedule` has passed.
*/
event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);
/**
* @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass.
*/
event DefaultAdminDelayChangeCanceled();
/**
* @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder.
*/
function defaultAdmin() external view returns (address);
/**
* @dev Returns a tuple of a `newAdmin` and an accept schedule.
*
* After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role
* by calling {acceptDefaultAdminTransfer}, completing the role transfer.
*
* A zero value only in `acceptSchedule` indicates no pending admin transfer.
*
* NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced.
*/
function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule);
/**
* @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started.
*
* This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set
* the acceptance schedule.
*
* NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this
* function returns the new delay. See {changeDefaultAdminDelay}.
*/
function defaultAdminDelay() external view returns (uint48);
/**
* @dev Returns a tuple of `newDelay` and an effect schedule.
*
* After the `schedule` passes, the `newDelay` will get into effect immediately for every
* new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}.
*
* A zero value only in `effectSchedule` indicates no pending delay change.
*
* NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay}
* will be zero after the effect schedule.
*/
function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule);
/**
* @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance
* after the current timestamp plus a {defaultAdminDelay}.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* Emits a DefaultAdminRoleChangeStarted event.
*/
function beginDefaultAdminTransfer(address newAdmin) external;
/**
* @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
*
* A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* May emit a DefaultAdminTransferCanceled event.
*/
function cancelDefaultAdminTransfer() external;
/**
* @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
*
* After calling the function:
*
* - `DEFAULT_ADMIN_ROLE` should be granted to the caller.
* - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder.
* - {pendingDefaultAdmin} should be reset to zero values.
*
* Requirements:
*
* - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`.
* - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed.
*/
function acceptDefaultAdminTransfer() external;
/**
* @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting
* into effect after the current timestamp plus a {defaultAdminDelay}.
*
* This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this
* method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay}
* set before calling.
*
* The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then
* calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin}
* complete transfer (including acceptance).
*
* The schedule is designed for two scenarios:
*
* - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by
* {defaultAdminDelayIncreaseWait}.
* - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`.
*
* A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event.
*/
function changeDefaultAdminDelay(uint48 newDelay) external;
/**
* @dev Cancels a scheduled {defaultAdminDelay} change.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* May emit a DefaultAdminDelayChangeCanceled event.
*/
function rollbackDefaultAdminDelay() external;
/**
* @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay})
* to take effect. Default to 5 days.
*
* When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with
* the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds)
* that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can
* be overrode for a custom {defaultAdminDelay} increase scheduling.
*
* IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise,
* there's a risk of setting a high new delay that goes into effect almost immediately without the
* possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds).
*/
function defaultAdminDelayIncreaseWait() external view returns (uint48);
}
"
},
"dependencies/@openzeppelin-contracts-5.2.0/access/AccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
"
},
"dependencies/@openzeppelin-contracts-5.2.0/utils/math/SafeCast.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest u
Submitted on: 2025-11-07 19:49:34
Comments
Log in to comment.
No comments yet.