Contract Name:
ERC4626_ST_AaveV3_JT_IdenticalAssets_Kernel
Contract Source Code:
<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { IRoycoVaultTranche } from "../interfaces/tranche/IRoycoVaultTranche.sol";
import { RoycoKernelInitParams } from "../libraries/RoycoKernelStorageLib.sol";
import { AaveV3_JT_Kernel } from "./base/junior/AaveV3_JT_Kernel.sol";
import { IdenticalAssetsQuoter } from "./base/quoter/IdenticalAssetsQuoter.sol";
import { ERC4626_ST_Kernel } from "./base/senior/ERC4626_ST_Kernel.sol";
/**
* @title ERC4626_ST_AaveV3_JT_IdenticalAssets_Kernel
* @notice The senior tranche is deployed into a ERC4626 compliant vault and the junior tranche is deployed into Aave V3
* @notice The tranche assets are identical in value and precision (eg. USDC for both tranches, USDC and USDT, etc.)
* @notice Tranche and NAV units are always expressed in the tranche asset's precision
*/
contract ERC4626_ST_AaveV3_JT_IdenticalAssets_Kernel is ERC4626_ST_Kernel, AaveV3_JT_Kernel, IdenticalAssetsQuoter {
/**
* @notice Initializes the Royco Kernel
* @param _params The standard initialization parameters for the Royco Kernel
* @param _stVault The ERC4626 compliant vault that the senior tranche will deploy into
* @param _aaveV3Pool The Aave V3 Pool that the junior tranche will deploy into
*/
function initialize(RoycoKernelInitParams calldata _params, address _stVault, address _aaveV3Pool) external initializer {
// Get the base assets for both tranches and ensure that they are identical
address stAsset = IRoycoVaultTranche(_params.seniorTranche).asset();
address jtAsset = IRoycoVaultTranche(_params.juniorTranche).asset();
// Initialize the base kernel state
__RoycoKernel_init(_params, stAsset, jtAsset);
// Initialize the ERC4626 senior tranche state
__ERC4626_ST_Kernel_init_unchained(_stVault, stAsset);
// Initialize the Aave V3 junior tranche state
__AaveV3_JT_Kernel_init_unchained(_aaveV3Pool, jtAsset);
// Initialize the identical assets quoter
__IdenticalAssetsQuoter_init_unchained(stAsset, jtAsset);
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { IERC165 } from "../../../lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol";
import { AssetClaims } from "../../libraries/Types.sol";
import { NAV_UNIT, TRANCHE_UNIT } from "../../libraries/Units.sol";
import { IRoycoAsyncCancellableVault } from "./IRoycoAsyncCancellableVault.sol";
import { IRoycoAsyncVault } from "./IRoycoAsyncVault.sol";
interface IRoycoVaultTranche is IERC165, IRoycoAsyncVault, IRoycoAsyncCancellableVault {
/**
* @notice Emitted when a deposit is made
* @param sender The address that made the deposit
* @param owner The address that owns the shares
* @param assets The amount of assets deposited
* @param shares The amount of shares minted
* @param metadata The format prefixed metadata of the deposit or empty bytes if no metadata is shared
*/
event Deposit(address indexed sender, address indexed owner, TRANCHE_UNIT assets, uint256 shares, bytes metadata);
/**
* @notice Emitted when a redemption is made
* @param sender The address that made the redemption
* @param receiver The address of the receiver of the redeemed assets
* @param claims A struct representing the assets received on redemption and their value at the time of redemption in NAV units
* @param shares The total amount of shares redeemed
* @param metadata The format prefixed metadata of the redemption or empty bytes if no metadata is shared
*/
event Redeem(address indexed sender, address indexed receiver, AssetClaims claims, uint256 shares, bytes metadata);
/**
* @notice Emitted when protocol fee shares are minted to the protocol fee recipient
* @param protocolFeeRecipient The address that received the protocol fee shares
* @param mintedProtocolFeeShares The number of protocol fee shares that were minted
* @param totalTrancheShares The total number of shares that exist in the tranche after minting any protocol fee shares post-sync
*/
event ProtocolFeeSharesMinted(address indexed protocolFeeRecipient, uint256 mintedProtocolFeeShares, uint256 totalTrancheShares);
/**
* @notice Returns the raw net asset value of the tranche's invested assets
* @dev Excludes yield splits, coverage applications, etc.
* @dev The NAV is expressed in the tranche's base asset
* @return nav The raw net asset value of the tranche's invested assets
*/
function getRawNAV() external view returns (NAV_UNIT nav);
/**
* @notice Returns the address of the kernel contract handling strategy logic
*/
function kernel() external view returns (address);
/**
* @notice Returns the identifier of the Royco market this tranche is linked to
*/
function marketId() external view returns (bytes32);
/**
* @notice Returns the total effective assets in the tranche's NAV units
* @dev Includes yield splits, coverage applications, etc.
* @dev The NAV is expressed in the tranche's base asset
* @return claims The breakdown of assets that represent the value of the tranche's shares
*/
function totalAssets() external view returns (AssetClaims memory claims);
/**
* @notice Returns the maximum amount of assets that can be deposited into the tranche
* @dev The assets are expressed in the tranche's base asset
* @param _receiver The address to receive the deposited assets
* @return assets The maximum amount of assets that can be deposited into the tranche
*/
function maxDeposit(address _receiver) external view returns (TRANCHE_UNIT assets);
/**
* @notice Returns the maximum amount of shares that can be redeemed from the tranche
* @dev The shares are expressed in the tranche's base asset
* @param _owner The address to redeem the shares from
* @return shares The maximum amount of shares that can be redeemed from the tranche
*/
function maxRedeem(address _owner) external view returns (uint256 shares);
/**
* @notice Returns the number of shares that would be minted for a given amount of assets
* @dev The assets are expressed in the tranche's base asset
* @dev Disabled if deposit execution is asynchronous
* @param _assets The amount of assets to preview the deposit for
* @return shares The number of shares that would be minted for a given amount of assets
*/
function previewDeposit(TRANCHE_UNIT _assets) external view returns (uint256 shares);
/**
* @notice Returns the number of shares that would be minted for a given amount of assets
* @dev The assets are expressed in the tranche's base asset
* @param _assets The amount of assets to convert to shares
* @return shares The number of shares that would be minted for a given amount of assets
*/
function convertToShares(TRANCHE_UNIT _assets) external view returns (uint256 shares);
/**
* @notice Returns the breakdown of assets that the shares have a claim on
* @dev The shares are expressed in the tranche's base asset
* @dev Disabled if redemption execution is asynchronous
* @param _shares The number of shares to convert to claims
* @return claims The breakdown of assets that the shares have a claim on
*/
function previewRedeem(uint256 _shares) external view returns (AssetClaims memory claims);
/**
* @notice Returns the breakdown of assets that the shares have a claim on
* @dev The shares are expressed in the tranche's base asset
* @param _shares The number of shares to convert to assets
* @return claims The breakdown of assets that the shares have a claim on
*/
function convertToAssets(uint256 _shares) external view returns (AssetClaims memory claims);
/**
* @notice Mints tranche shares to the receiver
* @dev The assets are expressed in the tranche's base asset
* @param _assets The amount of assets to mint
* @param _receiver The address to mint the shares to
* @param _controller The controller of the request
* @return shares The number of shares that were minted
* @return metadata The format prefixed metadata of the deposit or empty bytes if no metadata is shared
*/
function deposit(TRANCHE_UNIT _assets, address _receiver, address _controller) external returns (uint256 shares, bytes memory metadata);
/**
* @notice Redeems tranche shares from the owner
* @dev The shares are expressed in the tranche's base asset
* @param _shares The number of shares to redeem
* @param _receiver The address to redeem the shares to
* @param _controller The controller of the request
* @return claims The breakdown of assets that the redeemed shares have a claim on
* @return metadata The format prefixed metadata of the redemption or empty bytes if no metadata is shared
*/
function redeem(uint256 _shares, address _receiver, address _controller) external returns (AssetClaims memory claims, bytes memory metadata);
/**
* @notice Previews the number of shares that would be minted to the protocol fee recipient to satisfy the ratio of total assets that the fee represents
* @dev The fee assets are expressed in the tranche's base asset
* @param _protocolFeeAssets The fee accrued for this tranche as a result of the pre-op sync
* @param _trancheTotalAssets The total effective assets controlled by this tranche as a result of the pre-op sync
* @return mintedProtocolFeeShares The number of protocol fee shares that would be minted to the protocol fee recipient
* @return totalTrancheShares The total number of shares that exist in the tranche after minting any protocol fee shares post-sync
*/
function previewMintProtocolFeeShares(
NAV_UNIT _protocolFeeAssets,
NAV_UNIT _trancheTotalAssets
)
external
view
returns (uint256 mintedProtocolFeeShares, uint256 totalTrancheShares);
/**
* @notice Mints tranche shares to the protocol fee recipient, representing ownership over the fee assets of the tranche
* @dev Must be called by the tranche's kernel everytime protocol fees are accrued in its pre-op synchronization
* @param _protocolFeeAssets The fee accrued for this tranche as a result of the pre-op sync
* @param _protocolFeeRecipient The address to receive the freshly minted protocol fee shares
* @param _trancheTotalAssets The total effective assets controlled by this tranche as a result of the pre-op sync
* @return mintedProtocolFeeShares The number of protocol fee shares that were minted to the protocol fee recipient
* @return totalTrancheShares The total number of shares that exist in the tranche after minting any protocol fee shares post-sync
*/
function mintProtocolFeeShares(
NAV_UNIT _protocolFeeAssets,
NAV_UNIT _trancheTotalAssets,
address _protocolFeeRecipient
)
external
returns (uint256 mintedProtocolFeeShares, uint256 totalTrancheShares);
/**
* @notice Returns the address of the tranche's deposit asset
* @return asset The address of the tranche's deposit asset
*/
function asset() external view returns (address asset);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { NAV_UNIT } from "./Units.sol";
/**
* @notice Initialization parameters for the Royco Kernel
* @custom:field initialAuthority - The access manager for this kernel
* @custom:field seniorTranche - The address of the Royco senior tranche associated with this kernel
* @custom:field juniorTranche - The address of the Royco junior tranche associated with this kernel
* @custom:field accountant - The address of the Royco accountant used to perform per operation accounting for this kernel
* @custom:field protocolFeeRecipient - The market's protocol fee recipient
* @custom:field claimableAtTimestamp - The timestamp at which the redemption request is allowed to be claimed
* @custom:field jtRedemptionDelayInSeconds - The redemption delay in seconds that a JT LP has to wait between requesting and executing a redemption
*/
struct RoycoKernelInitParams {
address initialAuthority;
address seniorTranche;
address juniorTranche;
address accountant;
address protocolFeeRecipient;
uint24 jtRedemptionDelayInSeconds;
}
/**
* @notice Storage state for the Royco Kernel
* @custom:storage-location erc7201:Royco.storage.RoycoKernelState
* @custom:field seniorTranche - The address of the Royco senior tranche associated with this kernel
* @custom:field stAsset - The address of the asset that ST is denominated in: constitutes the ST's tranche units (type and precision)
* @custom:field juniorTranche - The address of the Royco junior tranche associated with this kernel
* @custom:field jtAsset - The address of the asset that JT is denominated in: constitutes the ST's tranche units (type and precision)
* @custom:field protocolFeeRecipient - The market's configured protocol fee recipient
* @custom:field accountant - The address of the Royco accountant used to perform per operation accounting for this kernel
* @custom:field jtRedemptionDelayInSeconds - The redemption delay in seconds that a JT LP has to wait between requesting and executing a redemption
* @custom:field jtControllerToRedemptionRequest - A mapping between a controller and their redemption request state for the junior tranche
*/
struct RoycoKernelState {
address seniorTranche;
address stAsset;
address juniorTranche;
address jtAsset;
address protocolFeeRecipient;
address accountant;
uint24 jtRedemptionDelayInSeconds;
mapping(address controller => RedemptionRequest request) jtControllerToRedemptionRequest;
}
/**
* @notice The state of a JT LP's redemption request
* @custom:field isCanceled - A boolean indicating whether the redemption request has been canceled
* @custom:field claimableAtTimestamp - The timestamp at which the redemption request is allowed to be claimed/executed
* @custom:field totalJTSharesToRedeem - The total number of JT shares to redeem
* @custom:field redemptionValueAtRequestTime - The NAV of the redemption request at the time it was requested
*/
struct RedemptionRequest {
bool isCanceled;
uint32 claimableAtTimestamp;
uint256 totalJTSharesToRedeem;
NAV_UNIT redemptionValueAtRequestTime;
}
/// @title RoycoKernelStorageLib
/// @notice Library for managing Royco Kernel storage using the ERC7201 pattern
library RoycoKernelStorageLib {
/// @dev Storage slot for RoycoKernelState using ERC-7201 pattern
// keccak256(abi.encode(uint256(keccak256("Royco.storage.RoycoKernelState")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant BASE_KERNEL_STORAGE_SLOT = 0xf8fc0d016168fef0a165a086b5a5dc3ffa533689ceaf1369717758ae5224c600;
/// @notice Initializes the Royco kernel state
/// @param _params The initialization parameters for the kernel
function __RoycoKernel_init(RoycoKernelInitParams memory _params, address _stAsset, address _jtAsset) internal {
// Set the initial state of the kernel
RoycoKernelState storage $ = _getRoycoKernelStorage();
$.seniorTranche = _params.seniorTranche;
$.stAsset = _stAsset;
$.juniorTranche = _params.juniorTranche;
$.jtAsset = _jtAsset;
$.protocolFeeRecipient = _params.protocolFeeRecipient;
$.accountant = _params.accountant;
$.jtRedemptionDelayInSeconds = _params.jtRedemptionDelayInSeconds;
}
/**
* @notice Returns a storage pointer to the RoycoKernelState storage
* @dev Uses ERC-7201 storage slot pattern for collision-resistant storage
* @return $ Storage pointer to the kernel's state
*/
function _getRoycoKernelStorage() internal pure returns (RoycoKernelState storage $) {
assembly ("memory-safe") {
$.slot := BASE_KERNEL_STORAGE_SLOT
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { IERC20, SafeERC20 } from "../../../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import { IPool } from "../../../interfaces/aave/IPool.sol";
import { IPoolAddressesProvider } from "../../../interfaces/aave/IPoolAddressesProvider.sol";
import { IPoolDataProvider } from "../../../interfaces/aave/IPoolDataProvider.sol";
import { ExecutionModel, IRoycoKernel } from "../../../interfaces/kernel/IRoycoKernel.sol";
import { MAX_TRANCHE_UNITS, ZERO_TRANCHE_UNITS } from "../../../libraries/Constants.sol";
import { NAV_UNIT, TRANCHE_UNIT, UnitsMathLib, toTrancheUnits, toUint256 } from "../../../libraries/Units.sol";
import { RoycoKernel, RoycoKernelStorageLib, SyncedAccountingState } from "../RoycoKernel.sol";
abstract contract AaveV3_JT_Kernel is RoycoKernel {
using SafeERC20 for IERC20;
using UnitsMathLib for TRANCHE_UNIT;
/// @dev Storage slot for AaveV3_JT_KernelState using ERC-7201 pattern
// keccak256(abi.encode(uint256(keccak256("Royco.storage.AaveV3_JT_KernelState")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AAVE_V3_JT_KERNEL_STORAGE_SLOT = 0xbd2cea01170a8a3a63be09b675f1b67e378a959a79f759c2a857613313f76400;
/// @inheritdoc IRoycoKernel
ExecutionModel public constant JT_DEPOSIT_EXECUTION_MODEL = ExecutionModel.SYNC;
/**
* @notice Storage state for the Royco Aave V3 Kernel
* @custom:storage-location erc7201:Royco.storage.AaveV3_JT_KernelState
* @custom:field pool - The address of the Aave V3 pool
* @custom:field poolAddressesProvider - The address of the Aave V3 pool addresses provider
* @custom:field jtAssetAToken - The address of the junior tranche base asset's A Token
*/
struct AaveV3_JT_KernelState {
address pool;
address poolAddressesProvider;
address jtAssetAToken;
}
/// @notice Thrown when the JT base asset is not a supported reserve token in the Aave V3 Pool
error UNSUPPORTED_RESERVE_TOKEN();
/// @notice Thrown when a low-level call fails
error FAILED_CALL();
/**
* @notice Initializes a kernel where the junior tranche is deployed into Aave V3 with a redemption delay
* @param _aaveV3Pool The address of the Aave V3 Pool
* @param _jtAsset The address of the base asset of the junior tranche
*/
function __AaveV3_JT_Kernel_init_unchained(address _aaveV3Pool, address _jtAsset) internal onlyInitializing {
// Initialize the Aave V3 junior tranche kernel state
// Ensure that the JT base asset is a supported reserve token in the Aave V3 Pool
address jtAssetAToken = IPool(_aaveV3Pool).getReserveAToken(_jtAsset);
require(jtAssetAToken != address(0), UNSUPPORTED_RESERVE_TOKEN());
// Extend a one time max approval to the Aave V3 pool for the JT's base asset
IERC20(_jtAsset).forceApprove(_aaveV3Pool, type(uint256).max);
// Set the initial state of the Aave V3 kernel
AaveV3_JT_KernelState storage $ = _getAaveV3_JT_KernelStorage();
$.pool = _aaveV3Pool;
$.poolAddressesProvider = address(IPool(_aaveV3Pool).ADDRESSES_PROVIDER());
$.jtAssetAToken = jtAssetAToken;
}
/// @inheritdoc IRoycoKernel
function jtPreviewDeposit(TRANCHE_UNIT _assets)
external
view
override
onlyJuniorTranche
returns (SyncedAccountingState memory stateBeforeDeposit, NAV_UNIT valueAllocated)
{
// Preview the deposit by converting the assets to NAV units and returning the NAV at which the shares will be minted
valueAllocated = jtConvertTrancheUnitsToNAVUnits(_assets);
stateBeforeDeposit = _previewSyncTrancheAccounting();
}
/// @inheritdoc RoycoKernel
function _getJuniorTrancheRawNAV() internal view override(RoycoKernel) returns (NAV_UNIT) {
// The tranche's balance of the AToken is the total assets it is owed from the Aave pool
/// @dev This does not treat illiquidity in the Aave pool as a loss: we assume that total lent will be withdrawable at some point
return jtConvertTrancheUnitsToNAVUnits(toTrancheUnits(IERC20(_getAaveV3_JT_KernelStorage().jtAssetAToken).balanceOf(address(this))));
}
/// @inheritdoc RoycoKernel
function _jtMaxDepositGlobally(address) internal view override(RoycoKernel) returns (TRANCHE_UNIT) {
// Retrieve the Pool's data provider and asset
IPoolDataProvider poolDataProvider =
IPoolDataProvider(IPoolAddressesProvider(_getAaveV3_JT_KernelStorage().poolAddressesProvider).getPoolDataProvider());
address asset = RoycoKernelStorageLib._getRoycoKernelStorage().jtAsset;
// If the reserve asset is inactive, frozen, or paused, supplies are forbidden
(uint256 decimals,,,,,,,, bool isActive, bool isFrozen) = poolDataProvider.getReserveConfigurationData(asset);
if (!isActive || isFrozen || poolDataProvider.getPaused(asset)) return ZERO_TRANCHE_UNITS;
// Get the supply cap for the reserve asset. If unset, the suppliable amount is unbounded
(, uint256 supplyCap) = poolDataProvider.getReserveCaps(asset);
if (supplyCap == 0) return MAX_TRANCHE_UNITS;
// Compute the total reserve assets supplied and accrued to the treasury
(uint256 totalAccruedToTreasury, uint256 totalLent) = _getTotalAccruedToTreasuryAndLent(poolDataProvider, asset);
uint256 currentlySupplied = totalLent + totalAccruedToTreasury;
// Supply cap was returned as whole tokens, so we must scale by underlying decimals
supplyCap = supplyCap * (10 ** decimals);
// If supply cap hit, no incremental supplies are permitted. Else, return the max suppliable amount within the cap.
return toTrancheUnits((currentlySupplied >= supplyCap) ? 0 : (supplyCap - currentlySupplied));
}
/**
* @notice Helper function to get the total accrued to treasury and total lent from the pool data provider
* @dev IPoolDataProvider.getReserveData returns a tuple of 11 words which saturates the stack
* @dev Uses a low-level static call to the pool data provider to avoid stack too deep errors
* @param _poolDataProvider The Aave V3 pool data provider
* @param _asset The asset to get the total lent data for
* @return totalAccruedToTreasury The total assets accrued to the Aave treasury that exist in the lending pool
* @return totalLent The total assets lent and owned by lenders of the pool
*/
function _getTotalAccruedToTreasuryAndLent(
IPoolDataProvider _poolDataProvider,
address _asset
)
internal
view
returns (uint256 totalAccruedToTreasury, uint256 totalLent)
{
bytes memory data = abi.encodeCall(IPoolDataProvider.getReserveData, (_asset));
bool success;
assembly ("memory-safe") {
// Load the free memory pointer, and allocate 0x60 bytes for the return data
let ptr := mload(0x40)
mstore(0x40, add(ptr, 0x60))
// Make the static call to the pool data provider
success := staticcall(gas(), _poolDataProvider, add(data, 0x20), mload(data), ptr, 0x60)
// Load the total accrued to treasury and total lent from the return data
// Refer IPoolDataProvider.getReserveData for the return data layout
totalAccruedToTreasury := mload(add(ptr, 0x20))
totalLent := mload(add(ptr, 0x40))
}
require(success, FAILED_CALL());
}
/// @inheritdoc RoycoKernel
function _jtMaxWithdrawableGlobally(address) internal view override(RoycoKernel) returns (TRANCHE_UNIT) {
// Retrieve the Pool's data provider and asset
AaveV3_JT_KernelState storage $ = _getAaveV3_JT_KernelStorage();
IPoolDataProvider poolDataProvider = IPoolDataProvider(IPoolAddressesProvider($.poolAddressesProvider).getPoolDataProvider());
address asset = RoycoKernelStorageLib._getRoycoKernelStorage().jtAsset;
// If the reserve asset is inactive or paused, withdrawals are forbidden
(,,,,,,,, bool isActive,) = poolDataProvider.getReserveConfigurationData(asset);
if (!isActive || poolDataProvider.getPaused(asset)) return ZERO_TRANCHE_UNITS;
// Return the unborrowed/reserve assets of the pool
return toTrancheUnits(IERC20(asset).balanceOf($.jtAssetAToken));
}
/// @inheritdoc RoycoKernel
function _jtPreviewWithdraw(TRANCHE_UNIT _jtAssets) internal pure override(RoycoKernel) returns (TRANCHE_UNIT withdrawnJTAssets) {
return _jtAssets;
}
/// @inheritdoc RoycoKernel
function _jtDepositAssets(TRANCHE_UNIT _jtAssets) internal override(RoycoKernel) {
// Supply the specified assets to the pool
// Max approval already given to the pool on initialization
IPool(_getAaveV3_JT_KernelStorage().pool).supply(RoycoKernelStorageLib._getRoycoKernelStorage().jtAsset, toUint256(_jtAssets), address(this), 0);
}
/// @inheritdoc RoycoKernel
function _jtWithdrawAssets(TRANCHE_UNIT _jtAssets, address _receiver) internal override(RoycoKernel) {
// Try and withdraw the requested assets from the Aave pool
AaveV3_JT_KernelState storage $ = _getAaveV3_JT_KernelStorage();
(bool withdrawalSucceeded,) =
$.pool.call(abi.encodeCall(IPool.withdraw, (RoycoKernelStorageLib._getRoycoKernelStorage().jtAsset, toUint256(_jtAssets), _receiver)));
if (withdrawalSucceeded) return;
// The Pool lacks the liquidity to withdraw the requested assets, transfer A Tokens instead
IERC20($.jtAssetAToken).safeTransfer(_receiver, toUint256(_jtAssets));
}
/**
* @notice Returns a storage pointer to the AaveV3_JT_KernelState storage
* @dev Uses ERC-7201 storage slot pattern for collision-resistant storage
* @return $ Storage pointer to the Aave V3 JT kernel state
*/
function _getAaveV3_JT_KernelStorage() internal pure returns (AaveV3_JT_KernelState storage $) {
assembly ("memory-safe") {
$.slot := AAVE_V3_JT_KERNEL_STORAGE_SLOT
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { IERC20Metadata } from "../../../../lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol";
import { NAV_UNIT, TRANCHE_UNIT, toNAVUnits, toTrancheUnits, toUint256 } from "../../../libraries/Units.sol";
import { RoycoKernel } from "../RoycoKernel.sol";
/**
* @title IdenticalAssetsQuoter
* @notice Quoter for markets where both tranches use the same unit precision and the NAV is expressed in tranche units
* @dev Supported use-cases include:
* - ST and JT share the exact same tranche asset and the NAV is expressed in that asset
* - ST and JT use in kind assets that share the same precision
* For example, USDC and USDT where NAV is expressed in USD with 6 decimals of precision
*/
abstract contract IdenticalAssetsQuoter is RoycoKernel {
/// @notice Thrown when the senior and junior tranche assets have the same precision
error TRANCHE_ASSET_DECIMALS_MISMATCH();
/**
* @notice Initializes the quoter for identical tranche assets
* @dev Assumes that the two assets have identical values
* @dev Reverts if the two assets don't have identical precision
* @param _stAsset The address of the base asset of the senior tranche
* @param _jtAsset The address of the base asset of the junior tranche
*/
function __IdenticalAssetsQuoter_init_unchained(address _stAsset, address _jtAsset) internal view onlyInitializing {
// This quoter stipulates that both tranche assets have identical precision
require(IERC20Metadata(_stAsset).decimals() == IERC20Metadata(_jtAsset).decimals(), TRANCHE_ASSET_DECIMALS_MISMATCH());
}
/// @inheritdoc RoycoKernel
/// @dev With identical precision, tranche units map 1:1 into NAV units
function stConvertTrancheUnitsToNAVUnits(TRANCHE_UNIT _stAssets) public pure override(RoycoKernel) returns (NAV_UNIT nav) {
return toNAVUnits(toUint256(_stAssets));
}
/// @inheritdoc RoycoKernel
/// @dev With identical precision, tranche units map 1:1 into NAV units
function jtConvertTrancheUnitsToNAVUnits(TRANCHE_UNIT _jtAssets) public pure override(RoycoKernel) returns (NAV_UNIT nav) {
return toNAVUnits(toUint256(_jtAssets));
}
/// @inheritdoc RoycoKernel
/// @dev With identical precision, NAV units map 1:1 into senior tranche units
function stConvertNAVUnitsToTrancheUnits(NAV_UNIT _nav) public pure override(RoycoKernel) returns (TRANCHE_UNIT stAssets) {
return toTrancheUnits(toUint256(_nav));
}
/// @inheritdoc RoycoKernel
/// @dev With identical precision, NAV units map 1:1 into junior tranche units
function jtConvertNAVUnitsToTrancheUnits(NAV_UNIT _nav) public pure override(RoycoKernel) returns (TRANCHE_UNIT jtAssets) {
return toTrancheUnits(toUint256(_nav));
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { IERC4626 } from "../../../../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import { IERC20, SafeERC20 } from "../../../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import { ExecutionModel, IRoycoKernel, SharesRedemptionModel } from "../../../interfaces/kernel/IRoycoKernel.sol";
import { AssetClaims } from "../../../libraries/Types.sol";
import { SyncedAccountingState } from "../../../libraries/Types.sol";
import { NAV_UNIT, TRANCHE_UNIT, UnitsMathLib, toTrancheUnits, toUint256 } from "../../../libraries/Units.sol";
import { ERC4626KernelState, ERC4626KernelStorageLib } from "../../../libraries/kernels/ERC4626KernelStorageLib.sol";
import { RoycoKernel, TrancheType } from "../RoycoKernel.sol";
abstract contract ERC4626_ST_Kernel is RoycoKernel {
using SafeERC20 for IERC20;
using UnitsMathLib for TRANCHE_UNIT;
/// @inheritdoc IRoycoKernel
ExecutionModel public constant ST_DEPOSIT_EXECUTION_MODEL = ExecutionModel.SYNC;
/// @inheritdoc IRoycoKernel
ExecutionModel public constant ST_REDEEM_EXECUTION_MODEL = ExecutionModel.SYNC;
/// @inheritdoc IRoycoKernel
SharesRedemptionModel public constant ST_REQUEST_REDEEM_SHARES_BEHAVIOR = SharesRedemptionModel.BURN_ON_CLAIM_REDEEM;
/// @notice Thrown when the ST base asset is different the the ERC4626 vault's base asset
error SENIOR_TRANCHE_AND_VAULT_ASSET_MISMATCH();
/**
* @notice Initializes a kernel where the senior tranche is deployed into an ERC4626 vault
* @param _stVault The address of the ERC4626 compliant vault the senior tranche will deploy into
* @param _stAsset The address of the base asset of the senior tranche
*/
function __ERC4626_ST_Kernel_init_unchained(address _stVault, address _stAsset) internal onlyInitializing {
// Ensure that the ST base asset is identical to the ERC4626 vault's base asset
require(IERC4626(_stVault).asset() == _stAsset, SENIOR_TRANCHE_AND_VAULT_ASSET_MISMATCH());
// Extend a one time max approval to the ERC4626 vault for the ST's base asset
IERC20(_stAsset).forceApprove(address(_stVault), type(uint256).max);
// Initialize the ERC4626 ST kernel storage
ERC4626KernelStorageLib._getERC4626KernelStorage().stVault = _stVault;
}
/// @inheritdoc IRoycoKernel
function stPreviewDeposit(TRANCHE_UNIT _assets) external view override returns (SyncedAccountingState memory stateBeforeDeposit, NAV_UNIT valueAllocated) {
IERC4626 stVault = IERC4626(ERC4626KernelStorageLib._getERC4626KernelStorage().stVault);
// Simulate the deposit of the assets into the underlying investment vault
uint256 stVaultSharesMinted = stVault.previewDeposit(toUint256(_assets));
// Convert the underlying vault shares to tranche units. This value may differ from _assets if a fee or slippage is incurred to the deposit.
TRANCHE_UNIT stAssetsAllocated = toTrancheUnits(stVault.convertToAssets(stVaultSharesMinted));
// Convert the assets allocated to NAV units and preview a sync to get the current NAV to mint shares at for the senior tranche
valueAllocated = stConvertTrancheUnitsToNAVUnits(stAssetsAllocated);
stateBeforeDeposit = _previewSyncTrancheAccounting();
}
/// @inheritdoc IRoycoKernel
function stPreviewRedeem(uint256 _shares) external view override returns (AssetClaims memory userClaim) {
userClaim = _previewRedeem(_shares, TrancheType.SENIOR);
}
/// @inheritdoc RoycoKernel
function _getSeniorTrancheRawNAV() internal view override(RoycoKernel) returns (NAV_UNIT) {
ERC4626KernelState storage $ = ERC4626KernelStorageLib._getERC4626KernelStorage();
// Must use convert to assets for the tranche owned shares in order to be exlusive of any fixed fees on withdrawal
// Cannot use max withdraw since it will treat illiquidity as a NAV loss
TRANCHE_UNIT stOwnedAssets = toTrancheUnits(IERC4626($.stVault).convertToAssets($.stOwnedShares));
return stConvertTrancheUnitsToNAVUnits(stOwnedAssets);
}
/// @inheritdoc RoycoKernel
function _stMaxDepositGlobally(address) internal view override(RoycoKernel) returns (TRANCHE_UNIT) {
// Max deposit takes global withdrawal limits into account
return toTrancheUnits(IERC4626(ERC4626KernelStorageLib._getERC4626KernelStorage().stVault).maxDeposit(address(this)));
}
/// @inheritdoc RoycoKernel
function _stMaxWithdrawableGlobally(address) internal view override(RoycoKernel) returns (TRANCHE_UNIT) {
// Max withdraw takes global withdrawal limits into account
return toTrancheUnits(IERC4626(ERC4626KernelStorageLib._getERC4626KernelStorage().stVault).maxWithdraw(address(this)));
}
/// @inheritdoc RoycoKernel
function _stPreviewWithdraw(TRANCHE_UNIT _stAssets) internal view override(RoycoKernel) returns (TRANCHE_UNIT withdrawnSTAssets) {
IERC4626 stVault = IERC4626(ERC4626KernelStorageLib._getERC4626KernelStorage().stVault);
// Convert the ST assets to underlying shares
uint256 stVaultShares = stVault.convertToShares(toUint256(_stAssets));
// Preview the amount of ST assets that would be redeemed for the given amount of underlying shares
withdrawnSTAssets = toTrancheUnits(stVault.previewRedeem(stVaultShares));
}
/// @inheritdoc RoycoKernel
function _stDepositAssets(TRANCHE_UNIT _stAssets) internal override(RoycoKernel) {
// Deposit the assets into the underlying investment vault and add to the number of ST controlled shares for this vault
ERC4626KernelState storage $ = ERC4626KernelStorageLib._getERC4626KernelStorage();
$.stOwnedShares += IERC4626($.stVault).deposit(toUint256(_stAssets), address(this));
}
/// @inheritdoc RoycoKernel
function _stWithdrawAssets(TRANCHE_UNIT _stAssets, address _receiver) internal override(RoycoKernel) {
ERC4626KernelState storage $ = ERC4626KernelStorageLib._getERC4626KernelStorage();
IERC4626 stVault = IERC4626($.stVault);
// Get the currently withdrawable liquidity from the vault
TRANCHE_UNIT maxWithdrawableAssets = toTrancheUnits(stVault.maxWithdraw(address(this)));
// If the vault has sufficient liquidity to withdraw the specified assets, do so
if (maxWithdrawableAssets >= _stAssets) {
$.stOwnedShares -= stVault.withdraw(toUint256(_stAssets), _receiver, address(this));
// If the vault has insufficient liquidity to withdraw the specified assets, transfer the equivalent number of shares to the receiver
} else {
// Transfer the assets equivalent of shares to the receiver
uint256 sharesEquivalentToWithdraw = ($.stOwnedShares -= stVault.convertToShares(toUint256(_stAssets)));
IERC20(address(stVault)).safeTransfer(_receiver, sharesEquivalentToWithdraw);
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { IRoycoAccountant } from "../interfaces/IRoycoAccountant.sol";
import { IRoycoKernel } from "../interfaces/kernel/IRoycoKernel.sol";
import { IRoycoVaultTranche } from "../interfaces/tranche/IRoycoVaultTranche.sol";
import { NAV_UNIT, TRANCHE_UNIT } from "./Units.sol";
/**
* @title AssetClaims
* @dev A struct representing claims on senior tranche assets, junior tranche assets, and NAV
* @custom:field stAssets - The claim on senior tranche assets denominated in ST's tranche units
* @custom:field jtAssets - The claim on junior tranche assets denominated in JT's tranche units
* @custom:field nav - The net asset value of these claims in NAV units
*/
struct AssetClaims {
TRANCHE_UNIT stAssets;
TRANCHE_UNIT jtAssets;
NAV_UNIT nav;
}
/**
* @title SyncedAccountingState
* @dev Contains all current mark to market NAV accounting data for the market's tranches
* @custom:field stRawNAV - The senior tranche's current raw NAV: the pure value of its invested assets
* @custom:field jtRawNAV - The junior tranche's current raw NAV: the pure value of its invested assets
* @custom:field stEffectiveNAV - Senior tranche effective NAV: includes applied coverage, its share of ST yield, and uncovered losses
* @custom:field jtEffectiveNAV - Junior tranche effective NAV: includes provided coverage, JT yield, its share of ST yield, and JT losses
* @custom:field stCoverageDebt - Coverage that has currently been applied to ST from the JT loss-absorption buffer
* @custom:field jtCoverageDebt - Losses that ST incurred after exhausting the JT loss-absorption buffer
* @custom:field stProtocolFeeAccrued - Protocol fee taken on ST yield on this sync
* @custom:field jtProtocolFeeAccrued - Protocol fee taken on JT yield on this sync
*/
struct SyncedAccountingState {
NAV_UNIT stRawNAV;
NAV_UNIT jtRawNAV;
NAV_UNIT stEffectiveNAV;
NAV_UNIT jtEffectiveNAV;
NAV_UNIT stCoverageDebt;
NAV_UNIT jtCoverageDebt;
NAV_UNIT stProtocolFeeAccrued;
NAV_UNIT jtProtocolFeeAccrued;
}
/**
* @title Operation
* @dev Defines the type of operation being executed by the user
* @custom:type ST_INCREASE_NAV - An operation that will potentially increase the NAV of ST
* @custom:type ST_DECREASE_NAV - An operation that will potentially decrease the NAV of ST
* @custom:type JT_INCREASE_NAV - An operation that will potentially increase the NAV of JT
* @custom:type JT_DECREASE_NAV - An operation that will potentially decrease the NAV of JT
*/
enum Operation {
ST_INCREASE_NAV,
ST_DECREASE_NAV,
JT_INCREASE_NAV,
JT_DECREASE_NAV
}
/**
* @title Action
* @dev Defines the action being executed by the user
* @custom:type DEPOSIT Depositing assets into the tranche
* @custom:type WITHDRAW Withdrawing assets from the tranche
*/
enum Action {
DEPOSIT,
WITHDRAW
}
/**
* @title TrancheType
* @dev Defines the two types of Royco tranches deployed per market.
* @custom:type JUNIOR The identifier for the junior tranche (first-loss capital)
* @custom:type SENIOR The identifier for the senior tranche (second-loss capital)
*/
enum TrancheType {
JUNIOR,
SENIOR
}
/**
* @title SharesRedemptionModel
* @dev Defines the behavior of the shares when a redeem request is made
* @custom:type BURN_ON_REQUEST_REDEEM The shares are burned when calling requestRedeem
* @custom:type BURN_ON_CLAIM_REDEEM The shares are burned when calling redeem
*/
enum SharesRedemptionModel {
BURN_ON_REQUEST_REDEEM,
BURN_ON_CLAIM_REDEEM
}
/**
* @title ExecutionModel
* @dev Defines the execution semantics for the deposit or withdrawal flow of a vault
* @custom:type SYNC Refers to the flow being synchronous (the vault uses ERC4626 for this flow)
* @custom:type ASYNC Refers to the flow being asynchronous (the vault uses ERC7540 for this flow)
*/
enum ExecutionModel {
SYNC,
ASYNC
}
/**
* @title ActionMetadataFormat
* @dev Defines the format of the metadata for the action
* @custom:type REDEMPTION_CLAIMABLE_AT_TIMESTAMP is followed by a uint256 representing the claimable at timestamp of the redemption request
*/
enum ActionMetadataFormat {
REDEMPTION_CLAIMABLE_AT_TIMESTAMP
}
/**
* @notice Parameters for deploying a new market
* @custom:field seniorTrancheName The name of the senior tranche
* @custom:field seniorTrancheSymbol The symbol of the senior tranche
* @custom:field juniorTrancheName The name of the junior tranche
* @custom:field juniorTrancheSymbol The symbol of the junior tranche
* @custom:field seniorAsset The underlying asset for the senior tranche
* @custom:field juniorAsset The underlying asset for the junior tranche
* @custom:field marketId The identifier of the Royco market
* @custom:field kernelImplementation The implementation address for the kernel
* @custom:field accountantImplementation The implementation address for the accountant
* @custom:field seniorTrancheImplementation The implementation address for the senior tranche
* @custom:field juniorTrancheImplementation The implementation address for the junior tranche
* @custom:field kernelInitializationData The initialization data for the kernel
* @custom:field accountantInitializationData The initialization data for the accountant
* @custom:field seniorTrancheInitializationData The initialization data for the senior tranche
* @custom:field juniorTrancheInitializationData The initialization data for the junior tranche
* @custom:field seniorTrancheProxyDeploymentSalt The salt for the senior tranche proxy deployment
* @custom:field juniorTrancheProxyDeploymentSalt The salt for the junior tranche proxy deployment
* @custom:field kernelProxyDeploymentSalt The salt for the kernel proxy deployment
* @custom:field accountantProxyDeploymentSalt The salt for the accountant proxy deployment
*/
struct MarketDeploymentParams {
// Tranche Deployment Parameters
string seniorTrancheName;
string seniorTrancheSymbol;
string juniorTrancheName;
string juniorTrancheSymbol;
address seniorAsset;
address juniorAsset;
bytes32 marketId;
// Implementation Addresses
IRoycoVaultTranche seniorTrancheImplementation;
IRoycoVaultTranche juniorTrancheImplementation;
IRoycoKernel kernelImplementation;
IRoycoAccountant accountantImplementation;
// Proxy Initialization Data
bytes seniorTrancheInitializationData;
bytes juniorTrancheInitializationData;
bytes kernelInitializationData;
bytes accountantInitializationData;
// Create2 Salts
bytes32 seniorTrancheProxyDeploymentSalt;
bytes32 juniorTrancheProxyDeploymentSalt;
bytes32 kernelProxyDeploymentSalt;
bytes32 accountantProxyDeploymentSalt;
// Initial Roles Configuration
RolesConfiguration[] roles;
}
/**
* @custom:field name - The name of the tranche (should be prefixed with "Royco-ST" or "Royco-JT") share token
* @custom:field symbol - The symbol of the tranche (should be prefixed with "ST" or "JT") share token
* @custom:field kernel - The tranche kernel responsible for defining the execution model and logic of the tranche
*/
struct TrancheDeploymentParams {
string name;
string symbol;
address kernel;
}
/**
* @notice The configuration for a role
* @custom:field target The target address of the role
* @custom:field selectors The selectors of the role
* @custom:field roles The roles of the role
*/
struct RolesConfiguration {
address target;
bytes4[] selectors;
uint64[] roles;
}
/**
* @notice The deployed contracts for a new market
* @custom:field seniorTranche The senior tranche contract
* @custom:field juniorTranche The junior tranche contract
* @custom:field accountant The accountant contract
* @custom:field kernel The kernel contract
*/
struct DeployedContracts {
IRoycoVaultTranche seniorTranche;
IRoycoVaultTranche juniorTranche;
IRoycoAccountant accountant;
IRoycoKernel kernel;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { Math } from "../../lib/openzeppelin-contracts/contracts/utils/math/Math.sol";
/// @notice Common unit of account for Royco NAV values (e.g., USD, BTC) used consistently across a market's tranches
/// @dev `NAV_UNIT` must be expressed in the same underlying unit and precision for both ST and JT within a market
type NAV_UNIT is uint256;
/// @notice Unit for tranche asset amounts (native token units for a specific tranche)
type TRANCHE_UNIT is uint256;
/// @title UnitsMathLib
/// @notice Typed math helpers for Royco units (NAV_UNIT and TRANCHE_UNIT)
/// @dev Wraps OpenZeppelin Math helpers and preserves unit typing on return values
library UnitsMathLib {
/// @notice Returns the minimum of two NAV-denominated quantities.
function min(NAV_UNIT _a, NAV_UNIT _b) internal pure returns (NAV_UNIT) {
return toNAVUnits(Math.min(toUint256(_a), toUint256(_b)));
}
/// @notice Returns the minimum of two tranche-denominated quantities.
function min(TRANCHE_UNIT _a, TRANCHE_UNIT _b) internal pure returns (TRANCHE_UNIT) {
return toTrancheUnits(Math.min(toUint256(_a), toUint256(_b)));
}
/// @notice Returns the signed delta `_a - _b` for NAV-denominated quantities.
function computeNAVDelta(NAV_UNIT _a, NAV_UNIT _b) internal pure returns (int256) {
return (toInt256(_a) - toInt256(_b));
}
/// @notice Returns `max(_a - _b, 0)` for NAV-denominated quantities.
function saturatingSub(NAV_UNIT _a, NAV_UNIT _b) internal pure returns (NAV_UNIT) {
return toNAVUnits(Math.saturatingSub(toUint256(_a), toUint256(_b)));
}
/// @notice Returns `(_a * _b) / _c` for NAV-denominated quantities with explicit rounding.
function mulDiv(NAV_UNIT _a, NAV_UNIT _b, NAV_UNIT _c, Math.Rounding _rounding) internal pure returns (NAV_UNIT) {
return toNAVUnits(Math.mulDiv(toUint256(_a), toUint256(_b), toUint256(_c), _rounding));
}
/// @notice Returns `(_a * _b) / _c` where `_a` is NAV-denominated and `_b/_c` are scalars, with explicit rounding.
function mulDiv(NAV_UNIT _a, uint256 _b, uint256 _c, Math.Rounding _rounding) internal pure returns (NAV_UNIT) {
return toNAVUnits(Math.mulDiv(toUint256(_a), _b, _c, _rounding));
}
/// @notice Returns `(_a * _b) / _c` where `_a/_c` are NAV-denominated and `_b` is a scalar, with explicit rounding.
function mulDiv(NAV_UNIT _a, uint256 _b, NAV_UNIT _c, Math.Rounding _rounding) internal pure returns (NAV_UNIT) {
return toNAVUnits(Math.mulDiv(toUint256(_a), _b, toUint256(_c), _rounding));
}
/// @notice Returns `(_a * _b) / _c` where `_a` is tranche-denominated and `_b/_c` are NAV-denominated, with explicit rounding.
function mulDiv(TRANCHE_UNIT _a, NAV_UNIT _b, NAV_UNIT _c, Math.Rounding _rounding) internal pure returns (TRANCHE_UNIT) {
return toTrancheUnits(Math.mulDiv(toUint256(_a), toUint256(_b), toUint256(_c), _rounding));
}
/// @notice Returns `(_a * _b) / _c` where `_a` is tranche-denominated and `_b/_c` are scalars, with explicit rounding.
function mulDiv(TRANCHE_UNIT _a, uint256 _b, uint256 _c, Math.Rounding _rounding) internal pure returns (TRANCHE_UNIT) {
return toTrancheUnits(Math.mulDiv(toUint256(_a), _b, _c, _rounding));
}
/// @notice Returns `(_a * _b) / _c` where `_a` is a scalar and `_b/_c` are NAV-denominated, with explicit rounding.
function mulDiv(uint256 _a, NAV_UNIT _b, NAV_UNIT _c, Math.Rounding _rounding) internal pure returns (uint256) {
return Math.mulDiv(_a, toUint256(_b), toUint256(_c), _rounding);
}
}
/// -----------------------------------------------------------------------
/// Global NAV_UNIT Helpers
/// -----------------------------------------------------------------------
function toNAVUnits(uint256 _assets) pure returns (NAV_UNIT) {
return NAV_UNIT.wrap(_assets);
}
function toNAVUnits(int256 _assets) pure returns (NAV_UNIT) {
// forge-lint: disable-next-line(unsafe-typecast)
return NAV_UNIT.wrap(uint256(_assets));
}
function toUint256(NAV_UNIT _units) pure returns (uint256) {
return NAV_UNIT.unwrap(_units);
}
function toInt256(NAV_UNIT _units) pure returns (int256) {
return int256(NAV_UNIT.unwrap(_units));
}
function addNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (NAV_UNIT) {
return NAV_UNIT.wrap(NAV_UNIT.unwrap(_a) + NAV_UNIT.unwrap(_b));
}
function subNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (NAV_UNIT) {
return NAV_UNIT.wrap(NAV_UNIT.unwrap(_a) - NAV_UNIT.unwrap(_b));
}
function mulNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (NAV_UNIT) {
return NAV_UNIT.wrap(NAV_UNIT.unwrap(_a) * NAV_UNIT.unwrap(_b));
}
function divNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (NAV_UNIT) {
return NAV_UNIT.wrap(NAV_UNIT.unwrap(_a) / NAV_UNIT.unwrap(_b));
}
function lessThanNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (bool) {
return NAV_UNIT.unwrap(_a) < NAV_UNIT.unwrap(_b);
}
function lessThanOrEqualToNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (bool) {
return NAV_UNIT.unwrap(_a) <= NAV_UNIT.unwrap(_b);
}
function greaterThanNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (bool) {
return NAV_UNIT.unwrap(_a) > NAV_UNIT.unwrap(_b);
}
function greaterThanOrEqualToNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (bool) {
return NAV_UNIT.unwrap(_a) >= NAV_UNIT.unwrap(_b);
}
function equalsNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (bool) {
return NAV_UNIT.unwrap(_a) == NAV_UNIT.unwrap(_b);
}
function notEqualsNAVUnits(NAV_UNIT _a, NAV_UNIT _b) pure returns (bool) {
return NAV_UNIT.unwrap(_a) != NAV_UNIT.unwrap(_b);
}
using {
addNAVUnits as +,
subNAVUnits as -,
mulNAVUnits as *,
divNAVUnits as /,
lessThanNAVUnits as <,
lessThanOrEqualToNAVUnits as <=,
greaterThanNAVUnits as >,
greaterThanOrEqualToNAVUnits as >=,
equalsNAVUnits as ==,
notEqualsNAVUnits as !=
} for NAV_UNIT global;
/// -----------------------------------------------------------------------
/// Global TRANCHE_UNIT Helpers
/// -----------------------------------------------------------------------
function toTrancheUnits(uint256 _assets) pure returns (TRANCHE_UNIT) {
return TRANCHE_UNIT.wrap(_assets);
}
function toUint256(TRANCHE_UNIT _units) pure returns (uint256) {
return TRANCHE_UNIT.unwrap(_units);
}
function addTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (TRANCHE_UNIT) {
return TRANCHE_UNIT.wrap(TRANCHE_UNIT.unwrap(_a) + TRANCHE_UNIT.unwrap(_b));
}
function subTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (TRANCHE_UNIT) {
return TRANCHE_UNIT.wrap(TRANCHE_UNIT.unwrap(_a) - TRANCHE_UNIT.unwrap(_b));
}
function mulTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (TRANCHE_UNIT) {
return TRANCHE_UNIT.wrap(TRANCHE_UNIT.unwrap(_a) * TRANCHE_UNIT.unwrap(_b));
}
function divTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (TRANCHE_UNIT) {
return TRANCHE_UNIT.wrap(TRANCHE_UNIT.unwrap(_a) / TRANCHE_UNIT.unwrap(_b));
}
function lessThanTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (bool) {
return TRANCHE_UNIT.unwrap(_a) < TRANCHE_UNIT.unwrap(_b);
}
function lessThanOrEqualToTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (bool) {
return TRANCHE_UNIT.unwrap(_a) <= TRANCHE_UNIT.unwrap(_b);
}
function greaterThanTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (bool) {
return TRANCHE_UNIT.unwrap(_a) > TRANCHE_UNIT.unwrap(_b);
}
function greaterThanOrEqualToTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (bool) {
return TRANCHE_UNIT.unwrap(_a) >= TRANCHE_UNIT.unwrap(_b);
}
function equalsTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (bool) {
return TRANCHE_UNIT.unwrap(_a) == TRANCHE_UNIT.unwrap(_b);
}
function notEqualsTrancheUnits(TRANCHE_UNIT _a, TRANCHE_UNIT _b) pure returns (bool) {
return TRANCHE_UNIT.unwrap(_a) != TRANCHE_UNIT.unwrap(_b);
}
using {
addTrancheUnits as +,
subTrancheUnits as -,
mulTrancheUnits as *,
divTrancheUnits as /,
lessThanTrancheUnits as <,
lessThanOrEqualToTrancheUnits as <=,
greaterThanTrancheUnits as >,
greaterThanOrEqualToTrancheUnits as >=,
equalsTrancheUnits as ==,
notEqualsTrancheUnits as !=
} for TRANCHE_UNIT global; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { TRANCHE_UNIT } from "../../libraries/Units.sol";
/// @title IRoycoAsyncCancellableVault: based on ERC-7887: Cancellation for ERC-7540 Tokenized Vaults
/// @notice Interface extending ERC-7540 asynchronous vaults with cancellation flows.
/// @dev Contracts implementing this interface MUST also implement ERC-165.
interface IRoycoAsyncCancellableVault {
// =============================
// Events
// =============================
/// @notice Emitted when a controller requests cancellation of a deposit Request.
/// @param controller The controller of the Request (may equal msg.sender or its approved operator).
/// @param requestId The identifier of the deposit Request being canceled.
/// @param sender The caller of the cancelDepositRequest.
event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);
/// @notice Emitted when a controller claims a deposit cancellation.
/// @param controller The controller of the canceled Request.
/// @param receiver The recipient of the returned assets.
/// @param requestId The identifier of the canceled Request.
/// @param sender The caller of the claimCancelDepositRequest.
/// @param assets The amount of assets claimed.
event CancelDepositClaim(address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, TRANCHE_UNIT assets);
/// @notice Emitted when a controller requests cancellation of a redeem Request.
/// @param controller The controller of the Request (may equal msg.sender or its approved operator).
/// @param requestId The identifier of the redeem Request being canceled.
/// @param sender The caller of the cancelRedeemRequest.
event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);
/// @notice Emitted when a controller claims a redeem cancellation.
/// @param controller The controller of the canceled Request.
/// @param receiver The recipient of the returned shares.
/// @param requestId The identifier of the canceled Request.
/// @param sender The caller of the claimCancelRedeemRequest.
/// @param shares The amount of shares claimed.
event CancelRedeemClaim(address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares);
// =============================
// Deposit Cancellation
// =============================
/// @notice Submit an asynchronous deposit cancellation Request.
/// @dev MUST emit {CancelDepositRequest}.
/// @param _requestId The identifier of the original deposit Request.
/// @param _controller The controller of the Request (must equal msg.sender unless operator-approved).
function cancelDepositRequest(uint256 _requestId, address _controller) external;
/// @notice Returns whether a deposit cancellation Request is pending for the given controller.
/// @dev MUST NOT vary by caller. MUST NOT revert except for unreasonable input overflow.
/// @param _requestId The identifier of the original deposit Request.
/// @param _controller The controller address.
/// @return isPending True if the cancellation is pending.
function pendingCancelDepositRequest(uint256 _requestId, address _controller) external view returns (bool isPending);
/// @notice Returns the amount of assets claimable for a deposit cancellation Request for the controller.
/// @dev MUST NOT vary by caller. MUST NOT revert except for unreasonable input overflow.
/// @param _requestId The identifier of the original deposit Request.
/// @param _controller The controller address.
/// @return assets The amount of assets claimable.
function claimableCancelDepositRequest(uint256 _requestId, address _controller) external view returns (TRANCHE_UNIT assets);
/// @notice Claim a deposit cancellation Request, transferring assets to the receiver.
/// @dev MUST emit {CancelDepositClaim}.
/// @param _requestId The identifier of the canceled deposit Request.
/// @param _receiver The recipient of assets.
/// @param _controller The controller of the Request (must equal msg.sender unless operator-approved).
function claimCancelDepositRequest(uint256 _requestId, address _receiver, address _controller) external;
// =============================
// Redeem Cancellation
// =============================
/// @notice Submit an asynchronous redeem cancellation Request.
/// @dev MUST emit {CancelRedeemRequest}.
/// @param _requestId The identifier of the original redeem Request.
/// @param _controller The controller of the Request (must equal msg.sender unless operator-approved).
function cancelRedeemRequest(uint256 _requestId, address _controller) external;
/// @notice Returns whether a redeem cancellation Request is pending for the given controller.
/// @dev MUST NOT vary by caller. MUST NOT revert except for unreasonable input overflow.
/// @param _requestId The identifier of the original redeem Request.
/// @param _controller The controller address.
/// @return isPending True if the cancellation is pending.
function pendingCancelRedeemRequest(uint256 _requestId, address _controller) external view returns (bool isPending);
/// @notice Returns the amount of shares claimable for a redeem cancellation Request for the controller.
/// @dev MUST NOT vary by caller. MUST NOT revert except for unreasonable input overflow.
/// @param _requestId The identifier of the original redeem Request.
/// @param _controller The controller address.
/// @return shares The amount of shares claimable.
function claimableCancelRedeemRequest(uint256 _requestId, address _controller) external view returns (uint256 shares);
/// @notice Claim a redeem cancellation Request, transferring shares to the receiver.
/// @dev MUST emit {CancelRedeemClaim}.
/// @param _requestId The identifier of the canceled redeem Request.
/// @param _receiver The recipient of shares.
/// @param _owner The owner for whom the shares are claimed (per draft spec).
function claimCancelRedeemRequest(uint256 _requestId, address _receiver, address _owner) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { AssetClaims } from "../../libraries/Types.sol";
import { TRANCHE_UNIT } from "../../libraries/Units.sol";
/**
* @title IRoycoAsyncVault: based on ERC-7540: Asynchronous ERC-4626 Tokenized Vaults
* @notice ERC-7540: Asynchronous ERC-4626 Tokenized Vaults
* @dev Specification: https://eips.ethereum.org/EIPS/eip-7540
*
* Extends ERC-4626 with asynchronous Request flows for deposits and/or redemptions.
* Implementations MAY choose to support either or both async flows; unsupported flows
* MUST follow ERC-4626 synchronous behavior. Implementations MUST support ERC-165.
*/
interface IRoycoAsyncVault {
/// @notice Operator approval updated for a controller.
/// @dev MUST be logged when operator status is set; MAY be logged when unchanged.
/// @param owner The controller setting an operator.
/// @param operator The operator being approved/revoked.
/// @param approved New approval status.
event OperatorSet(address indexed owner, address indexed operator, bool approved);
/// @notice Assets locked to request an asynchronous deposit.
/// @dev MUST be emitted by requestDeposit.
/// @param controller The controller of the Request.
/// @param owner The owner whose assets were locked.
/// @param requestId The identifier for the Request (see Request Ids semantics).
/// @param sender The caller of requestDeposit (may differ from owner).
/// @param assets The amount of assets requested.
/// @param metadata The format prefixed metadata of the deposit request or empty bytes if no metadata is shared
event DepositRequest(address indexed controller, address indexed owner, uint256 indexed requestId, address sender, TRANCHE_UNIT assets, bytes metadata);
/// @notice Shares locked (or assumed control of) to request an asynchronous redemption.
/// @dev MUST be emitted by requestRedeem.
/// @param controller The controller of the Request (may differ from owner).
/// @param owner The owner whose shares were locked or assumed.
/// @param requestId The identifier for the Request (see Request Ids semantics).
/// @param sender The caller of requestRedeem (may differ from owner).
/// @param shares The amount of shares requested to redeem.
/// @param metadata The format prefixed metadata of the redemption request or empty bytes if no metadata is shared
event RedeemRequest(address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 shares, bytes metadata);
/// @notice Transfer assets from owner and submit an async deposit Request.
/// @dev MUST emit DepositRequest. MUST support ERC20 approve/transferFrom on the asset.
/// @dev MUST revert if all assets cannot be requested (limits/slippage/approval/etc).
/// @param _assets Amount of assets to request.
/// @param _controller Controller of the Request (msg.sender unless operator-approved).
/// @param _owner Source of the assets; MUST be msg.sender unless operator-approved.
/// @return requestId Discriminator paired with controller (see Request Ids semantics).
/// @return metadata The format prefixed metadata of the deposit request or empty bytes if no metadata is shared
function requestDeposit(TRANCHE_UNIT _assets, address _controller, address _owner) external returns (uint256 requestId, bytes memory metadata);
/// @notice Amount of requested assets in Pending state for controller/requestId.
/// @dev MUST NOT include amounts in Claimable; MUST NOT vary by caller.
/// @param _requestId Request identifier.
/// @param _controller Controller address.
/// @return pendingAssets Amount in Pending.
function pendingDepositRequest(uint256 _requestId, address _controller) external view returns (TRANCHE_UNIT pendingAssets);
/// @notice Amount of requested assets in Claimable state for controller/requestId.
/// @dev MUST NOT include amounts in Pending; MUST NOT vary by caller.
/// @param _requestId Request identifier.
/// @param _controller Controller address.
/// @return claimableAssets Amount in Claimable.
function claimableDepositRequest(uint256 _requestId, address _controller) external view returns (TRANCHE_UNIT claimableAssets);
/// @notice Claim an async deposit by calling ERC-4626 deposit.
/// @dev Overload per ERC-7540. MUST revert unless msg.sender == controller or operator.
/// @param _assets Assets to claim.
/// @param _receiver Recipient of shares.
/// @param _controller Controller discriminating the claim when sender is operator.
/// @return shares Shares minted.
/// @return metadata The format prefixed metadata of the deposit or empty bytes if no metadata is shared
function deposit(TRANCHE_UNIT _assets, address _receiver, address _controller) external returns (uint256 shares, bytes memory metadata);
/// @notice Assume control of shares from owner and submit an async redeem Request.
/// @dev MUST emit RedeemRequest. MUST revert if all shares cannot be requested.
/// @param _shares Amount of shares to request redemption for.
/// @param _controller Controller of the Request (msg.sender unless operator-approved).
/// @param _owner Owner of the shares; MUST be msg.sender unless operator-approved.
/// @return requestId Discriminator paired with controller (see Request Ids semantics).
/// @return metadata The format prefixed metadata of the redemption request or empty bytes if no metadata is shared
function requestRedeem(uint256 _shares, address _controller, address _owner) external returns (uint256 requestId, bytes memory metadata);
/// @notice Amount of requested shares in Pending state for controller/requestId.
/// @dev MUST NOT include amounts in Claimable; MUST NOT vary by caller.
/// @param _requestId Request identifier.
/// @param _controller Controller address.
/// @return pendingShares Amount in Pending.
function pendingRedeemRequest(uint256 _requestId, address _controller) external view returns (uint256 pendingShares);
/// @notice Amount of requested shares in Claimable state for controller/requestId.
/// @dev MUST NOT include amounts in Pending; MUST NOT vary by caller.
/// @param _requestId Request identifier.
/// @param _controller Controller address.
/// @return claimableShares Amount in Claimable.
function claimableRedeemRequest(uint256 _requestId, address _controller) external view returns (uint256 claimableShares);
/// @notice Claim an async redemption by calling ERC-4626 redeem.
/// @dev Overload per ERC-7540. MUST revert unless msg.sender == controller or operator.
/// @param _shares Shares to redeem.
/// @param _receiver Recipient of assets.
/// @param _controller Controller discriminating the claim when sender is operator.
/// @return claims Assets returned.
/// @return metadata The format prefixed metadata of the redemption or empty bytes if no metadata is shared
function redeem(uint256 _shares, address _receiver, address _controller) external returns (AssetClaims memory claims, bytes memory metadata);
/// @notice Returns true if operator is approved for controller.
/// @param _controller Controller address.
/// @param _operator Operator address.
/// @return status Operator approval status.
function isOperator(address _controller, address _operator) external view returns (bool);
/// @notice Approve or revoke an operator for the msg.sender (controller).
/// @dev MUST set operator status, emit OperatorSet, and return true.
/// @param _operator Operator to set.
/// @param _approved New approval status.
/// @return success True.
function setOperator(address _operator, bool _approved) external returns (bool);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
if (!_safeTransfer(token, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
if (!_safeTransferFrom(token, from, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _safeTransfer(token, to, value, false);
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _safeTransferFrom(token, from, to, value, false);
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
if (!_safeApprove(token, spender, value, false)) {
if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity `token.transfer(to, value)` call, relaxing the requirement on the return value: the
* return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.transfer.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
/**
* @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, relaxing the requirement on the return
* value: the return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param from The sender of the tokens
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
mstore(0x60, 0)
}
}
/**
* @dev Imitates a Solidity `token.approve(spender, value)` call, relaxing the requirement on the return value:
* the return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param spender The spender of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.approve.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IPoolAddressesProvider } from "./IPoolAddressesProvider.sol";
/**
* @title IPool
* @author Aave
* @notice Defines the basic interface for an Aave Pool.
*/
interface IPool {
/**
* @notice Returns the PoolAddressesProvider connected to this contract
* @return The address of the PoolAddressesProvider
*/
function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
/**
* @notice Returns the aToken address of a reserve.
* @param asset The address of the underlying asset of the reserve
* @return The address of the aToken
*/
function getReserveAToken(address asset) external view returns (address);
/**
* @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User supplies 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
/**
* @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to The address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
*/
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IPoolAddressesProvider
* @author Aave
* @notice Defines the basic interface for a Pool Addresses Provider.
*/
interface IPoolAddressesProvider {
/**
* @notice Returns the address of the data provider.
* @return The address of the DataProvider
*/
function getPoolDataProvider() external view returns (address);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IPoolDataProvider
* @author Aave
* @notice Defines the basic interface of a PoolDataProvider
*/
interface IPoolDataProvider {
/**
* @notice Returns the configuration data of the reserve
* @dev Not returning borrow and supply caps for compatibility, nor pause flag
* @param asset The address of the underlying asset of the reserve
* @return decimals The number of decimals of the reserve
* @return ltv The ltv of the reserve
* @return liquidationThreshold The liquidationThreshold of the reserve
* @return liquidationBonus The liquidationBonus of the reserve
* @return reserveFactor The reserveFactor of the reserve
* @return usageAsCollateralEnabled True if the usage as collateral is enabled, false otherwise
* @return borrowingEnabled True if borrowing is enabled, false otherwise
* @return stableBorrowRateEnabled True if stable rate borrowing is enabled, false otherwise
* @return isActive True if it is active, false otherwise
* @return isFrozen True if it is frozen, false otherwise
*/
function getReserveConfigurationData(address asset)
external
view
returns (
uint256 decimals,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
uint256 reserveFactor,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive,
bool isFrozen
);
/**
* @notice Returns the caps parameters of the reserve
* @param asset The address of the underlying asset of the reserve
* @return borrowCap The borrow cap of the reserve
* @return supplyCap The supply cap of the reserve
*/
function getReserveCaps(address asset) external view returns (uint256 borrowCap, uint256 supplyCap);
/**
* @notice Returns if the pool is paused
* @param asset The address of the underlying asset of the reserve
* @return isPaused True if the pool is paused, false otherwise
*/
function getPaused(address asset) external view returns (bool isPaused);
/**
* @notice Returns the reserve data
* @param asset The address of the underlying asset of the reserve
* @return unbacked The amount of unbacked tokens
* @return accruedToTreasuryScaled The scaled amount of tokens accrued to treasury that is to be minted
* @return totalAToken The total supply of the aToken
* @return totalStableDebt The total stable debt of the reserve
* @return totalVariableDebt The total variable debt of the reserve
* @return liquidityRate The liquidity rate of the reserve
* @return variableBorrowRate The variable borrow rate of the reserve
* @return stableBorrowRate The stable borrow rate of the reserve
* @return averageStableBorrowRate The average stable borrow rate of the reserve
* @return liquidityIndex The liquidity index of the reserve
* @return variableBorrowIndex The variable borrow index of the reserve
* @return lastUpdateTimestamp The timestamp of the last update of the reserve
*/
function getReserveData(address asset)
external
view
returns (
uint256 unbacked,
uint256 accruedToTreasuryScaled,
uint256 totalAToken,
uint256 totalStableDebt,
uint256 totalVariableDebt,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { AssetClaims, ExecutionModel, SharesRedemptionModel, SyncedAccountingState } from "../../libraries/Types.sol";
import { TrancheType } from "../../libraries/Types.sol";
import { NAV_UNIT, TRANCHE_UNIT } from "../../libraries/Units.sol";
/**
* @title IRoycoKernel
* @notice Interface for the Royco kernel contract
* @dev The kernel contract is responsible for defining the execution model and logic of the Senior and Junior tranches of a given Royco market
*/
interface IRoycoKernel {
/**
* @notice Emitted when the protocol fee recipient is updated
* @param protocolFeeRecipient The new protocol fee recipient
*/
event ProtocolFeeRecipientUpdated(address protocolFeeRecipient);
/**
* @notice Emitted when the junior tranche redemption delay is updated
* @param jtRedemptionDelayInSeconds The new junior tranche redemption delay in seconds
*/
event JuniorTrancheRedemptionDelayUpdated(uint24 jtRedemptionDelayInSeconds);
/// @notice Thrown when any of the required initialization params are null
error NULL_ADDRESS();
/// @notice Thrown when the caller of a permissioned function isn't the market's senior tranche
error ONLY_SENIOR_TRANCHE();
/// @notice Thrown when the caller of a permissioned function isn't the market's junior tranche
error ONLY_JUNIOR_TRANCHE();
/// @notice Thrown when the total shares claimable for redemption are less than what the user is trying to redeem
error INSUFFICIENT_REDEEMABLE_SHARES(uint256 sharesToRedeem, uint256 redeemableShares);
/// @notice Thrown when the JT redemption request ID is invalid
error INVALID_REQUEST_ID(uint256 requestId);
/// @notice Thrown when the redemption is already canceled
error REDEMPTION_REQUEST_CANCELED();
/// @notice Thrown when trying to a cancel a redemption request that doesn't exist
error NONEXISTANT_REQUEST_TO_CANCEL();
/// @notice Thrown when trying to claim a cancellation without having an existing cancellation
error REDEMPTION_REQUEST_NOT_CANCELED();
/// @notice Thrown when the function is not implemented
error PREVIEW_REDEEM_DISABLED_FOR_ASYNC_REDEMPTION();
/**
* @notice Returns the execution model for the senior tranche's increase NAV operation
* @return The execution model for the senior tranche's increase NAV operation - SYNC or ASYNC
*/
function ST_DEPOSIT_EXECUTION_MODEL() external pure returns (ExecutionModel);
/**
* @notice Returns the execution model for the senior tranche's decrease NAV operation
* @return The execution model for the senior tranche's decrease NAV operation - SYNC or ASYNC
*/
function ST_REDEEM_EXECUTION_MODEL() external pure returns (ExecutionModel);
/**
* @notice Returns the execution model for the junior tranche's increase NAV operation
* @return The execution model for the junior tranche's increase NAV operation - SYNC or ASYNC
*/
function JT_DEPOSIT_EXECUTION_MODEL() external pure returns (ExecutionModel);
/**
* @notice Returns the execution model for the junior tranche's decrease NAV operation
* @return The execution model for the junior tranche's decrease NAV operation - SYNC or ASYNC
*/
function JT_REDEEM_EXECUTION_MODEL() external pure returns (ExecutionModel);
/**
* @notice Returns the request redeem shares behavior for the senior tranche
* @return The request redeem shares behavior for the senior tranche - BURN_ON_REQUEST_REDEEM or BURN_ON_CLAIM_REDEEM
*/
function ST_REQUEST_REDEEM_SHARES_BEHAVIOR() external pure returns (SharesRedemptionModel);
/**
* @notice Returns the request redeem shares behavior for the junior tranche
* @return The request redeem shares behavior for the junior tranche - BURN_ON_REQUEST_REDEEM or BURN_ON_CLAIM_REDEEM
*/
function JT_REQUEST_REDEEM_SHARES_BEHAVIOR() external pure returns (SharesRedemptionModel);
/**
* @notice Converts the specified ST assets denominated in its tranche units to the kernel's NAV units
* @param _stAssets The ST assets denominated in tranche units to convert to the kernel's NAV units
* @return nav The specified ST assets denominated in its tranche units converted to the kernel's NAV units
*/
function stConvertTrancheUnitsToNAVUnits(TRANCHE_UNIT _stAssets) external view returns (NAV_UNIT nav);
/**
* @notice Converts the specified JT assets denominated in its tranche units to the kernel's NAV units
* @param _jtAssets The JT assets denominated in tranche units to convert to the kernel's NAV units
* @return nav The specified JT assets denominated in its tranche units converted to the kernel's NAV units
*/
function jtConvertTrancheUnitsToNAVUnits(TRANCHE_UNIT _jtAssets) external view returns (NAV_UNIT nav);
/**
* @notice Converts the specified assets denominated in the kernel's NAV units to assets denominated in ST's tranche units
* @param _navAssets The NAV of the assets denominated in the kernel's NAV units to convert to assets denominated in ST's tranche units
* @return stAssets The specified NAV of the assets denominated in the kernel's NAV units converted to assets denominated in ST's tranche units
*/
function stConvertNAVUnitsToTrancheUnits(NAV_UNIT _navAssets) external view returns (TRANCHE_UNIT stAssets);
/**
* @notice Converts the specified assets denominated in the kernel's NAV units to assets denominated in JT's tranche units
* @param _navAssets The NAV of the assets denominated in the kernel's NAV units to convert to assets denominated in JT's tranche units
* @return jtAssets The specified NAV of the assets denominated in the kernel's NAV units converted to assets denominated in JT's tranche units
*/
function jtConvertNAVUnitsToTrancheUnits(NAV_UNIT _navAssets) external view returns (TRANCHE_UNIT jtAssets);
/**
* @notice Synchronizes and persists the raw and effective NAVs of both tranches
* @dev Only executes a pre-op sync because there is no operation being executed in the same call as this sync
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function syncTrancheAccounting() external returns (SyncedAccountingState memory state);
/**
* @notice Previews a synchronization of the raw and effective NAVs of both tranches
* @dev Does not mutate any state
* @param _trancheType An enum indicating which tranche to execute this preview for
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
* @return claims The claims on ST and JT assets that the specified tranche has denominated in tranche-native units
* @return totalTrancheShares The total number of shares that exist in the specified tranche after minting any protocol fee shares post-sync
*/
function previewSyncTrancheAccounting(TrancheType _trancheType)
external
view
returns (SyncedAccountingState memory state, AssetClaims memory claims, uint256 totalTrancheShares);
/**
* @notice Returns the maximum amount of assets that can be deposited into the senior tranche
* @param _receiver The address that is depositing the assets
* @return assets The maximum amount of assets that can be deposited into the senior tranche, denominated in the senior tranche's tranche units
*/
function stMaxDeposit(address _receiver) external view returns (TRANCHE_UNIT assets);
/**
* @notice Returns the maximum amount of assets that can be withdrawn from the senior tranche
* @param _owner The address that is withdrawing the assets
* @return claimOnStNAV The notional claims on ST assets that the senior tranche has denominated in kernel's NAV units
* @return claimOnJtNAV The notional claims on JT assets that the senior tranche has denominated in kernel's NAV units
* @return stMaxWithdrawableNAV The maximum amount of assets that can be withdrawn from the senior tranche, denominated in the kernel's NAV units
* @return jtMaxWithdrawableNAV The maximum amount of assets that can be withdrawn from the junior tranche, denominated in the kernel's NAV units
*/
function stMaxWithdrawable(address _owner)
external
view
returns (NAV_UNIT claimOnStNAV, NAV_UNIT claimOnJtNAV, NAV_UNIT stMaxWithdrawableNAV, NAV_UNIT jtMaxWithdrawableNAV);
/**
* @notice Previews the deposit of a specified amount of assets into the senior tranche
* @dev The kernel may decide to simulate the deposit and revert internally with the result
* @dev Should revert if deposits are asynchronous
* @param _assets The amount of assets to deposit, denominated in the senior tranche's tranche units
* @return stateBeforeDeposit The state of the senior tranche before the deposit, after applying the pre-op sync
* @return valueAllocated The value of the assets deposited, denominated in the kernel's NAV units
*/
function stPreviewDeposit(TRANCHE_UNIT _assets) external view returns (SyncedAccountingState memory stateBeforeDeposit, NAV_UNIT valueAllocated);
/**
* @notice Previews the redemption of a specified number of shares from the senior tranche
* @dev The kernel may decide to simulate the redemption and revert internally with the result
* @dev Should revert if redemptions are asynchronous
* @param _shares The number of shares to redeem
* @return userClaim The distribution of assets that would be transferred to the receiver on redemption, denominated in the respective tranches' tranche units
*/
function stPreviewRedeem(uint256 _shares) external view returns (AssetClaims memory userClaim);
/**
* @notice Processes the deposit of a specified amount of assets into the senior tranche
* @dev Assumes that the funds are transferred to the kernel before the deposit call is made
* @param _assets The amount of assets to deposit, denominated in the senior tranche's tranche units
* @param _caller The address that is depositing the assets
* @param _receiver The address that is receiving the shares
* @return valueAllocated The value of the assets deposited, denominated in the kernel's NAV units
* @return navToMintAt The NAV at which the shares will be minted, exclusive of valueAllocated
* @return metadata The format prefixed metadata of the deposit
*/
function stDeposit(
TRANCHE_UNIT _assets,
address _caller,
address _receiver
)
external
returns (NAV_UNIT valueAllocated, NAV_UNIT navToMintAt, bytes memory metadata);
/**
* @notice Processes the redemption of a specified number of shares from the senior tranche
* @dev The function is expected to transfer the senior and junior assets directly to the receiver, based on the redemption claims
* @param _shares The number of shares to redeem
* @param _controller The controller that is allowed to operate the redemption
* @param _receiver The address that is receiving the assets
* @return claims The distribution of assets that were transferred to the receiver on redemption, denominated in the respective tranches' tranche units
* @return metadata The format prefixed metadata of the redemption
*/
function stRedeem(uint256 _shares, address _controller, address _receiver) external returns (AssetClaims memory claims, bytes memory metadata);
/**
* @notice Returns the maximum amount of assets that can be deposited into the junior tranche
* @param _receiver The address that is depositing the assets
* @return assets The maximum amount of assets that can be deposited into the junior tranche, denominated in the junior tranche's tranche units
*/
function jtMaxDeposit(address _receiver) external view returns (TRANCHE_UNIT assets);
/**
* @notice Returns the maximum amount of assets that can be withdrawn from the junior tranche
* @param _owner The address that is withdrawing the assets
* @return claimOnStNAV The notional claims on ST assets that the junior tranche has denominated in kernel's NAV units
* @return claimOnJtNAV The notional claims on JT assets that the junior tranche has denominated in kernel's NAV units
* @return stMaxWithdrawableNAV The maximum amount of assets that can be withdrawn from the senior tranche, denominated in the kernel's NAV units
* @return jtMaxWithdrawableNAV The maximum amount of assets that can be withdrawn from the junior tranche, denominated in the kernel's NAV units
*/
function jtMaxWithdrawable(address _owner)
external
view
returns (NAV_UNIT claimOnStNAV, NAV_UNIT claimOnJtNAV, NAV_UNIT stMaxWithdrawableNAV, NAV_UNIT jtMaxWithdrawableNAV);
/**
* @notice Previews the deposit of a specified amount of assets into the junior tranche
* @dev The kernel may decide to simulate the deposit and revert internally with the result
* @dev Should revert if deposits are asynchronous
* @param _assets The amount of assets to deposit, denominated in the junior tranche's tranche units
* @return stateBeforeDeposit The state of the junior tranche before the deposit, after applying the pre-op sync
* @return valueAllocated The value of the assets deposited, denominated in the kernel's NAV units
*/
function jtPreviewDeposit(TRANCHE_UNIT _assets) external view returns (SyncedAccountingState memory stateBeforeDeposit, NAV_UNIT valueAllocated);
/**
* @notice Previews the redemption of a specified number of shares from the junior tranche
* @dev The kernel may decide to simulate the redemption and revert internally with the result
* @dev Should revert if redemptions are asynchronous
* @param _shares The number of shares to redeem
* @return userClaim The distribution of assets that would be transferred to the receiver on redemption, denominated in the respective tranches' tranche units
*/
function jtPreviewRedeem(uint256 _shares) external view returns (AssetClaims memory userClaim);
/**
* @notice Processes the deposit of a specified amount of assets into the junior tranche
* @dev Assumes that the funds are transferred to the kernel before the deposit call is made
* @param _assets The amount of assets to deposit, denominated in the junior tranche's tranche units
* @param _caller The address that is depositing the assets
* @param _receiver The address that is receiving the shares
* @return valueAllocated The value of the assets deposited, denominated in the kernel's NAV units
* @return navToMintAt The NAV at which the shares will be minted, exclusive of valueAllocated
* @return metadata The format prefixed metadata of the deposit
*/
function jtDeposit(
TRANCHE_UNIT _assets,
address _caller,
address _receiver
)
external
returns (NAV_UNIT valueAllocated, NAV_UNIT navToMintAt, bytes memory metadata);
/**
* @notice Requests a redemption for a specified amount of shares from the underlying investment opportunity
* @param _caller The address of the user requesting the withdrawal for the junior tranche
* @param _shares The amount of shares of the junior tranche being requested to be redeemed
* @param _controller The controller that is allowed to operate the lifecycle of the request.
* @return requestId The request ID of this withdrawal request
* @return metadata The format prefixed metadata of the redemption request or empty bytes if no metadata is shared
*/
function jtRequestRedeem(address _caller, uint256 _shares, address _controller) external returns (uint256 requestId, bytes memory metadata);
/**
* @notice Returns the amount of assets pending redemption for a specific controller
* @param _requestId The request ID of this withdrawal request
* @param _controller The controller to query pending redemptions for
* @return pendingShares The amount of shares pending redemption for the controller
*/
function jtPendingRedeemRequest(uint256 _requestId, address _controller) external view returns (uint256 pendingShares);
/**
* @notice Returns the amount of shares claimable from completed redemption requests for a specific controller
* @param _requestId The request ID of this withdrawal request
* @param _controller The controller to query claimable redemptions for
* @return claimableShares The amount of shares claimable from completed redemption requests
*/
function jtClaimableRedeemRequest(uint256 _requestId, address _controller) external view returns (uint256 claimableShares);
/**
* @notice Cancels a pending redeem request for the specified controller
* @dev This function is only relevant if the kernel supports redeem cancellation
* @param _requestId The request ID of this deposit request
* @param _controller The controller that is allowed to operate the cancellation
*/
function jtCancelRedeemRequest(uint256 _requestId, address _controller) external;
/**
* @notice Returns whether there is a pending redeem cancellation for the specified controller
* @dev This function is only relevant if the kernel supports redeem cancellation
* @param _requestId The request ID of this deposit request
* @param _controller The controller to query for pending cancellation
* @return isPending True if there is a pending redeem cancellation
*/
function jtPendingCancelRedeemRequest(uint256 _requestId, address _controller) external view returns (bool isPending);
/**
* @notice Returns the amount of assets claimable from a redeem cancellation for the specified controller
* @dev This function is only relevant if the kernel supports redeem cancellation
* @param _requestId The request ID of this deposit request
* @param _controller The controller to query for claimable cancellation assets
* @return shares The amount of shares claimable from redeem cancellation
*/
function jtClaimableCancelRedeemRequest(uint256 _requestId, address _controller) external view returns (uint256 shares);
/**
* @notice Claims a canceled redeem request for a specified controller
* @dev This function is only relevant if the kernel supports redeem cancellation
* @param _requestId The request ID of this deposit request
* @param _controller The controller corresponding to this request
* @return shares The amount of shares claimed from the canceled redeem request
*/
function jtClaimCancelRedeemRequest(uint256 _requestId, address _controller) external returns (uint256 shares);
/**
* @notice Processes the redemption of a specified number of shares from the junior tranche
* @dev The function is expected to transfer the senior and junior assets directly to the receiver, based on the redemption claims
* @param _shares The number of shares to redeem
* @param _controller The controller that is allowed to operate the redemption
* @param _receiver The address that is receiving the assets
* @return claims The distribution of assets that were transferred to the receiver on redemption, denominated in the respective tranches' tranche units
* @return metadata The format prefixed metadata of the redemption or empty bytes if no metadata is shared
*/
function jtRedeem(uint256 _shares, address _controller, address _receiver) external returns (AssetClaims memory claims, bytes memory metadata);
/**
* @notice Sets the new protocol fee recipient
* @param _protocolFeeRecipient The address of the new protocol fee recipient
*/
function setProtocolFeeRecipient(address _protocolFeeRecipient) external;
/**
* @notice Sets the new junior tranche redemption delay
* @param _jtRedemptionDelayInSeconds The new junior tranche redemption delay in seconds
*/
function setJuniorTrancheRedemptionDelay(uint24 _jtRedemptionDelayInSeconds) external;
/**
* @notice Returns the state of the kernel
* @param seniorTranche The address of the Royco senior tranche associated with this kernel
* @param stAsset The address of the asset that ST is denominated in: constitutes the ST's tranche units (type and precision)
* @param juniorTranche The address of the Royco junior tranche associated with this kernel
* @param jtAsset The address of the asset that JT is denominated in: constitutes the ST's tranche units (type and precision)
* @param protocolFeeRecipient The market's configured protocol fee recipient
* @param accountant The address of the Royco accountant used to perform per operation accounting for this kernel
* @param jtRedemptionDelayInSeconds The redemption delay in seconds that a JT LP has to wait between requesting and executing a redemption
*/
function getState()
external
view
returns (
address seniorTranche,
address stAsset,
address juniorTranche,
address jtAsset,
address protocolFeeRecipient,
address accountant,
uint24 jtRedemptionDelayInSeconds
);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { NAV_UNIT, TRANCHE_UNIT } from "./Units.sol";
/// @dev Constant for 0 NAV units
NAV_UNIT constant ZERO_NAV_UNITS = NAV_UNIT.wrap(0);
/// @dev Constant for 0 tranche units
TRANCHE_UNIT constant ZERO_TRANCHE_UNITS = TRANCHE_UNIT.wrap(0);
/// @dev Constant for the max value expressable as tranche units
TRANCHE_UNIT constant MAX_TRANCHE_UNITS = TRANCHE_UNIT.wrap(type(uint256).max);
/// @dev Constant for the WAD scaling factor
uint256 constant WAD = 1e18;
/// @dev Constant for the number of decimals of precision a WAD denominated quantity has
uint256 constant WAD_DECIMALS = 18;
/// @dev Constant for the RAY scaling factor
uint256 constant RAY = 1e27;
/// @dev The minimum configurable coverage percentage, scaled to WAD precision
uint256 constant MIN_COVERAGE_WAD = 0.01e18;
/// @dev The max protocol fee percentage on tranche yields, scaled to WAD precision
uint256 constant MAX_PROTOCOL_FEE_WAD = 1e18;
/// @dev The request ID for a purely controller-discriminated request in ERC-7540
uint256 constant ERC_7540_CONTROLLER_DISCRIMINATED_REQUEST_ID = 0; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { RoycoBase } from "../../base/RoycoBase.sol";
import { ExecutionModel, IRoycoKernel, SharesRedemptionModel } from "../../interfaces/kernel/IRoycoKernel.sol";
import { IRoycoVaultTranche } from "../../interfaces/tranche/IRoycoVaultTranche.sol";
import { ERC_7540_CONTROLLER_DISCRIMINATED_REQUEST_ID, ZERO_NAV_UNITS, ZERO_TRANCHE_UNITS } from "../../libraries/Constants.sol";
import { RedemptionRequest, RoycoKernelInitParams, RoycoKernelState, RoycoKernelStorageLib } from "../../libraries/RoycoKernelStorageLib.sol";
import { ActionMetadataFormat, AssetClaims, SyncedAccountingState, TrancheType } from "../../libraries/Types.sol";
import { Math, NAV_UNIT, TRANCHE_UNIT, UnitsMathLib } from "../../libraries/Units.sol";
import { UtilsLib } from "../../libraries/UtilsLib.sol";
import { IRoycoAccountant, Operation } from "./../../interfaces/IRoycoAccountant.sol";
import { console2 } from "forge-std/console2.sol";
/**
* @title RoycoKernel
* @notice Abstract contract for Royco kernel implementations
* @dev Provides the foundational logic for kernel contracts including pre and post operation NAV reconciliation, coverage enforcement logic,
* and base wiring for tranche synchronization. All concrete kernel implementations should inherit from the Royco Kernel.
*/
abstract contract RoycoKernel is IRoycoKernel, RoycoBase {
using UnitsMathLib for NAV_UNIT;
using UnitsMathLib for TRANCHE_UNIT;
using UtilsLib for bytes;
/// @inheritdoc IRoycoKernel
/// @dev There is always a redemption delay on the junior tranche
ExecutionModel public constant JT_REDEEM_EXECUTION_MODEL = ExecutionModel.ASYNC;
/// @inheritdoc IRoycoKernel
SharesRedemptionModel public constant JT_REQUEST_REDEEM_SHARES_BEHAVIOR = SharesRedemptionModel.BURN_ON_CLAIM_REDEEM;
/// @dev Permissions the function to only the market's senior tranche
/// @dev Should be placed on all ST deposit and withdraw functions
modifier onlySeniorTranche() {
require(msg.sender == RoycoKernelStorageLib._getRoycoKernelStorage().seniorTranche, ONLY_SENIOR_TRANCHE());
_;
}
/// @dev Permissions the function to only the market's junior tranche
/// @dev Should be placed on all JT deposit and withdraw functions
modifier onlyJuniorTranche() {
require(msg.sender == RoycoKernelStorageLib._getRoycoKernelStorage().juniorTranche, ONLY_JUNIOR_TRANCHE());
_;
}
/// @notice Modifer to check that the provided JT redemption request ID implies pure controller discrimination
/// @param _requestId The JT redemption request ID to validate
modifier checkJTRedemptionRequestId(uint256 _requestId) {
require(_requestId == ERC_7540_CONTROLLER_DISCRIMINATED_REQUEST_ID, INVALID_REQUEST_ID(_requestId));
_;
}
// =============================
// Initializer and State Accessor Functions
// =============================
/**
* @notice Initializes the base kernel state
* @dev Initializes any parent contracts and the base kernel state
* @param _params The standard initialization parameters for the Royco kernel
* @param _stAsset The address of the asset that ST is denominated in: constitutes the ST's tranche units (type and precision)
* @param _jtAsset The address of the asset that JT is denominated in: constitutes the JT's tranche units (type and precision)
*/
function __RoycoKernel_init(RoycoKernelInitParams memory _params, address _stAsset, address _jtAsset) internal onlyInitializing {
// Initialize the Royco base state
__RoycoBase_init(_params.initialAuthority);
// Initialize the Royco kernel state
__RoycoKernel_init_unchained(_params, _stAsset, _jtAsset);
}
/**
* @notice Initializes the base kernel state
* @param _params The initialization parameters for the base kernel
* @param _stAsset The address of the asset that ST is denominated in: constitutes the ST's tranche units (type and precision)
* @param _jtAsset The address of the asset that JT is denominated in: constitutes the JT's tranche units (type and precision)
*/
function __RoycoKernel_init_unchained(RoycoKernelInitParams memory _params, address _stAsset, address _jtAsset) internal onlyInitializing {
// Ensure that the tranche addresses, accountant, and protocol fee recipient are not null
require(
_params.seniorTranche != address(0) && _params.juniorTranche != address(0) && _params.accountant != address(0)
&& _params.protocolFeeRecipient != address(0),
NULL_ADDRESS()
);
// Initialize the base kernel state
RoycoKernelStorageLib.__RoycoKernel_init(_params, _stAsset, _jtAsset);
}
/// @inheritdoc IRoycoKernel
function getState()
external
view
override(IRoycoKernel)
returns (
address seniorTranche,
address stAsset,
address juniorTranche,
address jtAsset,
address protocolFeeRecipient,
address accountant,
uint24 jtRedemptionDelayInSeconds
)
{
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
return ($.seniorTranche, $.stAsset, $.juniorTranche, $.jtAsset, $.protocolFeeRecipient, $.accountant, $.jtRedemptionDelayInSeconds);
}
// =============================
// Quoter Functions
// =============================
/// @inheritdoc IRoycoKernel
function stConvertTrancheUnitsToNAVUnits(TRANCHE_UNIT _stAssets) public view virtual override(IRoycoKernel) returns (NAV_UNIT);
/// @inheritdoc IRoycoKernel
function jtConvertTrancheUnitsToNAVUnits(TRANCHE_UNIT _jtAssets) public view virtual override(IRoycoKernel) returns (NAV_UNIT);
/// @inheritdoc IRoycoKernel
function stConvertNAVUnitsToTrancheUnits(NAV_UNIT _navAssets) public view virtual override(IRoycoKernel) returns (TRANCHE_UNIT);
/// @inheritdoc IRoycoKernel
function jtConvertNAVUnitsToTrancheUnits(NAV_UNIT _navAssets) public view virtual override(IRoycoKernel) returns (TRANCHE_UNIT);
// =============================
// Senior and Junior Tranche Max Deposit and Redeem Functions
// =============================
/// @inheritdoc IRoycoKernel
function stMaxDeposit(address _receiver) public view virtual override(IRoycoKernel) returns (TRANCHE_UNIT) {
NAV_UNIT stMaxDepositableNAV = _accountant().maxSTDepositGivenCoverage(_getSeniorTrancheRawNAV(), _getJuniorTrancheRawNAV());
return UnitsMathLib.min(_stMaxDepositGlobally(_receiver), stConvertNAVUnitsToTrancheUnits(stMaxDepositableNAV));
}
/// @inheritdoc IRoycoKernel
function stMaxWithdrawable(address _owner)
public
view
virtual
override(IRoycoKernel)
returns (NAV_UNIT claimOnStNAV, NAV_UNIT claimOnJtNAV, NAV_UNIT stMaxWithdrawableNAV, NAV_UNIT jtMaxWithdrawableNAV)
{
// Get the total claims the senior tranche has on each tranche's assets
(, AssetClaims memory stNotionalClaims,) = previewSyncTrancheAccounting(TrancheType.SENIOR);
claimOnStNAV = stConvertTrancheUnitsToNAVUnits(stNotionalClaims.stAssets);
claimOnJtNAV = jtConvertTrancheUnitsToNAVUnits(stNotionalClaims.jtAssets);
// Bound the claims by the max withdrawable assets globally for each tranche and compute the cumulative NAV
stMaxWithdrawableNAV = stConvertTrancheUnitsToNAVUnits(_stMaxWithdrawableGlobally(_owner));
jtMaxWithdrawableNAV = jtConvertTrancheUnitsToNAVUnits(_jtMaxWithdrawableGlobally(_owner));
}
/// @inheritdoc IRoycoKernel
function jtMaxDeposit(address _receiver) public view virtual override(IRoycoKernel) returns (TRANCHE_UNIT) {
return _jtMaxDepositGlobally(_receiver);
}
/// @inheritdoc IRoycoKernel
function jtMaxWithdrawable(address _owner)
public
view
virtual
override(IRoycoKernel)
returns (NAV_UNIT claimOnStNAV, NAV_UNIT claimOnJtNAV, NAV_UNIT stMaxWithdrawableNAV, NAV_UNIT jtMaxWithdrawableNAV)
{
// Get the total claims the junior tranche has on each tranche's assets
(SyncedAccountingState memory state, AssetClaims memory jtNotionalClaims,) = previewSyncTrancheAccounting(TrancheType.JUNIOR);
// Get the max withdrawable ST and JT assets in NAV units from the accountant consider coverage requirement
(, NAV_UNIT stClaimableGivenCoverage, NAV_UNIT jtClaimableGivenCoverage) = _accountant()
.maxJTWithdrawalGivenCoverage(
state.stRawNAV,
state.jtRawNAV,
stConvertTrancheUnitsToNAVUnits(jtNotionalClaims.stAssets),
jtConvertTrancheUnitsToNAVUnits(jtNotionalClaims.jtAssets)
);
claimOnStNAV = stConvertTrancheUnitsToNAVUnits(jtNotionalClaims.stAssets);
claimOnJtNAV = jtConvertTrancheUnitsToNAVUnits(jtNotionalClaims.jtAssets);
// Bound the claims by the max withdrawable assets globally for each tranche and compute the cumulative NAV
stMaxWithdrawableNAV = UnitsMathLib.min(stConvertTrancheUnitsToNAVUnits(_stMaxWithdrawableGlobally(_owner)), stClaimableGivenCoverage);
jtMaxWithdrawableNAV = UnitsMathLib.min(jtConvertTrancheUnitsToNAVUnits(_jtMaxWithdrawableGlobally(_owner)), jtClaimableGivenCoverage);
}
// =============================
// External Tranche Accounting Synchronization Functions
// =============================
/// @inheritdoc IRoycoKernel
function syncTrancheAccounting() public virtual override(IRoycoKernel) whenNotPaused restricted returns (SyncedAccountingState memory state) {
// Execute a pre-op accounting sync via the accountant
return _preOpSyncTrancheAccounting();
}
/// @inheritdoc IRoycoKernel
function previewSyncTrancheAccounting(TrancheType _trancheType)
public
view
virtual
override(IRoycoKernel)
returns (SyncedAccountingState memory state, AssetClaims memory claims, uint256 totalTrancheShares)
{
// Preview an accounting sync via the accountant
state = _previewSyncTrancheAccounting();
// Decompose effective NAVs into self-backed NAV claims and cross-tranche NAV claims
(NAV_UNIT stNAVClaimOnSelf, NAV_UNIT stNAVClaimOnJT, NAV_UNIT jtNAVClaimOnSelf, NAV_UNIT jtNAVClaimOnST) = _decomposeNAVClaims(state);
// Marshal the tranche claims for this tranche given the decomposed claims
claims =
_marshalAssetClaims(_trancheType, state.stEffectiveNAV, state.jtEffectiveNAV, stNAVClaimOnSelf, stNAVClaimOnJT, jtNAVClaimOnSelf, jtNAVClaimOnST);
// Preview the total tranche shares after minting any protocol fee shares post-sync
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
if (_trancheType == TrancheType.SENIOR) {
(, totalTrancheShares) = IRoycoVaultTranche($.seniorTranche).previewMintProtocolFeeShares(state.stProtocolFeeAccrued, state.stEffectiveNAV);
} else {
(, totalTrancheShares) = IRoycoVaultTranche($.juniorTranche).previewMintProtocolFeeShares(state.jtProtocolFeeAccrued, state.jtEffectiveNAV);
}
}
// =============================
// Senior Tranche Deposit and Redeem Functions
// =============================
/// @inheritdoc IRoycoKernel
function stDeposit(
TRANCHE_UNIT _assets,
address,
address
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlySeniorTranche
returns (NAV_UNIT valueAllocated, NAV_UNIT navToMintAt, bytes memory)
{
// Execute a pre-op sync on accounting
navToMintAt = (_preOpSyncTrancheAccounting()).stEffectiveNAV;
// Deposit the assets into the underlying ST investment
_stDepositAssets(_assets);
// Execute a post-op sync on accounting and enforce the market's coverage requirement
NAV_UNIT stPostDepositNAV = (_postOpSyncTrancheAccountingAndEnforceCoverage(Operation.ST_INCREASE_NAV)).stEffectiveNAV;
// The value allocated after any fees/slippage incurred on deposit
valueAllocated = stPostDepositNAV - navToMintAt;
}
/// @inheritdoc IRoycoKernel
function stRedeem(
uint256 _shares,
address,
address _receiver
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlySeniorTranche
returns (AssetClaims memory userAssetClaims, bytes memory)
{
// Execute a pre-op sync on accounting
uint256 totalTrancheShares;
(, userAssetClaims, totalTrancheShares) = _preOpSyncTrancheAccounting(TrancheType.SENIOR);
// Scale total tranche asset claims by the ratio of shares this user owns of the tranche vault
// Protocol fee shares were minted in the pre-op sync, so the total tranche shares are up to date
userAssetClaims = UtilsLib.scaleAssetClaims(userAssetClaims, _shares, totalTrancheShares);
// Withdraw the asset claims from each tranche and transfer them to the receiver
_withdrawAssets(userAssetClaims, _receiver);
// Execute a post-op sync on accounting
_postOpSyncTrancheAccounting(Operation.ST_DECREASE_NAV);
}
// =============================
// Junior Tranche Deposit and Redeem Functions
// =============================
/// @inheritdoc IRoycoKernel
function jtDeposit(
TRANCHE_UNIT _assets,
address,
address
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlyJuniorTranche
returns (NAV_UNIT valueAllocated, NAV_UNIT navToMintAt, bytes memory)
{
// Execute a pre-op sync on accounting
navToMintAt = (_preOpSyncTrancheAccounting()).jtEffectiveNAV;
// Deposit the assets into the underlying ST investment
_jtDepositAssets(_assets);
// Execute a post-op sync on accounting and enforce the market's coverage requirement
NAV_UNIT jtPostDepositNAV = (_postOpSyncTrancheAccounting(Operation.JT_INCREASE_NAV)).jtEffectiveNAV;
// The value allocated after any fees/slippage incurred on deposit
valueAllocated = jtPostDepositNAV - navToMintAt;
}
/// @inheritdoc IRoycoKernel
function jtPreviewRedeem(uint256) public pure override returns (AssetClaims memory) {
revert PREVIEW_REDEEM_DISABLED_FOR_ASYNC_REDEMPTION();
}
/// @inheritdoc IRoycoKernel
function jtRequestRedeem(
address,
uint256 _shares,
address _controller
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlyJuniorTranche
returns (uint256 requestId, bytes memory metadata)
{
// Execute a pre-op sync on accounting
(SyncedAccountingState memory state,, uint256 totalTrancheShares) = _preOpSyncTrancheAccounting(TrancheType.JUNIOR);
// Ensure that the redemption request for this controller isn't canceled
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
RedemptionRequest storage request = $.jtControllerToRedemptionRequest[_controller];
require(!request.isCanceled, REDEMPTION_REQUEST_CANCELED());
/// @dev JT LPs are not entitled to any JT upside during the redemption delay, but they are liable for providing coverage to ST LPs during the redemption delay
// Compute the current NAV of the shares being requested to be redeemed
NAV_UNIT redemptionValueAtRequestTime = state.jtEffectiveNAV.mulDiv(_shares, totalTrancheShares, Math.Rounding.Floor);
// Add the shares to the total shares to redeem in the controller's current redemption request
// If an existing redemption request exists, it's redemption delay is refreshed based on the current time
request.totalJTSharesToRedeem += _shares;
request.redemptionValueAtRequestTime = request.redemptionValueAtRequestTime + redemptionValueAtRequestTime;
uint256 claimableAtTimestamp = request.claimableAtTimestamp = uint32(block.timestamp + $.jtRedemptionDelayInSeconds);
// JT Redeem Requests are purely controller-discriminated, so the request ID is always 0
requestId = ERC_7540_CONTROLLER_DISCRIMINATED_REQUEST_ID;
metadata = abi.encode(claimableAtTimestamp).format(ActionMetadataFormat.REDEMPTION_CLAIMABLE_AT_TIMESTAMP);
}
/// @inheritdoc IRoycoKernel
function jtPendingRedeemRequest(
uint256 _requestId,
address _controller
)
public
view
virtual
override(IRoycoKernel)
checkJTRedemptionRequestId(_requestId)
returns (uint256 pendingShares)
{
RedemptionRequest storage request = RoycoKernelStorageLib._getRoycoKernelStorage().jtControllerToRedemptionRequest[_controller];
// If the redemption is canceled or the request is claimable, no shares are still in a pending state
if (request.isCanceled || request.claimableAtTimestamp <= block.timestamp) return 0;
// The shares in the controller's redemption request are still pending
pendingShares = request.totalJTSharesToRedeem;
}
/// @inheritdoc IRoycoKernel
function jtClaimableRedeemRequest(
uint256 _requestId,
address _controller
)
public
view
virtual
override(IRoycoKernel)
checkJTRedemptionRequestId(_requestId)
returns (uint256 claimableShares)
{
// Get how many shares from the request are now in a redeemable (claimable) state
RedemptionRequest storage request = RoycoKernelStorageLib._getRoycoKernelStorage().jtControllerToRedemptionRequest[_controller];
claimableShares = _getRedeemableSharesForRequest(request);
}
/// @inheritdoc IRoycoKernel
function jtCancelRedeemRequest(
uint256 _requestId,
address _controller
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlyJuniorTranche
checkJTRedemptionRequestId(_requestId)
{
RedemptionRequest storage request = RoycoKernelStorageLib._getRoycoKernelStorage().jtControllerToRedemptionRequest[_controller];
// Cannot cancel an already canceled request
require(!request.isCanceled, REDEMPTION_REQUEST_CANCELED());
// Cannot cancel a non-existant redemption request
require(request.totalJTSharesToRedeem != 0, NONEXISTANT_REQUEST_TO_CANCEL());
// Mark this request as canceled
request.isCanceled = true;
}
/// @inheritdoc IRoycoKernel
function jtPendingCancelRedeemRequest(
uint256 _requestId,
address
)
public
pure
virtual
override(IRoycoKernel)
checkJTRedemptionRequestId(_requestId)
returns (bool isPending)
{
// Cancellation requests are always processed instantly, so there can never be a pending cancellation
isPending = false;
}
/// @inheritdoc IRoycoKernel
function jtClaimableCancelRedeemRequest(
uint256 _requestId,
address _controller
)
public
view
virtual
override(IRoycoKernel)
checkJTRedemptionRequestId(_requestId)
returns (uint256 shares)
{
RedemptionRequest storage request = RoycoKernelStorageLib._getRoycoKernelStorage().jtControllerToRedemptionRequest[_controller];
// If the redemption is not canceled, there are no shares to claim
if (!request.isCanceled) return 0;
// Return the shares for the redemption request that has been requested to be canceled
shares = request.totalJTSharesToRedeem;
}
/// @inheritdoc IRoycoKernel
function jtClaimCancelRedeemRequest(
uint256 _requestId,
address _controller
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlyJuniorTranche
checkJTRedemptionRequestId(_requestId)
returns (uint256 shares)
{
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
RedemptionRequest storage request = $.jtControllerToRedemptionRequest[_controller];
// Cannot claim back shares from a request that hasn't been cancelled
require(request.isCanceled, REDEMPTION_REQUEST_NOT_CANCELED());
// Return the number of shares that need to be claimed after request cancellation
shares = request.totalJTSharesToRedeem;
// Clear all redemption state since cancellation has been processed
delete $.jtControllerToRedemptionRequest[_controller];
}
/// @inheritdoc IRoycoKernel
function jtRedeem(
uint256 _shares,
address _controller,
address _receiver
)
public
virtual
override(IRoycoKernel)
whenNotPaused
onlyJuniorTranche
returns (AssetClaims memory userAssetClaims, bytes memory)
{
// Execute a pre-op sync on accounting
SyncedAccountingState memory state;
uint256 totalTrancheShares;
(state, userAssetClaims, totalTrancheShares) = _preOpSyncTrancheAccounting(TrancheType.JUNIOR);
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
RedemptionRequest storage request = $.jtControllerToRedemptionRequest[_controller];
// Ensure that the the shares that need to be redeemed are allowed to be redeemed for this controller
uint256 redeemableShares = _getRedeemableSharesForRequest(request);
require(_shares <= redeemableShares, INSUFFICIENT_REDEEMABLE_SHARES(_shares, redeemableShares));
// Compute the current NAV and the NAV at request time of the shares being redeemed
NAV_UNIT redemptionValueAtCurrentTime = state.jtEffectiveNAV.mulDiv(_shares, totalTrancheShares, Math.Rounding.Floor);
NAV_UNIT redemptionValueAtRequestTime = request.redemptionValueAtRequestTime.mulDiv(_shares, request.totalJTSharesToRedeem, Math.Rounding.Floor);
/// @dev JT LPs are not entitled to any JT upside during the redemption delay, but they are liable for providing coverage to ST LPs during the redemption delay
NAV_UNIT navOfSharesToRedeem = UnitsMathLib.min(redemptionValueAtCurrentTime, redemptionValueAtRequestTime);
// Update the request accounting based on the shares being redeemed
uint256 sharesRemaining = request.totalJTSharesToRedeem - _shares;
// If there are no remaining shares, delete the controller's redemption
if (sharesRemaining == 0) {
delete $.jtControllerToRedemptionRequest[_controller];
} else {
// Update the redemption value at request for the remaining shares by the amount that
request.redemptionValueAtRequestTime = request.redemptionValueAtRequestTime - redemptionValueAtRequestTime;
request.totalJTSharesToRedeem = sharesRemaining;
}
// Scale the claims based on the NAV to liquidate for the user relative to the total JT controlled NAV
userAssetClaims = UtilsLib.scaleAssetClaims(userAssetClaims, navOfSharesToRedeem, state.jtEffectiveNAV);
// Withdraw the asset claims from each tranche and transfer them to the receiver
_withdrawAssets(userAssetClaims, _receiver);
// Execute a post-op sync on accounting and enforce the market's coverage requirement
_postOpSyncTrancheAccountingAndEnforceCoverage(Operation.JT_DECREASE_NAV);
return (userAssetClaims, "");
}
// =============================
// Admin Functions
// =============================
/// @inheritdoc IRoycoKernel
function setProtocolFeeRecipient(address _protocolFeeRecipient) external override(IRoycoKernel) restricted {
require(_protocolFeeRecipient != address(0), NULL_ADDRESS());
RoycoKernelStorageLib._getRoycoKernelStorage().protocolFeeRecipient = _protocolFeeRecipient;
emit ProtocolFeeRecipientUpdated(_protocolFeeRecipient);
}
/// @inheritdoc IRoycoKernel
function setJuniorTrancheRedemptionDelay(uint24 _jtRedemptionDelayInSeconds) external override(IRoycoKernel) restricted {
RoycoKernelStorageLib._getRoycoKernelStorage().jtRedemptionDelayInSeconds = _jtRedemptionDelayInSeconds;
emit JuniorTrancheRedemptionDelayUpdated(_jtRedemptionDelayInSeconds);
}
// =============================
// Internal Tranche Accounting Synchronization Functions
// =============================
/**
* @notice Previews an accounting sync via the accountant
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function _previewSyncTrancheAccounting() internal view virtual returns (SyncedAccountingState memory state) {
// Preview an accounting sync via the accountant
state = _accountant().previewSyncTrancheAccounting(_getSeniorTrancheRawNAV(), _getJuniorTrancheRawNAV());
}
/**
* @notice Invokes the accountant to do a pre-operation (deposit and withdrawal) NAV sync and mints any protocol fee shares accrued
* @notice Also returns the asset claims and total tranche shares after minting any fees
* @dev Should be called on every NAV mutating user operation
* @param _trancheType An enum indicating which tranche to return claims and total tranche shares for
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
* @return claims The claims on ST and JT assets that the specified tranche has denominated in tranche-native units
* @return totalTrancheShares The total shares outstanding in the specified tranche after minting any protocol fee shares
*/
function _preOpSyncTrancheAccounting(TrancheType _trancheType)
internal
virtual
returns (SyncedAccountingState memory state, AssetClaims memory claims, uint256 totalTrancheShares)
{
// Execute the pre-op sync via the accountant
state = _accountant().preOpSyncTrancheAccounting(_getSeniorTrancheRawNAV(), _getJuniorTrancheRawNAV());
// Collect any protocol fees accrued from the sync to the fee recipient
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
address protocolFeeRecipient = $.protocolFeeRecipient;
uint256 stTotalTrancheSharesAfterMintingFees;
uint256 jtTotalTrancheSharesAfterMintingFees;
// If ST fees were accrued or we need to get total shares for ST, mint ST protocol fee shares to the protocol fee recipient
if (state.stProtocolFeeAccrued != ZERO_NAV_UNITS || _trancheType == TrancheType.SENIOR) {
(, stTotalTrancheSharesAfterMintingFees) =
IRoycoVaultTranche($.seniorTranche).mintProtocolFeeShares(state.stProtocolFeeAccrued, state.stEffectiveNAV, protocolFeeRecipient);
}
// If JT fees were accrued or we need to get total shares for JT, mint JT protocol fee shares to the protocol fee recipient
if (state.jtProtocolFeeAccrued != ZERO_NAV_UNITS || _trancheType == TrancheType.JUNIOR) {
(, jtTotalTrancheSharesAfterMintingFees) =
IRoycoVaultTranche($.juniorTranche).mintProtocolFeeShares(state.jtProtocolFeeAccrued, state.jtEffectiveNAV, protocolFeeRecipient);
}
// Set the total tranche shares to the specified tranche's shares after minting fees
totalTrancheShares = (_trancheType == TrancheType.SENIOR) ? stTotalTrancheSharesAfterMintingFees : jtTotalTrancheSharesAfterMintingFees;
// Decompose effective NAVs into self-backed NAV claims and cross-tranche NAV claims
(NAV_UNIT stNAVClaimOnSelf, NAV_UNIT stNAVClaimOnJT, NAV_UNIT jtNAVClaimOnSelf, NAV_UNIT jtNAVClaimOnST) = _decomposeNAVClaims(state);
// Marshal the tranche claims for this tranche given the decomposed claims
claims =
_marshalAssetClaims(_trancheType, state.stEffectiveNAV, state.jtEffectiveNAV, stNAVClaimOnSelf, stNAVClaimOnJT, jtNAVClaimOnSelf, jtNAVClaimOnST);
}
/**
* @notice Invokes the accountant to do a pre-operation (deposit and withdrawal) NAV sync and mints any protocol fee shares accrued
* @dev Should be called on every NAV mutating user operation
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function _preOpSyncTrancheAccounting() internal virtual returns (SyncedAccountingState memory state) {
// Execute the pre-op sync via the accountant
state = _accountant().preOpSyncTrancheAccounting(_getSeniorTrancheRawNAV(), _getJuniorTrancheRawNAV());
// Collect any protocol fees accrued from the sync to the fee recipient
RoycoKernelState storage $ = RoycoKernelStorageLib._getRoycoKernelStorage();
if (state.stProtocolFeeAccrued != ZERO_NAV_UNITS || state.jtProtocolFeeAccrued != ZERO_NAV_UNITS) {
address protocolFeeRecipient = $.protocolFeeRecipient;
// If ST fees were accrued or we need to get total shares for ST, mint ST protocol fee shares to the protocol fee recipient
if (state.stProtocolFeeAccrued != ZERO_NAV_UNITS) {
IRoycoVaultTranche($.seniorTranche).mintProtocolFeeShares(state.stProtocolFeeAccrued, state.stEffectiveNAV, protocolFeeRecipient);
}
// If JT fees were accrued or we need to get total shares for JT, mint JT protocol fee shares to the protocol fee recipient
if (state.jtProtocolFeeAccrued != ZERO_NAV_UNITS) {
IRoycoVaultTranche($.juniorTranche).mintProtocolFeeShares(state.jtProtocolFeeAccrued, state.jtEffectiveNAV, protocolFeeRecipient);
}
}
}
/**
* @notice Invokes the accountant to do a post-operation (deposit and withdrawal) NAV sync
* @dev Should be called on every NAV mutating user operation that doesn't require a coverage check
* @param _op The operation being executed in between the pre and post synchronizations
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function _postOpSyncTrancheAccounting(Operation _op) internal virtual returns (SyncedAccountingState memory state) {
// Execute the post-op sync on the accountant
console2.log("before post-op sync");
state = _accountant().postOpSyncTrancheAccounting(_getSeniorTrancheRawNAV(), _getJuniorTrancheRawNAV(), _op);
console2.log("after post-op sync");
}
/**
* @notice Invokes the accountant to do a post-operation (deposit and withdrawal) NAV sync and checks the market's coverage requirement is satisfied
* @dev Should be called on every NAV mutating user operation that requires a coverage check: ST deposit and JT withdrawal
* @param _op The operation being executed in between the pre and post synchronizations
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function _postOpSyncTrancheAccountingAndEnforceCoverage(Operation _op) internal virtual returns (SyncedAccountingState memory state) {
// Execute the post-op sync on the accountant
return _accountant().postOpSyncTrancheAccountingAndEnforceCoverage(_getSeniorTrancheRawNAV(), _getJuniorTrancheRawNAV(), _op);
}
/**
* @notice Decomposes effective NAVs into self-backed NAV claims and cross-tranche NAV claims
* @param _state The synced NAV, debt, and fee accounting containing all mark to market accounting data
* @return stNAVClaimOnSelf The portion of ST's effective NAV that must be funded by ST’s raw NAV
* @return stNAVClaimOnJT The portion of ST's effective NAV that must be funded by JT’s raw NAV
* @return jtNAVClaimOnSelf The portion of JT's effective NAV that must be funded by JT’s raw NAV
* @return jtNAVClaimOnST The portion of JT's effective NAV that must be funded by ST’s raw NAV
*/
function _decomposeNAVClaims(SyncedAccountingState memory _state)
internal
pure
virtual
returns (NAV_UNIT stNAVClaimOnSelf, NAV_UNIT stNAVClaimOnJT, NAV_UNIT jtNAVClaimOnSelf, NAV_UNIT jtNAVClaimOnST)
{
// Cross-tranche claims (only one direction should be non-zero under conservation)
stNAVClaimOnJT = UnitsMathLib.saturatingSub(_state.stEffectiveNAV, _state.stRawNAV);
jtNAVClaimOnST = UnitsMathLib.saturatingSub(_state.jtEffectiveNAV, _state.jtRawNAV);
// Self-backed portions (the remainder of each tranche’s effective NAV)
stNAVClaimOnSelf = UnitsMathLib.saturatingSub(_state.stRawNAV, jtNAVClaimOnST);
jtNAVClaimOnSelf = UnitsMathLib.saturatingSub(_state.jtRawNAV, stNAVClaimOnJT);
}
/**
* @notice Converts NAV denominated claim components into concrete claimable tranche units
* @param _trancheType An enum indicating which tranche to construct the claim for
* @param _stEffectiveNAV The effective NAV of the senior tranche
* @param _jtEffectiveNAV The effective NAV of the junior tranche
* @param _stNAVClaimOnSelf The portion of ST's effective NAV that must be funded by ST’s raw NAV
* @param _stNAVClaimOnJT The portion of ST's effective NAV that must be funded by JT’s raw NAV
* @param _jtNAVClaimOnSelf The portion of JT's effective NAV that must be funded by JT’s raw NAV
* @param _jtNAVClaimOnST The portion of JT's effective NAV that must be funded by ST’s raw NAV
* @return claims The claims on ST and JT assets that the specified tranche has denominated in tranche-native units
*/
function _marshalAssetClaims(
TrancheType _trancheType,
NAV_UNIT _stEffectiveNAV,
NAV_UNIT _jtEffectiveNAV,
NAV_UNIT _stNAVClaimOnSelf,
NAV_UNIT _stNAVClaimOnJT,
NAV_UNIT _jtNAVClaimOnSelf,
NAV_UNIT _jtNAVClaimOnST
)
internal
view
virtual
returns (AssetClaims memory claims)
{
if (_trancheType == TrancheType.SENIOR) {
if (_stNAVClaimOnSelf != ZERO_NAV_UNITS) claims.stAssets = stConvertNAVUnitsToTrancheUnits(_stNAVClaimOnSelf);
if (_stNAVClaimOnJT != ZERO_NAV_UNITS) claims.jtAssets = jtConvertNAVUnitsToTrancheUnits(_stNAVClaimOnJT);
claims.nav = _stEffectiveNAV;
} else {
if (_jtNAVClaimOnST != ZERO_NAV_UNITS) claims.stAssets = stConvertNAVUnitsToTrancheUnits(_jtNAVClaimOnST);
if (_jtNAVClaimOnSelf != ZERO_NAV_UNITS) claims.jtAssets = jtConvertNAVUnitsToTrancheUnits(_jtNAVClaimOnSelf);
claims.nav = _jtEffectiveNAV;
}
}
// =============================
// Internal Utility Functions
// =============================
/**
* @notice Withdraws any specified assets from each tranche and transfer them to the receiver
* @param _claims The ST and JT assets to withdraw and transfer to the specified receiver
* @param _receiver The receiver of the tranche asset claims
*/
function _withdrawAssets(AssetClaims memory _claims, address _receiver) internal virtual {
TRANCHE_UNIT stAssetsToClaim = _claims.stAssets;
TRANCHE_UNIT jtAssetsToClaim = _claims.jtAssets;
// Withdraw the ST and JT assets if non-zero
if (stAssetsToClaim != ZERO_TRANCHE_UNITS) _stWithdrawAssets(stAssetsToClaim, _receiver);
if (jtAssetsToClaim != ZERO_TRANCHE_UNITS) _jtWithdrawAssets(jtAssetsToClaim, _receiver);
}
/**
* @notice Previews the amount of ST and JT assets that would be redeemed for a given number of shares
* @param _shares The number of shares to redeem
* @param _trancheType The type of tranche to preview the redemption for
* @return userClaim The amount of ST and JT assets that would be redeemed for the given number of shares
*/
function _previewRedeem(uint256 _shares, TrancheType _trancheType) internal view virtual returns (AssetClaims memory userClaim) {
// Get the total claim of ST on the ST and JT assets, and scale it to the number of shares being redeemed
(, AssetClaims memory totalClaims, uint256 totalTrancheShares) = previewSyncTrancheAccounting(_trancheType);
AssetClaims memory scaledClaims = UtilsLib.scaleAssetClaims(totalClaims, _shares, totalTrancheShares);
// Preview the amount of ST assets that would be redeemed for the given amount of shares
userClaim.stAssets = _stPreviewWithdraw(scaledClaims.stAssets);
userClaim.jtAssets = _jtPreviewWithdraw(scaledClaims.jtAssets);
userClaim.nav = stConvertTrancheUnitsToNAVUnits(userClaim.stAssets) + jtConvertTrancheUnitsToNAVUnits(userClaim.jtAssets);
}
/**
* @notice Returns the amount of JT shares redeemable from a redemption request
* @param _request The redemption request to get redeemable shares for
* @return claimableShares The amount of JT shares currently redeemable from the specified redemption request
*/
function _getRedeemableSharesForRequest(RedemptionRequest storage _request) internal view virtual returns (uint256 claimableShares) {
// If the request is canceled or not claimable, no shares are claimable
if (_request.isCanceled || _request.claimableAtTimestamp > block.timestamp) return 0;
// Return the shares in the request
claimableShares = _request.totalJTSharesToRedeem;
}
/**
* @notice Returns this kernel's accountant casted to the IRoycoAccountant interface
* @return accountant The Royco Accountant for this kernel
*/
function _accountant() internal view returns (IRoycoAccountant accountant) {
return IRoycoAccountant(RoycoKernelStorageLib._getRoycoKernelStorage().accountant);
}
// =============================
// Internal NAV Retrieval Functions
// =============================
/**
* @notice Returns the raw net asset value of the senior tranche denominated in the NAV units (USD, BTC, etc.) for this kernel
* @return stRawNAV The pure net asset value of the senior tranche invested assets
*/
function _getSeniorTrancheRawNAV() internal view virtual returns (NAV_UNIT stRawNAV);
/**
* @notice Returns the raw net asset value of the junior tranche denominated in the NAV units (USD, BTC, etc.) for this kernel
* @return jtRawNAV The pure net asset value of the junior tranche invested assets
*/
function _getJuniorTrancheRawNAV() internal view virtual returns (NAV_UNIT jtRawNAV);
// =============================
// Internal Tranche Specific Helper Functions
// =============================
/**
* @notice Returns the maximum amount of assets that can be deposited into the senior tranche globally
* @dev Implementation should consider protocol-wide limits and liquidity constraints
* @param _receiver The receiver of the shares for the assets being deposited (used to enforce white/black lists)
*/
function _stMaxDepositGlobally(address _receiver) internal view virtual returns (TRANCHE_UNIT);
/**
* @notice Returns the maximum amount of assets that can be deposited into the junior tranche globally
* @dev Implementation should consider protocol-wide limits and liquidity constraints
* @param _receiver The receiver of the shares for the assets being deposited (used to enforce white/black lists)
*/
function _jtMaxDepositGlobally(address _receiver) internal view virtual returns (TRANCHE_UNIT);
/**
* @notice Returns the maximum amount of assets that can be withdrawn from the senior tranche globally
* @dev Implementation should consider protocol-wide limits and liquidity constraints
* @param _owner The owner of the assets being withdrawn (used to enforce white/black lists)
*/
function _stMaxWithdrawableGlobally(address _owner) internal view virtual returns (TRANCHE_UNIT);
/**
* @notice Returns the maximum amount of assets that can be withdrawn from the junior tranche globally
* @dev Implementation should consider protocol-wide limits and liquidity constraints
* @param _owner The owner of the assets being withdrawn (used to enforce white/black lists)
*/
function _jtMaxWithdrawableGlobally(address _owner) internal view virtual returns (TRANCHE_UNIT);
/**
* @notice Previews the amount of ST assets that would be redeemed for a given amount of ST assets
* @param _stAssets The ST assets denominated in its tranche units to redeem
* @return withdrawnSTAssets The amount of ST assets that would be redeemed for the given amount of ST assets
*/
function _stPreviewWithdraw(TRANCHE_UNIT _stAssets) internal view virtual returns (TRANCHE_UNIT withdrawnSTAssets);
/**
* @notice Previews the amount of JT assets that would be redeemed for a given amount of JT assets
* @param _jtAssets The JT assets denominated in its tranche units to redeem
* @return withdrawnJTAssets The amount of JT assets that would be redeemed for the given amount of JT assets
*/
function _jtPreviewWithdraw(TRANCHE_UNIT _jtAssets) internal view virtual returns (TRANCHE_UNIT withdrawnJTAssets);
/**
* @notice Deposits ST assets into its underlying investment opportunity
* @dev Mandates that the underlying ownership over the deposit (receipt tokens, underlying investment accounting, etc) is retained by the kernel
* @param _stAssets The ST assets denominated in its tranche units to deposit into its underlying investment opportunity
*/
function _stDepositAssets(TRANCHE_UNIT _stAssets) internal virtual;
/**
* @notice Deposits JT assets into its underlying investment opportunity
* @dev Mandates that the underlying ownership over the deposit (receipt tokens, underlying investment accounting, etc) is retained by the kernel
* @param _jtAssets The JT assets denominated in its tranche units to deposit into its underlying investment opportunity
*/
function _jtDepositAssets(TRANCHE_UNIT _jtAssets) internal virtual;
/**
* @notice Withdraws ST assets to the specified receiver
* @param _stAssets The ST assets denominated in its tranche units to withdraw to the receiver
* @param _receiver The receiver of the ST assets
*/
function _stWithdrawAssets(TRANCHE_UNIT _stAssets, address _receiver) internal virtual;
/**
* @notice Withdraws JT assets to the specified receiver
* @param _jtAssets The JT assets denominated in its tranche units to withdraw to the receiver
* @param _receiver The receiver of the JT assets
*/
function _jtWithdrawAssets(TRANCHE_UNIT _jtAssets, address _receiver) internal virtual;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (interfaces/IERC4626.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Deposit `assets` underlying tokens and send the corresponding number of vault shares (`shares`) to `receiver`.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly `shares` vault shares to `receiver` in exchange for `assets` underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
/**
* @notice Storage state for kernels that deposit into ERC4626 vaults
* @custom:storage-location erc7201:Royco.storage.ERC4626KernelState
* @custom:field stVault - The address of the ERC4626 vault for the ST
* @custom:field stOwnedShares - The number of shares ST owns for ST's ERC4626 vault
* @custom:field jtVault - The address of the ERC4626 vault for the JT
* @custom:field jtOwnedShares - The number of shares JT owns for JT's ERC4626 vault
*/
struct ERC4626KernelState {
address stVault;
uint256 stOwnedShares;
address jtVault;
uint256 jtOwnedShares;
}
/**
* @title ERC4626KernelStorageLib
* @notice A lightweight storage library for reading and mutating state for kernels that deposit into ERC4626 vaults
*/
library ERC4626KernelStorageLib {
/// @dev Storage slot for ERC4626KernelState using ERC-7201 pattern
// keccak256(abi.encode(uint256(keccak256("Royco.storage.ERC4626KernelState")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC4626_KERNEL_STORAGE_SLOT = 0x31dcae1a6c8e7be3177d6c56be6f186dd279c19bdd7d7f4820a1be934a634800;
/**
* @notice Returns a storage pointer to the ERC4626KernelState storage
* @dev Uses ERC-7201 storage slot pattern for collision-resistant storage
* @return $ Storage pointer to the ERC4626 ST kernel state
*/
function _getERC4626KernelStorage() internal pure returns (ERC4626KernelState storage $) {
assembly ("memory-safe") {
$.slot := ERC4626_KERNEL_STORAGE_SLOT
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { Operation, SyncedAccountingState } from "../libraries/Types.sol";
import { NAV_UNIT } from "../libraries/Units.sol";
/**
* @title IRoycoAccountant
* @notice Interface for the RoycoAccountant contract that manages tranche NAVs and coverage requirements
*/
interface IRoycoAccountant {
/**
* @notice Initialization parameters for the Royco Accountant
* @custom:field kernel - The kernel that this accountant maintains NAV, debt, and fee accounting for
* @custom:field protocolFeeWAD - The market's configured protocol fee percentage taken from yield earned by senior and junior tranches, scaled to WAD precision
* @custom:field coverageWAD - The coverage ratio that the senior tranche is expected to be protected by, scaled to WAD precision
* @custom:field betaWAD - The junior tranche's sensitivity to the same downside stress that affects the senior tranche, scaled to WAD precision
* For example, beta is 0 when JT is in the RFR and 1 when JT is in the same opportunity as senior
* @custom:field rdm - The market's Reward Distribution Model (RDM), responsible for determining the ST's yield split between ST and JT
* @custom:field protocolFeeRecipient - The market's configured protocol fee recipient
*/
struct RoycoAccountantInitParams {
address kernel;
uint64 protocolFeeWAD;
uint64 coverageWAD;
uint96 betaWAD;
address rdm;
}
/**
* @notice Storage state for the Royco Accountant
* @custom:storage-location erc7201:Royco.storage.RoycoAccountantState
* @custom:field kernel - The kernel that this accountant maintains NAV, debt, and fee accounting for
* @custom:field coverageWAD - The coverage percentage that the senior tranche is expected to be protected by, scaled to WAD precision
* @custom:field betaWAD - JT's percentage sensitivity to the same downside stress that affects ST, scaled to WAD precision
* For example, beta is 0 when JT is in the RFR and 1e18 (100%) when JT is in the same opportunity as senior
* @custom:field protocolFeeWAD - The market's configured protocol fee percentage taken from yield earned by senior and junior tranches, scaled to WAD precision
* @custom:field rdm - The market's Reward Distribution Model (RDM), responsible for determining the ST's yield split between ST and JT
* @custom:field lastSTRawNAV - The last recorded pure NAV (excluding any coverage taken and yield shared) of the senior tranche
* @custom:field lastJTRawNAV - The last recorded pure NAV (excluding any coverage given and yield shared) of the junior tranche
* @custom:field lastSTEffectiveNAV - The last recorded effective NAV (including any prior applied coverage, ST yield distribution, and uncovered losses) of the senior tranche
* @custom:field lastJTEffectiveNAV - The last recorded effective NAV (including any prior provided coverage, JT yield, ST yield distribution, and JT losses) of the junior tranche
* @custom:field lastJTCoverageDebt - The losses that ST incurred after exhausting the JT loss-absorption buffer: represents the first claim on capital the senior tranche has on future recoveries
* @custom:field lastSTCoverageDebt - The coverage that has been applied to ST from the JT loss-absorption buffer : represents the second claim on capital the junior tranche has on future recoveries
* @custom:field twJTYieldShareAccruedWAD - The time-weighted junior tranche yield share (RDM output) since the last yield distribution, scaled to WAD precision
* @custom:field lastAccrualTimestamp - The last time the time-weighted JT yield share accumulator was updated
* @custom:field lastDistributionTimestamp - The last time a yield distribution occurred
*/
struct RoycoAccountantState {
address kernel;
uint64 protocolFeeWAD;
uint64 coverageWAD;
uint96 betaWAD;
address rdm;
NAV_UNIT lastSTRawNAV;
NAV_UNIT lastJTRawNAV;
NAV_UNIT lastSTEffectiveNAV;
NAV_UNIT lastJTEffectiveNAV;
NAV_UNIT lastJTCoverageDebt;
NAV_UNIT lastSTCoverageDebt;
uint192 twJTYieldShareAccruedWAD;
uint32 lastAccrualTimestamp;
uint32 lastDistributionTimestamp;
}
/**
* @notice Emitted when JT's share of ST yield is accrued based on the market's utilization since the last accrual
* @param jtYieldShareWAD JT's instantaneous yield share (RDM output) based on utilization since the last accrual
* @param twJTYieldShareAccruedWAD The time-weighted JT yield share accrued since the last yield distribution
* @param accrualTimestamp The timestamp of this JT yield share accrual
*/
event JuniorTrancheYieldShareAccrued(uint256 jtYieldShareWAD, uint256 twJTYieldShareAccruedWAD, uint32 accrualTimestamp);
/**
* @notice Emitted when a pre-operation tranche accounting synchronization is executed
* @param resultingState The resulting market state after synchronizing the tranche accounting
*/
event PreOpTrancheAccountingSynced(SyncedAccountingState resultingState);
/**
* @notice Emitted when a post-operation tranche accounting synchronization is executed
* @param op The operation executed right before this accounting synchronization
* @param resultingState The resulting market state after synchronizing the tranche accounting
*/
event PostOpTrancheAccountingSynced(Operation op, SyncedAccountingState resultingState);
/// @notice Thrown when the caller of the function is not the accountant's configured Royco Kernel
error ONLY_ROYCO_KERNEL();
/// @notice Thrown when the accountant's coverage config is invalid
error INVALID_COVERAGE_CONFIG();
/// @notice Thrown when the RDM address is null on initialization
error NULL_RDM_ADDRESS();
/// @notice Thrown when the configured protocol fee exceeds the maximum
error MAX_PROTOCOL_FEE_EXCEEDED();
/// @notice Thrown when the sum of the raw NAVs don't equal the sum of the effective NAVs of both tranches
error NAV_CONSERVATION_VIOLATION();
/// @notice Thrown when an operation results in an invalid NAV state in the post-operation synchronization
error INVALID_POST_OP_STATE(Operation _op);
/// @notice Thrown when the market's coverage requirement is unsatisfied
error COVERAGE_REQUIREMENT_UNSATISFIED();
/**
* @notice Synchronizes the effective NAVs and debt obligations of both tranches before any tranche operation (deposit or withdrawal)
* @dev Accrues JT yield share over time based on the market's RDM output
* @dev Applies unrealized PnL and yield distribution
* @dev Persists updated NAV and debt checkpoints for the next sync to use as reference
* @param _stRawNAV The senior tranche's current raw NAV: the pure value of its invested assets
* @param _jtRawNAV The junior tranche's current raw NAV: the pure value of its invested assets
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function preOpSyncTrancheAccounting(NAV_UNIT _stRawNAV, NAV_UNIT _jtRawNAV) external returns (SyncedAccountingState memory state);
/**
* @notice Previews a synchronization of tranche NAVs based on the underlying PNL(s) and their effects on the current state of the loss waterfall
* @param _stRawNAV The senior tranche's current raw NAV: the pure value of its invested assets
* @param _jtRawNAV The junior tranche's current raw NAV: the pure value of its invested assets
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function previewSyncTrancheAccounting(NAV_UNIT _stRawNAV, NAV_UNIT _jtRawNAV) external view returns (SyncedAccountingState memory state);
/**
* @notice Applies post-operation (deposit and withdrawal) raw NAV deltas to effective NAV checkpoints
* @dev Interprets deltas strictly as deposits/withdrawals with no yield or coverage logic
* @param _stRawNAV The senior tranche's current raw NAV: the pure value of its invested assets
* @param _jtRawNAV The junior tranche's current raw NAV: the pure value of its invested assets
* @param _op The operation being executed in between the pre and post synchronizations
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function postOpSyncTrancheAccounting(NAV_UNIT _stRawNAV, NAV_UNIT _jtRawNAV, Operation _op) external returns (SyncedAccountingState memory state);
/**
* @notice Applies post-operation (deposit and withdrawal) raw NAV deltas to effective NAV checkpoints and enforces the coverage condition of the market
* @dev Interprets deltas strictly as deposits/withdrawals with no yield or coverage logic
* @dev Reverts if the coverage requirement is unsatisfied
* @param _stRawNAV The senior tranche's current raw NAV: the pure value of its invested assets
* @param _jtRawNAV The junior tranche's current raw NAV: the pure value of its invested assets
* @param _op The operation being executed in between the pre and post synchronizations
* @return state The synced NAV, debt, and fee accounting containing all mark to market accounting data
*/
function postOpSyncTrancheAccountingAndEnforceCoverage(
NAV_UNIT _stRawNAV,
NAV_UNIT _jtRawNAV,
Operation _op
)
external
returns (SyncedAccountingState memory state);
/**
* @notice Returns if the market’s coverage requirement is satisfied
* @dev If this condition is unsatisfied, senior deposits and junior withdrawals must be blocked to prevent undercollateralized senior exposure
* @return satisfied A boolean indicating whether the market's coverage requirement is satisfied based on the persisted NAV checkpoints
*/
function isCoverageRequirementSatisfied() external view returns (bool satisfied);
/**
* @notice Returns the maximum assets depositable into the senior tranche without violating the market's coverage requirement
* @dev Always rounds in favor of senior tranche protection
* @param _stRawNAV The senior tranche's current raw NAV: the pure value of its invested assets
* @param _jtRawNAV The junior tranche's current raw NAV: the pure value of its invested assets
* @return maxSTDeposit The maximum assets depositable into the senior tranche without violating the market's coverage requirement
*/
function maxSTDepositGivenCoverage(NAV_UNIT _stRawNAV, NAV_UNIT _jtRawNAV) external view returns (NAV_UNIT maxSTDeposit);
/**
* @notice Returns the maximum assets withdrawable from the junior tranche without violating the market's coverage requirement
* @dev Always rounds in favor of senior tranche protection
* @param _stRawNAV The senior tranche's current raw NAV: the pure value of its invested assets
* @param _jtRawNAV The junior tranche's current raw NAV: the pure value of its invested assets
* @param _jtClaimOnStUnits The total claims on ST assets that the junior tranche has denominated in NAV units
* @param _jtClaimOnJtUnits The total claims on JT assets that the junior tranche has denominated in NAV units
* @return totalNAVClaimable The maximum NAV that can be claimed from the junior tranche without violating the market's coverage requirement
* @return stClaimable The maximum claims on ST assets that the junior tranche can withdraw, denominated in NAV units
* @return jtClaimable The maximum claims on JT assets that the junior tranche can withdraw, denominated in NAV units
*/
function maxJTWithdrawalGivenCoverage(
NAV_UNIT _stRawNAV,
NAV_UNIT _jtRawNAV,
NAV_UNIT _jtClaimOnStUnits,
NAV_UNIT _jtClaimOnJtUnits
)
external
view
returns (NAV_UNIT totalNAVClaimable, NAV_UNIT stClaimable, NAV_UNIT jtClaimable);
/**
* @notice Updates the RDM (Reward Distribution Model) address
* @dev Only callable by a designated admin
* @param _rdm The new RDM address to set
*/
function setRDM(address _rdm) external;
/**
* @notice Updates the protocol fee percentage
* @dev Only callable by a designated admin
* @param _protocolFeeWAD The new protocol fee percentage in WAD format
*/
function setProtocolFee(uint64 _protocolFeeWAD) external;
/**
* @notice Updates the coverage percentage requirement
* @dev Only callable by a designated admin
* @param _coverageWAD The new coverage percentage in WAD format
*/
function setCoverage(uint64 _coverageWAD) external;
/**
* @notice Updates the beta sensitivity parameter
* @dev Only callable by a designated admin
* @param _betaWAD The new beta parameter in WAD format representing JT's sensitivity to downside stress
*/
function setBeta(uint96 _betaWAD) external;
/**
* @notice Returns the state of the accountant
* @return state The state of the accountant
*/
function getState() external view returns (RoycoAccountantState memory state);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `condition ? a : b`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `condition ? a : b`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
/**
* @dev Counts the number of leading zero bits in a uint256.
*/
function clz(uint256 x) internal pure returns (uint256) {
return ternary(x == 0, 256, 255 - log2(x));
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { UUPSUpgradeable } from "../../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import { RoycoAuth } from "../auth/RoycoAuth.sol";
abstract contract RoycoBase is UUPSUpgradeable, RoycoAuth {
/// @dev Disable the initializers
constructor() {
_disableInitializers();
}
/// @notice Initializes the Royco base contract
/// @param _initialAuthority The initial authority for the contract
function __RoycoBase_init(address _initialAuthority) internal onlyInitializing {
__RoycoAuth_init(_initialAuthority);
}
/// @dev Restricts the upgrade to only the authorized roles
function _authorizeUpgrade(address newImplementation) internal override restricted { }
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { Math } from "../../lib/openzeppelin-contracts/contracts/utils/math/Math.sol";
import { WAD, ZERO_NAV_UNITS } from "./Constants.sol";
import { ActionMetadataFormat, AssetClaims } from "./Types.sol";
import { NAV_UNIT, TRANCHE_UNIT, UnitsMathLib, toUint256 } from "./Units.sol";
library UtilsLib {
using UnitsMathLib for NAV_UNIT;
using UnitsMathLib for TRANCHE_UNIT;
using Math for uint256;
/**
* @notice Computes the utilization of the Royco market given the market's state
* @dev Informally: total covered exposure / junior loss absorbtion buffer
* @dev Formally: Utilization = ((ST_RAW_NAV + (JT_RAW_NAV * BETA_%)) * COV_%) / JT_EFFECTIVE_NAV
* @param _stRawNAV The raw net asset value of the senior tranche invested assets
* @param _jtRawNAV The raw net asset value of the junior tranche invested assets
* @param _betaWAD The JT's sensitivity to the same downside stress that affects ST scaled to WAD precision
* For example, beta is 0 when JT is in the RFR and 1 when JT is in the same opportunity as senior
* @param _coverageWAD The ratio of current total exposure that is expected to be covered by the junior capital scaled to WAD precision
* @param _jtEffectiveNAV The junior tranche net asset value after applying provided coverage, JT yield, ST yield distribution, and JT losses
* @return utilization The utilization of the Royco market scaled to WAD precision
*/
function computeUtilization(
NAV_UNIT _stRawNAV,
NAV_UNIT _jtRawNAV,
uint256 _betaWAD,
uint256 _coverageWAD,
NAV_UNIT _jtEffectiveNAV
)
internal
pure
returns (uint256 utilization)
{
// If there is no senior capital to protect, utilization is 0
if (_stRawNAV == ZERO_NAV_UNITS) return 0;
// If there is no remaining JT loss-absorption buffer, utilization is effectively infinite
if (_jtEffectiveNAV == ZERO_NAV_UNITS) return type(uint256).max;
// Round in favor of ensuring senior tranche protection
utilization = toUint256((_stRawNAV + _jtRawNAV.mulDiv(_betaWAD, WAD, Math.Rounding.Ceil)).mulDiv(_coverageWAD, _jtEffectiveNAV, Math.Rounding.Ceil));
}
/**
* @notice Scales the claims on ST and JT assets of a tranche by a given shares assuming total shares in a vault
* @param _claims The claims on ST and JT assets of the tranche
* @param _shares The number of shares to scale the claims by
* @param _totalTrancheShares The total number of shares that exist in the tranche
* @return scaledClaims The scaled claims on ST and JT assets of the tranche
*/
function scaleAssetClaims(AssetClaims memory _claims, uint256 _shares, uint256 _totalTrancheShares)
internal
pure
returns (AssetClaims memory scaledClaims)
{
scaledClaims.nav = _claims.nav.mulDiv(_shares, _totalTrancheShares, Math.Rounding.Floor);
scaledClaims.stAssets = _claims.stAssets.mulDiv(_shares, _totalTrancheShares, Math.Rounding.Floor);
scaledClaims.jtAssets = _claims.jtAssets.mulDiv(_shares, _totalTrancheShares, Math.Rounding.Floor);
}
/**
* @notice Scales the claims on ST and JT assets of a tranche by a given shares assuming total shares in a vault
* @param _claims The claims on ST and JT assets of the tranche
* @param _navNumerator The NAV to use for the numerator
* @param _navDenominator The NAV to use for the denominator
* @return scaledClaims The scaled claims on ST and JT assets of the tranche
*/
function scaleAssetClaims(
AssetClaims memory _claims,
NAV_UNIT _navNumerator,
NAV_UNIT _navDenominator
)
internal
pure
returns (AssetClaims memory scaledClaims)
{
scaledClaims.nav = _claims.nav.mulDiv(_navNumerator, _navDenominator, Math.Rounding.Floor);
scaledClaims.stAssets = _claims.stAssets.mulDiv(_navNumerator, _navDenominator, Math.Rounding.Floor);
scaledClaims.jtAssets = _claims.jtAssets.mulDiv(_navNumerator, _navDenominator, Math.Rounding.Floor);
}
/**
* @notice Formats the metadata for the action
* @param _data The data to format the metadata with
* @param _format The format of the metadata
* @return formattedMetadata The formatted metadata
*/
function format(bytes memory _data, ActionMetadataFormat _format) internal pure returns (bytes memory) {
return abi.encodePacked(uint16(_format), _data);
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import {console as console2} from "./console.sol"; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// 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 uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol"; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol"; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import { AccessManagedUpgradeable } from "../../lib/openzeppelin-contracts-upgradeable/contracts/access/manager/AccessManagedUpgradeable.sol";
import { PausableUpgradeable } from "../../lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol";
import { IRoycoAuth } from "../interfaces/IRoycoAuth.sol";
/**
* @title RoycoAuth
* @notice Abstract contract that provides access control and pausability functionality for Royco contracts
*/
abstract contract RoycoAuth is AccessManagedUpgradeable, PausableUpgradeable, IRoycoAuth {
function __RoycoAuth_init(address _initialAuthority) internal onlyInitializing {
__AccessManaged_init(_initialAuthority);
__Pausable_init();
}
/// @inheritdoc IRoycoAuth
function pause() external virtual restricted {
_pause();
}
/// @inheritdoc IRoycoAuth
function unpause() external virtual restricted {
_unpause();
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
library console {
address constant CONSOLE_ADDRESS =
0x000000000000000000636F6e736F6c652e6c6f67;
function _sendLogPayloadImplementation(bytes memory payload) internal view {
address consoleAddress = CONSOLE_ADDRESS;
/// @solidity memory-safe-assembly
assembly {
pop(
staticcall(
gas(),
consoleAddress,
add(payload, 32),
mload(payload),
0,
0
)
)
}
}
function _castToPure(
function(bytes memory) internal view fnIn
) internal pure returns (function(bytes memory) pure fnOut) {
assembly {
fnOut := fnIn
}
}
function _sendLogPayload(bytes memory payload) internal pure {
_castToPure(_sendLogPayloadImplementation)(payload);
}
function log() internal pure {
_sendLogPayload(abi.encodeWithSignature("log()"));
}
function logInt(int256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
}
function logUint(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function logString(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function logBool(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function logAddress(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function logBytes(bytes memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
}
function logBytes1(bytes1 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
}
function logBytes2(bytes2 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
}
function logBytes3(bytes3 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
}
function logBytes4(bytes4 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
}
function logBytes5(bytes5 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
}
function logBytes6(bytes6 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
}
function logBytes7(bytes7 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
}
function logBytes8(bytes8 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
}
function logBytes9(bytes9 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
}
function logBytes10(bytes10 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
}
function logBytes11(bytes11 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
}
function logBytes12(bytes12 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
}
function logBytes13(bytes13 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
}
function logBytes14(bytes14 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
}
function logBytes15(bytes15 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
}
function logBytes16(bytes16 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
}
function logBytes17(bytes17 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
}
function logBytes18(bytes18 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
}
function logBytes19(bytes19 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
}
function logBytes20(bytes20 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
}
function logBytes21(bytes21 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
}
function logBytes22(bytes22 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
}
function logBytes23(bytes23 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
}
function logBytes24(bytes24 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
}
function logBytes25(bytes25 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
}
function logBytes26(bytes26 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
}
function logBytes27(bytes27 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
}
function logBytes28(bytes28 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
}
function logBytes29(bytes29 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
}
function logBytes30(bytes30 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
}
function logBytes31(bytes31 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
}
function logBytes32(bytes32 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
}
function log(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function log(int256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
}
function log(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function log(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function log(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function log(uint256 p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
}
function log(uint256 p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
}
function log(uint256 p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
}
function log(uint256 p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
}
function log(string memory p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
}
function log(string memory p0, int256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1));
}
function log(string memory p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
}
function log(string memory p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
}
function log(string memory p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
}
function log(bool p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
}
function log(bool p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
}
function log(bool p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
}
function log(bool p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
}
function log(address p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
}
function log(address p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
}
function log(address p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
}
function log(address p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
}
function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
}
function log(uint256 p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
}
function log(uint256 p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
}
function log(uint256 p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
}
function log(uint256 p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
}
function log(uint256 p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
}
function log(uint256 p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
}
function log(uint256 p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
}
function log(uint256 p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
}
function log(string memory p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
}
function log(string memory p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
}
function log(string memory p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
}
function log(string memory p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
}
function log(string memory p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
}
function log(string memory p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
}
function log(string memory p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
}
function log(string memory p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
}
function log(string memory p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
}
function log(string memory p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
}
function log(string memory p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
}
function log(string memory p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
}
function log(bool p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
}
function log(bool p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
}
function log(bool p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
}
function log(bool p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
}
function log(bool p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
}
function log(bool p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
}
function log(bool p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
}
function log(bool p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
}
function log(bool p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
}
function log(bool p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
}
function log(bool p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
}
function log(bool p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
}
function log(bool p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
}
function log(bool p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
}
function log(bool p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
}
function log(bool p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
}
function log(address p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
}
function log(address p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
}
function log(address p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
}
function log(address p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
}
function log(address p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
}
function log(address p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
}
function log(address p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
}
function log(address p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
}
function log(address p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
}
function log(address p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
}
function log(address p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
}
function log(address p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
}
function log(address p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
}
function log(address p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
}
function log(address p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
}
function log(address p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.22;
import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* @custom:stateless
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
/**
* @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC-1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/AccessManaged.sol)
pragma solidity ^0.8.20;
import {AuthorityUtils} from "@openzeppelin/contracts/access/manager/AuthorityUtils.sol";
import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
/**
* @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be
* permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface,
* implementing a policy that allows certain callers to access certain functions.
*
* IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public`
* functions, and ideally only used in `external` functions. See {restricted}.
*/
abstract contract AccessManagedUpgradeable is Initializable, ContextUpgradeable, IAccessManaged {
/// @custom:storage-location erc7201:openzeppelin.storage.AccessManaged
struct AccessManagedStorage {
address _authority;
bool _consumingSchedule;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessManaged")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessManagedStorageLocation = 0xf3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00;
function _getAccessManagedStorage() private pure returns (AccessManagedStorage storage $) {
assembly {
$.slot := AccessManagedStorageLocation
}
}
/**
* @dev Initializes the contract connected to an initial authority.
*/
function __AccessManaged_init(address initialAuthority) internal onlyInitializing {
__AccessManaged_init_unchained(initialAuthority);
}
function __AccessManaged_init_unchained(address initialAuthority) internal onlyInitializing {
_setAuthority(initialAuthority);
}
/**
* @dev Restricts access to a function as defined by the connected Authority for this contract and the
* caller and selector of the function that entered the contract.
*
* [IMPORTANT]
* ====
* In general, this modifier should only be used on `external` functions. It is okay to use it on `public`
* functions that are used as external entry points and are not called internally. Unless you know what you're
* doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security
* implications! This is because the permissions are determined by the function that entered the contract, i.e. the
* function at the bottom of the call stack, and not the function where the modifier is visible in the source code.
* ====
*
* [WARNING]
* ====
* Avoid adding this modifier to the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`]
* function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These
* functions are the only execution paths where a function selector cannot be unambiguously determined from the calldata
* since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function
* if no calldata is provided. (See {_checkCanCall}).
*
* The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length.
* ====
*/
modifier restricted() {
_checkCanCall(_msgSender(), _msgData());
_;
}
/// @inheritdoc IAccessManaged
function authority() public view virtual returns (address) {
AccessManagedStorage storage $ = _getAccessManagedStorage();
return $._authority;
}
/// @inheritdoc IAccessManaged
function setAuthority(address newAuthority) public virtual {
address caller = _msgSender();
if (caller != authority()) {
revert AccessManagedUnauthorized(caller);
}
if (newAuthority.code.length == 0) {
revert AccessManagedInvalidAuthority(newAuthority);
}
_setAuthority(newAuthority);
}
/// @inheritdoc IAccessManaged
function isConsumingScheduledOp() public view returns (bytes4) {
AccessManagedStorage storage $ = _getAccessManagedStorage();
return $._consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0);
}
/**
* @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the
* permissions set by the current authority.
*/
function _setAuthority(address newAuthority) internal virtual {
AccessManagedStorage storage $ = _getAccessManagedStorage();
$._authority = newAuthority;
emit AuthorityUpdated(newAuthority);
}
/**
* @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata
* is less than 4 bytes long.
*/
function _checkCanCall(address caller, bytes calldata data) internal virtual {
AccessManagedStorage storage $ = _getAccessManagedStorage();
(bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay(
authority(),
caller,
address(this),
bytes4(data[0:4])
);
if (!immediate) {
if (delay > 0) {
$._consumingSchedule = true;
IAccessManager(authority()).consumeScheduledOp(caller, data);
$._consumingSchedule = false;
} else {
revert AccessManagedUnauthorized(caller);
}
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.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 PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @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();
_;
}
function __Pausable_init() internal onlyInitializing {
}
function __Pausable_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
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 {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
interface IRoycoAuth {
/// @notice Pauses the contract
function pause() external;
/// @notice Unpauses the contract
function unpause() external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC1822.sol)
pragma solidity >=0.4.16;
/**
* @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.21;
import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This library provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
*/
library ERC1967Utils {
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit IERC1967.Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the ERC-1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit IERC1967.AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the ERC-1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit IERC1967.BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/manager/AuthorityUtils.sol)
pragma solidity ^0.8.20;
import {IAuthority} from "./IAuthority.sol";
library AuthorityUtils {
/**
* @dev Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility
* for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data.
* This helper function takes care of invoking `canCall` in a backwards compatible way without reverting.
*/
function canCallWithDelay(
address authority,
address caller,
address target,
bytes4 selector
) internal view returns (bool immediate, uint32 delay) {
bytes memory data = abi.encodeCall(IAuthority.canCall, (caller, target, selector));
assembly ("memory-safe") {
mstore(0x00, 0x00)
mstore(0x20, 0x00)
if staticcall(gas(), authority, add(data, 0x20), mload(data), 0x00, 0x40) {
immediate := mload(0x00)
delay := mload(0x20)
// If delay does not fit in a uint32, return 0 (no delay)
// equivalent to: if gt(delay, 0xFFFFFFFF) { delay := 0 }
delay := mul(delay, iszero(shr(32, delay)))
}
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (access/manager/IAccessManager.sol)
pragma solidity >=0.8.4;
interface IAccessManager {
/**
* @dev A delayed operation was scheduled.
*/
event OperationScheduled(
bytes32 indexed operationId,
uint32 indexed nonce,
uint48 schedule,
address caller,
address target,
bytes data
);
/**
* @dev A scheduled operation was executed.
*/
event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce);
/**
* @dev A scheduled operation was canceled.
*/
event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce);
/**
* @dev Informational labelling for a roleId.
*/
event RoleLabel(uint64 indexed roleId, string label);
/**
* @dev Emitted when `account` is granted `roleId`.
*
* NOTE: The meaning of the `since` argument depends on the `newMember` argument.
* If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role,
* otherwise it indicates the execution delay for this account and roleId is updated.
*/
event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember);
/**
* @dev Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous.
*/
event RoleRevoked(uint64 indexed roleId, address indexed account);
/**
* @dev Role acting as admin over a given `roleId` is updated.
*/
event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);
/**
* @dev Role acting as guardian over a given `roleId` is updated.
*/
event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian);
/**
* @dev Grant delay for a given `roleId` will be updated to `delay` when `since` is reached.
*/
event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since);
/**
* @dev Target mode is updated (true = closed, false = open).
*/
event TargetClosed(address indexed target, bool closed);
/**
* @dev Role required to invoke `selector` on `target` is updated to `roleId`.
*/
event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId);
/**
* @dev Admin delay for a given `target` will be updated to `delay` when `since` is reached.
*/
event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since);
error AccessManagerAlreadyScheduled(bytes32 operationId);
error AccessManagerNotScheduled(bytes32 operationId);
error AccessManagerNotReady(bytes32 operationId);
error AccessManagerExpired(bytes32 operationId);
error AccessManagerLockedRole(uint64 roleId);
error AccessManagerBadConfirmation();
error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId);
error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector);
error AccessManagerUnauthorizedConsume(address target);
error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector);
error AccessManagerInvalidInitialAdmin(address initialAdmin);
/**
* @dev Check if an address (`caller`) is authorised to call a given function on a given contract directly (with
* no restriction). Additionally, it returns the delay needed to perform the call indirectly through the {schedule}
* & {execute} workflow.
*
* This function is usually called by the targeted contract to control immediate execution of restricted functions.
* Therefore we only return true if the call can be performed without any delay. If the call is subject to a
* previously set delay (not zero), then the function should return false and the caller should schedule the operation
* for future execution.
*
* If `allowed` is true, the delay can be disregarded and the operation can be immediately executed, otherwise
* the operation can be executed if and only if delay is greater than 0.
*
* NOTE: The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that
* is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail
* to identify the indirect workflow, and will consider calls that require a delay to be forbidden.
*
* NOTE: This function does not report the permissions of the admin functions in the manager itself. These are defined by the
* {AccessManager} documentation.
*/
function canCall(
address caller,
address target,
bytes4 selector
) external view returns (bool allowed, uint32 delay);
/**
* @dev Expiration delay for scheduled proposals. Defaults to 1 week.
*
* IMPORTANT: Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately,
* disabling any scheduling usage.
*/
function expiration() external view returns (uint32);
/**
* @dev Minimum setback for all delay updates, with the exception of execution delays. It
* can be increased without setback (and reset via {revokeRole} in the event of an
* accidental increase). Defaults to 5 days.
*/
function minSetback() external view returns (uint32);
/**
* @dev Get whether the contract is closed disabling any access. Otherwise role permissions are applied.
*
* NOTE: When the manager itself is closed, admin functions are still accessible to avoid locking the contract.
*/
function isTargetClosed(address target) external view returns (bool);
/**
* @dev Get the role required to call a function.
*/
function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64);
/**
* @dev Get the admin delay for a target contract. Changes to contract configuration are subject to this delay.
*/
function getTargetAdminDelay(address target) external view returns (uint32);
/**
* @dev Get the id of the role that acts as an admin for the given role.
*
* The admin permission is required to grant the role, revoke the role and update the execution delay to execute
* an operation that is restricted to this role.
*/
function getRoleAdmin(uint64 roleId) external view returns (uint64);
/**
* @dev Get the role that acts as a guardian for a given role.
*
* The guardian permission allows canceling operations that have been scheduled under the role.
*/
function getRoleGuardian(uint64 roleId) external view returns (uint64);
/**
* @dev Get the role current grant delay.
*
* Its value may change at any point without an event emitted following a call to {setGrantDelay}.
* Changes to this value, including effect timepoint are notified in advance by the {RoleGrantDelayChanged} event.
*/
function getRoleGrantDelay(uint64 roleId) external view returns (uint32);
/**
* @dev Get the access details for a given account for a given role. These details include the timepoint at which
* membership becomes active, and the delay applied to all operations by this user that requires this permission
* level.
*
* Returns:
* [0] Timestamp at which the account membership becomes valid. 0 means role is not granted.
* [1] Current execution delay for the account.
* [2] Pending execution delay for the account.
* [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled.
*/
function getAccess(
uint64 roleId,
address account
) external view returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect);
/**
* @dev Check if a given account currently has the permission level corresponding to a given role. Note that this
* permission might be associated with an execution delay. {getAccess} can provide more details.
*/
function hasRole(uint64 roleId, address account) external view returns (bool isMember, uint32 executionDelay);
/**
* @dev Give a label to a role, for improved role discoverability by UIs.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleLabel} event.
*/
function labelRole(uint64 roleId, string calldata label) external;
/**
* @dev Add `account` to `roleId`, or change its execution delay.
*
* This gives the account the authorization to call any function that is restricted to this role. An optional
* execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation
* that is restricted to members of this role. The user will only be able to execute the operation after the delay has
* passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}).
*
* If the account has already been granted this role, the execution delay will be updated. This update is not
* immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is
* called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any
* operation executed in the 3 hours that follows this update was indeed scheduled before this update.
*
* Requirements:
*
* - the caller must be an admin for the role (see {getRoleAdmin})
* - granted role must not be the `PUBLIC_ROLE`
*
* Emits a {RoleGranted} event.
*/
function grantRole(uint64 roleId, address account, uint32 executionDelay) external;
/**
* @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has
* no effect.
*
* Requirements:
*
* - the caller must be an admin for the role (see {getRoleAdmin})
* - revoked role must not be the `PUBLIC_ROLE`
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function revokeRole(uint64 roleId, address account) external;
/**
* @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in
* the role this call has no effect.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function renounceRole(uint64 roleId, address callerConfirmation) external;
/**
* @dev Change admin role for a given role.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleAdminChanged} event
*/
function setRoleAdmin(uint64 roleId, uint64 admin) external;
/**
* @dev Change guardian role for a given role.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleGuardianChanged} event
*/
function setRoleGuardian(uint64 roleId, uint64 guardian) external;
/**
* @dev Update the delay for granting a `roleId`.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleGrantDelayChanged} event.
*/
function setGrantDelay(uint64 roleId, uint32 newDelay) external;
/**
* @dev Set the role required to call functions identified by the `selectors` in the `target` contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetFunctionRoleUpdated} event per selector.
*/
function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external;
/**
* @dev Set the delay for changing the configuration of a given target contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetAdminDelayUpdated} event.
*/
function setTargetAdminDelay(address target, uint32 newDelay) external;
/**
* @dev Set the closed flag for a contract.
*
* Closing the manager itself won't disable access to admin methods to avoid locking the contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetClosed} event.
*/
function setTargetClosed(address target, bool closed) external;
/**
* @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the
* operation is not yet scheduled, has expired, was executed, or was canceled.
*/
function getSchedule(bytes32 id) external view returns (uint48);
/**
* @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never
* been scheduled.
*/
function getNonce(bytes32 id) external view returns (uint32);
/**
* @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to
* choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays
* required for the caller. The special value zero will automatically set the earliest possible time.
*
* Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when
* the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this
* scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}.
*
* Emits a {OperationScheduled} event.
*
* NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If
* this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target
* contract if it is using standard Solidity ABI encoding.
*/
function schedule(
address target,
bytes calldata data,
uint48 when
) external returns (bytes32 operationId, uint32 nonce);
/**
* @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the
* execution delay is 0.
*
* Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the
* operation wasn't previously scheduled (if the caller doesn't have an execution delay).
*
* Emits an {OperationExecuted} event only if the call was scheduled and delayed.
*/
function execute(address target, bytes calldata data) external payable returns (uint32);
/**
* @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled
* operation that is cancelled.
*
* Requirements:
*
* - the caller must be the proposer, a guardian of the targeted function, or a global admin
*
* Emits a {OperationCanceled} event.
*/
function cancel(address caller, address target, bytes calldata data) external returns (uint32);
/**
* @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed
* (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error.
*
* This is useful for contracts that want to enforce that calls targeting them were scheduled on the manager,
* with all the verifications that it implies.
*
* Emit a {OperationExecuted} event.
*/
function consumeScheduledOp(address caller, bytes calldata data) external;
/**
* @dev Hashing function for delayed operations.
*/
function hashOperation(address caller, address target, bytes calldata data) external view returns (bytes32);
/**
* @dev Changes the authority of a target managed by this manager instance.
*
* Requirements:
*
* - the caller must be a global admin
*/
function updateAuthority(address target, address newAuthority) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAccessManaged.sol)
pragma solidity >=0.8.4;
interface IAccessManaged {
/**
* @dev Authority that manages this contract was updated.
*/
event AuthorityUpdated(address authority);
error AccessManagedUnauthorized(address caller);
error AccessManagedRequiredDelay(address caller, uint32 delay);
error AccessManagedInvalidAuthority(address authority);
/**
* @dev Returns the current authority.
*/
function authority() external view returns (address);
/**
* @dev Transfers control to a new authority. The caller must be the current authority.
*/
function setAuthority(address) external;
/**
* @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
* being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
* attacker controlled calls.
*/
function isConsumingScheduledOp() external view returns (bytes4);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (proxy/beacon/IBeacon.sol)
pragma solidity >=0.4.16;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1967.sol)
pragma solidity >=0.4.11;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
import {LowLevelCall} from "./LowLevelCall.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
if (LowLevelCall.callNoReturn(recipient, amount, "")) {
// call successful, nothing to do
return;
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
bool success = LowLevelCall.callNoReturn(target, value, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
bool success = LowLevelCall.staticcallNoReturn(target, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
bool success = LowLevelCall.delegatecallNoReturn(target, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*
* NOTE: This function is DEPRECATED and may be removed in the next major release.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (success && (returndata.length > 0 || target.code.length > 0)) {
return returndata;
} else if (success) {
revert AddressEmptyCode(target);
} else if (returndata.length > 0) {
LowLevelCall.bubbleRevert(returndata);
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else if (returndata.length > 0) {
LowLevelCall.bubbleRevert(returndata);
} else {
revert Errors.FailedCall();
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAuthority.sol)
pragma solidity >=0.4.16;
/**
* @dev Standard interface for permissioning originally defined in Dappsys.
*/
interface IAuthority {
/**
* @dev Returns true if the caller can invoke on a target the function identified by a function selector.
*/
function canCall(address caller, address target, bytes4 selector) external view returns (bool allowed);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/LowLevelCall.sol)
pragma solidity ^0.8.20;
/**
* @dev Library of low level call functions that implement different calling strategies to deal with the return data.
*
* WARNING: Using this library requires an advanced understanding of Solidity and how the EVM works. It is recommended
* to use the {Address} library instead.
*/
library LowLevelCall {
/// @dev Performs a Solidity function call using a low level `call` and ignoring the return data.
function callNoReturn(address target, bytes memory data) internal returns (bool success) {
return callNoReturn(target, 0, data);
}
/// @dev Same as {callNoReturn}, but allows to specify the value to be sent in the call.
function callNoReturn(address target, uint256 value, bytes memory data) internal returns (bool success) {
assembly ("memory-safe") {
success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `call` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function callReturn64Bytes(
address target,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
return callReturn64Bytes(target, 0, data);
}
/// @dev Same as {callReturnBytes32Pair}, but allows to specify the value to be sent in the call.
function callReturn64Bytes(
address target,
uint256 value,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Performs a Solidity function call using a low level `staticcall` and ignoring the return data.
function staticcallNoReturn(address target, bytes memory data) internal view returns (bool success) {
assembly ("memory-safe") {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `staticcall` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function staticcallReturn64Bytes(
address target,
bytes memory data
) internal view returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Performs a Solidity function call using a low level `delegatecall` and ignoring the return data.
function delegatecallNoReturn(address target, bytes memory data) internal returns (bool success) {
assembly ("memory-safe") {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `delegatecall` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function delegatecallReturn64Bytes(
address target,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Returns the size of the return data buffer.
function returnDataSize() internal pure returns (uint256 size) {
assembly ("memory-safe") {
size := returndatasize()
}
}
/// @dev Returns a buffer containing the return data from the last call.
function returnData() internal pure returns (bytes memory result) {
assembly ("memory-safe") {
result := mload(0x40)
mstore(result, returndatasize())
returndatacopy(add(result, 0x20), 0x00, returndatasize())
mstore(0x40, add(result, add(0x20, returndatasize())))
}
}
/// @dev Revert with the return data from the last call.
function bubbleRevert() internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
}
function bubbleRevert(bytes memory returndata) internal pure {
assembly ("memory-safe") {
revert(add(returndata, 0x20), mload(returndata))
}
}
}