Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"smart-contracts-public/src/redemption/RedemptionGateway.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import "@openzeppelin/contracts/access/manager/AccessManaged.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IInstantRedemption.sol";
import "./IWindowRedemption.sol";
import "../token/IShareToken.sol";
import "../compliance/IKYCRegistry.sol";
/**
* @title RedemptionGateway
* @notice Single entry-point for users to redeem shares. Routes to instant or window modules.
* @dev Business rule: a redemption window, when open, has exclusive precedence over instant mode.
*
* **Responsibilities**
* - Enforce KYC and basic argument checks at the gateway boundary.
* - Delegate to {IInstantRedemption} or {IWindowRedemption} and bubble up reverts.
* - Expose consolidated read-only views used by frontends and monitoring.
*
* **Security**
* - Pausable and reentrancy-protected; administrative setters gated by {AccessManaged}.
*/
contract RedemptionGateway is AccessManaged, ReentrancyGuard, Pausable {
// ============ Types ============
enum RedemptionMode {
NONE,
INSTANT,
WINDOW
}
// ============ Roles ============
// Roles are now managed by AccessManager
// ============ State ============
IInstantRedemption public instantRedemption;
IWindowRedemption public windowRedemption;
IShareToken public immutable shareToken;
IKYCRegistry public immutable kyc;
// ============ Events ============
event InstantRedemptionSet(address indexed module);
event WindowRedemptionSet(address indexed module);
event InstantRedemptionRouted(address indexed user, uint256 shares, uint256 payout);
event WindowRedemptionRouted(address indexed user, address indexed module, uint256 amount);
// ============ Errors ============
error InvalidModule();
error KYCRequired();
error InvalidAmount();
error WrongMode(uint8 expected, uint8 actual);
// ============ Constructor ============
/**
* @param _accessManager Address of the AccessManager
* @param _instantRedemption Address of the InstantRedemption module
* @param _windowRedemption Address of the WindowRedemption module
* @param _shareToken Address of the ShareToken
* @param _kyc Address of the KYC registry
*/
constructor(
address _accessManager,
address _instantRedemption,
address _windowRedemption,
address _shareToken,
address _kyc
) AccessManaged(_accessManager) {
// Validate addresses are not zero
if (_accessManager == address(0)) revert InvalidModule();
if (_instantRedemption == address(0)) revert InvalidModule();
if (_windowRedemption == address(0)) revert InvalidModule();
if (_shareToken == address(0)) revert InvalidModule();
if (_kyc == address(0)) revert InvalidModule();
// Store validated addresses
instantRedemption = IInstantRedemption(_instantRedemption);
windowRedemption = IWindowRedemption(_windowRedemption);
shareToken = IShareToken(_shareToken);
kyc = IKYCRegistry(_kyc);
}
// ============ Instant Redemption Functions ============
/**
* @notice Process an instant redemption through the gateway
* @param shares Amount of shares to redeem
* @param minPayout Minimum payout amount (slippage protection)
*/
function redeemInstant(uint256 shares, uint256 minPayout) external nonReentrant whenNotPaused {
// Enforce mutual exclusivity: block instant while a window is open
RedemptionMode mode = currentMode();
if (mode != RedemptionMode.INSTANT) {
revert WrongMode(uint8(RedemptionMode.INSTANT), uint8(mode));
}
if (!kyc.isKYCApproved(msg.sender)) revert KYCRequired();
if (shares == 0) revert InvalidAmount();
// Instant redemption module will transfer shares directly from user
// and will revert if allowance is insufficient
instantRedemption.redeemFor(msg.sender, shares, minPayout);
emit InstantRedemptionRouted(msg.sender, shares, minPayout);
}
/**
* @notice Preview instant redemption
* @param user User address
* @param shares Amount of shares
* @return grossPayout Gross payout amount
* @return fee Fee amount
* @return netPayout Net payout after fee
* @return available Whether redemption would succeed
*/
function previewInstantRedemption(address user, uint256 shares)
external
view
returns (uint256 grossPayout, uint256 fee, uint256 netPayout, bool available)
{
return instantRedemption.previewRedemption(user, shares);
}
// ============ Window Redemption Functions ============
/**
* @notice Submit a window redemption request
* @param shares Amount of shares to request for redemption
*/
function submitWindowRequest(uint256 shares) external nonReentrant whenNotPaused {
// Enforce mutual exclusivity: only allow during window mode
RedemptionMode mode = currentMode();
if (mode != RedemptionMode.WINDOW) {
revert WrongMode(uint8(RedemptionMode.WINDOW), uint8(mode));
}
if (!kyc.isKYCApproved(msg.sender)) revert KYCRequired();
if (shares == 0) revert InvalidAmount();
// Window module will transfer shares directly from user
// and will revert if allowance is insufficient
windowRedemption.submitRequestFor(msg.sender, shares);
emit WindowRedemptionRouted(msg.sender, address(windowRedemption), shares);
}
/**
* @notice Adjust a window redemption request
* @param newShares New amount of shares for the request
*/
function adjustWindowRequest(uint256 newShares) external nonReentrant whenNotPaused {
// Enforce mutual exclusivity: only allow during window mode
RedemptionMode mode = currentMode();
if (mode != RedemptionMode.WINDOW) {
revert WrongMode(uint8(RedemptionMode.WINDOW), uint8(mode));
}
if (!kyc.isKYCApproved(msg.sender)) revert KYCRequired();
// Window module will handle token transfers directly with user
windowRedemption.adjustRequestFor(msg.sender, newShares);
}
/**
* @notice Cancel a window redemption request
*/
function cancelWindowRequest() external nonReentrant whenNotPaused {
// Enforce mutual exclusivity: only allow during window mode
RedemptionMode mode = currentMode();
if (mode != RedemptionMode.WINDOW) {
revert WrongMode(uint8(RedemptionMode.WINDOW), uint8(mode));
}
// Window module will return shares directly to user
windowRedemption.cancelRequestFor(msg.sender);
}
/**
* @notice Claim payout from a settled window
* @param windowId The window ID to claim from
*/
function claimWindowPayout(uint256 windowId) external nonReentrant whenNotPaused {
if (!kyc.isKYCApproved(msg.sender)) revert KYCRequired();
// Window module will handle payouts directly to user
windowRedemption.claimFor(windowId, msg.sender);
}
/**
* @notice Get user's window request
* @param windowId Window ID
* @param user User address
* @return shares Amount of shares requested
* @return claimed Amount already claimed
*/
function getWindowRequest(uint256 windowId, address user)
external
view
returns (uint256 shares, uint256 claimed)
{
IWindowRedemption.UserRequest memory request =
windowRedemption.getUserRequest(windowId, user);
return (request.shares, request.claimed);
}
// ============ Admin Functions ============
/**
* @notice Update instant redemption module
* @param _instantRedemption New instant redemption module address
*/
function setInstantRedemption(address _instantRedemption) external restricted {
if (_instantRedemption == address(0)) revert InvalidModule();
// Validate interface by calling a view function
try IInstantRedemption(_instantRedemption).paused() returns (bool) {
// Interface is valid
} catch {
revert InvalidModule();
}
instantRedemption = IInstantRedemption(_instantRedemption);
emit InstantRedemptionSet(_instantRedemption);
}
/**
* @notice Update window redemption module
* @param _windowRedemption New window redemption module address
*/
function setWindowRedemption(address _windowRedemption) external restricted {
if (_windowRedemption == address(0)) revert InvalidModule();
// Validate interface by calling a view function
try IWindowRedemption(_windowRedemption).isWindowOpen() returns (bool) {
// Interface is valid
} catch {
revert InvalidModule();
}
windowRedemption = IWindowRedemption(_windowRedemption);
emit WindowRedemptionSet(_windowRedemption);
}
/**
* @notice Pause all redemptions
*/
function pause() external restricted {
_pause();
}
/**
* @notice Unpause all redemptions
*/
function unpause() external restricted {
_unpause();
}
// ============ View Functions ============
/**
* @notice Get current redemption mode
* @dev Rules:
* - Gateway-level pause overrides and returns `NONE`.
* - Window has precedence from opening through settlement (including closed-but-unsettled).
* - Instant is available only when no window is open and the current window is settled.
* - If the selected module is paused, returns `NONE`.
* @return Current mode (NONE=0, INSTANT=1, WINDOW=2)
*/
function currentMode() public view returns (RedemptionMode) {
// Gateway-level pause overrides everything
if (paused()) return RedemptionMode.NONE;
// Window takes priority while open OR until it is settled
// This enforces mutual exclusivity from window open through settlement.
if (windowRedemption.isWindowOpen()) {
return windowRedemption.paused() ? RedemptionMode.NONE : RedemptionMode.WINDOW;
}
// If a window was opened and is not yet settled, remain in WINDOW mode
{
uint256 id = windowRedemption.currentWindowId();
IWindowRedemption.Window memory w = windowRedemption.getWindow(id);
if (w.openTime != 0 && !w.isSettled) {
return windowRedemption.paused() ? RedemptionMode.NONE : RedemptionMode.WINDOW;
}
}
// Default to instant when no window is open
return instantRedemption.paused() ? RedemptionMode.NONE : RedemptionMode.INSTANT;
}
/**
* @notice Check if window is open for requests
* @return isOpen Whether window is currently open
*/
function isWindowOpen() external view returns (bool) {
return windowRedemption.isWindowOpen();
}
/**
* @notice Get current window ID
* @return windowId Current window ID
*/
function currentWindowId() external view returns (uint256) {
return windowRedemption.currentWindowId();
}
/**
* @notice Get current daily redemption stats
* @return day Current day index
* @return globalSpending Global spending for the day
*/
function getDailyRedemptions() external view returns (uint256 day, uint256 globalSpending) {
return instantRedemption.getDailyRedemptions();
}
/**
* @notice Get user's instant redemption spending for today
* @param user User address
* @return spending User's spending for current day
*/
function getUserDailySpending(address user) external view returns (uint256) {
return instantRedemption.getUserDailySpending(user);
}
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/AccessManaged.sol)
pragma solidity ^0.8.20;
import {AuthorityUtils} from "./AuthorityUtils.sol";
import {IAccessManager} from "./IAccessManager.sol";
import {IAccessManaged} from "./IAccessManaged.sol";
import {Context} from "../../utils/Context.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 AccessManaged is Context, IAccessManaged {
address private _authority;
bool private _consumingSchedule;
/**
* @dev Initializes the contract connected to an initial authority.
*/
constructor(address initialAuthority) {
_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) {
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) {
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 {
_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 {
(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);
}
}
}
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/utils/Pausable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
"content": "// 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);
}
"
},
"smart-contracts-public/src/redemption/IInstantRedemption.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @title IInstantRedemption
* @notice Interface for the "instant" redemption module invoked by {RedemptionGateway}.
* @dev The concrete implementation should:
* - Enforce KYC via an external registry.
* - Enforce daily/global/user limits and fee logic.
* - Transfer/burn shares and pull/withdraw payout tokens from the vault.
*
* All values are denominated as noted by the implementation; payout amounts are in payout-token units.
*/
interface IInstantRedemption {
// Functions called by gateway
function redeemFor(address user, uint256 shares, uint256 minPayout) external;
function previewRedemption(address user, uint256 shares)
external
view
returns (uint256 grossPayout, uint256 fee, uint256 netPayout, bool available);
// View functions for status
function paused() external view returns (bool);
function getDailyRedemptions() external view returns (uint256 day, uint256 globalSpending);
function getUserDailySpending(address user) external view returns (uint256);
}
"
},
"smart-contracts-public/src/redemption/IWindowRedemption.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @title IWindowRedemption
* @notice Interface for the batched/windowed redemption module coordinated by {RedemptionGateway}.
* @dev Windows collect share requests, later settle pro‑rata using snapshot prices. Provides
* view methods for UI and off-chain settlement monitoring.
*/
interface IWindowRedemption {
// Struct needed for return values
struct Window {
uint256 openTime;
uint256 submissionDeadline;
uint256 closeTime;
uint256 totalSharesRequested;
uint256 totalValueRequested;
uint256 fundingAmount;
uint256 fulfillmentRate;
uint256 totalClaimed;
bool isSettled;
bool isFinalized;
address payoutToken;
uint256 sharePriceAtClose;
uint256 payoutPriceAtSettlement;
}
struct UserRequest {
uint256 shares;
uint256 claimed;
}
// Functions called by gateway
function submitRequestFor(address user, uint256 shares) external;
function adjustRequestFor(address user, uint256 newShares) external;
function cancelRequestFor(address user) external;
function claimFor(uint256 windowId, address user) external;
// View functions for status
function paused() external view returns (bool);
function isWindowOpen() external view returns (bool);
function currentWindowId() external view returns (uint256);
function getWindow(uint256 windowId) external view returns (Window memory);
function getUserRequest(uint256 windowId, address user)
external
view
returns (UserRequest memory);
}
"
},
"smart-contracts-public/src/token/IShareToken.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @title IShareToken
* @notice Minimal ERC20-compatible interface expected by the protocol's deposit and redemption flows.
* @dev Implemented by {ShareToken}. Functions are deliberately narrow to reduce coupling.
* - All amounts use the token's own decimals.
* - {mint} and {burn} are typically restricted via AccessManager roles in the implementation.
*/
interface IShareToken {
function burn(address user, uint256 amount) external;
function mint(address to, uint256 amount) external;
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function decimals() external view returns (uint8);
}
"
},
"smart-contracts-public/src/compliance/IKYCRegistry.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
interface IKYCRegistry {
function isKYCApproved(address user) external view returns (bool);
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol": {
"content": "// 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)))
}
}
}
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.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 case 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 operation 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 contract 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;
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol": {
"content": "// 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);
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
"
},
"smart-contracts-public/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol": {
"content": "// 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);
}
"
}
},
"settings": {
"remappings": [
"@chainlink/=smart-contracts-public/lib/chainlink/",
"@openzeppelin/contracts/=smart-contracts-public/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/contracts/",
"forge-std/=smart-contracts-public/lib/forge-std/src/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"chainlink/=smart-contracts-public/lib/chainlink/",
"erc4626-tests/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=smart-contracts-public/lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 500
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}
}}
Submitted on: 2025-10-01 13:35:20
Comments
Log in to comment.
No comments yet.