Source Code
Latest 25 from a total of 187 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Create Policy Wi... | 24422139 | 310 days ago | IN | 0 ETH | 0.00002586 | ||||
| Create Policy Wi... | 24422111 | 310 days ago | IN | 0 ETH | 0.00002421 | ||||
| Create Policy Wi... | 24422025 | 310 days ago | IN | 0 ETH | 0.00003566 | ||||
| Create Policy Wi... | 22996956 | 343 days ago | IN | 0 ETH | 0.00015073 | ||||
| Create Policy Wi... | 22996647 | 343 days ago | IN | 0 ETH | 0.00011126 | ||||
| Create Policy Wi... | 22996599 | 343 days ago | IN | 0 ETH | 0.00015393 | ||||
| Create Policy Wi... | 22358994 | 358 days ago | IN | 0 ETH | 0.00004642 | ||||
| Create Policy Wi... | 22355513 | 358 days ago | IN | 0 ETH | 0.0000342 | ||||
| Create Policy Wi... | 22355365 | 358 days ago | IN | 0 ETH | 0.00003603 | ||||
| Create Policy Wi... | 22355355 | 358 days ago | IN | 0 ETH | 0.00003591 | ||||
| Create Policy Wi... | 22355344 | 358 days ago | IN | 0 ETH | 0.00003637 | ||||
| Create Policy Wi... | 22355329 | 358 days ago | IN | 0 ETH | 0.00003659 | ||||
| Create Policy Wi... | 22355317 | 358 days ago | IN | 0 ETH | 0.00003658 | ||||
| Create Policy Wi... | 22355167 | 358 days ago | IN | 0 ETH | 0.000037 | ||||
| Create Policy Wi... | 22355155 | 358 days ago | IN | 0 ETH | 0.00003732 | ||||
| Create Policy Wi... | 22355140 | 358 days ago | IN | 0 ETH | 0.00003814 | ||||
| Create Policy Wi... | 22355106 | 358 days ago | IN | 0 ETH | 0.00003817 | ||||
| Create Policy Wi... | 22355068 | 358 days ago | IN | 0 ETH | 0.00003813 | ||||
| Create Policy Wi... | 22355026 | 358 days ago | IN | 0 ETH | 0.00003837 | ||||
| Create Policy Wi... | 22355003 | 358 days ago | IN | 0 ETH | 0.00003864 | ||||
| Create Policy Wi... | 22354982 | 358 days ago | IN | 0 ETH | 0.00003872 | ||||
| Create Policy Wi... | 22354957 | 358 days ago | IN | 0 ETH | 0.00003869 | ||||
| Create Policy Wi... | 22354892 | 358 days ago | IN | 0 ETH | 0.00003895 | ||||
| Create Policy Wi... | 22354865 | 358 days ago | IN | 0 ETH | 0.00003822 | ||||
| Create Policy Wi... | 22354850 | 358 days ago | IN | 0 ETH | 0.00003814 |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
FlightProduct
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IAuthorization} from "../../authorization/IAuthorization.sol";
import {IComponents} from "../../instance/module/IComponents.sol";
import {IPolicy} from "../../instance/module/IPolicy.sol";
import {Amount, AmountLib} from "../../type/Amount.sol";
import {ClaimId} from "../../type/ClaimId.sol";
import {Component} from "../../shared/Component.sol";
import {FeeLib} from "../../type/Fee.sol";
import {FlightLib} from "./FlightLib.sol";
import {FlightMessageVerifier} from "./FlightMessageVerifier.sol";
import {FlightOracle} from "./FlightOracle.sol";
import {InstanceReader} from "../../instance/InstanceReader.sol";
import {NftId, NftIdLib} from "../../type/NftId.sol";
import {PayoutId} from "../../type/PayoutId.sol";
import {Product} from "../../product/Product.sol";
import {ReferralLib} from "../../type/Referral.sol";
import {RiskId, RiskIdLib} from "../../type/RiskId.sol";
import {RequestId} from "../../type/RequestId.sol";
import {Seconds, SecondsLib} from "../../type/Seconds.sol";
import {Str, StrLib} from "../../type/String.sol";
import {Timestamp, TimestampLib} from "../../type/Timestamp.sol";
/// @dev FlightProduct implements the flight delay product.
contract FlightProduct is
Product
{
event LogFlightPolicyPurchased(NftId policyNftId, string flightData, Amount premiumAmount);
event LogFlightPolicyClosed(NftId policyNftId, Amount payoutAmount);
event LogFlightStatusProcessed(RequestId requestId, RiskId riskId, bytes1 status, int256 delayMinutes, uint8 payoutOption);
event LogFlightPoliciesProcessed(RiskId riskId, uint8 payoutOption, uint256 policiesProcessed, uint256 policiesRemaining);
// solhint-disable
Amount public MIN_PREMIUM;
Amount public MAX_PREMIUM;
Amount public MAX_PAYOUT;
Amount public MAX_TOTAL_PAYOUT; // Maximum risk per flight/risk
// Minimum time before departure for applying
Seconds public MIN_TIME_BEFORE_DEPARTURE;
// Maximum time before departure for applying
Seconds public MAX_TIME_BEFORE_DEPARTURE;
// Maximum duration of flight
Seconds public MAX_FLIGHT_DURATION;
// Max time to process claims after departure
Seconds public LIFETIME;
// ['observations','late15','late30','late45','cancelled','diverted']
// no payouts for delays of 30' or less
uint8[6] public WEIGHT_PATTERN;
// Minimum number of observations for valid prediction/premium calculation
uint256 public MIN_OBSERVATIONS;
// Maximum cumulated weighted premium per risk
uint256 public MARGIN_PERCENT;
// Maximum number of policies to process in one callback
uint8 public MAX_POLICIES_TO_PROCESS;
// solhint-enable
bool internal _testMode;
mapping(RiskId riskId => RequestId requestId) internal _requests;
// GIF V3 specifics
NftId internal _defaultBundleNftId;
NftId internal _oracleNftId;
struct FlightRisk {
Str flightData; // example: "LX 180 ZRH BKK 20241104"
Timestamp departureTime;
// this field contains static data required by the frontend and is not directly used by the product
string departureTimeLocal; // example "2024-10-14T10:10:00.000 Asia/Seoul"
Timestamp arrivalTime;
// this field contains static data required by the frontend and is not directly used by the product
string arrivalTimeLocal; // example "2024-10-14T10:10:00.000 Asia/Seoul"
Amount sumOfSumInsuredAmounts;
bytes1 status; // 'L'ate, 'C'ancelled, 'D'iverted, ...
int256 delayMinutes;
uint8 payoutOption;
Timestamp statusUpdatedAt;
}
struct ApplicationData {
string flightData;
Timestamp departureTime;
string departureTimeLocal;
Timestamp arrivalTime;
string arrivalTimeLocal;
Amount premiumAmount;
uint256[6] statistics;
}
struct PermitData {
address owner;
address spender;
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
constructor(
address registry,
NftId instanceNftId,
string memory componentName,
IAuthorization authorization
)
{
address initialOwner = msg.sender;
_initialize(
registry,
instanceNftId,
componentName,
authorization,
initialOwner);
}
//--- external functions ------------------------------------------------//
//--- unpermissioned functions ------------------------------------------//
function setOracleNftId()
external
{
_oracleNftId = _getInstanceReader().getProductInfo(
getNftId()).oracleNftId[0];
}
function calculatePayoutAmounts(
FlightProduct flightProduct,
Amount premium,
uint256[6] memory statistics
)
external
view
returns (
uint256 weight,
Amount[5] memory payoutAmounts,
Amount sumInsuredAmount // simply the max of payoutAmounts
)
{
return FlightLib.calculatePayoutAmounts(
flightProduct,
premium,
statistics);
}
/// @dev Creates a policy using a permit for the policy holder.
/// The policy holder is defined as the owner parameter of the permit data.
/// NOTE: This function makes the assumption that the product token
/// supports permits. This assumption is not verfied.
function createPolicyWithPermit(
PermitData memory permit,
ApplicationData memory application
)
external
virtual
restricted()
returns (
RiskId riskId,
NftId policyNftId
)
{
// process permit data
_processPermit(permit);
// create policy
address policyHolder = permit.owner;
(
riskId,
policyNftId
) = _createPolicy(
policyHolder,
StrLib.toStr(application.flightData),
application.departureTime,
application.departureTimeLocal,
application.arrivalTime,
application.arrivalTimeLocal,
application.premiumAmount,
application.statistics);
}
/// @dev Callback for flight status oracle.
/// Function may only be alled by oracle service.
function flightStatusCallback(
RequestId requestId,
bytes memory responseData
)
external
virtual
restricted()
{
FlightOracle.FlightStatusResponse memory response = abi.decode(
responseData, (FlightOracle.FlightStatusResponse));
_processFlightStatus(
requestId,
response.riskId,
response.status,
response.delayMinutes);
}
function resendRequest(RequestId requestId)
external
virtual
restricted()
{
_resendRequest(requestId);
}
/// @dev Manual fallback function for product owner.
function processPayoutsAndClosePolicies(
RiskId riskId,
uint8 maxPoliciesToProcess
)
external
virtual
restricted()
onlyOwner()
{
_processPayoutsAndClosePolicies(
riskId,
maxPoliciesToProcess);
}
//--- owner functions ---------------------------------------------------//
/// @dev Call after product registration with the instance
/// when the product token/tokenhandler is available
function setConstants(
Amount minPremium,
Amount maxPremium,
Amount maxPayout,
Amount maxTotalPayout,
Seconds minTimeBeforeDeparture,
Seconds maxTimeBeforeDeparture,
uint8 maxPoliciesToProcess
)
external
virtual
restricted()
onlyOwner()
{
MIN_PREMIUM = minPremium;
MAX_PREMIUM = maxPremium;
MAX_PAYOUT = maxPayout;
MAX_TOTAL_PAYOUT = maxTotalPayout;
MIN_TIME_BEFORE_DEPARTURE = minTimeBeforeDeparture;
MAX_TIME_BEFORE_DEPARTURE = maxTimeBeforeDeparture;
MAX_POLICIES_TO_PROCESS = maxPoliciesToProcess;
}
function setDefaultBundle(NftId bundleNftId) external restricted() onlyOwner() { _defaultBundleNftId = bundleNftId; }
function setTestMode(bool testMode) external restricted() onlyOwner() { _testMode = testMode; }
function approveTokenHandler(IERC20Metadata token, Amount amount) external restricted() onlyOwner() { _approveTokenHandler(token, amount); }
function setLocked(bool locked) external onlyOwner() { _setLocked(locked); }
function setWallet(address newWallet) external restricted() onlyOwner() { _setWallet(newWallet); }
//--- view functions ----------------------------------------------------//
function calculateNetPremium(
Amount, // sumInsuredAmount: not used in this product
RiskId, // riskId: not used in this product
Seconds, // lifetime: not used in this product, a flight is a one time risk
bytes memory applicationData // holds the premium amount the customer is willing to pay
)
external
virtual override
view
returns (Amount netPremiumAmount)
{
(netPremiumAmount, ) = abi.decode(applicationData, (Amount, Amount[5]));
}
function getOracleNftId() public view returns (NftId oracleNftId) { return _oracleNftId; }
function isTestMode() public view returns (bool) { return _testMode; }
function getFlightRisk(
RiskId riskId,
bool requireRiskExists
)
public
view
returns (
bool exists,
FlightRisk memory flightRisk
)
{
(exists, flightRisk) = FlightLib.getFlightRisk(
_getInstanceReader(),
getNftId(),
riskId,
requireRiskExists);
}
function getRequestForRisk(RiskId riskId) public view returns (RequestId requestId) { return _requests[riskId]; }
function decodeFlightRiskData(bytes memory data) public pure returns (FlightRisk memory) { return abi.decode(data, (FlightRisk)); }
//--- internal functions ------------------------------------------------//
function _processPermit(
PermitData memory permit
)
internal
virtual
restricted()
{
address tokenAddress = address(getToken());
// process permit data
ERC20Permit(tokenAddress).permit(
permit.owner,
permit.spender,
permit.value,
permit.deadline,
permit.v,
permit.r,
permit.s);
}
function _createPolicy(
address policyHolder,
Str flightData,
Timestamp departureTime,
string memory departureTimeLocal,
Timestamp arrivalTime,
string memory arrivalTimeLocal,
Amount premiumAmount,
uint256[6] memory statistics
)
internal
virtual
returns (
RiskId riskId,
NftId policyNftId
)
{
// checks
// disabled for now - using rbac for security
FlightLib.checkApplicationData(
this,
flightData,
departureTime,
arrivalTime,
premiumAmount);
(riskId, policyNftId) = _prepareApplication(
policyHolder,
flightData,
departureTime,
departureTimeLocal,
arrivalTime,
arrivalTimeLocal,
premiumAmount,
statistics);
_createPolicy(
policyNftId,
TimestampLib.zero(), // do not ativate yet
premiumAmount); // max premium amount
// interactions (token transfer + callback to token holder, if contract)
_collectPremium(
policyNftId,
departureTime); // activate at scheduled departure time of flight
// send oracle request for for new risk to obtain flight status (interacts with flight oracle contract)
if (_requests[riskId].eqz()) {
_requests[riskId] = _sendRequest(
_oracleNftId,
abi.encode(
FlightOracle.FlightStatusRequest(
riskId,
flightData,
departureTime)),
// allow up to 30 days to process the claim
arrivalTime.addSeconds(SecondsLib.fromDays(30)),
"flightStatusCallback");
}
emit LogFlightPolicyPurchased(policyNftId, flightData.toString(), premiumAmount);
}
function _prepareApplication(
address policyHolder,
Str flightData,
Timestamp departureTime,
string memory departureTimeLocal,
Timestamp arrivalTime,
string memory arrivalTimeLocal,
Amount premiumAmount,
uint256[6] memory statistics
)
internal
virtual
returns (
RiskId riskId,
NftId policyNftId
)
{
Amount[5] memory payoutAmounts;
Amount sumInsuredAmount;
(
riskId,
payoutAmounts,
sumInsuredAmount
) = _createRiskAndPayoutAmounts(
flightData,
departureTime,
departureTimeLocal,
arrivalTime,
arrivalTimeLocal,
premiumAmount,
statistics);
policyNftId = _createApplication(
policyHolder,
riskId,
sumInsuredAmount,
premiumAmount,
LIFETIME,
_defaultBundleNftId,
ReferralLib.zero(),
abi.encode(
premiumAmount,
payoutAmounts)); // application data
}
function _createRiskAndPayoutAmounts(
Str flightData,
Timestamp departureTime,
string memory departureTimeLocal,
Timestamp arrivalTime,
string memory arrivalTimeLocal,
Amount premiumAmount,
uint256[6] memory statistics
)
internal
virtual
returns (
RiskId riskId,
Amount[5] memory payoutAmounts,
Amount sumInsuredAmount
)
{
uint256 weight;
(
weight,
payoutAmounts,
sumInsuredAmount
) = FlightLib.calculatePayoutAmounts(
this,
premiumAmount,
statistics);
riskId = _checkAndUpdateFlightRisk(
flightData,
departureTime,
departureTimeLocal,
arrivalTime,
arrivalTimeLocal,
sumInsuredAmount,
weight);
}
function _checkAndUpdateFlightRisk(
Str flightData,
Timestamp departureTime,
string memory departureTimeLocal,
Timestamp arrivalTime,
string memory arrivalTimeLocal,
Amount sumInsuredAmount,
uint256 weight
)
internal
virtual
returns (RiskId riskId)
{
bool exists;
FlightRisk memory flightRisk;
(riskId, exists, flightRisk) = FlightLib.getFlightRisk(
_getInstanceReader(),
getNftId(),
flightData,
departureTime,
departureTimeLocal,
arrivalTime,
arrivalTimeLocal);
// create risk, if new
if (!exists) {
bytes32 riskKey = FlightLib.getRiskKey(flightData);
_createRisk(riskKey, abi.encode(flightRisk));
}
FlightLib.checkClusterRisk(
flightRisk.sumOfSumInsuredAmounts,
sumInsuredAmount,
MAX_TOTAL_PAYOUT);
// update existing risk with additional sum insured amount
flightRisk.sumOfSumInsuredAmounts = flightRisk.sumOfSumInsuredAmounts + sumInsuredAmount;
_updateRisk(riskId, abi.encode(flightRisk));
}
function _processFlightStatus(
RequestId requestId,
RiskId riskId,
bytes1 status,
int256 delayMinutes
)
internal
virtual
{
// check risk exists
(, FlightRisk memory flightRisk) = getFlightRisk(riskId, true);
// update status, if not yet set
if (flightRisk.statusUpdatedAt.eqz()) {
flightRisk.statusUpdatedAt = TimestampLib.current();
flightRisk.status = status;
flightRisk.delayMinutes = delayMinutes;
flightRisk.payoutOption = FlightLib.checkAndGetPayoutOption(
requestId, riskId, status, delayMinutes);
_updateRisk(riskId, abi.encode(flightRisk));
}
(,, uint8 payoutOption) = _processPayoutsAndClosePolicies(
riskId,
MAX_POLICIES_TO_PROCESS);
// logging
emit LogFlightStatusProcessed(requestId, riskId, status, delayMinutes, payoutOption);
}
function _processPayoutsAndClosePolicies(
RiskId riskId,
uint8 maxPoliciesToProcess
)
internal
virtual
returns (
bool riskExists,
bool statusAvailable,
uint8 payoutOption
)
{
// determine numbers of policies to process
InstanceReader reader = _getInstanceReader();
(riskExists, statusAvailable, payoutOption) = FlightLib.getPayoutOption(reader, getNftId(), riskId);
// return with default values if risk does not exist or status is not yet available
if (!riskExists || !statusAvailable) {
return (riskExists, statusAvailable, payoutOption);
}
uint256 policiesToProcess = reader.policiesForRisk(riskId);
uint256 policiesProcessed = policiesToProcess < maxPoliciesToProcess ? policiesToProcess : maxPoliciesToProcess;
// assemble array with policies to process
NftId [] memory policies = new NftId[](policiesProcessed);
for (uint256 i = 0; i < policiesProcessed; i++) {
policies[i] = reader.getPolicyForRisk(riskId, i);
}
// go through policies
for (uint256 i = 0; i < policiesProcessed; i++) {
NftId policyNftId = policies[i];
Amount payoutAmount = FlightLib.getPayoutAmount(
reader.getPolicyInfo(policyNftId).applicationData,
payoutOption);
// create claim/payout (if applicable)
_resolvePayout(
policyNftId,
payoutAmount);
// expire and close policy
_expire(policyNftId, TimestampLib.current());
_close(policyNftId);
emit LogFlightPolicyClosed(policyNftId, payoutAmount);
}
// logging
emit LogFlightPoliciesProcessed(riskId, payoutOption, policiesProcessed, policiesToProcess - policiesProcessed);
}
function _resolvePayout(
NftId policyNftId,
Amount payoutAmount
)
internal
virtual
{
// no action if no payout
if (payoutAmount.eqz()) {
return;
}
// create confirmed claim
ClaimId claimId = _submitClaim(policyNftId, payoutAmount, "");
_confirmClaim(policyNftId, claimId, payoutAmount, "");
// create and execute payout
PayoutId payoutId = _createPayout(policyNftId, claimId, payoutAmount, "");
_processPayout(policyNftId, payoutId);
}
function _initialize(
address registry,
NftId instanceNftId,
string memory componentName,
IAuthorization authorization,
address initialOwner
)
internal
initializer()
{
__Product_init(
registry,
instanceNftId,
componentName,
IComponents.ProductInfo({
isProcessingFundedClaims: false,
isInterceptingPolicyTransfers: false,
hasDistribution: false,
expectedNumberOfOracles: 1,
numberOfOracles: 0,
poolNftId: NftIdLib.zero(),
distributionNftId: NftIdLib.zero(),
oracleNftId: new NftId[](0)
}),
IComponents.FeeInfo({
productFee: FeeLib.zero(),
processingFee: FeeLib.zero(),
distributionFee: FeeLib.zero(),
minDistributionOwnerFee: FeeLib.zero(),
poolFee: FeeLib.zero(),
stakingFee: FeeLib.zero(),
performanceFee: FeeLib.zero()
}),
authorization,
initialOwner); // number of oracles
MAX_FLIGHT_DURATION = SecondsLib.fromDays(2);
LIFETIME = SecondsLib.fromDays(30);
WEIGHT_PATTERN = [0, 0, 0, 30, 50, 50];
MIN_OBSERVATIONS = 10;
MARGIN_PERCENT = 30;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManaged.sol)
pragma solidity ^0.8.20;
import {IAuthority} from "@openzeppelin/contracts/access/manager/IAuthority.sol";
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 "../../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 unambiguosly 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);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManager.sol)
pragma solidity ^0.8.20;
import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {MulticallUpgradeable} from "../../utils/MulticallUpgradeable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev AccessManager is a central contract to store the permissions of a system.
*
* A smart contract under the control of an AccessManager instance is known as a target, and will inherit from the
* {AccessManaged} contract, be connected to this contract as its manager and implement the {AccessManaged-restricted}
* modifier on a set of functions selected to be permissioned. Note that any function without this setup won't be
* effectively restricted.
*
* The restriction rules for such functions are defined in terms of "roles" identified by an `uint64` and scoped
* by target (`address`) and function selectors (`bytes4`). These roles are stored in this contract and can be
* configured by admins (`ADMIN_ROLE` members) after a delay (see {getTargetAdminDelay}).
*
* For each target contract, admins can configure the following without any delay:
*
* * The target's {AccessManaged-authority} via {updateAuthority}.
* * Close or open a target via {setTargetClosed} keeping the permissions intact.
* * The roles that are allowed (or disallowed) to call a given function (identified by its selector) through {setTargetFunctionRole}.
*
* By default every address is member of the `PUBLIC_ROLE` and every target function is restricted to the `ADMIN_ROLE` until configured otherwise.
* Additionally, each role has the following configuration options restricted to this manager's admins:
*
* * A role's admin role via {setRoleAdmin} who can grant or revoke roles.
* * A role's guardian role via {setRoleGuardian} who's allowed to cancel operations.
* * A delay in which a role takes effect after being granted through {setGrantDelay}.
* * A delay of any target's admin action via {setTargetAdminDelay}.
* * A role label for discoverability purposes with {labelRole}.
*
* Any account can be added and removed into any number of these roles by using the {grantRole} and {revokeRole} functions
* restricted to each role's admin (see {getRoleAdmin}).
*
* Since all the permissions of the managed system can be modified by the admins of this instance, it is expected that
* they will be highly secured (e.g., a multisig or a well-configured DAO).
*
* NOTE: This contract implements a form of the {IAuthority} interface, but {canCall} has additional return data so it
* doesn't inherit `IAuthority`. It is however compatible with the `IAuthority` interface since the first 32 bytes of
* the return data are a boolean as expected by that interface.
*
* NOTE: Systems that implement other access control mechanisms (for example using {Ownable}) can be paired with an
* {AccessManager} by transferring permissions (ownership in the case of {Ownable}) directly to the {AccessManager}.
* Users will be able to interact with these contracts through the {execute} function, following the access rules
* registered in the {AccessManager}. Keep in mind that in that context, the msg.sender seen by restricted functions
* will be {AccessManager} itself.
*
* WARNING: When granting permissions over an {Ownable} or {AccessControl} contract to an {AccessManager}, be very
* mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or
* {{AccessControl-renounceRole}}.
*/
contract AccessManagerUpgradeable is Initializable, ContextUpgradeable, MulticallUpgradeable, IAccessManager {
using Time for *;
// Structure that stores the details for a target contract.
struct TargetConfig {
mapping(bytes4 selector => uint64 roleId) allowedRoles;
Time.Delay adminDelay;
bool closed;
}
// Structure that stores the details for a role/account pair. This structures fit into a single slot.
struct Access {
// Timepoint at which the user gets the permission.
// If this is either 0 or in the future, then the role permission is not available.
uint48 since;
// Delay for execution. Only applies to restricted() / execute() calls.
Time.Delay delay;
}
// Structure that stores the details of a role.
struct Role {
// Members of the role.
mapping(address user => Access access) members;
// Admin who can grant or revoke permissions.
uint64 admin;
// Guardian who can cancel operations targeting functions that need this role.
uint64 guardian;
// Delay in which the role takes effect after being granted.
Time.Delay grantDelay;
}
// Structure that stores the details for a scheduled operation. This structure fits into a single slot.
struct Schedule {
// Moment at which the operation can be executed.
uint48 timepoint;
// Operation nonce to allow third-party contracts to identify the operation.
uint32 nonce;
}
uint64 public constant ADMIN_ROLE = type(uint64).min; // 0
uint64 public constant PUBLIC_ROLE = type(uint64).max; // 2**64-1
/// @custom:storage-location erc7201:openzeppelin.storage.AccessManager
struct AccessManagerStorage {
mapping(address target => TargetConfig mode) _targets;
mapping(uint64 roleId => Role) _roles;
mapping(bytes32 operationId => Schedule) _schedules;
// Used to identify operations that are currently being executed via {execute}.
// This should be transient storage when supported by the EVM.
bytes32 _executionId;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessManager")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessManagerStorageLocation = 0x40c6c8c28789853c7efd823ab20824bbd71718a8a5915e855f6f288c9a26ad00;
function _getAccessManagerStorage() private pure returns (AccessManagerStorage storage $) {
assembly {
$.slot := AccessManagerStorageLocation
}
}
/**
* @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in
* {_getAdminRestrictions}.
*/
modifier onlyAuthorized() {
_checkAuthorized();
_;
}
function __AccessManager_init(address initialAdmin) internal onlyInitializing {
__AccessManager_init_unchained(initialAdmin);
}
function __AccessManager_init_unchained(address initialAdmin) internal onlyInitializing {
if (initialAdmin == address(0)) {
revert AccessManagerInvalidInitialAdmin(address(0));
}
// admin is active immediately and without any execution delay.
_grantRole(ADMIN_ROLE, initialAdmin, 0, 0);
}
// =================================================== GETTERS ====================================================
/// @inheritdoc IAccessManager
function canCall(
address caller,
address target,
bytes4 selector
) public view virtual returns (bool immediate, uint32 delay) {
if (isTargetClosed(target)) {
return (false, 0);
} else if (caller == address(this)) {
// Caller is AccessManager, this means the call was sent through {execute} and it already checked
// permissions. We verify that the call "identifier", which is set during {execute}, is correct.
return (_isExecuting(target, selector), 0);
} else {
uint64 roleId = getTargetFunctionRole(target, selector);
(bool isMember, uint32 currentDelay) = hasRole(roleId, caller);
return isMember ? (currentDelay == 0, currentDelay) : (false, 0);
}
}
/// @inheritdoc IAccessManager
function expiration() public view virtual returns (uint32) {
return 1 weeks;
}
/// @inheritdoc IAccessManager
function minSetback() public view virtual returns (uint32) {
return 5 days;
}
/// @inheritdoc IAccessManager
function isTargetClosed(address target) public view virtual returns (bool) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._targets[target].closed;
}
/// @inheritdoc IAccessManager
function getTargetFunctionRole(address target, bytes4 selector) public view virtual returns (uint64) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._targets[target].allowedRoles[selector];
}
/// @inheritdoc IAccessManager
function getTargetAdminDelay(address target) public view virtual returns (uint32) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._targets[target].adminDelay.get();
}
/// @inheritdoc IAccessManager
function getRoleAdmin(uint64 roleId) public view virtual returns (uint64) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._roles[roleId].admin;
}
/// @inheritdoc IAccessManager
function getRoleGuardian(uint64 roleId) public view virtual returns (uint64) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._roles[roleId].guardian;
}
/// @inheritdoc IAccessManager
function getRoleGrantDelay(uint64 roleId) public view virtual returns (uint32) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._roles[roleId].grantDelay.get();
}
/// @inheritdoc IAccessManager
function getAccess(
uint64 roleId,
address account
) public view virtual returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
Access storage access = $._roles[roleId].members[account];
since = access.since;
(currentDelay, pendingDelay, effect) = access.delay.getFull();
return (since, currentDelay, pendingDelay, effect);
}
/// @inheritdoc IAccessManager
function hasRole(
uint64 roleId,
address account
) public view virtual returns (bool isMember, uint32 executionDelay) {
if (roleId == PUBLIC_ROLE) {
return (true, 0);
} else {
(uint48 hasRoleSince, uint32 currentDelay, , ) = getAccess(roleId, account);
return (hasRoleSince != 0 && hasRoleSince <= Time.timestamp(), currentDelay);
}
}
// =============================================== ROLE MANAGEMENT ===============================================
/// @inheritdoc IAccessManager
function labelRole(uint64 roleId, string calldata label) public virtual onlyAuthorized {
if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
emit RoleLabel(roleId, label);
}
/// @inheritdoc IAccessManager
function grantRole(uint64 roleId, address account, uint32 executionDelay) public virtual onlyAuthorized {
_grantRole(roleId, account, getRoleGrantDelay(roleId), executionDelay);
}
/// @inheritdoc IAccessManager
function revokeRole(uint64 roleId, address account) public virtual onlyAuthorized {
_revokeRole(roleId, account);
}
/// @inheritdoc IAccessManager
function renounceRole(uint64 roleId, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessManagerBadConfirmation();
}
_revokeRole(roleId, callerConfirmation);
}
/// @inheritdoc IAccessManager
function setRoleAdmin(uint64 roleId, uint64 admin) public virtual onlyAuthorized {
_setRoleAdmin(roleId, admin);
}
/// @inheritdoc IAccessManager
function setRoleGuardian(uint64 roleId, uint64 guardian) public virtual onlyAuthorized {
_setRoleGuardian(roleId, guardian);
}
/// @inheritdoc IAccessManager
function setGrantDelay(uint64 roleId, uint32 newDelay) public virtual onlyAuthorized {
_setGrantDelay(roleId, newDelay);
}
/**
* @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted.
*
* Emits a {RoleGranted} event.
*/
function _grantRole(
uint64 roleId,
address account,
uint32 grantDelay,
uint32 executionDelay
) internal virtual returns (bool) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
if (roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
bool newMember = $._roles[roleId].members[account].since == 0;
uint48 since;
if (newMember) {
since = Time.timestamp() + grantDelay;
$._roles[roleId].members[account] = Access({since: since, delay: executionDelay.toDelay()});
} else {
// No setback here. Value can be reset by doing revoke + grant, effectively allowing the admin to perform
// any change to the execution delay within the duration of the role admin delay.
($._roles[roleId].members[account].delay, since) = $._roles[roleId].members[account].delay.withUpdate(
executionDelay,
0
);
}
emit RoleGranted(roleId, account, executionDelay, since, newMember);
return newMember;
}
/**
* @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}.
* Returns true if the role was previously granted.
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function _revokeRole(uint64 roleId, address account) internal virtual returns (bool) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
if (roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
if ($._roles[roleId].members[account].since == 0) {
return false;
}
delete $._roles[roleId].members[account];
emit RoleRevoked(roleId, account);
return true;
}
/**
* @dev Internal version of {setRoleAdmin} without access control.
*
* Emits a {RoleAdminChanged} event.
*
* NOTE: Setting the admin role as the `PUBLIC_ROLE` is allowed, but it will effectively allow
* anyone to set grant or revoke such role.
*/
function _setRoleAdmin(uint64 roleId, uint64 admin) internal virtual {
AccessManagerStorage storage $ = _getAccessManagerStorage();
if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
$._roles[roleId].admin = admin;
emit RoleAdminChanged(roleId, admin);
}
/**
* @dev Internal version of {setRoleGuardian} without access control.
*
* Emits a {RoleGuardianChanged} event.
*
* NOTE: Setting the guardian role as the `PUBLIC_ROLE` is allowed, but it will effectively allow
* anyone to cancel any scheduled operation for such role.
*/
function _setRoleGuardian(uint64 roleId, uint64 guardian) internal virtual {
AccessManagerStorage storage $ = _getAccessManagerStorage();
if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
$._roles[roleId].guardian = guardian;
emit RoleGuardianChanged(roleId, guardian);
}
/**
* @dev Internal version of {setGrantDelay} without access control.
*
* Emits a {RoleGrantDelayChanged} event.
*/
function _setGrantDelay(uint64 roleId, uint32 newDelay) internal virtual {
AccessManagerStorage storage $ = _getAccessManagerStorage();
if (roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
uint48 effect;
($._roles[roleId].grantDelay, effect) = $._roles[roleId].grantDelay.withUpdate(newDelay, minSetback());
emit RoleGrantDelayChanged(roleId, newDelay, effect);
}
// ============================================= FUNCTION MANAGEMENT ==============================================
/// @inheritdoc IAccessManager
function setTargetFunctionRole(
address target,
bytes4[] calldata selectors,
uint64 roleId
) public virtual onlyAuthorized {
for (uint256 i = 0; i < selectors.length; ++i) {
_setTargetFunctionRole(target, selectors[i], roleId);
}
}
/**
* @dev Internal version of {setTargetFunctionRole} without access control.
*
* Emits a {TargetFunctionRoleUpdated} event.
*/
function _setTargetFunctionRole(address target, bytes4 selector, uint64 roleId) internal virtual {
AccessManagerStorage storage $ = _getAccessManagerStorage();
$._targets[target].allowedRoles[selector] = roleId;
emit TargetFunctionRoleUpdated(target, selector, roleId);
}
/// @inheritdoc IAccessManager
function setTargetAdminDelay(address target, uint32 newDelay) public virtual onlyAuthorized {
_setTargetAdminDelay(target, newDelay);
}
/**
* @dev Internal version of {setTargetAdminDelay} without access control.
*
* Emits a {TargetAdminDelayUpdated} event.
*/
function _setTargetAdminDelay(address target, uint32 newDelay) internal virtual {
AccessManagerStorage storage $ = _getAccessManagerStorage();
uint48 effect;
($._targets[target].adminDelay, effect) = $._targets[target].adminDelay.withUpdate(newDelay, minSetback());
emit TargetAdminDelayUpdated(target, newDelay, effect);
}
// =============================================== MODE MANAGEMENT ================================================
/// @inheritdoc IAccessManager
function setTargetClosed(address target, bool closed) public virtual onlyAuthorized {
_setTargetClosed(target, closed);
}
/**
* @dev Set the closed flag for a contract. This is an internal setter with no access restrictions.
*
* Emits a {TargetClosed} event.
*/
function _setTargetClosed(address target, bool closed) internal virtual {
AccessManagerStorage storage $ = _getAccessManagerStorage();
if (target == address(this)) {
revert AccessManagerLockedAccount(target);
}
$._targets[target].closed = closed;
emit TargetClosed(target, closed);
}
// ============================================== DELAYED OPERATIONS ==============================================
/// @inheritdoc IAccessManager
function getSchedule(bytes32 id) public view virtual returns (uint48) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
uint48 timepoint = $._schedules[id].timepoint;
return _isExpired(timepoint) ? 0 : timepoint;
}
/// @inheritdoc IAccessManager
function getNonce(bytes32 id) public view virtual returns (uint32) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._schedules[id].nonce;
}
/// @inheritdoc IAccessManager
function schedule(
address target,
bytes calldata data,
uint48 when
) public virtual returns (bytes32 operationId, uint32 nonce) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
address caller = _msgSender();
// Fetch restrictions that apply to the caller on the targeted function
(, uint32 setback) = _canCallExtended(caller, target, data);
uint48 minWhen = Time.timestamp() + setback;
// if call with delay is not authorized, or if requested timing is too soon
if (setback == 0 || (when > 0 && when < minWhen)) {
revert AccessManagerUnauthorizedCall(caller, target, _checkSelector(data));
}
// Reuse variable due to stack too deep
when = uint48(Math.max(when, minWhen)); // cast is safe: both inputs are uint48
// If caller is authorised, schedule operation
operationId = hashOperation(caller, target, data);
_checkNotScheduled(operationId);
unchecked {
// It's not feasible to overflow the nonce in less than 1000 years
nonce = $._schedules[operationId].nonce + 1;
}
$._schedules[operationId].timepoint = when;
$._schedules[operationId].nonce = nonce;
emit OperationScheduled(operationId, nonce, when, caller, target, data);
// Using named return values because otherwise we get stack too deep
}
/**
* @dev Reverts if the operation is currently scheduled and has not expired.
* (Note: This function was introduced due to stack too deep errors in schedule.)
*/
function _checkNotScheduled(bytes32 operationId) private view {
AccessManagerStorage storage $ = _getAccessManagerStorage();
uint48 prevTimepoint = $._schedules[operationId].timepoint;
if (prevTimepoint != 0 && !_isExpired(prevTimepoint)) {
revert AccessManagerAlreadyScheduled(operationId);
}
}
/// @inheritdoc IAccessManager
// Reentrancy is not an issue because permissions are checked on msg.sender. Additionally,
// _consumeScheduledOp guarantees a scheduled operation is only executed once.
// slither-disable-next-line reentrancy-no-eth
function execute(address target, bytes calldata data) public payable virtual returns (uint32) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
address caller = _msgSender();
// Fetch restrictions that apply to the caller on the targeted function
(bool immediate, uint32 setback) = _canCallExtended(caller, target, data);
// If caller is not authorised, revert
if (!immediate && setback == 0) {
revert AccessManagerUnauthorizedCall(caller, target, _checkSelector(data));
}
bytes32 operationId = hashOperation(caller, target, data);
uint32 nonce;
// If caller is authorised, check operation was scheduled early enough
// Consume an available schedule even if there is no currently enforced delay
if (setback != 0 || getSchedule(operationId) != 0) {
nonce = _consumeScheduledOp(operationId);
}
// Mark the target and selector as authorised
bytes32 executionIdBefore = $._executionId;
$._executionId = _hashExecutionId(target, _checkSelector(data));
// Perform call
Address.functionCallWithValue(target, data, msg.value);
// Reset execute identifier
$._executionId = executionIdBefore;
return nonce;
}
/// @inheritdoc IAccessManager
function cancel(address caller, address target, bytes calldata data) public virtual returns (uint32) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
address msgsender = _msgSender();
bytes4 selector = _checkSelector(data);
bytes32 operationId = hashOperation(caller, target, data);
if ($._schedules[operationId].timepoint == 0) {
revert AccessManagerNotScheduled(operationId);
} else if (caller != msgsender) {
// calls can only be canceled by the account that scheduled them, a global admin, or by a guardian of the required role.
(bool isAdmin, ) = hasRole(ADMIN_ROLE, msgsender);
(bool isGuardian, ) = hasRole(getRoleGuardian(getTargetFunctionRole(target, selector)), msgsender);
if (!isAdmin && !isGuardian) {
revert AccessManagerUnauthorizedCancel(msgsender, caller, target, selector);
}
}
delete $._schedules[operationId].timepoint; // reset the timepoint, keep the nonce
uint32 nonce = $._schedules[operationId].nonce;
emit OperationCanceled(operationId, nonce);
return nonce;
}
/// @inheritdoc IAccessManager
function consumeScheduledOp(address caller, bytes calldata data) public virtual {
address target = _msgSender();
if (IAccessManaged(target).isConsumingScheduledOp() != IAccessManaged.isConsumingScheduledOp.selector) {
revert AccessManagerUnauthorizedConsume(target);
}
_consumeScheduledOp(hashOperation(caller, target, data));
}
/**
* @dev Internal variant of {consumeScheduledOp} that operates on bytes32 operationId.
*
* Returns the nonce of the scheduled operation that is consumed.
*/
function _consumeScheduledOp(bytes32 operationId) internal virtual returns (uint32) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
uint48 timepoint = $._schedules[operationId].timepoint;
uint32 nonce = $._schedules[operationId].nonce;
if (timepoint == 0) {
revert AccessManagerNotScheduled(operationId);
} else if (timepoint > Time.timestamp()) {
revert AccessManagerNotReady(operationId);
} else if (_isExpired(timepoint)) {
revert AccessManagerExpired(operationId);
}
delete $._schedules[operationId].timepoint; // reset the timepoint, keep the nonce
emit OperationExecuted(operationId, nonce);
return nonce;
}
/// @inheritdoc IAccessManager
function hashOperation(address caller, address target, bytes calldata data) public view virtual returns (bytes32) {
return keccak256(abi.encode(caller, target, data));
}
// ==================================================== OTHERS ====================================================
/// @inheritdoc IAccessManager
function updateAuthority(address target, address newAuthority) public virtual onlyAuthorized {
IAccessManaged(target).setAuthority(newAuthority);
}
// ================================================= ADMIN LOGIC ==================================================
/**
* @dev Check if the current call is authorized according to admin logic.
*/
function _checkAuthorized() private {
address caller = _msgSender();
(bool immediate, uint32 delay) = _canCallSelf(caller, _msgData());
if (!immediate) {
if (delay == 0) {
(, uint64 requiredRole, ) = _getAdminRestrictions(_msgData());
revert AccessManagerUnauthorizedAccount(caller, requiredRole);
} else {
_consumeScheduledOp(hashOperation(caller, address(this), _msgData()));
}
}
}
/**
* @dev Get the admin restrictions of a given function call based on the function and arguments involved.
*
* Returns:
* - bool restricted: does this data match a restricted operation
* - uint64: which role is this operation restricted to
* - uint32: minimum delay to enforce for that operation (max between operation's delay and admin's execution delay)
*/
function _getAdminRestrictions(
bytes calldata data
) private view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) {
if (data.length < 4) {
return (false, 0, 0);
}
bytes4 selector = _checkSelector(data);
// Restricted to ADMIN with no delay beside any execution delay the caller may have
if (
selector == this.labelRole.selector ||
selector == this.setRoleAdmin.selector ||
selector == this.setRoleGuardian.selector ||
selector == this.setGrantDelay.selector ||
selector == this.setTargetAdminDelay.selector
) {
return (true, ADMIN_ROLE, 0);
}
// Restricted to ADMIN with the admin delay corresponding to the target
if (
selector == this.updateAuthority.selector ||
selector == this.setTargetClosed.selector ||
selector == this.setTargetFunctionRole.selector
) {
// First argument is a target.
address target = abi.decode(data[0x04:0x24], (address));
uint32 delay = getTargetAdminDelay(target);
return (true, ADMIN_ROLE, delay);
}
// Restricted to that role's admin with no delay beside any execution delay the caller may have.
if (selector == this.grantRole.selector || selector == this.revokeRole.selector) {
// First argument is a roleId.
uint64 roleId = abi.decode(data[0x04:0x24], (uint64));
return (true, getRoleAdmin(roleId), 0);
}
return (false, 0, 0);
}
// =================================================== HELPERS ====================================================
/**
* @dev An extended version of {canCall} for internal usage that checks {_canCallSelf}
* when the target is this contract.
*
* Returns:
* - bool immediate: whether the operation can be executed immediately (with no delay)
* - uint32 delay: the execution delay
*/
function _canCallExtended(
address caller,
address target,
bytes calldata data
) private view returns (bool immediate, uint32 delay) {
if (target == address(this)) {
return _canCallSelf(caller, data);
} else {
return data.length < 4 ? (false, 0) : canCall(caller, target, _checkSelector(data));
}
}
/**
* @dev A version of {canCall} that checks for admin restrictions in this contract.
*/
function _canCallSelf(address caller, bytes calldata data) private view returns (bool immediate, uint32 delay) {
if (data.length < 4) {
return (false, 0);
}
if (caller == address(this)) {
// Caller is AccessManager, this means the call was sent through {execute} and it already checked
// permissions. We verify that the call "identifier", which is set during {execute}, is correct.
return (_isExecuting(address(this), _checkSelector(data)), 0);
}
(bool enabled, uint64 roleId, uint32 operationDelay) = _getAdminRestrictions(data);
if (!enabled) {
return (false, 0);
}
(bool inRole, uint32 executionDelay) = hasRole(roleId, caller);
if (!inRole) {
return (false, 0);
}
// downcast is safe because both options are uint32
delay = uint32(Math.max(operationDelay, executionDelay));
return (delay == 0, delay);
}
/**
* @dev Returns true if a call with `target` and `selector` is being executed via {executed}.
*/
function _isExecuting(address target, bytes4 selector) private view returns (bool) {
AccessManagerStorage storage $ = _getAccessManagerStorage();
return $._executionId == _hashExecutionId(target, selector);
}
/**
* @dev Returns true if a schedule timepoint is past its expiration deadline.
*/
function _isExpired(uint48 timepoint) private view returns (bool) {
return timepoint + expiration() <= Time.timestamp();
}
/**
* @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes
*/
function _checkSelector(bytes calldata data) private pure returns (bytes4) {
return bytes4(data[0:4]);
}
/**
* @dev Hashing function for execute protection
*/
function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) {
return keccak256(abi.encode(target, selector));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 reininitialization) 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 Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Multicall.sol)
pragma solidity ^0.8.20;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ContextUpgradeable} from "./ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* Consider any assumption about calldata validation performed by the sender may be violated if it's not especially
* careful about sending transactions invoking {multicall}. For example, a relay address that filters function
* selectors won't filter calls nested within a {multicall} operation.
*
* NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).
* If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data`
* to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of
* {_msgSender} are not propagated to subcalls.
*/
abstract contract MulticallUpgradeable is Initializable, ContextUpgradeable {
function __Multicall_init() internal onlyInitializing {
}
function __Multicall_init_unchained() internal onlyInitializing {
}
/**
* @dev Receives and executes a batch of function calls on this contract.
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
bytes memory context = msg.sender == _msgSender()
? new bytes(0)
: msg.data[msg.data.length - _contextSuffixLength():];
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context));
}
return results;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManaged.sol)
pragma solidity ^0.8.20;
import {IAuthority} from "./IAuthority.sol";
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 unambiguosly 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);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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) {
(bool success, bytes memory data) = authority.staticcall(
abi.encodeCall(IAuthority.canCall, (caller, target, selector))
);
if (success) {
if (data.length >= 0x40) {
(immediate, delay) = abi.decode(data, (bool, uint32));
} else if (data.length >= 0x20) {
immediate = abi.decode(data, (bool));
}
}
return (immediate, delay);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManaged.sol)
pragma solidity ^0.8.20;
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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManager.sol)
pragma solidity ^0.8.20;
import {IAccessManaged} from "./IAccessManaged.sol";
import {Time} from "../../utils/types/Time.sol";
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 AccessManagerLockedAccount(address account);
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 `immediate` 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 this manager itself. These are defined by the
* {_canCallSelf} function instead.
*/
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.
*/
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, uint32, uint32, uint48);
/**
* @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, uint32);
/**
* @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.
*
* 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, uint32);
/**
* @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;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAuthority.sol)
pragma solidity ^0.8.20;
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)
pragma solidity ^0.8.20;
import {IERC20Permit} from "./IERC20Permit.sol";
import {ERC20} from "../ERC20.sol";
import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
import {EIP712} from "../../../utils/cryptography/EIP712.sol";
import {Nonces} from "../../../utils/Nonces.sol";
/**
* @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
bytes32 private constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/**
* @dev Permit deadline has expired.
*/
error ERC2612ExpiredSignature(uint256 deadline);
/**
* @dev Mismatched signature.
*/
error ERC2612InvalidSigner(address signer, address owner);
/**
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
* It's a good idea to use the same `name` that is defined as the ERC20 token name.
*/
constructor(string memory name) EIP712(name, "1") {}
/**
* @inheritdoc IERC20Permit
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (block.timestamp > deadline) {
revert ERC2612ExpiredSignature(deadline);
}
bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
if (signer != owner) {
revert ERC2612InvalidSigner(signer, owner);
}
_approve(owner, spender, value);
}
/**
* @inheritdoc IERC20Permit
*/
function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
return super.nonces(owner);
}
/**
* @inheritdoc IERC20Permit
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
return _domainSeparatorV4();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 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 {
using Address for address;
/**
* @dev An operation with an ERC20 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 {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @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 {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
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.
*/
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.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), 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 data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), 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 data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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 AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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
* {FailedInnerCall} 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 AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @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, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @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, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @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 {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// 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 (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @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 {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: By default this function reads _name which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: By default this function reads _version which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* 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[EIP 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return 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.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev 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 {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 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 prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, 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 {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
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^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// 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^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice 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) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @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 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides tracking nonces for addresses. Nonces will only increment.
*/
abstract contract Nonces {
/**
* @dev The nonce used for an `account` is not the expected current nonce.
*/
error InvalidAccountNonce(address account, uint256 currentNonce);
mapping(address account => uint256) private _nonces;
/**
* @dev Returns the next unused nonce for an address.
*/
function nonces(address owner) public view virtual returns (uint256) {
return _nonces[owner];
}
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256) {
// For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
// decremented or reset. This guarantees that the nonce never overflows.
unchecked {
// It is important to do x++ and not ++x here.
return _nonces[owner]++;
}
}
/**
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
*/
function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
uint256 current = _useNonce(owner);
if (nonce != current) {
revert InvalidAccountNonce(owner, current);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* 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;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @dev This library provides helpers for manipulating time-related objects.
*
* It uses the following types:
* - `uint48` for timepoints
* - `uint32` for durations
*
* While the library doesn't provide specific types for timepoints and duration, it does provide:
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
* - additional helper functions
*/
library Time {
using Time for *;
/**
* @dev Get the block timestamp as a Timepoint.
*/
function timestamp() internal view returns (uint48) {
return SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) {
(uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32, uint32, uint48) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IAccess} from "./IAccess.sol";
import {IAccessAdmin} from "./IAccessAdmin.sol";
import {IAuthorization} from "./IAuthorization.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IServiceAuthorization} from "./IServiceAuthorization.sol";
import {AccessAdminLib} from "./AccessAdminLib.sol";
import {AccessManagerCloneable} from "./AccessManagerCloneable.sol";
import {Blocknumber, BlocknumberLib} from "../type/Blocknumber.sol";
import {ContractLib} from "../shared/ContractLib.sol";
import {NftId, NftIdLib} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RoleId, RoleIdLib, ADMIN_ROLE, PUBLIC_ROLE} from "../type/RoleId.sol";
import {Selector, SelectorSetLib} from "../type/Selector.sol";
import {Str, StrLib} from "../type/String.sol";
import {TimestampLib} from "../type/Timestamp.sol";
import {VersionPart} from "../type/Version.sol";
/**
* @dev A generic access amin contract that implements role based access control based on OpenZeppelin's AccessManager contract.
* The contract provides read functions to query all available roles, targets and access rights.
* This contract works for both a constructor based deployment or a deployment based on cloning and initialization.
*/
contract AccessAdmin is
AccessManagedUpgradeable,
IAccessAdmin
{
using EnumerableSet for EnumerableSet.AddressSet;
/// @dev admin name used for logging only
string internal _adminName;
/// @dev the access manager driving the access admin contract
/// hold link to registry and release version
AccessManagerCloneable internal _authority;
/// @dev the authorization contract used for initial access control
IAuthorization internal _authorization;
// /// @dev stores the deployer address and allows to create initializers
// /// that are restricted to the deployer address.
// address internal _deployer;
/// @dev the linked NFT ID
NftId internal _linkedNftId;
/// @dev store role info per role id
mapping(RoleId roleId => RoleInfo info) internal _roleInfo;
/// @dev store role name info per role name
mapping(Str roleName => RoleNameInfo nameInfo) internal _roleForName;
/// @dev store array with all created roles
RoleId [] internal _roleIds;
// @dev target type specific role id counters
mapping(TargetType => uint64) internal _nextRoleId;
/// @dev store set of current role members for given role
mapping(RoleId roleId => EnumerableSet.AddressSet roleMembers) internal _roleMembers;
/// @dev store target info per target address
mapping(address target => TargetInfo info) internal _targetInfo;
/// @dev store role name info per role name
mapping(Str targetName => address target) internal _targetForName;
/// @dev store array with all created targets
address [] internal _targets;
/// @dev store all managed functions per target
mapping(address target => SelectorSetLib.Set selectors) internal _targetFunctions;
/// @dev function infos array
mapping(address target => mapping(Selector selector => FunctionInfo)) internal _functionInfo;
/// @dev temporary dynamic functions array
bytes4[] private _functions;
//-------------- initialization functions ------------------------------//
/// @dev Initializes this admin with the provided accessManager (and authorization specification).
/// Internally initializes access manager with this admin and creates basic role setup.
function initialize(
address authority,
string memory adminName
)
public
initializer()
{
__AccessAdmin_init(authority, adminName);
}
/// @dev Initializes this admin with the provided accessManager and name.
/// IMPORTANT
/// - cloning of an access admin and initialization MUST be done in the same tx.
/// - this function as well as any completeSetup functions MUST be called in the same tx.
function __AccessAdmin_init(
address authority,
string memory adminName
)
internal
onlyInitializing()
{
AccessAdminLib.checkInitParameters(authority, adminName);
_authority = AccessManagerCloneable(authority);
_authority.initialize(address(this));
// delayed additional check for authority after its initialization
if (!ContractLib.isAuthority(authority)) {
revert ErrorAccessAdminAccessManagerNotAccessManager(authority);
}
// effects
// set and initialize this access manager contract as
// the admin (ADMIN_ROLE) of the provided authority
__AccessManaged_init(authority);
// set name for logging
_adminName = adminName;
// set initial linked NFT ID to zero
_linkedNftId = NftIdLib.zero();
// setup admin role
_createRoleUnchecked(
ADMIN_ROLE(), AccessAdminLib.adminRoleInfo());
// add this contract as admin role member, as contract roles cannot be revoked
// and max member count is 1 for admin role this access admin contract will
// always be the only admin of the access manager.
_roleMembers[
RoleIdLib.toRoleId(_authority.ADMIN_ROLE())].add(address(this));
// setup public role
_createRoleUnchecked(
PUBLIC_ROLE(), AccessAdminLib.publicRoleInfo());
}
//--- view functions for access admin ---------------------------------------//
function getRelease() public view virtual returns (VersionPart release) {
return _authority.getRelease();
}
function getRegistry() public view returns (IRegistry registry) {
return _authority.getRegistry();
}
function getLinkedNftId() external view returns (NftId linkedNftId) {
return _linkedNftId;
}
function getAuthorization() public view returns (IAuthorization authorization) {
return _authorization;
}
function isLocked() public view returns (bool locked) {
return _authority.isLocked();
}
//--- view functions for roles ------------------------------------------//
function roles() external view returns (uint256 numberOfRoles) {
return _roleIds.length;
}
function getRoleId(uint256 idx) external view returns (RoleId roleId) {
return _roleIds[idx];
}
function getAdminRole() public view returns (RoleId roleId) {
return RoleId.wrap(_authority.ADMIN_ROLE());
}
function getPublicRole() public view returns (RoleId roleId) {
return RoleId.wrap(_authority.PUBLIC_ROLE());
}
function roleExists(RoleId roleId) public view returns (bool exists) {
return _roleInfo[roleId].targetType != TargetType.Undefined;
}
function getRoleForName(string memory name) public view returns (RoleId roleId, bool exists) {
roleId = _roleForName[StrLib.toStr(name)].roleId;
exists = false;
if (roleId.gtz() || AccessAdminLib.isAdminRoleName(name)) {
exists = true;
}
}
function getRoleInfo(RoleId roleId) public view returns (RoleInfo memory) {
return _roleInfo[roleId];
}
function isRoleActive(RoleId roleId) external view returns (bool isActive) {
return _roleInfo[roleId].pausedAt > TimestampLib.current();
}
function isRoleCustom(RoleId roleId) external view returns (bool isActive) {
return _roleInfo[roleId].targetType == TargetType.Custom;
}
function roleMembers(RoleId roleId) external view returns (uint256 numberOfMembers) {
return _roleMembers[roleId].length();
}
function getRoleMember(RoleId roleId, uint256 idx) external view returns (address account) {
return _roleMembers[roleId].at(idx);
}
function isRoleMember(RoleId roleId, address account) public view returns (bool) {
(bool isMember, ) = _authority.hasRole(
RoleId.unwrap(roleId),
account);
return isMember;
}
function isRoleAdmin(RoleId roleId, address account) public virtual view returns (bool) {
return isRoleMember(_roleInfo[roleId].adminRoleId, account);
}
//--- view functions for targets ----------------------------------------//
function targetExists(address target) public view returns (bool exists) {
return _targetInfo[target].createdAt.gtz();
}
function targets() external view returns (uint256 numberOfTargets) {
return _targets.length;
}
function getTargetAddress(uint256 idx) external view returns (address target) {
return _targets[idx];
}
function getTargetInfo(address target) public view returns (TargetInfo memory targetInfo) {
return _targetInfo[target];
}
function getTargetForName(Str name) public view returns (address target) {
return _targetForName[name];
}
function isTargetLocked(address target) public view returns (bool locked) {
return _authority.isLocked() || _authority.isTargetClosed(target);
}
//--- view functions for target functions -------------------------------//
function authorizedFunctions(address target) external view returns (uint256 numberOfFunctions) {
return SelectorSetLib.size(_targetFunctions[target]);
}
function getAuthorizedFunction(
address target,
uint256 idx
)
external
view
returns (
FunctionInfo memory func,
RoleId roleId
)
{
Selector selector = SelectorSetLib.at(_targetFunctions[target], idx);
func = _functionInfo[target][selector];
roleId = AccessAdminLib.getFunctionRoleId(_authority, target, selector);
// roleId = RoleIdLib.toRoleId(
// _authority.getTargetFunctionRole(
// target,
// selector.toBytes4()));
}
function getFunctionInfo(address target, Selector selector)
external
view
returns (FunctionInfo memory functionInfo)
{
return _functionInfo[target][selector];
}
//--- internal/private functions -------------------------------------------------//
function _linkToNftOwnable(address registerable) internal {
if (!getRegistry().isRegistered(registerable)) {
revert ErrorAccessAdminNotRegistered(registerable);
}
_linkedNftId = getRegistry().getNftIdForAddress(registerable);
}
function _createRoles(
IServiceAuthorization authorization
)
internal
{
RoleId[] memory roles = authorization.getRoles();
for(uint256 i = 0; i < roles.length; i++) {
RoleId authzRoleId = roles[i];
IAccess.RoleInfo memory roleInfo = authorization.getRoleInfo(authzRoleId);
(RoleId roleId, bool exists) = getRoleForName(roleInfo.name.toString());
if (!exists) {
if (!AccessAdminLib.isDynamicRoleId(authzRoleId) || roleInfo.targetType == TargetType.Custom) {
roleId = authzRoleId;
}
_createRole(
roleId,
roleInfo,
true);
}
}
}
/// @dev Creates a role based on the provided parameters.
/// Checks that the provided role and role id and role name not already used.
function _createRole(
RoleId roleId,
RoleInfo memory info,
bool revertOnExistingRole
)
internal
{
bool isAdminOrPublicRole = AccessAdminLib.checkRoleCreation(this, roleId, info, revertOnExistingRole);
if (!isAdminOrPublicRole) {
_createRoleUnchecked(roleId, info);
}
}
function _createRoleUnchecked(
RoleId roleId,
RoleInfo memory info
)
private
{
// create role info
info.createdAt = TimestampLib.current();
info.pausedAt = TimestampLib.max();
_roleInfo[roleId] = info;
// create role name info
_roleForName[info.name] = RoleNameInfo({
roleId: roleId,
exists: true});
// add role to list of roles
_roleIds.push(roleId);
emit LogAccessAdminRoleCreated(_adminName, roleId, info.targetType, info.adminRoleId, info.name.toString());
}
/// @dev Activates or deactivates role.
/// The role activ property is indirectly controlled over the pausedAt timestamp.
function _setRoleActive(RoleId roleId, bool active)
internal
{
AccessAdminLib.checkRoleExists(this, roleId, false, false);
if (active) {
_roleInfo[roleId].pausedAt = TimestampLib.max();
} else {
_roleInfo[roleId].pausedAt = TimestampLib.current();
}
Blocknumber lastUpdateIn = _roleInfo[roleId].lastUpdateIn;
_roleInfo[roleId].lastUpdateIn = BlocknumberLib.current();
emit LogAccessAdminRoleActivatedSet(_adminName, roleId, active, lastUpdateIn);
}
/// @dev grant the specified role to the provided account
function _grantRoleToAccount(RoleId roleId, address account)
internal
{
AccessAdminLib.checkRoleExists(this, roleId, true, false);
// check max role members will not be exceeded
if (_roleMembers[roleId].length() >= _roleInfo[roleId].maxMemberCount) {
revert ErrorAccessAdminRoleMembersLimitReached(roleId, _roleInfo[roleId].maxMemberCount);
}
// check account is contract for contract role
if (
_roleInfo[roleId].targetType != TargetType.Custom &&
!ContractLib.isContract(account) // will fail in account's constructor
) {
revert ErrorAccessAdminRoleMemberNotContract(roleId, account);
}
// effects
_roleMembers[roleId].add(account);
_authority.grantRole(
RoleId.unwrap(roleId),
account,
0);
emit LogAccessAdminRoleGranted(
_adminName,
account,
AccessAdminLib.getRoleName(this, roleId));
}
/// @dev revoke the specified role from the provided account
function _revokeRoleFromAccount(RoleId roleId, address account)
internal
{
AccessAdminLib.checkRoleExists(this, roleId, false, false);
// check for attempt to revoke contract role
if (_roleInfo[roleId].targetType != TargetType.Custom) {
revert ErrorAccessAdminRoleMemberRemovalDisabled(roleId, account);
}
// effects
_roleMembers[roleId].remove(account);
_authority.revokeRole(
RoleId.unwrap(roleId),
account);
emit LogAccessAdminRoleRevoked(_adminName, account, _roleInfo[roleId].name.toString());
}
function _getOrCreateTargetRoleIdAndName(
address target,
string memory targetName,
TargetType targetType
)
internal
returns (
RoleId roleId,
string memory roleName,
bool exists
)
{
roleName = AccessAdminLib.toRoleName(targetName);
(roleId, exists) = getRoleForName(roleName);
if (exists) {
return (roleId, roleName, true);
}
// get roleId
if (targetType == TargetType.Service || targetType == TargetType.GenericService) {
roleId = AccessAdminLib.getServiceRoleId(target, targetType);
} else {
uint64 nextRoleId = _nextRoleId[targetType];
roleId = AccessAdminLib.getTargetRoleId(target, targetType, nextRoleId);
// increment target type specific role id counter
_nextRoleId[targetType]++;
}
}
function _createTarget(
address target,
string memory targetName,
TargetType targetType,
bool checkAuthority
)
internal
returns (RoleId contractRoleId)
{
// checks
AccessAdminLib.checkTargetCreation(this, target, targetName, checkAuthority);
// effects
contractRoleId = _createTargetUnchecked(
target,
targetName,
targetType,
checkAuthority);
// deal with token handler, if applicable
(
address tokenHandler,
string memory tokenHandlerName
) = AccessAdminLib.getTokenHandler(target, targetName, targetType);
if (tokenHandler != address(0)) {
_createTargetUnchecked(
tokenHandler,
tokenHandlerName,
targetType,
checkAuthority);
}
}
/// @dev Creates a new target and a corresponding contract role.
/// The function assigns the role to the target and logs the creation.
function _createTargetUnchecked(
address target,
string memory targetName,
TargetType targetType,
bool managed
)
internal
returns (RoleId targetRoleId)
{
// create target role (if not existing)
string memory roleName;
bool roleExists;
(targetRoleId, roleName, roleExists) = _getOrCreateTargetRoleIdAndName(target, targetName, targetType);
if (!roleExists) {
_createRole(
targetRoleId,
AccessAdminLib.roleInfo(
ADMIN_ROLE(),
targetType,
1,
roleName),
true); // revert on existing role
}
// create target info
Str name = StrLib.toStr(targetName);
_targetInfo[target] = TargetInfo({
name: name,
targetType: targetType,
roleId: targetRoleId,
createdAt: TimestampLib.current(),
lastUpdateIn: BlocknumberLib.current()});
// create name to target mapping
_targetForName[name] = target;
// add target to list of targets
_targets.push(target);
// grant contract role to target
_grantRoleToAccount(targetRoleId, target);
emit LogAccessAdminTargetCreated(_adminName, targetName, managed, target, targetRoleId);
}
function _setTargetLocked(address target, bool locked)
internal
{
AccessAdminLib.checkTargetExists(this, target);
_authority.setTargetClosed(target, locked);
// logging
Blocknumber lastUpdateIn = _targetInfo[target].lastUpdateIn;
_targetInfo[target].lastUpdateIn = BlocknumberLib.current();
emit LogAccessAdminTargetLockedSet(_adminName, target, locked, lastUpdateIn);
}
/// @dev Authorize the functions of the target for the specified role.
function _authorizeFunctions(IAuthorization authorization, Str target, RoleId roleId)
internal
{
_authorizeTargetFunctions(
getTargetForName(target),
AccessAdminLib.getAuthorizedRole(
this,
authorization,
roleId),
authorization.getAuthorizedFunctions(
target,
roleId),
false,
true);
}
/// @dev Authorize the functions of the target for the specified role.
/// Flag addFunctions determines if functions are added or removed.
function _authorizeTargetFunctions(
address target,
RoleId roleId,
FunctionInfo[] memory functions,
bool onlyComponentOrContractTargets,
bool addFunctions
)
internal
{
// checks
AccessAdminLib.checkTargetAndRoleForFunctions(
this,
target,
roleId,
onlyComponentOrContractTargets);
if (addFunctions && roleId == getAdminRole()) {
revert ErrorAccessAdminAuthorizeForAdminRoleInvalid(target);
}
_authority.setTargetFunctionRole(
target,
AccessAdminLib.getSelectors(functions),
RoleId.unwrap(roleId));
// update function set and log function grantings
for (uint256 i = 0; i < functions.length; i++) {
_updateFunctionAccess(
target,
roleId,
functions[i],
addFunctions);
}
}
function _updateFunctionAccess(
address target,
RoleId roleId,
FunctionInfo memory func,
bool addFunction
)
internal
{
// update functions info
Selector selector = func.selector;
Blocknumber lastUpdateIn = _functionInfo[target][selector].lastUpdateIn;
// update function sets
if (addFunction) { SelectorSetLib.add(_targetFunctions[target], selector); }
else { SelectorSetLib.remove(_targetFunctions[target], selector); }
_functionInfo[target][selector] = func;
_functionInfo[target][selector].lastUpdateIn = BlocknumberLib.current();
// logging
emit LogAccessAdminFunctionGranted(
_adminName,
target,
AccessAdminLib.toFunctionGrantingString(this, func.name, roleId),
lastUpdateIn);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {IAccess} from "./IAccess.sol";
import {IAccessAdmin} from "./IAccessAdmin.sol";
import {IAuthorization} from "./IAuthorization.sol";
import {IComponent} from "../shared/IComponent.sol";
import {IAuthorizedComponent} from "../shared/IAuthorizedComponent.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IService} from "../shared/IService.sol";
import {IServiceAuthorization} from "./IServiceAuthorization.sol";
import {AccessManagerCloneable} from "./AccessManagerCloneable.sol";
import {BlocknumberLib} from "../type/Blocknumber.sol";
import {ContractLib} from "../shared/ContractLib.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RoleId, RoleIdLib, ADMIN_ROLE, PUBLIC_ROLE} from "../type/RoleId.sol";
import {Selector, SelectorLib} from "../type/Selector.sol";
import {Str, StrLib} from "../type/String.sol";
import {TimestampLib} from "../type/Timestamp.sol";
import {VersionPart, VersionPartLib} from "../type/Version.sol";
library AccessAdminLib { // ACCESS_ADMIN_LIB
string public constant TOKEN_HANDLER_SUFFIX = "Th";
string public constant ROLE_SUFFIX = "_Role";
uint64 public constant SERVICE_DOMAIN_ROLE_FACTOR = 100;
uint64 public constant COMPONENT_ROLE_FACTOR = 1000;
uint64 public constant COMPONENT_ROLE_MAX = 19000;
uint64 public constant CORE_ROLE_MIN = 100;
uint64 public constant SERVICE_ROLE_MIN = 1000; // + service domain * SERVICE_ROLE_FACTOR + release
uint64 public constant SERVICE_ROLE_FACTOR = 1000;
uint64 public constant INSTANCE_ROLE_MIN = 100000;
// MUST match with Authorization.COMPONENT_ROLE_MIN
uint64 public constant COMPONENT_ROLE_MIN = 110000;
uint64 public constant CUSTOM_ROLE_MIN = 1000000;
function ADMIN_ROLE_NAME() public pure returns (string memory) {
return "AdminRole";
}
function isAdminRoleName(string memory name) public pure returns (bool) {
return StrLib.eq(name, ADMIN_ROLE_NAME());
}
function PUBLIC_ROLE_NAME() public pure returns (string memory) {
return "PublicRole";
}
function getAdminRole() public pure returns (RoleId adminRoleId) {
// see oz AccessManagerUpgradeable
return RoleId.wrap(type(uint64).min);
}
function getPublicRole() public pure returns (RoleId publicRoleId) {
// see oz AccessManagerUpgradeable
return RoleId.wrap(type(uint64).max);
}
function isAdminOrPublicRole(string memory name)
public
view
returns (bool)
{
return StrLib.eq(name, ADMIN_ROLE_NAME())
|| StrLib.eq(name, PUBLIC_ROLE_NAME());
}
function isDynamicRoleId(RoleId roleId)
public
pure
returns (bool)
{
return roleId.toInt() >= COMPONENT_ROLE_MIN;
}
function adminRoleInfo()
public
view
returns (IAccess.RoleInfo memory)
{
return roleInfo(
getAdminRole(),
IAccess.TargetType.Core,
1,
ADMIN_ROLE_NAME());
}
function publicRoleInfo()
public
view
returns (IAccess.RoleInfo memory)
{
return roleInfo(
getAdminRole(),
IAccess.TargetType.Custom,
type(uint32).max,
PUBLIC_ROLE_NAME());
}
function coreRoleInfo(string memory name)
public
view
returns (IAccess.RoleInfo memory)
{
return roleInfo(
getAdminRole(),
IAccess.TargetType.Core,
1,
name);
}
function serviceRoleInfo(string memory serviceName)
public
view
returns (IAccess.RoleInfo memory)
{
return roleInfo(
getAdminRole(),
IAccess.TargetType.Service,
1,
serviceName);
}
/// @dev Creates a role info object from the provided parameters
function roleInfo(
RoleId adminRoleId,
IAccess.TargetType targetType,
uint32 maxMemberCount,
string memory roleName
)
public
view
returns (IAccess.RoleInfo memory info)
{
return IAccess.RoleInfo({
name: StrLib.toStr(roleName),
adminRoleId: adminRoleId,
targetType: targetType,
maxMemberCount: maxMemberCount,
createdAt: TimestampLib.current(),
pausedAt: TimestampLib.max(),
lastUpdateIn: BlocknumberLib.current()});
}
function getSelectors(
IAccess.FunctionInfo[] memory functions
)
public
pure
returns (
bytes4[] memory selectors
)
{
uint256 n = functions.length;
selectors = new bytes4[](n);
for (uint256 i = 0; i < n; i++) {
selectors[i] = functions[i].selector.toBytes4();
}
}
function checkInitParameters(
address authority,
string memory adminName
)
public
view
{
// only contract check (authority might not yet be initialized at this time)
if (!ContractLib.isContract(authority)) {
revert IAccessAdmin.ErrorAccessAdminAuthorityNotContract(authority);
}
// check name not empty
if (bytes(adminName).length == 0) {
revert IAccessAdmin.ErrorAccessAdminAccessManagerEmptyName();
}
}
function checkRoleCreation(
IAccessAdmin accessAdmin,
RoleId roleId,
IAccess.RoleInfo memory info,
bool revertOnExistingRole
)
public
view
returns (bool isAdminOrPublicRole)
{
// check
if (roleId == ADMIN_ROLE() || roleId == PUBLIC_ROLE()) {
return true;
}
// check role does not yet exist
if(revertOnExistingRole && accessAdmin.roleExists(roleId)) {
revert IAccessAdmin.ErrorAccessAdminRoleAlreadyCreated(
roleId,
accessAdmin.getRoleInfo(roleId).name.toString());
}
// check admin role exists
if(!accessAdmin.roleExists(info.adminRoleId)) {
revert IAccessAdmin.ErrorAccessAdminRoleAdminNotExisting(info.adminRoleId);
}
// check role name is not empty
if(info.name.length() == 0) {
revert IAccessAdmin.ErrorAccessAdminRoleNameEmpty(roleId);
}
// check role name is not used for another role
(RoleId roleIdForName, bool exists) = accessAdmin.getRoleForName(StrLib.toString(info.name));
if(revertOnExistingRole && exists) {
revert IAccessAdmin.ErrorAccessAdminRoleNameAlreadyExists(
roleId,
info.name.toString(),
roleIdForName);
}
return false;
}
function checkRoleExists(
IAccessAdmin accessAdmin,
RoleId roleId,
bool onlyActiveRole,
bool allowAdminAndPublicRoles
)
internal
view
{
// check role exists
if (!accessAdmin.roleExists(roleId)) {
revert IAccessAdmin.ErrorAccessAdminRoleUnknown(roleId);
}
// if onlyActiveRoles: check if role is disabled
if (onlyActiveRole && accessAdmin.getRoleInfo(roleId).pausedAt <= TimestampLib.current()) {
revert IAccessAdmin.ErrorAccessAdminRoleIsPaused(roleId);
}
// if not allowAdminAndPublicRoles, check if role is admin or public role
if (!allowAdminAndPublicRoles) {
checkNotAdminOrPublicRole(roleId);
}
}
function checkNotAdminOrPublicRole(RoleId roleId) public pure {
if (roleId == ADMIN_ROLE()) {
revert IAccessAdmin.ErrorAccessAdminInvalidUseOfAdminRole();
}
if (roleId == PUBLIC_ROLE()) {
revert IAccessAdmin.ErrorAccessAdminInvalidUseOfPublicRole();
}
}
function checkTargetCreation(
IAccessAdmin accessAdmin,
address target,
string memory targetName,
bool checkAuthority
)
public
view
{
// check target does not yet exist
if(accessAdmin.targetExists(target)) {
revert IAccessAdmin.ErrorAccessAdminTargetAlreadyCreated(
target,
accessAdmin.getTargetInfo(target).name.toString());
}
// check target name is not empty
Str name = StrLib.toStr(targetName);
if(name.length() == 0) {
revert IAccessAdmin.ErrorAccessAdminTargetNameEmpty(target);
}
// check target name is not used for another target
address targetForName = accessAdmin.getTargetForName(name);
if(targetForName != address(0)) {
revert IAccessAdmin.ErrorAccessAdminTargetNameAlreadyExists(
target,
targetName,
targetForName);
}
// check target is an access managed contract
if (!ContractLib.isAccessManaged(target)) {
revert IAccessAdmin.ErrorAccessAdminTargetNotAccessManaged(target);
}
// check target shares authority with this contract
if (checkAuthority) {
address targetAuthority = AccessManagedUpgradeable(target).authority();
if (targetAuthority != accessAdmin.authority()) {
revert IAccessAdmin.ErrorAccessAdminTargetAuthorityMismatch(accessAdmin.authority(), targetAuthority);
}
}
}
function checkComponentInitialization(
IAccessAdmin accessAdmin,
IAuthorization instanceAuthorization,
address componentAddress,
ObjectType expectedType
)
public
view
returns (IAuthorization componentAuthorization)
{
checkIsRegistered(address(accessAdmin.getRegistry()), componentAddress, expectedType);
VersionPart expecteRelease = accessAdmin.getRelease();
IAuthorizedComponent component = IAuthorizedComponent(componentAddress);
componentAuthorization = component.getAuthorization();
checkAuthorization(
address(instanceAuthorization),
address(componentAuthorization),
expectedType,
expecteRelease,
false, // expectServiceAuthorization,
false); // checkAlreadyInitialized
}
function checkTargetAndRoleForFunctions(
IAccessAdmin accessAdmin,
address target,
RoleId roleId,
bool onlyComponentOrContractTargets
)
public
view
{
// check target exists
IAccess.TargetType targetType = accessAdmin.getTargetInfo(target).targetType;
if (targetType == IAccess.TargetType.Undefined) {
revert IAccessAdmin.ErrorAccessAdminTargetNotCreated(target);
}
// check target type
if (onlyComponentOrContractTargets) {
if (targetType != IAccess.TargetType.Component && targetType != IAccess.TargetType.Contract) {
revert IAccessAdmin.ErrorAccessAdminNotComponentOrCustomTarget(target);
}
}
// check role exist
checkRoleExists(accessAdmin, roleId, true, true);
}
function checkTargetExists(
IAccessAdmin accessAdmin,
address target
)
public
view
{
// check not yet created
if (!accessAdmin.targetExists(target)) {
revert IAccessAdmin.ErrorAccessAdminTargetNotCreated(target);
}
}
function checkAuthorization(
address authorizationOld,
address authorization,
ObjectType expectedDomain,
VersionPart expectedRelease,
bool expectServiceAuthorization,
bool checkAlreadyInitialized
)
public
view
{
// checks
// check not yet initialized
if (checkAlreadyInitialized && authorizationOld != address(0)) {
revert IAccessAdmin.ErrorAccessAdminAlreadyInitialized(authorizationOld);
}
// check contract type matches
if (expectServiceAuthorization) {
if (!ContractLib.supportsInterface(authorization, type(IServiceAuthorization).interfaceId)) {
revert IAccessAdmin.ErrorAccessAdminNotServiceAuthorization(authorization);
}
} else {
if (!ContractLib.supportsInterface(authorization, type(IAuthorization).interfaceId)) {
revert IAccessAdmin.ErrorAccessAdminNotAuthorization(authorization);
}
}
// check domain matches
ObjectType domain = IAuthorization(authorization).getDomain();
if (domain != expectedDomain) {
revert IAccessAdmin.ErrorAccessAdminDomainMismatch(authorization, expectedDomain, domain);
}
// check release matches
VersionPart authorizationRelease = IAuthorization(authorization).getRelease();
if (authorizationRelease != expectedRelease) {
revert IAccessAdmin.ErrorAccessAdminReleaseMismatch(authorization, expectedRelease, authorizationRelease);
}
}
function checkIsRegistered(
address registry,
address target,
ObjectType expectedType
)
public
view
{
checkRegistry(registry);
ObjectType tagetType = IRegistry(registry).getObjectInfo(target).objectType;
if (tagetType.eqz()) {
revert IAccessAdmin.ErrorAccessAdminNotRegistered(target);
}
if (tagetType != expectedType) {
revert IAccessAdmin.ErrorAccessAdminTargetTypeMismatch(target, expectedType, tagetType);
}
}
function checkRegistry(
address registry
)
public
view
{
if (!ContractLib.isRegistry(registry)) {
revert IAccessAdmin.ErrorAccessAdminNotRegistry(registry);
}
}
function getAuthorizedRole(
IAccessAdmin accessAdmin,
IAuthorization authorization,
RoleId roleId
)
public
view
returns (RoleId authorizedRoleId)
{
string memory roleName = authorization.getRoleInfo(roleId).name.toString();
(authorizedRoleId, ) = accessAdmin.getRoleForName(roleName);
}
function getFunctionRoleId(
AccessManagerCloneable authority,
address target,
Selector selector
)
public
view
returns (RoleId functionRoleId)
{
return RoleIdLib.toRoleId(
authority.getTargetFunctionRole(
target,
selector.toBytes4()));
}
function getServiceRoleId(
address serviceAddress,
IAccess.TargetType serviceTargetType
)
public
view
returns (RoleId serviceRoleId)
{
IService service = IService(serviceAddress);
if (serviceTargetType == IAccess.TargetType.Service) {
return RoleIdLib.toServiceRoleId(service.getDomain(), service.getRelease());
} else if (serviceTargetType == IAccess.TargetType.GenericService) {
return RoleIdLib.toGenericServiceRoleId(service.getDomain());
}
revert IAccessAdmin.ErrorAccessAdminInvalidServiceType(serviceAddress, serviceTargetType);
}
function getVersionedServiceRoleId(
ObjectType serviceDomain,
VersionPart release
)
public
pure
returns (RoleId serviceRoleId)
{
return RoleIdLib.toRoleId(
SERVICE_ROLE_MIN + SERVICE_ROLE_FACTOR * serviceDomain.toInt() + release.toInt());
}
function getGenericServiceRoleId(
ObjectType serviceDomain
)
public
pure
returns (RoleId serviceRoleId)
{
return RoleIdLib.toRoleId(
SERVICE_ROLE_MIN + SERVICE_ROLE_FACTOR * serviceDomain.toInt() + VersionPartLib.releaseMax().toInt());
}
function getCustomRoleId(uint64 index)
public
pure
returns (RoleId customRoleId)
{
return RoleIdLib.toRoleId(CUSTOM_ROLE_MIN + index);
}
function isCustomRole(RoleId roleId)
public
pure
returns (bool)
{
return roleId.toInt() >= CUSTOM_ROLE_MIN;
}
function getTargetRoleId(
address target,
IAccess.TargetType targetType,
uint64 index
)
public
view
returns (RoleId targetRoleId)
{
if (targetType == IAccess.TargetType.Core) {
return RoleIdLib.toRoleId(CORE_ROLE_MIN + index);
}
if (targetType == IAccess.TargetType.Service || targetType == IAccess.TargetType.GenericService ) {
return getServiceRoleId(target, targetType);
}
if (targetType == IAccess.TargetType.Instance) {
return RoleIdLib.toRoleId(INSTANCE_ROLE_MIN + index);
}
if (targetType == IAccess.TargetType.Component) {
return RoleIdLib.toRoleId(COMPONENT_ROLE_MIN + index);
}
if (targetType == IAccess.TargetType.Custom
|| targetType == IAccess.TargetType.Contract)
{
return RoleIdLib.toRoleId(CUSTOM_ROLE_MIN + index);
}
revert IAccessAdmin.ErrorAccessAdminInvalidTargetType(target, targetType);
}
function getTokenHandler(
address target,
string memory targetName,
IAccess.TargetType targetType
)
public
view
returns (
address tokenHandler,
string memory tokenHandlerName
)
{
// not component or core (we need to check core because of staking)
if (targetType != IAccess.TargetType.Component && targetType != IAccess.TargetType.Core) {
return (address(0), "");
}
// not contract
if (!ContractLib.isContract(target)) {
return (address(0), "");
}
// not component
if (!ContractLib.supportsInterface(target, type(IComponent).interfaceId)) {
return (address(0), "");
}
tokenHandler = address(IComponent(target).getTokenHandler());
tokenHandlerName = string(abi.encodePacked(targetName, TOKEN_HANDLER_SUFFIX));
}
function toFunctionGrantingString(
IAccessAdmin accessAdmin,
Str functionName,
RoleId roleId
)
public
view
returns (string memory)
{
return string(
abi.encodePacked(
functionName.toString(),
"(): ",
getRoleName(accessAdmin, roleId)));
}
function getRoleName(
IAccessAdmin accessAdmin,
RoleId roleId
)
public
view
returns (string memory)
{
if (accessAdmin.roleExists(roleId)) {
return accessAdmin.getRoleInfo(roleId).name.toString();
}
return "<unknown-role>";
}
function toRoleName(string memory name) public pure returns (string memory) {
return string(
abi.encodePacked(
name,
ROLE_SUFFIX));
}
function toFunction(
bytes4 selector,
string memory name
)
public
view
returns (IAccess.FunctionInfo memory)
{
if(selector == bytes4(0)) {
revert IAccessAdmin.ErrorAccessAdminSelectorZero();
}
if(bytes(name).length == 0) {
revert IAccessAdmin.ErrorAccessAdminFunctionNameEmpty();
}
return IAccess.FunctionInfo({
name: StrLib.toStr(name),
selector: SelectorLib.toSelector(selector),
createdAt: TimestampLib.current(),
lastUpdateIn: BlocknumberLib.current()});
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {AccessManagerUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagerUpgradeable.sol";
import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import {InitializableERC165} from "../shared/InitializableERC165.sol";
import {RegistryLinked} from "../shared/RegistryLinked.sol";
import {VersionPart} from "../type/Version.sol";
/// @dev An AccessManager based on OpenZeppelin that is cloneable and has a central lock property.
/// The lock property allows to lock all services of a release in a central place.
/// Cloned by upon release preparation and instance cloning.
contract AccessManagerCloneable is
AccessManagerUpgradeable,
InitializableERC165,
RegistryLinked
{
error ErrorAccessManagerCallerNotAdmin(address caller);
error ErrorAccessManagerRegistryAlreadySet(address registry);
error ErrorAccessManagerInvalidRelease(VersionPart release);
error ErrorAccessManagerTargetAdminLocked(address target);
error ErrorAccessManagerCallerAdminLocked(address caller);
VersionPart private _release;
bool private _isLocked;
modifier onlyAdminRole() {
(bool isMember, ) = hasRole(ADMIN_ROLE, msg.sender);
if(!isMember) {
revert ErrorAccessManagerCallerNotAdmin(msg.sender);
}
_;
}
function initialize(address admin)
public
initializer()
{
__ERC165_init();
__AccessManager_init(admin);
_registerInterface(type(IAccessManager).interfaceId);
}
/// @dev Completes the setup of the access manager.
/// Links the access manager to the registry and sets the release version.
function completeSetup(
address registry,
VersionPart release
)
external
onlyAdminRole
reinitializer(uint64(release.toInt()))
{
_checkAndSetRegistry(registry);
_checkAndSetRelease(release);
}
/// @dev Returns true if the caller is authorized to call the target with the given selector and the manager lock is not set to locked.
/// Feturn values as in OpenZeppelin AccessManager.
/// For a locked manager the function reverts with ErrorAccessManagerTargetAdminLocked.
function canCall(
address caller,
address target,
bytes4 selector
)
public
view
virtual override
returns (
bool immediate,
uint32 delay
)
{
// locking of all contracts under control of this access manager
if (_isLocked) {
revert ErrorAccessManagerTargetAdminLocked(target);
}
(immediate, delay) = super.canCall(caller, target, selector);
}
/// @dev Locks/unlocks all services of this access manager.
/// Only the corresponding access admin can lock/unlock the services.
function setLocked(bool locked)
external
onlyAdminRole()
{
_isLocked = locked;
}
/// @dev Returns the release version of this access manager.
/// For the registry admin release 3 is returned.
/// For the release admin and the instance admin the actual release version is returned.
function getRelease() external view returns (VersionPart release) {
return _release;
}
/// @dev Returns true iff all contracts of this access manager are locked.
function isLocked()
public
view
returns (bool)
{
return _isLocked;
}
function _checkAndSetRelease(VersionPart release)
internal
{
if (!release.isValidRelease()) {
revert ErrorAccessManagerInvalidRelease(release);
}
_release = release;
}
function _checkAndSetRegistry(address registry)
internal
{
// checks
if(address(getRegistry()) != address(0)) {
revert ErrorAccessManagerRegistryAlreadySet(address(getRegistry()) );
}
// effects
__RegistryLinked_init(registry);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {Blocknumber} from "../type/Blocknumber.sol";
import {RoleId} from "../type/RoleId.sol";
import {Selector} from "../type/Selector.sol";
import {Str} from "../type/String.sol";
import {Timestamp} from "../type/Timestamp.sol";
interface IAccess {
enum TargetType {
Undefined, // no target must have this type
Core, // GIF core contracts
GenericService, // release independent service contracts
Service, // service contracts
Instance, // instance contracts
Component, // instance contracts
Contract, // normal contracts
Custom // use case specific rules for contracts or normal accounts
}
struct RoleInfo {
// slot 0
RoleId adminRoleId; // 64
TargetType targetType; // ?
uint32 maxMemberCount; // 32
Timestamp createdAt; // 40
Timestamp pausedAt; // 40
Blocknumber lastUpdateIn; // 40
// slot 1
Str name; // 256
}
// TODO recalc slot allocation
struct TargetInfo {
Str name;
TargetType targetType;
RoleId roleId;
Timestamp createdAt;
Blocknumber lastUpdateIn;
}
struct FunctionInfo {
// slot 0
Str name; // function name
// slot 1
Selector selector; // function selector
Timestamp createdAt;
Blocknumber lastUpdateIn;
}
struct RoleNameInfo {
// slot 0
RoleId roleId;
bool exists;
}
struct TargeNameInfo {
// slot 0
address target;
bool exists;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {IAccess} from "./IAccess.sol";
import {IAuthorization} from "./IAuthorization.sol";
import {IRegistryLinked} from "../shared/IRegistryLinked.sol";
import {IRelease} from "../registry/IRelease.sol";
import {Blocknumber} from "../type/Blocknumber.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RoleId} from "../type/RoleId.sol";
import {Str} from "../type/String.sol";
import {VersionPart} from "../type/Version.sol";
/// @dev Base interface for registry admin, release admin, and instance admin
interface IAccessAdmin is
IAccessManaged,
IAccess,
IRegistryLinked,
IRelease
{
// roles, targets and functions
event LogAccessAdminRoleCreated(string admin, RoleId roleId, TargetType targetType, RoleId roleAdminId, string name);
event LogAccessAdminTargetCreated(string admin, string name, bool managed, address target, RoleId roleId);
event LogAccessAdminRoleActivatedSet(string admin, RoleId roleId, bool active, Blocknumber lastUpdateIn);
event LogAccessAdminRoleGranted(string admin, address account, string roleName);
event LogAccessAdminRoleRevoked(string admin, address account, string roleName);
event LogAccessAdminTargetLockedSet(string admin, address target, bool locked, Blocknumber lastUpdateIn);
event LogAccessAdminFunctionGranted(string admin, address target, string func, Blocknumber lastUpdateIn);
// only deployer modifier
error ErrorAccessAdminNotDeployer();
// only role admin modifier
error ErrorAccessAdminNotAdminOfRole(RoleId adminRoleId, address account);
// only role owner modifier
error ErrorAccessAdminNotRoleOwner(RoleId roleId, address account);
// role management
error ErrorAccessAdminInvalidUseOfAdminRole();
error ErrorAccessAdminInvalidUseOfPublicRole();
error ErrorAccessAdminRoleNotCustom(RoleId roleId);
// initialization
error ErrorAccessAdminNotRegistry(address registry);
error ErrorAccessAdminAuthorityNotContract(address authority);
error ErrorAccessAdminAccessManagerNotAccessManager(address authority);
error ErrorAccessAdminAccessManagerEmptyName();
// check target
error ErrorAccessAdminInvalidTargetType(address target, TargetType targetType);
error ErrorAccessAdminInvalidServiceType(address target, TargetType serviceTargetType);
error ErrorAccessAdminTargetNotCreated(address target);
error ErrorAccessAdminTargetNotRegistered(address target);
error ErrorAccessAdminTargetTypeMismatch(address target, ObjectType expectedType, ObjectType actualType);
// check authorization
error ErrorAccessAdminAlreadyInitialized(address authorization);
error ErrorAccessAdminNotAuthorization(address authorization);
error ErrorAccessAdminNotServiceAuthorization(address serviceAuthorization);
error ErrorAccessAdminDomainMismatch(address authorization, ObjectType expectedDomain, ObjectType actualDomain);
error ErrorAccessAdminReleaseMismatch(address authorization, VersionPart expectedRelease, VersionPart actualRelease);
// link to nft
error ErrorAccessAdminNotRegistered(address registerable);
// initialize authority
error ErrorAccessAdminAdminRoleMissing();
// create role
error ErrorAccessAdminRoleAlreadyCreated(RoleId roleId, string name);
error ErrorAccessAdminRoleAdminNotExisting(RoleId adminRoleId);
error ErrorAccessAdminRoleNameEmpty(RoleId roleId);
error ErrorAccessAdminRoleNameAlreadyExists(RoleId roleId, string name, RoleId existingRoleId);
// grant/revoke/renounce role
error ErrorAccessAdminRoleUnknown(RoleId roleId);
error ErrorAccessAdminRoleIsLocked(RoleId roleId);
error ErrorAccessAdminRoleIsPaused(RoleId roleId);
error ErrorAccessAdminRoleMembersLimitReached(RoleId roleId, uint256 memberCountLimit);
error ErrorAccessAdminRoleMemberNotContract(RoleId roleId, address notContract);
error ErrorAccessAdminRoleMemberRemovalDisabled(RoleId roleId, address expectedMember);
// create target
error ErrorAccessAdminTargetAlreadyCreated(address target, string name);
error ErrorAccessAdminTargetNameEmpty(address target);
error ErrorAccessAdminTargetNameAlreadyExists(address target, string name, address existingTarget);
error ErrorAccessAdminTargetNotAccessManaged(address target);
error ErrorAccessAdminTargetAuthorityMismatch(address expectedAuthority, address actualAuthority);
// lock target
error ErrorAccessAdminTagetNotLockable();
error ErrorAccessAdminTargetAlreadyLocked(address target, bool isLocked);
// authorize target functions
error ErrorAccessAdminNotComponentOrCustomTarget(address target);
error ErrorAccessAdminAuthorizeForAdminRoleInvalid(address target);
// toFunction
error ErrorAccessAdminSelectorZero();
error ErrorAccessAdminFunctionNameEmpty();
// check target
error ErrorAccessAdminTargetUnknown(address target);
//--- view functions ----------------------------------------------------//
function getAuthorization() external view returns (IAuthorization authorization);
function getLinkedNftId() external view returns (NftId linkedNftId);
function isLocked() external view returns (bool locked);
function roles() external view returns (uint256 numberOfRoles);
function getRoleId(uint256 idx) external view returns (RoleId roleId);
function roleExists(RoleId roleId) external view returns (bool exists);
function getRoleForName(string memory name) external view returns (RoleId roleId, bool exists);
function getRoleInfo(RoleId roleId) external view returns (RoleInfo memory roleInfo);
function isRoleActive(RoleId roleId) external view returns (bool isActive);
function isRoleCustom(RoleId roleId) external view returns (bool isCustom);
function isRoleMember(RoleId roleId, address account) external view returns (bool);
function isRoleAdmin(RoleId roleId, address account) external view returns (bool);
function roleMembers(RoleId roleId) external view returns (uint256 numberOfMembers);
function getRoleMember(RoleId roleId, uint256 idx) external view returns (address account);
function targetExists(address target) external view returns (bool exists);
function getTargetForName(Str name) external view returns (address target);
function targets() external view returns (uint256 numberOfTargets);
function getTargetAddress(uint256 idx) external view returns (address target);
function getTargetInfo(address target) external view returns (TargetInfo memory targetInfo);
function isTargetLocked(address target) external view returns (bool locked);
function authorizedFunctions(address target) external view returns (uint256 numberOfFunctions);
function getAuthorizedFunction(address target, uint256 idx) external view returns (FunctionInfo memory func, RoleId roleId);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IServiceAuthorization} from "./IServiceAuthorization.sol";
import {Str} from "../type/String.sol";
interface IAuthorization is
IServiceAuthorization
{
/// @dev Returns the token hander name.
/// Only components have a token handler.
function getTokenHandlerName() external view returns(string memory name);
/// @dev Returns the token hander target.
/// Only components have a token handler.
function getTokenHandlerTarget() external view returns(Str target);
/// @dev Returns the complete list of targets.
function getTargets() external view returns(Str[] memory targets);
/// @dev Returns true iff the specified target exists.
function targetExists(Str target) external view returns(bool exists);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IAccess} from "../authorization/IAccess.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RoleId} from "../type/RoleId.sol";
import {Str} from "../type/String.sol";
import {VersionPart} from "../type/Version.sol";
interface IServiceAuthorization is
IERC165,
IAccess
{
error ErrorAuthorizationMainTargetNameEmpty();
error ErrorAuthorizationTargetDomainZero();
error ErrorAuthorizationReleaseInvalid(uint8 release);
error ErrorAuthorizationCommitHashInvalid(string commitHash);
/// @dev Returns the main domain of the authorization.
function getDomain() external view returns(ObjectType targetDomain);
/// @dev Returns the release (VersionPart) for which the authorizations are defined by this contract.
/// Matches with the release returned by the linked service authorization.
function getRelease() external view returns(VersionPart release);
/// @dev Returns the commit hash for the related GIF release.
function getCommitHash() external view returns(string memory commitHash);
/// @dev Returns the main target id name as string.
/// This name is used to derive the target id and a corresponding target role name
/// Overwrite this function to change the basic pool target name.
function getMainTargetName() external view returns (string memory name);
/// @dev Returns the main target.
function getMainTarget() external view returns(Str target);
/// @dev Returns the full list of service domains for this release.
/// Services need to be registered for the release in revers order of this list.
function getServiceDomains() external view returns(ObjectType[] memory serviceDomains);
/// @dev Returns the service domain for the provided index.
function getServiceDomain(uint256 idx) external view returns(ObjectType serviceDomain);
/// @dev Returns the service target for the specified domain.
function getServiceTarget(ObjectType serviceDomain) external view returns(Str serviceTarget);
/// @dev Returns the service target for the specified domain.
function getServiceRole(ObjectType serviceDomain) external view returns(RoleId serviceRoleId);
/// @dev Returns the expected service address for the provided domain.
function getServiceAddress(ObjectType serviceDomain) external view returns(address service);
/// @dev Returns the role id associated with the target.
/// If no role is associated with the target the zero role id is returned.
function getTargetRole(Str target) external view returns(RoleId roleId);
/// @dev Returns true iff the role exists.
function roleExists(RoleId roleId) external view returns(bool exists);
/// @dev Returns the list of involved roles.
function getRoles() external view returns(RoleId[] memory roles);
/// @dev Returns the role info for the provided role id.
function getRoleInfo(RoleId roleId) external view returns (RoleInfo memory roleInfo);
/// @dev Returns the name for the provided role id.
function getRoleName(RoleId roleId) external view returns (string memory roleName);
/// @dev For the given target the list of authorized role ids is returned
function getAuthorizedRoles(Str target) external view returns(RoleId[] memory roleIds);
/// @dev For the given target and role id the list of authorized functions is returned
function getAuthorizedFunctions(Str target, RoleId roleId) external view returns(FunctionInfo[] memory authorizatedFunctions);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IPolicy} from "../instance/module/IPolicy.sol";
import {IService} from "../shared/IService.sol";
import {Amount} from "../type/Amount.sol";
import {DistributorType} from "../type/DistributorType.sol";
import {InstanceReader} from "../instance/InstanceReader.sol";
import {NftId} from "../type/NftId.sol";
import {ReferralId, ReferralStatus} from "../type/Referral.sol";
import {Seconds} from "../type/Seconds.sol";
import {Timestamp} from "../type/Timestamp.sol";
import {UFixed} from "../type/UFixed.sol";
interface IDistributionService is IService {
error ErrorDistributionServiceCallerNotRegistered(address caller);
error ErrorDistributionServiceParentNftIdNotInstance(NftId nftId, NftId parentNftId);
error ErrorDistributionServiceCallerNotDistributor(address caller);
error ErrorDistributionServiceInvalidReferralId(ReferralId referralId);
error ErrorDistributionServiceMaxReferralsExceeded(uint256 limit, uint256 maxReferrals);
error ErrorDistributionServiceDiscountTooLow(UFixed minDiscountPercentage, UFixed discountPercentage);
error ErrorDistributionServiceDiscountTooHigh(UFixed maxDiscountPercentage, UFixed discountPercentage);
error ErrorDistributionServiceExpiryTooLong(Seconds maxReferralLifetime, Timestamp expiryAt);
error ErrorDistributionServiceInvalidReferral();
error ErrorDistributionServiceExpirationInvalid(Timestamp expiryAt);
error ErrorDistributionServiceCommissionTooHigh(uint256 commissionPercentage, uint256 maxCommissionPercentage);
error ErrorDistributionServiceMinFeeTooHigh(uint256 minFee, uint256 limit);
error ErrorDistributionServiceDistributorTypeDistributionMismatch(DistributorType distributorType, NftId distributorTypeDistributionNftId, NftId distributionNftId);
error ErrorDistributionServiceDistributorDistributionMismatch(NftId distributorNftId, NftId distributorDistributionNftId, NftId distributionNftId);
error ErrorDistributionServiceCommissionWithdrawAmountExceedsLimit(Amount amount, Amount limit);
error ErrorDistributionServiceVariableFeesTooHight(uint256 maxDiscountPercentage, uint256 limit);
error ErrorDistributionServiceMaxDiscountTooHigh(uint256 maxDiscountPercentage, uint256 limit);
error ErrorDistributionServiceReferralInvalid(NftId distributionNftId, ReferralId referralId);
error ErrorDistributionServiceInvalidFeeTransferred(Amount transferredDistributionFeeAmount, Amount expectedDistributionFeeAmount);
error ErrorDistributionServiceReferralDistributionMismatch(ReferralId referralId, NftId referralDistributionNft, NftId distributionNftId);
event LogDistributionServiceCommissionWithdrawn(NftId distributorNftId, address recipient, address tokenAddress, Amount amount);
event LogDistributionServiceDistributorTypeCreated(NftId distributionNftId, string name);
event LogDistributionServiceDistributorCreated(NftId distributionNftId, NftId distributorNftId, DistributorType distributorType, address distributor);
event LogDistributionServiceDistributorTypeChanged(NftId distributorNftId, DistributorType oldDistributorType, DistributorType newDistributorType);
event LogDistributionServiceReferralCreated(NftId distributionNftId, NftId distributorNftId, ReferralId referralId, string code);
event LogDistributionServiceReferralProcessed(NftId distributionNftId, NftId distributorNftId, ReferralId referralId, uint32 usedReferrals);
event LogDistributionServiceSaleProcessed(NftId distributionNftId, ReferralId referralId);
function createDistributorType(
string memory name,
UFixed minDiscountPercentage,
UFixed maxDiscountPercentage,
UFixed commissionPercentage,
uint32 maxReferralCount,
Seconds maxReferralLifetime,
bool allowSelfReferrals,
bool allowRenewals,
bytes memory data
)
external
returns (DistributorType distributorType);
function createDistributor(
address distributor,
DistributorType distributorType,
bytes memory data
) external returns (NftId distributorNftId);
function changeDistributorType(
NftId distributorNftId,
DistributorType newDistributorType,
bytes memory data
) external;
function createReferral(
NftId distributorNftId,
string memory code,
UFixed discountPercentage,
uint32 maxReferrals,
Timestamp expiryAt,
bytes memory data
)
external
returns (ReferralId referralId);
/// @dev callback from product service when a referral is used.
/// Calling this will increment the referral usage counter.
function processReferral(
NftId distributionNftId,
ReferralId referralId
) external;
/// @dev callback from product service when selling a policy for a specific referralId
function processSale(
NftId distributionNftId,
ReferralId referralId,
IPolicy.PremiumInfo memory premium
) external;
function referralIsValid(
NftId distributorNftId,
ReferralId referralId
) external view returns (bool isValid);
/// @dev Withdraw commission for the distributor
/// @param distributorNftId the distributor Nft Id
/// @param amount the amount to withdraw. If set to AMOUNT_MAX, the full commission available is withdrawn
/// @return withdrawnAmount the effective withdrawn amount
function withdrawCommission(NftId distributorNftId, Amount amount) external returns (Amount withdrawnAmount);
/// @dev Returns the discount percentage for the provided referral code.
/// The function retuns both the percentage and the status of the referral code.
function getDiscountPercentage(InstanceReader instanceReader, ReferralId referralId) external view returns (UFixed discountPercentage, ReferralStatus status);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IPolicy} from "../../instance/module/IPolicy.sol";
import {IPolicyService} from "../../product/IPolicyService.sol";
import {Amount, AmountLib} from "../../type/Amount.sol";
import {FlightMessageVerifier} from "./FlightMessageVerifier.sol";
import {FlightProduct} from "./FlightProduct.sol";
import {InstanceReader} from "../../instance/InstanceReader.sol";
import {NftId} from "../../type/NftId.sol";
import {RequestId} from "../../type/RequestId.sol";
import {RiskId, RiskIdLib} from "../../type/RiskId.sol";
import {Seconds} from "../../type/Seconds.sol";
import {StateId} from "../../type/StateId.sol";
import {Str} from "../../type/String.sol";
import {Timestamp, TimestampLib} from "../../type/Timestamp.sol";
library FlightLib {
event LogFlightProductErrorUnprocessableStatus(RequestId requestId, RiskId riskId, bytes1 status);
event LogFlightProductErrorUnexpectedStatus(RequestId requestId, RiskId riskId, bytes1 status, int256 delayMinutes);
error ErrorFlightProductRiskInvalid(RiskId riskId);
error ErrorFlightProductPremiumAmountTooSmall(Amount premiumAmount, Amount minPremium);
error ErrorFlightProductPremiumAmountTooLarge(Amount premiumAmount, Amount maxPremium);
error ErrorFlightProductArrivalBeforeDepartureTime(Timestamp departureTime, Timestamp arrivalTime);
error ErrorFlightProductArrivalAfterMaxFlightDuration(Timestamp arrivalTime, Timestamp maxArrivalTime, Seconds maxDuration);
error ErrorFlightProductDepartureBeforeMinTimeBeforeDeparture(Timestamp departureTime, Timestamp now, Seconds minTimeBeforeDeparture);
error ErrorFlightProductDepartureAfterMaxTimeBeforeDeparture(Timestamp departureTime, Timestamp now, Seconds maxTimeBeforeDeparture);
error ErrorFlightProductNotEnoughObservations(uint256 observations, uint256 minObservations);
error ErrorFlightProductClusterRisk(Amount totalSumInsured, Amount maxTotalPayout);
function checkApplicationData(
FlightProduct flightProduct,
Str flightData,
Timestamp departureTime,
Timestamp arrivalTime,
Amount premiumAmount
)
public
view
{
_checkApplicationData(flightProduct, premiumAmount, arrivalTime, departureTime);
}
function _checkApplicationData(
FlightProduct flightProduct,
Amount premiumAmount,
Timestamp arrivalTime,
Timestamp departureTime
)
internal
view
{
bool testMode = flightProduct.isTestMode();
// solhint-disable
if (premiumAmount < flightProduct.MIN_PREMIUM()) {
revert ErrorFlightProductPremiumAmountTooSmall(premiumAmount, flightProduct.MIN_PREMIUM());
}
if (premiumAmount > flightProduct.MAX_PREMIUM()) {
revert ErrorFlightProductPremiumAmountTooLarge(premiumAmount, flightProduct.MAX_PREMIUM());
}
if (arrivalTime <= departureTime) {
revert ErrorFlightProductArrivalBeforeDepartureTime(departureTime, arrivalTime);
}
if (arrivalTime > departureTime.addSeconds(flightProduct.MAX_FLIGHT_DURATION())) {
revert ErrorFlightProductArrivalAfterMaxFlightDuration(arrivalTime, departureTime, flightProduct.MAX_FLIGHT_DURATION());
}
// test mode allows the creation for policies that are outside restricted policy creation times
if (!testMode && departureTime < TimestampLib.current().addSeconds(flightProduct.MIN_TIME_BEFORE_DEPARTURE())) {
revert ErrorFlightProductDepartureBeforeMinTimeBeforeDeparture(departureTime, TimestampLib.current(), flightProduct.MIN_TIME_BEFORE_DEPARTURE());
}
if (!testMode && departureTime > TimestampLib.current().addSeconds(flightProduct.MAX_TIME_BEFORE_DEPARTURE())) {
revert ErrorFlightProductDepartureAfterMaxTimeBeforeDeparture(departureTime, TimestampLib.current(), flightProduct.MAX_TIME_BEFORE_DEPARTURE());
}
// solhint-enable
}
function checkClusterRisk(
Amount sumOfSumInsuredAmounts,
Amount sumInsuredAmount,
Amount maxTotalPayout
)
public
pure
{
if (sumOfSumInsuredAmounts + sumInsuredAmount > maxTotalPayout) {
revert ErrorFlightProductClusterRisk(sumOfSumInsuredAmounts + sumInsuredAmount, maxTotalPayout);
}
}
/// @dev calculates payout option based on flight status and delay minutes.
/// Is not a view function as it emits log evens in case of unexpected status.
function checkAndGetPayoutOption(
RequestId requestId,
RiskId riskId,
bytes1 status,
int256 delayMinutes
)
public
returns (uint8 payoutOption)
{
// default: no payout
payoutOption = type(uint8).max;
// check status
if (status != "L" && status != "A" && status != "C" && status != "D") {
emit LogFlightProductErrorUnprocessableStatus(requestId, riskId, status);
return payoutOption;
}
if (status == "A") {
// todo: active, reschedule oracle call + 45 min
emit LogFlightProductErrorUnexpectedStatus(requestId, riskId, status, delayMinutes);
return payoutOption;
}
// trigger payout if applicable
if (status == "C") { payoutOption = 3; }
else if (status == "D") { payoutOption = 4; }
else if (delayMinutes >= 15 && delayMinutes < 30) { payoutOption = 0; }
else if (delayMinutes >= 30 && delayMinutes < 45) { payoutOption = 1; }
else if (delayMinutes >= 45) { payoutOption = 2; }
}
function calculateWeight(
FlightProduct flightProduct,
uint256[6] memory statistics
)
public
view
returns (uint256 weight)
{
// check we have enough observations
if (statistics[0] < flightProduct.MIN_OBSERVATIONS()) {
revert ErrorFlightProductNotEnoughObservations(statistics[0], flightProduct.MIN_OBSERVATIONS());
}
weight = 0;
for (uint256 i = 1; i < 6; i++) {
weight += flightProduct.WEIGHT_PATTERN(i) * statistics[i] * 10000 / statistics[0];
}
// To avoid div0 in the payout section, we have to make a minimal assumption on weight
if (weight == 0) {
weight = 100000 / statistics[0];
}
// TODO comment on intended effect
weight = (weight * (100 + flightProduct.MARGIN_PERCENT())) / 100;
}
// REMARK: each flight may get different payouts depending on the latest statics
function calculatePayoutAmounts(
FlightProduct flightProduct,
Amount premium,
uint256[6] memory statistics
)
public
view
returns (
uint256 weight,
Amount[5] memory payoutAmounts,
Amount sumInsuredAmount // simply the max of payoutAmounts
)
{
if (premium < flightProduct.MIN_PREMIUM()) {
revert ErrorFlightProductPremiumAmountTooSmall(premium, flightProduct.MIN_PREMIUM());
}
if (premium > flightProduct.MAX_PREMIUM()) {
revert ErrorFlightProductPremiumAmountTooLarge(premium, flightProduct.MAX_PREMIUM());
}
sumInsuredAmount = AmountLib.zero();
weight = calculateWeight(flightProduct, statistics);
for (uint256 i = 0; i < 5; i++) {
Amount payoutAmount = AmountLib.toAmount(
premium.toInt() * flightProduct.WEIGHT_PATTERN(i + 1) * 10000 / weight);
// cap payout and update sum insured if applicable
if (payoutAmount > flightProduct.MAX_PAYOUT()) { payoutAmount = flightProduct.MAX_PAYOUT(); }
if (payoutAmount > sumInsuredAmount) { sumInsuredAmount = payoutAmount; }
payoutAmounts[i] = payoutAmount;
}
}
function getPayoutOption(
InstanceReader reader,
NftId productNftId,
RiskId riskId
)
public
view
returns (
bool exists,
bool statusAvailable,
uint8 payoutOption
)
{
FlightProduct.FlightRisk memory flightRisk;
(exists, flightRisk) = getFlightRisk(
reader,
productNftId,
riskId,
false);
statusAvailable = flightRisk.statusUpdatedAt.gtz();
payoutOption = flightRisk.payoutOption;
}
function getPayoutAmount(
bytes memory applicationData,
uint8 payoutOption
)
public
pure
returns (Amount payoutAmount)
{
if (payoutOption == type(uint8).max) {
return AmountLib.zero();
}
// retrieve payout amounts from application data
(, Amount[5] memory payoutAmounts) = abi.decode(
applicationData, (Amount, Amount[5]));
// get payout amount for selected option
payoutAmount = payoutAmounts[payoutOption];
}
function getFlightRisk(
InstanceReader reader,
NftId productNftId,
Str flightData,
Timestamp departureTime,
string memory departureTimeLocal,
Timestamp arrivalTime,
string memory arrivalTimeLocal
)
public
view
returns (
RiskId riskId,
bool exists,
FlightProduct.FlightRisk memory flightRisk
)
{
riskId = getRiskId(productNftId, flightData);
(exists, flightRisk) = getFlightRisk(reader, productNftId, riskId, false);
// create new risk if not existing
if (!exists) {
flightRisk = FlightProduct.FlightRisk({
flightData: flightData,
departureTime: departureTime,
departureTimeLocal: departureTimeLocal,
arrivalTime: arrivalTime,
arrivalTimeLocal: arrivalTimeLocal,
sumOfSumInsuredAmounts: AmountLib.toAmount(0),
status: bytes1(0),
delayMinutes: 0,
payoutOption: uint8(0),
statusUpdatedAt: TimestampLib.zero()});
}
}
function getFlightRisk(
InstanceReader reader,
NftId productNftId,
RiskId riskId,
bool requireRiskExists
)
public
view
returns (
bool exists,
FlightProduct.FlightRisk memory flightRisk
)
{
// check if risk exists
exists = reader.isProductRisk(productNftId, riskId);
if (!exists && requireRiskExists) {
revert ErrorFlightProductRiskInvalid(riskId);
}
// get risk data if risk exists
if (exists) {
flightRisk = abi.decode(
reader.getRiskInfo(riskId).data, (FlightProduct.FlightRisk));
}
}
function getRiskId(
NftId productNftId,
Str flightData
)
public
view
returns (RiskId riskId)
{
bytes32 riskKey = getRiskKey(flightData);
riskId = getRiskId(productNftId, riskKey);
}
function getRiskKey(
Str flightData
)
internal
pure
returns (bytes32 riskKey)
{
return keccak256(abi.encode(flightData));
}
function getRiskId(NftId productNftId, bytes32 riskKey) internal view returns (RiskId riskId) {
return RiskIdLib.toRiskId(productNftId, riskKey);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Amount} from "../../type/Amount.sol";
import {Str} from "../../type/String.sol";
import {Timestamp} from "../../type/Timestamp.sol";
contract FlightMessageVerifier is
Ownable
{
error ErrorFlightMessageVerifierSignerZero();
error ErrorFlightMessageVerifierContractSignerNotSupported();
address private _expectedSigner;
constructor() Ownable(msg.sender) { }
function setExpectedSigner(address signer) external onlyOwner {
if (signer == address(0)) { revert ErrorFlightMessageVerifierSignerZero(); }
if (signer.code.length > 0) { revert ErrorFlightMessageVerifierContractSignerNotSupported(); }
_expectedSigner = signer;
}
function getExpectedSigner() external view returns(address) {
return _expectedSigner;
}
/// @dev creates digest hash based on application parameters
/// proposal:
/// use "LX 180 ZRH BKK 20241104" (23 chars, should be enough for all flights)
/// carriers, airports: https://www.iata.org/en/publications/directories/code-search/
/// flight numbers: https://en.wikipedia.org/wiki/Flight_number
/// instead of separate strings, coding/decoding done anyway off-chain
function getRatingsHash(
Str flightData,
Timestamp departureTime,
Timestamp arrivalTime,
Amount premiumAmount,
uint256[6] memory statistics
)
public
view
returns(bytes32)
{
return MessageHashUtils.toEthSignedMessageHash(
abi.encode(
flightData,
departureTime,
arrivalTime,
premiumAmount,
statistics));
}
function verifyRatingsHash(
Str flightData,
Timestamp departureTime,
Timestamp arrivalTime,
Amount premiumAmount,
uint256[6] memory statistics,
// bytes memory signature,
uint8 v,
bytes32 r,
bytes32 s
)
public
view
returns (
address actualSigner,
ECDSA.RecoverError errorStatus,
bool success
)
{
bytes32 messageHash = getRatingsHash(
flightData,
departureTime,
arrivalTime,
premiumAmount,
statistics);
(
actualSigner,
errorStatus,
) = ECDSA.tryRecover(messageHash, v, r, s);
success = (
errorStatus == ECDSA.RecoverError.NoError
&& actualSigner == _expectedSigner);
}
// TODO re-enable or cleanup
// function checkAndRegisterSignature (
// address policyHolder,
// address protectedWallet,
// uint256 protectedBalance,
// uint256 duration,
// uint256 bundleId,
// bytes32 signatureId,
// bytes calldata signature
// )
// external
// {
// bytes32 signatureHash = keccak256(abi.encode(signature));
// require(!_signatureIsUsed[signatureHash], "ERROR:DMH-001:SIGNATURE_USED");
// address signer = getSignerFromDigestAndSignature(
// protectedWallet,
// protectedBalance,
// duration,
// bundleId,
// signatureId,
// signature);
// require(policyHolder == signer, "ERROR:DMH-002:SIGNATURE_INVALID");
// _signatureIsUsed[signatureHash] = true;
// }
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAuthorization} from "../../authorization/IAuthorization.sol";
import {ACTIVE, FULFILLED, FAILED} from "../../type/StateId.sol";
import {NftId} from "../../type/NftId.sol";
import {BasicOracle} from "../../oracle/BasicOracle.sol";
import {RequestId} from "../../type/RequestId.sol";
import {LibRequestIdSet} from "../../type/RequestIdSet.sol";
import {RiskId} from "../../type/RiskId.sol";
import {StateId} from "../../type/StateId.sol";
import {Str} from "../../type/String.sol";
import {Timestamp, TimestampLib} from "../../type/Timestamp.sol";
contract FlightOracle is
BasicOracle
{
struct FlightStatusRequest {
RiskId riskId;
Str flightData; // "LX 180 ZRH BKK 20241104"
Timestamp departureTime; // is this needed or is flight number and date unique aready?
}
struct FlightStatusResponse {
RiskId riskId;
bytes1 status;
int256 delayMinutes;
}
event LogFlightOracleRequestReceived(RequestId requestId, NftId requesterId);
event LogFlightOracleResponseSent(RequestId requestId, bytes1 status, int256 delay);
event LogFlightOracleRequestCancelled(RequestId requestId);
// TODO decide if this variable should be moved to instance store
// if so it need to manage active requests by requestor nft id
LibRequestIdSet.Set internal _activeRequests;
constructor(
address registry,
NftId productNftId,
string memory componentName,
IAuthorization authorization
)
{
address initialOwner = msg.sender;
initialize(
registry,
productNftId,
authorization,
initialOwner,
componentName
);
}
function initialize(
address registry,
NftId productNftId,
IAuthorization authorization,
address initialOwner,
string memory name
)
public
virtual
initializer()
{
_initializeBasicOracle(
registry,
productNftId,
authorization,
initialOwner,
name);
}
function respondWithFlightStatus(
RequestId requestId,
bytes1 status,
int256 delayMinutes
)
external
restricted()
{
// obtain riskId for request
bytes memory requestData = _getInstanceReader().getRequestInfo(requestId).requestData;
(RiskId riskId,,) = abi.decode(requestData, (RiskId, Str, Timestamp));
// assemble response data
bytes memory responseData = abi.encode(
FlightStatusResponse ({
riskId: riskId,
status: status,
delayMinutes: delayMinutes}));
// logging
emit LogFlightOracleResponseSent(requestId, status, delayMinutes);
// effects + interaction (via framework to receiving component)
_respond(requestId, responseData);
// TODO decide if the code below should be moved to GIF
// check callback result
bool requestFulfilled = _getInstanceReader().getRequestState(
requestId) == FULFILLED();
// remove from active requests when successful
if (requestFulfilled) {
LibRequestIdSet.remove(_activeRequests, requestId);
}
}
//--- view functions ----------------------------------------------------//
// TODO decide if the code below should be moved to GIF
function activeRequests()
external
view
returns(uint256 numberOfRequests)
{
return LibRequestIdSet.size(_activeRequests);
}
// TODO decide if the code below should be moved to GIF
function getActiveRequest(uint256 idx)
external
view
returns(RequestId requestId)
{
return LibRequestIdSet.getElementAt(_activeRequests, idx);
}
function isActiveRequest(RequestId requestId)
external
view
returns(bool isActive)
{
return LibRequestIdSet.contains(_activeRequests, requestId);
}
function getRequestState(RequestId requestId)
external
view
returns (
RiskId riskId,
string memory flightData,
StateId requestState,
bool readyForResponse,
bool waitingForResend
)
{
bytes memory requestData = _getInstanceReader().getRequestInfo(requestId).requestData;
Str fltData;
Timestamp departureTime;
(riskId, fltData, departureTime) = abi.decode(requestData, (RiskId, Str, Timestamp));
flightData = fltData.toString();
requestState = _getInstanceReader().getRequestState(requestId);
readyForResponse = requestState == ACTIVE() && TimestampLib.current() >= departureTime;
waitingForResend = requestState == FAILED();
}
function decodeFlightStatusRequestData(bytes memory data) external pure returns (FlightStatusRequest memory) {
return abi.decode(data, (FlightStatusRequest));
}
//--- internal functions ------------------------------------------------//
/// @dev use case specific handling of oracle requests
/// for now only log is emitted to verify that request has been received by oracle component
function _request(
RequestId requestId,
NftId requesterId,
bytes calldata requestData,
Timestamp expiryAt
)
internal
virtual override
{
FlightStatusRequest memory request = abi.decode(requestData, (FlightStatusRequest));
// TODO decide if the line below should be moved to GIF
LibRequestIdSet.add(_activeRequests, requestId);
emit LogFlightOracleRequestReceived(requestId, requesterId);
}
/// @dev use case specific handling of oracle requests
/// for now only log is emitted to verify that cancelling has been received by oracle component
function _cancel(
RequestId requestId
)
internal
virtual override
{
// TODO decide if the line below should be moved to GIF
LibRequestIdSet.remove(_activeRequests, requestId);
emit LogFlightOracleRequestCancelled(requestId);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Blocknumber, BlocknumberLib} from "../../type/Blocknumber.sol";
import {NftId} from "../../type/NftId.sol";
import {Amount} from "../../type/Amount.sol";
contract BalanceStore {
error ErrorBalanceStoreTargetAlreadyRegistered(NftId targetNftId);
error ErrorBalanceStoreTargetNotRegistered(NftId targetNftId);
event LogBalanceStoreTargetRegistered(NftId targetNftId);
event LogBalanceStoreFeesIncreased(NftId targetNftId, Amount addedAmount, Amount newBalance, Blocknumber lastUpdatedIn);
event LogBalanceStoreFeesDecreased(NftId targetNftId, Amount addedAmount, Amount newBalance, Blocknumber lastUpdatedIn);
event LogBalanceStoreLockedIncreased(NftId targetNftId, Amount addedAmount, Amount newBalance, Blocknumber lastUpdatedIn);
event LogBalanceStoreLockedDecreased(NftId targetNftId, Amount addedAmount, Amount newBalance, Blocknumber lastUpdatedIn);
event LogBalanceStoreBalanceIncreased(NftId targetNftId, Amount addedAmount, Amount newBalance, Blocknumber lastUpdatedIn);
event LogBalanceStoreBalanceDecreased(NftId targetNftId, Amount addedAmount, Amount newBalance, Blocknumber lastUpdatedIn);
mapping(NftId nftId => Amount balance) private _balanceAmount;
mapping(NftId nftId => Amount locked) private _lockedAmount;
mapping(NftId nftId => Amount fees) private _feeAmount;
// used to indicate if the target has been registered as well as when it was last updated (not used externally atm)
mapping(NftId nftId => Blocknumber lastUpdatedIn) private _lastUpdatedIn;
modifier onlyRegisteredTarget(NftId targetNftId) {
if (!_lastUpdatedIn[targetNftId].gtz()) {
revert ErrorBalanceStoreTargetNotRegistered(targetNftId);
}
_;
}
function getBalanceAmount(NftId targetNftId) external view returns (Amount balanceAmount) { return _balanceAmount[targetNftId]; }
function getLockedAmount(NftId targetNftId) external view returns (Amount lockedAmount) { return _lockedAmount[targetNftId]; }
function getFeeAmount(NftId targetNftId) external view returns (Amount feeAmount) { return _feeAmount[targetNftId]; }
function getAmounts(NftId targetNftId)
external
view
returns (
Amount balanceAmount,
Amount lockedAmount,
Amount feeAmount
)
{
balanceAmount = _balanceAmount[targetNftId];
lockedAmount = _lockedAmount[targetNftId];
feeAmount = _feeAmount[targetNftId];
}
function _registerBalanceTarget(NftId targetNftId) internal {
if (_lastUpdatedIn[targetNftId].gtz()) {
revert ErrorBalanceStoreTargetAlreadyRegistered(targetNftId);
}
_setLastUpdatedIn(targetNftId);
emit LogBalanceStoreTargetRegistered(targetNftId);
}
//--- fee management ----------------------------------------------------//
function _increaseFees(NftId targetNftId, Amount amount) internal onlyRegisteredTarget(targetNftId) returns (Amount newBalance) {
newBalance = _feeAmount[targetNftId] + amount;
_feeAmount[targetNftId] = newBalance;
emit LogBalanceStoreFeesIncreased(targetNftId, amount, newBalance, _lastUpdatedIn[targetNftId]);
_setLastUpdatedIn(targetNftId);
}
function _decreaseFees(NftId targetNftId, Amount amount) internal onlyRegisteredTarget(targetNftId) returns (Amount newBalance) {
newBalance = _feeAmount[targetNftId] - amount;
_feeAmount[targetNftId] = newBalance;
emit LogBalanceStoreFeesDecreased(targetNftId, amount, newBalance, _lastUpdatedIn[targetNftId]);
_setLastUpdatedIn(targetNftId);
}
//--- locked management -------------------------------------------------//
function _increaseLocked(NftId targetNftId, Amount amount) internal onlyRegisteredTarget(targetNftId) returns (Amount newBalance) {
newBalance = _lockedAmount[targetNftId] + amount;
_lockedAmount[targetNftId] = newBalance;
emit LogBalanceStoreLockedIncreased(targetNftId, amount, newBalance, _lastUpdatedIn[targetNftId]);
_setLastUpdatedIn(targetNftId);
}
function _decreaseLocked(NftId targetNftId, Amount amount) internal onlyRegisteredTarget(targetNftId) returns (Amount newBalance) {
newBalance = _lockedAmount[targetNftId] - amount;
_lockedAmount[targetNftId] = newBalance;
emit LogBalanceStoreLockedDecreased(targetNftId, amount, newBalance, _lastUpdatedIn[targetNftId]);
_setLastUpdatedIn(targetNftId);
}
//--- balance management ------------------------------------------------//
function _increaseBalance(NftId targetNftId, Amount amount) internal onlyRegisteredTarget(targetNftId) returns (Amount newBalance) {
newBalance = _balanceAmount[targetNftId] + amount;
_balanceAmount[targetNftId] = newBalance;
emit LogBalanceStoreBalanceIncreased(targetNftId, amount, newBalance, _lastUpdatedIn[targetNftId]);
_setLastUpdatedIn(targetNftId);
}
function _decreaseBalance(NftId targetNftId, Amount amount) internal onlyRegisteredTarget(targetNftId) returns (Amount newBalance) {
newBalance = _balanceAmount[targetNftId] - amount;
_balanceAmount[targetNftId] = newBalance;
emit LogBalanceStoreBalanceDecreased(targetNftId, amount, newBalance, _lastUpdatedIn[targetNftId]);
_setLastUpdatedIn(targetNftId);
}
//--- internal/private functions ----------------------------------------//
function _setLastUpdatedIn(NftId targetNftId) internal {
_lastUpdatedIn[targetNftId] = BlocknumberLib.current();
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {IRegistry} from "../../registry/IRegistry.sol";
abstract contract Cloneable is
AccessManagedUpgradeable
{
IRegistry internal _registry;
/// @dev call to initialize MUST be made in the same transaction as cloning of the contract
function __Cloneable_init(
address authority,
address registry
)
internal
onlyInitializing
{
__AccessManaged_init(authority);
_registry = IRegistry(registry);
}
function getRegistry() external view returns (IRegistry) {
return _registry;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Blocknumber, BlocknumberLib} from "../../type/Blocknumber.sol";
import {NftId} from "../../type/NftId.sol";
import {Amount} from "../../type/Amount.sol";
import {RequestId, RequestIdLib} from "../../type/RequestId.sol";
contract ObjectCounter {
// TODO refactor risk id
// mapping(NftId productNftId => uint64 risks) private _riskCounter;
uint256 private _requestCounter = 0;
function _createNextRequestId() internal returns (RequestId requestId) {
_requestCounter++;
requestId = RequestIdLib.toRequestId(_requestCounter);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {COMPONENT, BUNDLE, POLICY, REQUEST, RISK, CLAIM, PAYOUT, POOL, PREMIUM, PRODUCT, DISTRIBUTION, DISTRIBUTOR, DISTRIBUTOR_TYPE, REFERRAL, FEE} from "../../type/ObjectType.sol";
import {ACTIVE, PAUSED, ARCHIVED, CLOSED, APPLIED, COLLATERALIZED, REVOKED, SUBMITTED, CONFIRMED, DECLINED, EXPECTED, PAID, FULFILLED, FAILED, CANCELLED} from "../../type/StateId.sol";
import {Lifecycle} from "../../shared/Lifecycle.sol";
contract ObjectLifecycle is
Lifecycle,
Initializable
{
function _initializeLifecycle() internal onlyInitializing
{
_setupLifecycle();
}
function _setupLifecycle()
internal
override
{
_setupBundleLifecycle();
_setupComponentLifecycle();
_setupPolicyLifecycle();
_setupPremiumLifecycle();
_setupClaimLifecycle();
_setupPayoutLifecycle();
_setupRiskLifecycle();
_setupRequestLifecycle();
// setup dummy lifecycles to manage with key value store
_setUpPoolLifecycle();
_setUpProductLifecycle();
_setUpDistributionLifecycle();
}
function _setupComponentLifecycle() private {
setInitialState(COMPONENT(), ACTIVE());
setStateTransition(COMPONENT(), ACTIVE(), PAUSED());
setStateTransition(COMPONENT(), PAUSED(), ACTIVE());
setStateTransition(COMPONENT(), PAUSED(), ARCHIVED());
}
function _setupBundleLifecycle() private {
setInitialState(BUNDLE(), ACTIVE());
setStateTransition(BUNDLE(), ACTIVE(), CLOSED());
}
function _setupPolicyLifecycle() private {
setInitialState(POLICY(), APPLIED());
setStateTransition(POLICY(), APPLIED(), REVOKED());
setStateTransition(POLICY(), APPLIED(), DECLINED());
setStateTransition(POLICY(), APPLIED(), COLLATERALIZED());
setStateTransition(POLICY(), COLLATERALIZED(), CLOSED());
}
function _setupPremiumLifecycle() private {
setInitialState(PREMIUM(), EXPECTED());
setStateTransition(PREMIUM(), EXPECTED(), PAID());
}
function _setupClaimLifecycle() private {
setInitialState(CLAIM(), SUBMITTED());
setStateTransition(CLAIM(), SUBMITTED(), REVOKED());
setStateTransition(CLAIM(), SUBMITTED(), CONFIRMED());
setStateTransition(CLAIM(), SUBMITTED(), DECLINED());
setStateTransition(CLAIM(), CONFIRMED(), CLOSED());
setStateTransition(CLAIM(), CONFIRMED(), CANCELLED());
}
function _setupPayoutLifecycle() private {
setInitialState(PAYOUT(), EXPECTED());
setStateTransition(PAYOUT(), EXPECTED(), PAID());
setStateTransition(PAYOUT(), EXPECTED(), CANCELLED());
}
function _setupRiskLifecycle() private {
setInitialState(RISK(), ACTIVE());
setStateTransition(RISK(), ACTIVE(), CLOSED());
}
function _setupRequestLifecycle() private {
setInitialState(REQUEST(), ACTIVE());
setStateTransition(REQUEST(), ACTIVE(), FULFILLED());
setStateTransition(REQUEST(), ACTIVE(), FAILED());
setStateTransition(REQUEST(), FAILED(), FULFILLED());
setStateTransition(REQUEST(), ACTIVE(), CANCELLED());
}
// dummy lifecycle only
function _setUpPoolLifecycle() private {
setInitialState(POOL(), ACTIVE());
}
// dummy lifecycle only
function _setUpProductLifecycle() private {
setInitialState(PRODUCT(), ACTIVE());
setInitialState(FEE(), ACTIVE());
}
// dummy lifecycles only
function _setUpDistributionLifecycle() private {
setInitialState(DISTRIBUTION(), ACTIVE());
setInitialState(DISTRIBUTOR(), ACTIVE());
setInitialState(DISTRIBUTOR_TYPE(), ACTIVE());
setInitialState(REFERRAL(), ACTIVE());
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Cloneable} from "./Cloneable.sol";
import {LibKey32Set} from "../../type/Key32Set.sol";
import {NftId} from "../../type/NftId.sol";
import {Key32} from "../../type/Key32.sol";
contract ObjectSet is
Cloneable
{
using LibKey32Set for LibKey32Set.Set;
event LogObjectSetInitialized(address instance);
error ErrorObjectSetNftIdInvalid(NftId instanceNftId);
mapping(NftId compnentNftId => LibKey32Set.Set objects) internal _activeObjects;
mapping(NftId compnentNftId => LibKey32Set.Set objects) internal _allObjects;
address internal _instanceAddress;
/// @dev This initializer needs to be called from the instance itself.
function initialize(address authority, address registry)
external
initializer()
{
_instanceAddress = msg.sender;
__Cloneable_init(authority, registry);
emit LogObjectSetInitialized(address(_instanceAddress));
}
function getInstanceAddress() external view returns (address) {
return _instanceAddress;
}
function _add(NftId componentNftId, Key32 key) internal {
LibKey32Set.Set storage allSet = _allObjects[componentNftId];
LibKey32Set.Set storage activeSet = _activeObjects[componentNftId];
allSet.add(key);
activeSet.add(key);
}
function _activate(NftId componentNftId, Key32 key) internal {
_activeObjects[componentNftId].add(key);
}
function _deactivate(NftId componentNftId, Key32 key) internal {
_activeObjects[componentNftId].remove(key);
}
function _objects(NftId componentNftId) internal view returns (uint256) {
return _allObjects[componentNftId].size();
}
function _contains(NftId componentNftId, Key32 key) internal view returns (bool) {
return _allObjects[componentNftId].contains(key);
}
function _getObject(NftId componentNftId, uint256 idx) internal view returns (Key32) {
return _allObjects[componentNftId].getElementAt(idx);
}
function _activeObjs(NftId componentNftId) internal view returns (uint256) {
return _activeObjects[componentNftId].size();
}
function _isActive(NftId componentNftId, Key32 key) internal view returns (bool) {
return _activeObjects[componentNftId].contains(key);
}
function _getActiveObject(NftId componentNftId, uint256 idx) internal view returns (Key32) {
return _activeObjects[componentNftId].getElementAt(idx);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IBundle} from "../module/IBundle.sol";
import {IInstance} from "../IInstance.sol";
import {IRisk} from "../module/IRisk.sol";
import {NftId} from "../../type/NftId.sol";
import {RiskId} from "../../type/RiskId.sol";
library ObjectSetHelperLib {
function getRiskInfo(address instanceAddress, RiskId riskId) public view returns (IRisk.RiskInfo memory) {
return IInstance(instanceAddress).getInstanceReader().getRiskInfo(riskId);
}
function getProductNftId(address instanceAddress, RiskId riskId) public view returns (NftId) {
return getRiskInfo(instanceAddress, riskId).productNftId;
}
function getBundleInfo(address instanceAddress, NftId bundleNftId) public view returns (IBundle.BundleInfo memory) {
return IInstance(instanceAddress).getInstanceReader().getBundleInfo(bundleNftId);
}
function getPoolNftId(address instanceAddress, NftId bundleNftId) public view returns (NftId) {
return getBundleInfo(instanceAddress, bundleNftId).poolNftId;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IBaseStore} from "./IBaseStore.sol";
import {Blocknumber, BlocknumberLib} from "../type/Blocknumber.sol";
import {Key32, KeyId, Key32Lib} from "../type/Key32.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {StateId, KEEP_STATE} from "../type/StateId.sol";
import {Lifecycle} from "../shared/Lifecycle.sol";
abstract contract BaseStore is
Lifecycle,
IBaseStore
{
mapping(Key32 key32 => IBaseStore.Metadata metadata) private _metadata;
function _createMetadata(
Key32 key32
)
internal
{
ObjectType objectType = key32.toObjectType();
if (objectType.eqz()) {
revert ErrorBaseStoreTypeUndefined(objectType);
}
Metadata storage metadata = _metadata[key32];
if (metadata.updatedIn.gtz()) {
revert ErrorBaseStoreAlreadyCreated(key32, objectType);
}
if(!hasLifecycle(objectType)) {
revert ErrorBaseStoreNoLifecycle(objectType);
}
Blocknumber blocknumber = BlocknumberLib.current();
StateId initialState = getInitialState(objectType);
// set metadata
metadata.objectType = objectType;
metadata.state = initialState;
metadata.updatedIn = blocknumber;
}
function _updateState(
Key32 key32,
StateId state
)
internal
returns (Blocknumber lastUpdatedIn, StateId oldState)
{
if (state.eqz()) {
revert ErrorBaseStoreStateZero(key32);
}
Metadata storage metadata = _metadata[key32];
oldState = metadata.state;
lastUpdatedIn = metadata.updatedIn;
if (oldState.eqz()) {
revert ErrorBaseStoreNotExisting(key32);
}
// update state
if(state != KEEP_STATE()) {
checkTransition(oldState, metadata.objectType, oldState, state);
metadata.state = state;
// solhint-disable-next-line avoid-tx-origin
}
// update metadata
metadata.updatedIn = BlocknumberLib.current();
}
function exists(Key32 key32) public view returns (bool) {
return _metadata[key32].state.gtz();
}
function getMetadata(Key32 key32) public view returns (Metadata memory metadata) {
return _metadata[key32];
}
function getState(Key32 key32) public view returns (StateId state) {
return _metadata[key32].state;
}
function toKey32(ObjectType objectType, KeyId id) external pure override returns(Key32) {
return Key32Lib.toKey32(objectType, id);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {LibNftIdSet} from "../type/NftIdSet.sol";
import {NftId, NftIdLib} from "../type/NftId.sol";
import {Key32} from "../type/Key32.sol";
import {BUNDLE} from "../type/ObjectType.sol";
import {ObjectSet} from "./base/ObjectSet.sol";
import {ObjectSetHelperLib} from "./base/ObjectSetHelperLib.sol";
contract BundleSet is
ObjectSet
{
using LibNftIdSet for LibNftIdSet.Set;
event LogBundleSetPolicyLinked(NftId bundleNftId, NftId policyNftId);
event LogBundleSetPolicyUnlinked(NftId bundleNftId, NftId policyNftId);
event LogBundleSetBundleAdded(NftId poolNftId, NftId bundleNftId);
event LogBundleSetBundleUnlocked(NftId poolNftId, NftId bundleNftId);
event LogBundleSetBundleLocked(NftId poolNftId, NftId bundleNftId);
event LogBundleSetBundleClosed(NftId poolNftId, NftId bundleNftId);
error ErrorBundleSetPolicyAlreadyActivated(NftId policyNftId);
error ErrorBundleSetBundleLocked(NftId bundleNftId, NftId policyNftId);
error ErrorBundleSetPolicyWithOpenClaims(NftId policyNftId, uint256 openClaimsCount);
error ErrorBundleSetPolicyNotCloseable(NftId policyNftId);
error ErrorBundleSetBundleUnknown(NftId bundleNftId);
error ErrorBundleSetBundleNotRegistered(NftId bundleNftId);
mapping(NftId bundleNftId => LibNftIdSet.Set policies) internal _activePolicies;
/// @dev links a policy to its bundle
function linkPolicy(NftId poolNftId, NftId bundleNftId, NftId policyNftId) external restricted() {
// ensure bundle is unlocked (in active set) and registered with this instance
if (!_isActive(poolNftId, _toBundleKey32(bundleNftId))) {
revert ErrorBundleSetBundleLocked(bundleNftId, policyNftId);
}
_activePolicies[bundleNftId].add(policyNftId);
emit LogBundleSetPolicyLinked(bundleNftId, policyNftId);
}
/// @dev unlinks a policy from its bundle
function unlinkPolicy(NftId poolNftId, NftId bundleNftId, NftId policyNftId) external restricted() {
// ensure bundle is registered with this instance
if (!_contains(poolNftId, _toBundleKey32(bundleNftId))) {
revert ErrorBundleSetBundleUnknown(bundleNftId);
}
_activePolicies[bundleNftId].remove(policyNftId);
emit LogBundleSetPolicyUnlinked(bundleNftId, policyNftId);
}
/// @dev add a new bundle to a pool registerd with this instance
// the corresponding pool is fetched via instance reader
function add(NftId bundleNftId) external restricted() {
NftId poolNftId = ObjectSetHelperLib.getPoolNftId(_instanceAddress, bundleNftId);
// ensure pool is registered with instance
if(poolNftId.eqz()) {
revert ErrorBundleSetBundleNotRegistered(bundleNftId);
}
_add(poolNftId, _toBundleKey32(bundleNftId));
emit LogBundleSetBundleAdded(poolNftId, bundleNftId);
}
/// @dev unlocked (active) bundles are available to collateralize new policies
function unlock(NftId bundleNftId) external restricted() {
NftId poolNftId = ObjectSetHelperLib.getPoolNftId(_instanceAddress, bundleNftId);
_activate(poolNftId, _toBundleKey32(bundleNftId));
emit LogBundleSetBundleUnlocked(poolNftId, bundleNftId);
}
/// @dev locked (deactivated) bundles may not collateralize any new policies
function lock(NftId bundleNftId) external restricted() {
NftId poolNftId = ObjectSetHelperLib.getPoolNftId(_instanceAddress, bundleNftId);
_deactivate(poolNftId, _toBundleKey32(bundleNftId));
emit LogBundleSetBundleLocked(poolNftId, bundleNftId);
}
function checkBundle(NftId productNftId, NftId bundleId)
public
view
returns (bool exists, bool active)
{
Key32 bundleKey32 = bundleId.toKey32(BUNDLE());
exists = _contains(productNftId, bundleKey32);
if (exists) {
active = _isActive(productNftId, bundleKey32);
}
}
function bundles(NftId poolNftId) external view returns(uint256) {
return _objects(poolNftId);
}
function getBundleNftId(NftId poolNftId, uint256 idx) external view returns(NftId) {
return NftIdLib.toNftId(_getObject(poolNftId, idx).toKeyId());
}
function activeBundles(NftId poolNftId) external view returns(uint256) {
return _activeObjs(poolNftId);
}
function getActiveBundleNftId(NftId poolNftId, uint256 idx) external view returns(NftId) {
return NftIdLib.toNftId(_getActiveObject(poolNftId, idx).toKeyId());
}
function activePolicies(NftId bundleNftId) external view returns(uint256) {
return _activePolicies[bundleNftId].size();
}
function getActivePolicy(NftId bundleNftId, uint256 idx) external view returns(NftId policyNftId) {
return _activePolicies[bundleNftId].getElementAt(idx);
}
function _toBundleKey32(NftId nftId) private pure returns (Key32) {
return nftId.toKey32(BUNDLE());
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ILifecycle} from "../shared/ILifecycle.sol";
import {Blocknumber} from "../type/Blocknumber.sol";
import {Key32, KeyId} from "../type/Key32.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {StateId} from "../type/StateId.sol";
interface IBaseStore is ILifecycle {
error ErrorBaseStoreTypeUndefined(ObjectType objectType);
error ErrorBaseStoreAlreadyCreated(Key32 key, ObjectType objectType);
error ErrorBaseStoreNoLifecycle(ObjectType objectType);
error ErrorBaseStoreStateZero(Key32 key);
error ErrorBaseStoreNotExisting(Key32 key);
struct Metadata {
// slot 0
ObjectType objectType;
StateId state;
Blocknumber updatedIn;
}
/// @dev check if a metadata entry with the key exists
function exists(Key32 key) external view returns (bool);
/// @dev retrieve the metadata for a given key
function getMetadata(Key32 key) external view returns (Metadata memory metadata);
/// @dev retrieve the state for a given key
function getState(Key32 key) external view returns (StateId state);
/// @dev convert an object type and an id to a key32
function toKey32(ObjectType objectType, KeyId id) external pure returns(Key32);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAccess} from "../authorization/IAccess.sol";
import {IRegisterable} from "../shared/IRegisterable.sol";
import {Amount} from "../type/Amount.sol";
import {BundleSet} from "./BundleSet.sol";
import {RiskSet} from "./RiskSet.sol";
import {InstanceAdmin} from "./InstanceAdmin.sol";
import {InstanceReader} from "./InstanceReader.sol";
import {InstanceStore} from "./InstanceStore.sol";
import {NftId} from "../type/NftId.sol";
import {ProductStore} from "./ProductStore.sol";
import {RoleId} from "../type/RoleId.sol";
import {Seconds} from "../type/Seconds.sol";
import {UFixed} from "../type/UFixed.sol";
interface IInstance is
IRegisterable
{
// role handling
event LogInstanceCustomRoleCreated(RoleId roleId, string roleName, RoleId adminRoleId, uint32 maxMemberCount);
event LogInstanceCustomRoleActiveSet(RoleId roleId, bool active, address caller);
event LogInstanceCustomRoleGranted(RoleId roleId, address account, address caller);
event LogInstanceCustomRoleRevoked(RoleId roleId, address account, address caller);
// target handling
event LogInstanceCustomTargetCreated(address target, RoleId targetRoleId, string name);
event LogInstanceTargetLocked(address target, bool locked);
event LogInstanceCustomTargetFunctionRoleSet(address target, bytes4[] selectors, RoleId roleId);
// modifier is onlyRoleAdmin
error ErrorInstanceNotCustomRole(RoleId roleId);
error ErrorInstanceNotRoleAdmin(RoleId roleId, address account);
error ErrorInstanceInstanceAdminZero();
error ErrorInstanceInstanceAdminAlreadySet(address instanceAdmin);
error ErrorInstanceInstanceAdminAuthorityMismatch(address instanceAuthority);
error ErrorInstanceBundleSetAlreadySet(address instanceBundleSet);
error ErrorInstanceBundleSetInstanceMismatch(address instance);
error ErrorInstanceBundleSetAuthorityMismatch(address instanceAuthority);
error ErrorInstanceRiskSetAlreadySet(address instanceRiskSet);
error ErrorInstanceRiskSetInstanceMismatch(address instance);
error ErrorInstanceRiskSetAuthorityMismatch(address instanceAuthority);
error ErrorInstanceInstanceReaderInstanceMismatch(address instanceAuthority);
error ErrorInstanceInstanceStoreAlreadySet(address instanceStore);
error ErrorInstanceInstanceStoreAuthorityMismatch(address instanceAuthority);
struct InstanceContracts {
InstanceAdmin instanceAdmin;
InstanceStore instanceStore;
ProductStore productStore;
BundleSet bundleSet;
RiskSet riskSet;
InstanceReader instanceReader;
}
struct InstanceInfo {
uint64 requestsCount;
}
///--- instance ---------------------------------------------------------//
/// @dev Locks/unlocks the complete instance, including all its components.
function setInstanceLocked(bool locked) external;
/// @dev Upgrades the instance reader to the specified target.
function upgradeInstanceReader() external;
/// @dev Sets the instance reader for the instance.
/// Permissioned: only the instance service may call this function.
function setInstanceReader(InstanceReader instanceReader) external;
///--- staking ----------------------------------------------------------//
/// @dev Sets the duration for locking new stakes on this instance..
function setStakingLockingPeriod(Seconds stakeLockingPeriod) external;
/// @dev Sets the staking reward rate [apr] for this instance.
function setStakingRewardRate(UFixed rewardRate) external;
/// @dev Sets the maximum staked amount for this instance.
function setStakingMaxAmount(Amount maxStakedAmount) external;
/// @dev Refills the staking reward reserves for the specified target.
function refillStakingRewardReserves(Amount dipAmount) external returns (Amount newBalance);
/// @dev Defunds the staking reward reserves for the specified target.
function withdrawStakingRewardReserves(Amount dipAmount) external returns (Amount newBalance);
///--- product/component ------------------------------------------------//
/// @dev Locks/unlocks the specified target.
function setTargetLocked(address target, bool locked) external;
/// @dev Register a product with the instance.
function registerProduct(address product, address token) external returns (NftId productNftId);
///--- authz ------------------------------------------------------------//
/// @dev Creates a new custom role for the calling instance.
/// Custom roles are intended to be used for access control of custom components and its helper contracts.
/// Custom roles are not intended to be used as target roles for custom contracts.
function createRole(string memory roleName, RoleId adminRoleId, uint32 maxMemberCount) external returns (RoleId roleId);
/// @dev Activates/deactivates the specified role.
/// Only instance owner or account with role admin role can call this function.
function setRoleActive(RoleId roleId, bool active) external;
/// @dev Grants the specified role to the account.
/// Only active roles can be granted.
/// Only instance owner or account with role admin role can call this function.
function grantRole(RoleId roleId, address account) external;
/// @dev Revokes the specified role from the account.
/// Only instance owner or account with role admin role can call this function.
function revokeRole(RoleId roleId, address account) external;
/// @dev Creates a new custom target.
/// Custom targets are intended to be used for access control helper contracts of components.
/// Custom targets are not intended to be used for components.
function createTarget(address target, string memory name) external returns (RoleId contractRoleId);
/// @dev Authorizes the specified functions for the target and provided role.
function authorizeFunctions(address target, RoleId roleId, IAccess.FunctionInfo[] memory functions) external;
/// @dev Removes any role authorization for the specified functions.
function unauthorizeFunctions(address target, IAccess.FunctionInfo[] memory functions) external;
//--- getters -----------------------------------------------------------//
/// @dev returns the overall locking state of the instance (including all components)
function isInstanceLocked() external view returns (bool isLocked);
/// @dev returns the locking state of the specified target
function isTargetLocked(address target) external view returns (bool isLocked);
// get products
function products() external view returns (uint256 productCount);
function getProduct(uint256 idx) external view returns (NftId productNftId);
// get supporting contracts
function getInstanceReader() external view returns (InstanceReader);
function getBundleSet() external view returns (BundleSet);
function getRiskSet() external view returns (RiskSet);
function getInstanceAdmin() external view returns (InstanceAdmin);
function getInstanceStore() external view returns (InstanceStore);
function getProductStore() external view returns (ProductStore);
function isTokenRegistryDisabled() external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAccess} from "../authorization/IAccess.sol";
import {IInstance} from "./IInstance.sol";
import {IService} from "../shared/IService.sol";
import {Amount} from "../type/Amount.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RoleId} from "../type/RoleId.sol";
import {Seconds} from "../type/Seconds.sol";
import {UFixed} from "../type/UFixed.sol";
import {VersionPart} from "../type/Version.sol";
interface IInstanceService is IService {
// onlyInstance
error ErrorInstanceServiceNotRegistered(address instance);
error ErrorInstanceServiceNotInstance(address instance, ObjectType objectType);
error ErrorInstanceServiceInstanceVersionMismatch(NftId instanceNftId, VersionPart expectedRelease, VersionPart instanceRelease);
error ErrorInstanceServiceComponentNotInstanceLinked(address component);
error ErrorInstanceServiceMasterInstanceAlreadySet();
error ErrorInstanceServiceMasterInstanceAdminAlreadySet();
error ErrorInstanceServiceMasterBundleSetAlreadySet();
error ErrorInstanceServiceMasterRiskSetAlreadySet();
error ErrorInstanceServiceInstanceAddressZero();
error ErrorInstanceServiceMasterInstanceReaderNotSet();
error ErrorInstanceServiceInstanceReaderAddressZero();
error ErrorInstanceServiceInstanceReaderSameAsMasterInstanceReader();
error ErrorInstanceServiceInstanceReaderInstanceMismatch();
error ErrorInstanceServiceAccessManagerZero();
error ErrorInstanceServiceInstanceAdminZero();
error ErrorInstanceServiceInstanceReaderZero();
error ErrorInstanceServiceBundleSetZero();
error ErrorInstanceServiceRiskSetZero();
error ErrorInstanceServiceInstanceStoreZero();
error ErrorInstanceServiceProductStoreZero();
error ErrorInstanceServiceInstanceAuthorityMismatch();
error ErrorInstanceServiceBundleSetAuthorityMismatch();
error ErrorInstanceServiceRiskSetAuthorityMismatch();
error ErrorInstanceServiceInstanceReaderInstanceMismatch2();
error ErrorInstanceServiceBundleSetInstanceMismatch();
error ErrorInstanceServiceRiskSetInstanceMismatch();
error ErrorInstanceServiceInstanceStoreAuthorityMismatch();
error ErrorInstanceServiceProductStoreAuthorityMismatch();
error ErrorInstanceServiceRequestUnauhorized(address caller);
error ErrorInstanceServiceNotInstanceNftId(NftId nftId);
error ErrorInstanceServiceComponentNotRegistered(address componentAddress);
error ErrorInstanceServiceInstanceComponentMismatch(NftId instanceNftId, NftId componentNftId);
error ErrorInstanceServiceInvalidComponentType(address componentAddress, ObjectType expectedType, ObjectType componentType);
event LogInstanceServiceInstanceLocked(NftId instanceNftId, bool locked);
event LogInstanceServiceInstanceCreated(NftId instanceNftId, address instance);
event LogInstanceServiceMasterInstanceReaderUpgraded(NftId instanceNfId, address newInstanceReader);
event LogInstanceServiceInstanceReaderUpgraded(NftId instanceNfId, address newInstanceReader);
/// @dev Creates a new custom role for the calling instance.
function createRole(string memory roleName, RoleId adminRoleId, uint32 maxMemberCount) external returns (RoleId roleId);
/// @dev Sets the specified custom role as active or inactive for the calling instance.
function setRoleActive(RoleId roleId, bool active) external;
/// @dev Grants the specified custom role to the specified account for the calling instance.
function grantRole(RoleId roleId, address account) external;
/// @dev Revokes the specified custom role from the specified account for the calling instance.
function revokeRole(RoleId roleId, address account) external;
/// @dev Creates a new custom target for the calling instance.
/// All custom trargets are created with a corresponding contract role.
function createTarget(address target, string memory name) external returns (RoleId contractRoleId);
/// @dev Authorizes the specified functions for the specified target.
function authorizeFunctions(address target, RoleId roleId, IAccess.FunctionInfo[] memory functions) external;
/// @dev Removes any role authorization for the specified functions.
function unauthorizeFunctions(address target, IAccess.FunctionInfo[] memory functions) external;
/// @dev Locks/unlocks the specified target constrolled by the corresponding instance admin.
function setTargetLocked(address target, bool locked) external;
/// @dev Locks the complete instance, including all its components.
function setInstanceLocked(bool locked) external;
/// @dev Creates a new instance.
/// The caller becomes the owner of the new instance.
/// Creation of a new instance is achieved by this service through the creation and registration
/// of a new clone of the master instance and then setting up the initial wiring and authorization
/// of the necessary components.
/// @param allowAnyToken specifies whether the new instance is allowed to use any token or
/// only tokens that are registered in the `TokenRegistry`. Use of tokens **not** registered in the
/// `TokenRegistry` may result in problems with token handline and is therefor not recommended. The
/// use of such instances **is not supported** by Etherisc.
function createInstance(bool allowAnyToken)
external
returns (
IInstance instance,
NftId instanceNftId
);
function upgradeInstanceReader() external;
function upgradeMasterInstanceReader(address instanceReaderAddress) external;
function setStakingLockingPeriod(Seconds stakeLockingPeriod) external;
function setStakingRewardRate(UFixed rewardRate) external;
function setStakingMaxAmount(Amount maxStakedAmount) external;
function refillInstanceRewardReserves(address rewardProvider, Amount dipAmount) external returns (Amount newBalance);
/// @dev Defunds the staking reward reserves for the specified target.
function withdrawInstanceRewardReserves(Amount dipAmount) external returns (Amount newBalance);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {IAccess} from "../authorization/IAccess.sol";
import {IAuthorization} from "../authorization/IAuthorization.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IInstance} from "./IInstance.sol";
import {AccessAdmin} from "../authorization/AccessAdmin.sol";
import {AccessAdminLib} from "../authorization/AccessAdminLib.sol";
import {AccessManagerCloneable} from "../authorization/AccessManagerCloneable.sol";
import {ObjectType, INSTANCE} from "../type/ObjectType.sol";
import {RoleId, ADMIN_ROLE} from "../type/RoleId.sol";
import {Str} from "../type/String.sol";
import {VersionPart} from "../type/Version.sol";
import {INSTANCE_TARGET_NAME, INSTANCE_ADMIN_TARGET_NAME, INSTANCE_STORE_TARGET_NAME, PRODUCT_STORE_TARGET_NAME, BUNDLE_SET_TARGET_NAME, RISK_SET_TARGET_NAME} from "./TargetNames.sol";
contract InstanceAdmin is
AccessAdmin
{
// onlyInstanceService
error ErrorInstanceAdminNotInstanceService(address caller);
// authorizeFunctions
error ErrorInstanceAdminNotComponentOrCustomTarget(address target);
IInstance internal _instance;
IRegistry internal _registry;
uint64 internal _customRoleIdNext;
modifier onlyInstanceService() {
if (msg.sender != _registry.getServiceAddress(INSTANCE(), getRelease())) {
revert ErrorInstanceAdminNotInstanceService(msg.sender);
}
_;
}
/// @dev Only used for master instance admin.
constructor(address accessManager) {
initialize(
accessManager,
"MasterInstanceAdmin");
}
/// @dev Completes the initialization of this instance admin using the provided instance, registry and version.
/// Important: Initialization of instance admin is only complete after calling this function.
/// Important: The instance MUST be registered and all instance supporting contracts must be wired to this instance.
function completeSetup(
address registry,
address authorization,
VersionPart release,
address instance
)
external
reinitializer(uint64(release.toInt()))
{
// checks
AccessAdminLib.checkIsRegistered(registry, instance, INSTANCE());
// effects
AccessManagerCloneable(
authority()).completeSetup(
registry,
release);
AccessAdminLib.checkAuthorization(
address(_authorization),
authorization,
INSTANCE(), // expectedDomain
release, // expectedRelease
false, // expectServiceAuthorization
true); // checkAlreadyInitialized
_registry = IRegistry(registry);
_instance = IInstance(instance);
_authorization = IAuthorization(authorization);
_customRoleIdNext = 0;
// link nft ownability to instance
_linkToNftOwnable(instance);
// setup roles and services
_createRoles(_authorization);
_setupServices(_authorization);
// setup instance targets
_createInstanceTargets(_authorization.getMainTargetName());
// authorize functions of instance contracts
_createTargetAuthorizations(_authorization);
}
/// @dev grants the service roles to the service addresses based on the authorization specification.
/// Service addresses used for the granting are determined by the registry and the release of this instance.
function _setupServices(IAuthorization authorization)
internal
{
ObjectType[] memory serviceDomains = authorization.getServiceDomains();
for(uint256 i = 0; i < serviceDomains.length; i++) {
ObjectType serviceDomain = serviceDomains[i];
RoleId serviceRoleId = authorization.getServiceRole(serviceDomain);
address service = _registry.getServiceAddress(serviceDomain, getRelease());
_grantRoleToAccount(
serviceRoleId,
service);
}
}
function _createInstanceTargets(string memory instanceTargetName)
internal
{
_createInstanceTarget(address(_instance), instanceTargetName);
_createInstanceTarget(address(this), INSTANCE_ADMIN_TARGET_NAME);
_createInstanceTarget(address(_instance.getInstanceStore()), INSTANCE_STORE_TARGET_NAME);
_createInstanceTarget(address(_instance.getProductStore()), PRODUCT_STORE_TARGET_NAME);
_createInstanceTarget(address(_instance.getBundleSet()), BUNDLE_SET_TARGET_NAME);
_createInstanceTarget(address(_instance.getRiskSet()), RISK_SET_TARGET_NAME);
}
function _createInstanceTarget(address target, string memory name) internal {
_createTarget(target, name, TargetType.Instance, true);
}
/// @dev Initializes the authorization for the specified component.
/// Important: The component MUST be registered.
function initializeComponentAuthorization(
address componentAddress,
ObjectType expectedType
)
external
restricted()
{
IAuthorization authorization = AccessAdminLib.checkComponentInitialization(
this, _authorization, componentAddress, expectedType);
// effects
_createRoles(authorization);
_createTarget(componentAddress, authorization.getMainTargetName(), TargetType.Component, true);
_createTargetAuthorizations(authorization);
}
/// @dev Creates a custom role.
function createRole(
string memory name,
RoleId adminRoleId,
uint32 maxMemberCount
)
external
restricted()
returns (RoleId roleId)
{
// create roleId
roleId = AccessAdminLib.getCustomRoleId(_customRoleIdNext++);
// create role
_createRole(
roleId,
AccessAdminLib.roleInfo(
adminRoleId,
IAccess.TargetType.Custom,
maxMemberCount,
name),
true); // revert on existing role
}
/// @dev Activtes/pauses the specified role.
function setRoleActive(RoleId roleId, bool active)
external
restricted()
{
_setRoleActive(roleId, active);
}
/// @dev Grants the provided role to the specified account
function grantRole(
RoleId roleId,
address account)
external
restricted()
{
_grantRoleToAccount(roleId, account);
}
/// @dev Revokes the provided role from the specified account
function revokeRole(
RoleId roleId,
address account)
external
restricted()
{
_revokeRoleFromAccount(roleId, account);
}
/// @dev Create a new contract target.
/// The target needs to be an access managed contract.
function createTarget(
address target,
string memory name
)
external
restricted()
returns (RoleId contractRoleId)
{
return _createTarget(
target,
name,
TargetType.Contract,
true); // check authority matches
}
/// @dev Add function authorizations for the specified component or custom target.
function authorizeFunctions(
address target,
RoleId roleId,
IAccess.FunctionInfo[] memory functions
)
external
restricted()
{
_authorizeTargetFunctions(target, roleId, functions, true, true);
}
/// @dev Removes function authorizations for the specified component or custom target.
function unauthorizeFunctions(
address target,
IAccess.FunctionInfo[] memory functions
)
external
restricted()
{
_authorizeTargetFunctions(target, ADMIN_ROLE(), functions, true, false);
}
/// @dev locks the instance and all its releated targets including component and custom targets.
function setInstanceLocked(bool locked)
external
// not restricted(): need to operate on locked instances to unlock instance
onlyInstanceService()
{
AccessManagerCloneable accessManager = AccessManagerCloneable(authority());
accessManager.setLocked(locked);
}
function setTargetLocked(address target, bool locked)
external
// not restricted(): need to operate on locked instances to unlock instance
onlyInstanceService()
{
_setTargetLocked(target, locked);
}
function setContractLocked(address target, bool locked)
external
restricted() // component service
{
_setTargetLocked(target, locked);
}
/// @dev Returns the instance authorization specification used to set up this instance admin.
function getInstanceAuthorization()
external
view
returns (IAuthorization instanceAuthorizaion)
{
return _authorization;
}
// ------------------- Internal functions ------------------- //
function _createTargetAuthorizations(IAuthorization authorization)
internal
{
Str[] memory targets = authorization.getTargets();
Str target;
for(uint256 i = 0; i < targets.length; i++) {
target = targets[i];
RoleId[] memory authorizedRoles = authorization.getAuthorizedRoles(target);
for(uint256 j = 0; j < authorizedRoles.length; j++) {
_authorizeFunctions(authorization, target, authorizedRoles[j]);
}
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IAccess} from "../authorization/IAccess.sol";
import {IBaseStore} from "./IBaseStore.sol";
import {IBundle} from "../instance/module/IBundle.sol";
import {IComponents} from "../instance/module/IComponents.sol";
import {IDistribution} from "../instance/module/IDistribution.sol";
import {IDistributionService} from "../distribution/IDistributionService.sol";
import {IInstance} from "./IInstance.sol";
import {IOracle} from "../oracle/IOracle.sol";
import {IPolicy} from "../instance/module/IPolicy.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IRisk} from "../instance/module/IRisk.sol";
import {AccessAdminLib} from "../authorization/AccessAdminLib.sol";
import {Amount} from "../type/Amount.sol";
import {BundleSet} from "./BundleSet.sol";
import {BUNDLE, COMPONENT, DISTRIBUTION, PREMIUM, POLICY} from "../type/ObjectType.sol";
import {ClaimId, ClaimIdLib} from "../type/ClaimId.sol";
import {DistributorType} from "../type/DistributorType.sol";
import {InstanceAdmin} from "./InstanceAdmin.sol";
import {InstanceStore} from "./InstanceStore.sol";
import {Key32} from "../type/Key32.sol";
import {NftId} from "../type/NftId.sol";
import {PayoutId, PayoutIdLib} from "../type/PayoutId.sol";
import {PolicyServiceLib} from "../product/PolicyServiceLib.sol";
import {ProductStore} from "./ProductStore.sol";
import {ReferralId, ReferralStatus, ReferralLib} from "../type/Referral.sol";
import {RequestId} from "../type/RequestId.sol";
import {RiskId} from "../type/RiskId.sol";
import {RiskSet} from "./RiskSet.sol";
import {RoleId, INSTANCE_OWNER_ROLE} from "../type/RoleId.sol";
import {StateId} from "../type/StateId.sol";
import {Str, StrLib} from "../type/String.sol";
import {TokenHandler} from "../shared/TokenHandler.sol";
import {UFixed, UFixedLib} from "../type/UFixed.sol";
/// @dev Central reader contract for a specific instance.
/// Provides reading functions for all instance data and related component data.
contract InstanceReader {
error ErrorInstanceReaderAlreadyInitialized();
error ErrorInstanceReaderInstanceAddressZero();
bool private _initialized = false;
IRegistry internal _registry;
IInstance internal _instance;
InstanceAdmin internal _instanceAdmin;
InstanceStore internal _store;
ProductStore internal _productStore;
BundleSet internal _bundleSet;
RiskSet internal _riskSet;
IDistributionService internal _distributionService;
/// @dev This initializer needs to be called from the instance itself.
function initialize() public {
if(_initialized) {
revert ErrorInstanceReaderAlreadyInitialized();
}
initializeWithInstance(msg.sender);
}
/// @dev Initializer to upgrade instance reader via instance service
function initializeWithInstance(address instanceAddress)
public
{
if(_initialized) {
revert ErrorInstanceReaderAlreadyInitialized();
}
_initialized = true;
_instance = IInstance(instanceAddress);
_instanceAdmin = _instance.getInstanceAdmin();
_registry = _instance.getRegistry();
_store = _instance.getInstanceStore();
_productStore = _instance.getProductStore();
_bundleSet = _instance.getBundleSet();
_riskSet = _instance.getRiskSet();
_distributionService = IDistributionService(_registry.getServiceAddress(DISTRIBUTION(), _instance.getRelease()));
}
//--- instance functions ---------------------------------------------------------//
/// @dev Returns the registry this instance is registered in.
function getRegistry() public view returns (IRegistry registry) {
return _registry;
}
/// @dev Returns the instance NFT ID.
function getInstanceNftId() public view returns (NftId instanceNftid) {
return _registry.getNftIdForAddress(address(_instance));
}
/// @dev Returns the instance contract.
function getInstance() public view returns (IInstance instance) {
return _instance;
}
//--- component functions ------------------------------------------------------//
/// @dev Returns the component info for the given component NFT ID.
function getComponentInfo(NftId componentNftId) public view returns (IComponents.ComponentInfo memory info) {
return _store.getComponentInfo(componentNftId);
}
/// @dev Returns the registered token for the given component NFT ID.
function getToken(NftId componentNftId) public view returns (IERC20Metadata token) {
TokenHandler tokenHandler = getTokenHandler(componentNftId);
if (address(tokenHandler) != address(0)) { return tokenHandler.TOKEN(); }
}
/// @dev Returns the current wallet address for the given component NFT ID.
/// The wallet address is either the component's own address or any other wallet address specified by the component owner.
/// The wallet holds the component's funds. Tokens collected by the component are transferred to the wallet and
/// Tokens distributed from the component are transferred from this wallet.
function getWallet(NftId componentNftId) public view returns (address wallet) {
IComponents.ComponentInfo memory info = getComponentInfo(componentNftId);
if (address(info.tokenHandler) != address(0)) {
return info.tokenHandler.getWallet();
}
}
/// @dev Returns the token handler for the given component NFT ID.
/// The token handler manages all transfers from/to the component's wallet.
/// To allow a component to collect funds from an account, it has to create a corresponding allowance from the
/// account to the address of the component's token handler.
function getTokenHandler(NftId componentNftId) public view returns (TokenHandler tokenHandler) {
IComponents.ComponentInfo memory info = _store.getComponentInfo(componentNftId);
if(address(info.tokenHandler) != address(0)) {
return info.tokenHandler;
}
}
/// @dev Returns the current token balance amount for the given component NFT ID.
/// The balance amount includes the fee amount.
function getBalanceAmount(NftId targetNftId) external view returns (Amount) {
return _store.getBalanceAmount(targetNftId);
}
/// @dev Returns the current fee amount for the given NFT ID.
/// The target NFT ID may reference a component, a distributor or a bundle.
function getFeeAmount(NftId targetNftId) external view returns (Amount) {
return _store.getFeeAmount(targetNftId);
}
/// @dev Returns the currently locked amount for the given NFT ID.
/// The target NFT ID may reference a pool or a bundle.
function getLockedAmount(NftId targetNftId) external view returns (Amount) {
return _store.getLockedAmount(targetNftId);
}
//--- product functions ------------------------------------------------------//
/// @dev Returns the number of registered products.
function products() public view returns (uint256 productCount) {
return _instance.products();
}
/// @dev Returns th product NFT ID for the given index.
function getProduct(uint256 idx) public view returns (NftId productNftId) {
return _instance.getProduct(idx);
}
/// @dev Returns the product info for the given product NFT ID.
function getProductInfo(NftId productNftId) public view returns (IComponents.ProductInfo memory info) {
return _productStore.getProductInfo(productNftId);
}
/// @dev Returns the current fee settings for the given product NFT ID.
function getFeeInfo(NftId productNftId) public view returns (IComponents.FeeInfo memory feeInfo) {
return _productStore.getFeeInfo(productNftId);
}
//--- risk functions ---------------------------------------------------------//
/// @dev Returns the total number of registered risks for the specified product.
function risks(NftId productNftId) public view returns (uint256 riskCount) {
return _riskSet.risks(productNftId);
}
/// @dev Returns the number of active risks for the specified product.
function activeRisks(NftId productNftId) public view returns (uint256 activeRiskCount) {
return _riskSet.activeRisks(productNftId);
}
/// @dev Returns the risk ID for the given product NFT ID and (registered) risk index.
function getRiskId(NftId productNftId, uint256 idx) public view returns (RiskId riskId) {
return _riskSet.getRiskId(productNftId, idx);
}
/// @dev Returns the active risk ID for the given product NFT ID and (active) risk index.
function getActiveRiskId(NftId productNftId, uint256 idx) public view returns (RiskId riskId) {
return _riskSet.getActiveRiskId(productNftId, idx);
}
/// @dev Returns true if the specified risk exists for the given product NFT ID.
function isProductRisk(NftId productNftId, RiskId riskId) public view returns (bool exists) {
return _riskSet.hasRisk(productNftId, riskId);
}
/// @dev Returns the risk info for the given risk ID.
function getRiskInfo(RiskId riskId) public view returns (IRisk.RiskInfo memory info) {
return _productStore.getRiskInfo(riskId);
}
/// @dev Returns the risk state for the given risk ID.
function getRiskState(RiskId riskId) public view returns (StateId stateId) {
return _productStore.getState(riskId.toKey32());
}
//--- policy functions -------------------------------------------------------//
/// @dev Returns the number of linked policies for the given risk ID.
function policiesForRisk(RiskId riskId) public view returns (uint256 linkedPolicies) {
return _riskSet.linkedPolicies(riskId);
}
/// @dev Returns the linked policy NFT ID for the given risk ID and index.
function getPolicyForRisk(RiskId riskId, uint256 idx) public view returns (NftId linkedPolicyNftId) {
return _riskSet.getLinkedPolicyNftId(riskId, idx);
}
/// @dev Returns the number of linked policies for the given bundle NFT ID.
function policiesForBundle(NftId bundleNftId) public view returns (uint256 linkedPolicies) {
return _bundleSet.activePolicies(bundleNftId);
}
/// @dev Returns the linked policy NFT ID for the given risk ID and index.
function getPolicyForBundle(NftId bundleNftId, uint256 idx) public view returns (NftId linkedPolicyNftId) {
return _bundleSet.getActivePolicy(bundleNftId, idx);
}
/// @dev Returns the info for the given policy NFT ID.
function getPolicyInfo(NftId policyNftId) public view returns (IPolicy.PolicyInfo memory info) {
return _productStore.getPolicyInfo(policyNftId);
}
/// @dev Returns the state for the given policy NFT ID.
function getPolicyState(NftId policyNftId) public view returns (StateId state) {
return _productStore.getState(_toPolicyKey(policyNftId));
}
/// @dev Returns true iff policy is active.
function policyIsActive(NftId policyNftId) public view returns (bool isCloseable) {
return PolicyServiceLib.policyIsActive(this, policyNftId);
}
//--- claim functions -------------------------------------------------------//
/// @dev Returns the number of claims for the given policy NFT ID.
function claims(NftId policyNftId) public view returns (uint16 claimCount) {
return getPolicyInfo(policyNftId).claimsCount;
}
/// @dev Returns the claim ID for the given policy NFT ID and index.
function getClaimId(uint256 idx) public pure returns (ClaimId claimId) {
return ClaimIdLib.toClaimId(idx + 1);
}
/// @dev Returns the claim info for the given policy NFT ID and claim ID.
function getClaimInfo(NftId policyNftId, ClaimId claimId) public view returns (IPolicy.ClaimInfo memory info) {
return _productStore.getClaimInfo(policyNftId, claimId);
}
/// @dev Returns the current claim state for the given policy NFT ID and claim ID.
function getClaimState(NftId policyNftId, ClaimId claimId) public view returns (StateId state) {
return _productStore.getState(claimId.toKey32(policyNftId));
}
/// @dev Returns the remaining claimable amount for the given policy NFT ID.
/// The remaining claimable amount is the difference between the sum insured amount and total approved claim amounts so far.
function getRemainingClaimableAmount(NftId policyNftId)
public view returns (Amount remainingClaimableAmount) {
IPolicy.PolicyInfo memory info = getPolicyInfo(policyNftId);
return info.sumInsuredAmount - info.claimAmount;
}
//--- payout functions -------------------------------------------------------//
/// @dev Returns the number of payouts for the given policy NFT ID and claim ID.
function payouts(NftId policyNftId, ClaimId claimId) public view returns (uint24 payoutCount) {
return getClaimInfo(policyNftId, claimId).payoutsCount;
}
/// @dev Returns the payout ID for the given claim ID and index.
function getPayoutId(ClaimId claimId, uint24 idx) public pure returns (PayoutId payoutId) {
return PayoutIdLib.toPayoutId(claimId, idx + 1);
}
/// @dev Returns the payout info for the given policy NFT ID and payout ID.
function getPayoutInfo(NftId policyNftId, PayoutId payoutId) public view returns (IPolicy.PayoutInfo memory info) {
return _productStore.getPayoutInfo(policyNftId, payoutId);
}
/// @dev Returns the payout state for the given policy NFT ID and payout ID.
function getPayoutState(NftId policyNftId, PayoutId payoutId) public view returns (StateId state) {
return _productStore.getState(payoutId.toKey32(policyNftId));
}
//--- premium functions -------------------------------------------------------//
/// @dev Returns the premium info for the given policy NFT ID.
function getPremiumInfo(NftId policyNftId) public view returns (IPolicy.PremiumInfo memory info) {
return _productStore.getPremiumInfo(policyNftId);
}
/// @dev Returns the premium state for the given policy NFT ID.
function getPremiumState(NftId policyNftId) public view returns (StateId state) {
return _productStore.getState(_toPremiumKey(policyNftId));
}
//--- oracle functions ---------------------------------------------------------//
/// @dev Returns the request info for the given oracle request ID.
function getRequestInfo(RequestId requestId) public view returns (IOracle.RequestInfo memory requestInfo) {
return _store.getRequestInfo(requestId);
}
/// @dev Returns the request info for the given oracle request ID.
function getRequestState(RequestId requestId) public view returns (StateId state) {
return getState(requestId.toKey32());
}
//--- pool functions -----------------------------------------------------------//
/// @dev Returns the pool info for the given pool NFT ID.
function getPoolInfo(NftId poolNftId) public view returns (IComponents.PoolInfo memory info) {
return _store.getPoolInfo(poolNftId);
}
//--- bundle functions -------------------------------------------------------//
/// @dev Returns the total number of registered bundles for the given pool.
function bundles(NftId poolNftId) public view returns (uint256 bundleCount) {
return _bundleSet.bundles(poolNftId);
}
/// @dev Returns the number of active bundles for the given pool.
function activeBundles(NftId poolNftId) public view returns (uint256 bundleCount) {
return _bundleSet.activeBundles(poolNftId);
}
/// @dev Returns the bunde NFT ID for the given pool and index.
function getBundleNftId(NftId poolNftId, uint256 idx) public view returns (NftId bundleNftId) {
return _bundleSet.getBundleNftId(poolNftId, idx);
}
/// @dev Returns the active bunde NFT ID for the given pool and index.
function getActiveBundleNftId(NftId poolNftId, uint256 idx) public view returns (NftId bundleNftId) {
return _bundleSet.getActiveBundleNftId(poolNftId, idx);
}
/// @dev Returns the bundle info for the given bundle NFT ID.
function getBundleInfo(NftId bundleNftId) public view returns (IBundle.BundleInfo memory info) {
return _store.getBundleInfo(bundleNftId);
}
/// @dev Returns the bundle state for the given bundle NFT ID.
function getBundleState(NftId bundleNftId) public view returns (StateId state) {
return getState(_toBundleKey(bundleNftId));
}
//--- distribution functions -------------------------------------------------------//
function getDistributorTypeInfo(DistributorType distributorType) public view returns (IDistribution.DistributorTypeInfo memory info) {
return _store.getDistributorTypeInfo(distributorType);
}
function getDistributorInfo(NftId distributorNftId) public view returns (IDistribution.DistributorInfo memory info) {
return _store.getDistributorInfo(distributorNftId);
}
//--- referral functions -------------------------------------------------------//
function toReferralId(NftId distributionNftId, string memory referralCode) public pure returns (ReferralId referralId) {
return ReferralLib.toReferralId(distributionNftId, referralCode);
}
function isReferralValid(NftId distributionNftId, ReferralId referralId) external view returns (bool isValid) {
return _distributionService.referralIsValid(distributionNftId, referralId);
}
function getReferralInfo(ReferralId referralId) public view returns (IDistribution.ReferralInfo memory info) {
return _store.getReferralInfo(referralId);
}
function getDiscountPercentage(ReferralId referralId)
public
view
returns (
UFixed discountPercentage,
ReferralStatus status
)
{
return IDistributionService(
_registry.getServiceAddress(
DISTRIBUTION(),
_instance.getRelease())).getDiscountPercentage(
this, // instance reader
referralId);
}
//--- authorization functions -------------------------------------------------------//
/// @dev Returns the number of defined roles.
function roles() public view returns (uint256) {
return _instanceAdmin.roles();
}
/// @dev Returns the role ID for the given index.
function getRoleId(uint256 idx) public view returns (RoleId roleId) {
return _instanceAdmin.getRoleId(uint64(idx));
}
/// @dev Returns the role ID for the given index.
function getRoleForName(string memory name) public view returns (RoleId roleId, bool exists) {
return _instanceAdmin.getRoleForName(name);
}
/// @dev Returns the role ID for the instance owner role.
/// This role may be used as a "root" admin role for other custom roles defined for this instance.
function getInstanceOwnerRole() public pure returns (RoleId roleId) {
return INSTANCE_OWNER_ROLE();
}
/// @dev Returns the role info for the given role ID.
function getRoleInfo(RoleId roleId) public view returns (IAccess.RoleInfo memory roleInfo) {
return _instanceAdmin.getRoleInfo(roleId);
}
/// @dev Returns true iff the provided role ID is defined for this instance.
function roleExists(RoleId roleId) public view returns (bool exists) {
return _instanceAdmin.roleExists(roleId);
}
/// @dev Returns true iff the provided role ID represents a custom role ID.
function isRoleCustom(RoleId roleId) public view returns (bool isCustom) {
return _instanceAdmin.isRoleCustom(roleId);
}
/// @dev Returns true iff the provided role ID is active.
function isRoleActive(RoleId roleId) public view returns (bool isActive) {
return _instanceAdmin.isRoleActive(roleId);
}
/// @dev Returns the number of members (accounts) for the given role ID.
function roleMembers(RoleId roleId) public view returns (uint256 numberOfMembers) {
return _instanceAdmin.roleMembers(roleId);
}
/// @dev Returns the member (account address) for the given role ID and index.
function getRoleMember(RoleId roleId, uint256 idx) public view returns (address account) {
return _instanceAdmin.getRoleMember(roleId, idx);
}
/// @dev Returns true iff the given account is a member of the specified role ID.
function isRoleMember(RoleId roleId, address account) public view returns (bool isMember) {
return _instanceAdmin.isRoleMember(roleId, account);
}
/// @dev Returns true iff the given account is an admin of the specified role ID.
/// Role admins may grant and revoke the role to other accounts.
function isRoleAdmin(RoleId roleId, address account) public view returns (bool isMember) {
return _instanceAdmin.isRoleAdmin(roleId, account);
}
/// @dev Returns the number of targets (contracts) defined for this instance.
function targets() public view returns (uint256 targetCount) {
return _instanceAdmin.targets();
}
/// @dev Returns the target address for the given index.
function getTargetAddress(uint256 idx) public view returns (address target) {
return _instanceAdmin.getTargetAddress(idx);
}
/// @dev Returns the target info for the given target address.
function getTargetInfo(address target) public view returns (IAccess.TargetInfo memory targetInfo) {
return _instanceAdmin.getTargetInfo(target);
}
/// @dev Returns true iff the given target is defined for this instance.
function targetExists(address target) public view returns (bool exists) {
return _instanceAdmin.targetExists(target);
}
/// @dev Returns true iff the given target is locked.
function isLocked(address target) public view returns (bool) {
return _instanceAdmin.isTargetLocked(target);
}
/// @dev Returns the number of authorized functions for the given target.
function authorizedFunctions(address target) external view returns (uint256 numberOfFunctions) {
return _instanceAdmin.authorizedFunctions(target);
}
/// @dev Returns the authorized function info for the given target and index.
function getAuthorizedFunction(address target, uint256 idx) external view returns (IAccess.FunctionInfo memory func, RoleId roleId) {
return _instanceAdmin.getAuthorizedFunction(target, idx);
}
/// @dev Returns a function info for the given function signature and function name.
/// The function signature must not be zero and the function name must not be empty.
function toFunction(bytes4 signature, string memory name) public view returns (IAccess.FunctionInfo memory) {
return AccessAdminLib.toFunction(signature, name);
}
//--- low level function ----------------------------------------------------//
function getInstanceAdmin() external view returns (InstanceAdmin instanceAdmin) {
return _instanceAdmin;
}
function getBundleSet() external view returns (BundleSet bundleSet) {
return _bundleSet;
}
function getRiskSet() external view returns (RiskSet riskSet) {
return _riskSet;
}
function getMetadata(Key32 key) public view returns (IBaseStore.Metadata memory metadata) {
return _store.getMetadata(key);
}
function getState(Key32 key) public view returns (StateId state) {
return _store.getState(key);
}
function toInt(UFixed value) public pure returns (uint256) {
return UFixedLib.toInt(value);
}
function toString(Str str) public pure returns (string memory) {
return StrLib.toString(str);
}
function toUFixed(uint256 value, int8 exp) public pure returns (UFixed) {
return UFixedLib.toUFixed(value, exp);
}
//--- internal functions ----------------------------------------------------//
function _toPolicyKey(NftId policyNftId) internal pure returns (Key32) {
return policyNftId.toKey32(POLICY());
}
function _toPremiumKey(NftId policyNftId) internal pure returns (Key32) {
return policyNftId.toKey32(PREMIUM());
}
function _toBundleKey(NftId poolNftId) internal pure returns (Key32) {
return poolNftId.toKey32(BUNDLE());
}
function _toComponentKey(NftId componentNftId) internal pure returns (Key32) {
return componentNftId.toKey32(COMPONENT());
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {IBundle} from "./module/IBundle.sol";
import {IComponents} from "./module/IComponents.sol";
import {IDistribution} from "./module/IDistribution.sol";
import {IInstance} from "./IInstance.sol";
import {IOracle} from "../oracle/IOracle.sol";
import {Amount} from "../type/Amount.sol";
import {BaseStore} from "./BaseStore.sol";
import {Blocknumber} from "../type/Blocknumber.sol";
import {Key32} from "../type/Key32.sol";
import {NftId} from "../type/NftId.sol";
import {ClaimId} from "../type/ClaimId.sol";
import {ObjectType, BUNDLE, POOL, COMPONENT, DISTRIBUTOR} from "../type/ObjectType.sol";
import {RequestId} from "../type/RequestId.sol";
import {StateId} from "../type/StateId.sol";
import {ReferralId} from "../type/Referral.sol";
import {DistributorType} from "../type/DistributorType.sol";
import {PayoutId} from "../type/PayoutId.sol";
import {BalanceStore} from "./base/BalanceStore.sol";
import {ObjectCounter} from "./base/ObjectCounter.sol";
import {ObjectLifecycle} from "./base/ObjectLifecycle.sol";
contract InstanceStore is
AccessManagedUpgradeable,
BalanceStore,
ObjectCounter,
ObjectLifecycle,
BaseStore
{
event LogProductStoreComponentInfoCreated(NftId componentNftId, StateId state, address createdby, address txOrigin);
event LogProductStoreComponentInfoUpdated(NftId componentNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStorePoolInfoCreated(NftId poolNftId, StateId state, address createdBy, address txOrigin);
event LogProductStorePoolInfoUpdated(NftId poolNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreDistributorTypeInfoCreated(DistributorType distributorType, StateId state, address createdBy, address txOrigin);
event LogProductStoreDistributorTypeInfoUpdated(DistributorType distributorType, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreDistributorInfoCreated(NftId distributorNftId, StateId state, address createdBy, address txOrigin);
event LogProductStoreDistributorInfoUpdated(NftId distributorNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreReferralInfoCreated(ReferralId referralId, StateId state, address createdBy, address txOrigin);
event LogProductStoreReferralInfoUpdated(ReferralId referralId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreBundleInfoCreated(NftId bundleNftId, StateId state, address createdBy, address txOrigin);
event LogProductStoreBundleInfoUpdated(NftId bundleNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreRequestInfoCreated(RequestId requestId, StateId state, address createdBy, address txOrigin);
event LogProductStoreRequestInfoUpdated(RequestId requestId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
mapping(Key32 => IComponents.ComponentInfo) private _components;
mapping(Key32 => IComponents.PoolInfo) private _pools;
mapping(Key32 => IDistribution.DistributorTypeInfo) private _distributorTypes;
mapping(Key32 => IDistribution.DistributorInfo) private _distributors;
mapping(Key32 => IDistribution.ReferralInfo) private _referrals;
mapping(Key32 => IBundle.BundleInfo) private _bundles;
mapping(Key32 => IOracle.RequestInfo) private _requests;
/// @dev This initializer needs to be called from the instance itself.
function initialize()
public
initializer()
{
address instance = msg.sender;
address authority = IInstance(instance).authority();
__AccessManaged_init(authority);
// double initialization, safe
_initializeLifecycle();
}
//--- Component ---------------------------------------------------------//
function createComponent(
NftId componentNftId,
IComponents.ComponentInfo memory componentInfo
)
external
restricted()
{
_registerBalanceTarget(componentNftId);
// _create(_toNftKey32(componentNftId, COMPONENT()), abi.encode(componentInfo));
Key32 key = _toNftKey32(componentNftId, COMPONENT());
_createMetadata(key);
_components[key] = componentInfo;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreComponentInfoCreated(componentNftId, getState(key), msg.sender, tx.origin);
}
function updateComponent(
NftId componentNftId,
IComponents.ComponentInfo memory componentInfo,
StateId newState
)
external
restricted()
{
// _update(_toNftKey32(componentNftId, COMPONENT()), abi.encode(componentInfo), newState);
Key32 key = _toNftKey32(componentNftId, COMPONENT());
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_components[key] = componentInfo;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreComponentInfoUpdated(componentNftId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getComponentInfo(NftId componentNftId) external view returns (IComponents.ComponentInfo memory componentInfo) {
return _components[_toNftKey32(componentNftId, COMPONENT())];
}
//--- Pool --------------------------------------------------------------//
function createPool(
NftId poolNftId,
IComponents.PoolInfo memory info
)
external
restricted()
{
Key32 key = _toNftKey32(poolNftId, POOL());
_createMetadata(key);
_pools[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePoolInfoCreated(poolNftId, getState(key), msg.sender, tx.origin);
}
function updatePool(NftId poolNftId, IComponents.PoolInfo memory info, StateId newState) external restricted() {
Key32 key = _toNftKey32(poolNftId, POOL());
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_pools[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePoolInfoUpdated(poolNftId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getPoolInfo(NftId poolNftId) external view returns (IComponents.PoolInfo memory info) {
return _pools[_toNftKey32(poolNftId, POOL())];
}
//--- DistributorType ---------------------------------------------------//
function createDistributorType(DistributorType distributorType, IDistribution.DistributorTypeInfo memory info) external restricted() {
Key32 key = distributorType.toKey32();
_createMetadata(key);
_distributorTypes[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreDistributorTypeInfoCreated(distributorType, getState(key), msg.sender, tx.origin);
}
function updateDistributorType(DistributorType distributorType, IDistribution.DistributorTypeInfo memory info, StateId newState) external restricted() {
Key32 key = distributorType.toKey32();
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_distributorTypes[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreDistributorTypeInfoUpdated(distributorType, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function updateDistributorTypeState(DistributorType distributorType, StateId newState) external restricted() {
Key32 key = distributorType.toKey32();
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreDistributorTypeInfoUpdated(distributorType, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getDistributorTypeInfo(DistributorType distributorType) external view returns (IDistribution.DistributorTypeInfo memory info) {
return _distributorTypes[distributorType.toKey32()];
}
//--- Distributor -------------------------------------------------------//
function createDistributor(NftId distributorNftId, IDistribution.DistributorInfo memory info) external restricted() {
_registerBalanceTarget(distributorNftId);
Key32 key = _toNftKey32(distributorNftId, DISTRIBUTOR());
_createMetadata(key);
_distributors[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreDistributorInfoCreated(distributorNftId, getState(key), msg.sender, tx.origin);
}
function updateDistributor(NftId distributorNftId, IDistribution.DistributorInfo memory info, StateId newState) external restricted() {
Key32 key = _toNftKey32(distributorNftId, DISTRIBUTOR());
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_distributors[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreDistributorInfoUpdated(distributorNftId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function updateDistributorState(NftId distributorNftId, StateId newState) external restricted() {
Key32 key = _toNftKey32(distributorNftId, DISTRIBUTOR());
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreDistributorInfoUpdated(distributorNftId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getDistributorInfo(NftId distributorNftId) external view returns (IDistribution.DistributorInfo memory info) {
return _distributors[_toNftKey32(distributorNftId, DISTRIBUTOR())];
}
//--- Referral ----------------------------------------------------------//
function createReferral(ReferralId referralId, IDistribution.ReferralInfo memory referralInfo) external restricted() {
Key32 key = referralId.toKey32();
_createMetadata(key);
_referrals[key] = referralInfo;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreReferralInfoCreated(referralId, getState(key), msg.sender, tx.origin);
}
function updateReferral(ReferralId referralId, IDistribution.ReferralInfo memory referralInfo, StateId newState) external restricted() {
Key32 key = referralId.toKey32();
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_referrals[key] = referralInfo;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreReferralInfoUpdated(referralId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function updateReferralState(ReferralId referralId, StateId newState) external restricted() {
Key32 key = referralId.toKey32();
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreReferralInfoUpdated(referralId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getReferralInfo(ReferralId referralId) external view returns (IDistribution.ReferralInfo memory referralInfo) {
return _referrals[referralId.toKey32()];
}
//--- Bundle ------------------------------------------------------------//
function createBundle(NftId bundleNftId, IBundle.BundleInfo memory bundle) external restricted() {
_registerBalanceTarget(bundleNftId);
Key32 key = _toNftKey32(bundleNftId, BUNDLE());
_createMetadata(key);
_bundles[key] = bundle;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreBundleInfoCreated(bundleNftId, getState(key), msg.sender, tx.origin);
}
function updateBundle(NftId bundleNftId, IBundle.BundleInfo memory bundle, StateId newState) external restricted() {
Key32 key = _toNftKey32(bundleNftId, BUNDLE());
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_bundles[key] = bundle;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreBundleInfoUpdated(bundleNftId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function updateBundleState(NftId bundleNftId, StateId newState) external restricted() {
Key32 key = _toNftKey32(bundleNftId, BUNDLE());
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreBundleInfoUpdated(bundleNftId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getBundleInfo(NftId bundleNftId) external view returns (IBundle.BundleInfo memory bundle) {
return _bundles[_toNftKey32(bundleNftId, BUNDLE())];
}
//--- Request -----------------------------------------------------------//
function createRequest(IOracle.RequestInfo memory request) external restricted() returns (RequestId requestId) {
requestId = _createNextRequestId();
Key32 key = requestId.toKey32();
_createMetadata(key);
_requests[key] = request;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreRequestInfoCreated(requestId, getState(key), msg.sender, tx.origin);
}
function updateRequest(RequestId requestId, IOracle.RequestInfo memory request, StateId newState) external restricted() {
Key32 key = requestId.toKey32();
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
_requests[key] = request;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreRequestInfoUpdated(requestId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function updateRequestState(RequestId requestId, StateId newState) external restricted() {
Key32 key = requestId.toKey32();
(Blocknumber updatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreRequestInfoUpdated(requestId, oldState, newState, msg.sender, tx.origin, updatedIn);
}
function getRequestInfo(RequestId requestId) external view returns (IOracle.RequestInfo memory request) {
return _requests[requestId.toKey32()];
}
//--- balance and fee management functions ------------------------------//
function increaseBalance(NftId targetNftId, Amount amount) external restricted() returns (Amount newBalance) {
return _increaseBalance(targetNftId, amount);
}
function decreaseBalance(NftId targetNftId, Amount amount) external restricted() returns (Amount newBalance) {
return _decreaseBalance(targetNftId, amount);
}
function increaseFees(NftId targetNftId, Amount amount) external restricted() returns (Amount newFeeBalance) {
return _increaseFees(targetNftId, amount);
}
function decreaseFees(NftId targetNftId, Amount amount) external restricted() returns (Amount newFeeBalance) {
return _decreaseFees(targetNftId, amount);
}
function increaseLocked(NftId targetNftId, Amount amount) external restricted() returns (Amount newBalance) {
return _increaseLocked(targetNftId, amount);
}
function decreaseLocked(NftId targetNftId, Amount amount) external restricted() returns (Amount newBalance) {
return _decreaseLocked(targetNftId, amount);
}
//--- internal view/pure functions --------------------------------------//
function _toNftKey32(NftId nftId, ObjectType objectType) private pure returns (Key32) {
return nftId.toKey32(objectType);
}
function _toClaimKey32(NftId policyNftId, ClaimId claimId) private pure returns (Key32) {
return claimId.toKey32(policyNftId);
}
function _toPayoutKey32(NftId policyNftId, PayoutId payoutId) private pure returns (Key32) {
return payoutId.toKey32(policyNftId);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {NftId} from "../../type/NftId.sol";
import {Fee} from "../../type/Fee.sol";
import {Timestamp} from "../../type/Timestamp.sol";
interface IBundle {
struct BundleInfo {
// slot 0
Timestamp activatedAt;
Timestamp expiredAt; // no new policies starting with this timestamp
Timestamp closedAt; // no open policies, locked amount = 0
NftId poolNftId;
// slot 1
Fee fee; // bundle fee on net premium amounts
// slot 2
bytes filter; // required conditions for applications to be considered for collateralization by this bundle
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount} from "../../type/Amount.sol";
import {Fee} from "../../type/Fee.sol";
import {NftId} from "../../type/NftId.sol";
import {TokenHandler} from "../../shared/TokenHandler.sol";
import {UFixed} from "../../type/UFixed.sol";
interface IComponents {
struct ComponentInfo {
// slot 0
string name; // component name (needs to be unique per instance)
// slot 1
TokenHandler tokenHandler;
}
struct ProductInfo {
// slot 0
bool isProcessingFundedClaims; // custom logic to react to pool events for funded claims
bool isInterceptingPolicyTransfers; // custom logic for policy nft transfers
bool hasDistribution; // flag to indicate if distribution is enabled
uint8 expectedNumberOfOracles; // expected number of oracles
uint8 numberOfOracles; // actual number of oracles
NftId poolNftId; // mandatory
NftId distributionNftId; // 0..1 (optional)
// slot 1
NftId [] oracleNftId; // 0..n (optional)
}
struct FeeInfo {
// slot 0
Fee productFee; // product fee on net premium
// slot 1
Fee processingFee; // product fee on payout amounts
// slot 2
Fee distributionFee; // distribution fee for sales that do not include commissions
// slot 3
Fee minDistributionOwnerFee; // min fee required by distribution owner (not including commissions for distributors)
// slot 4
Fee poolFee; // pool fee on net premium
// slot 5
Fee stakingFee; // pool fee on staked capital from investor
// slot 6
Fee performanceFee; // pool fee on profits from capital investors
}
struct PoolInfo {
// slot 0
Amount maxBalanceAmount; // max balance amount allowed for pool
UFixed collateralizationLevel; // factor to calculate collateral for sum insurance (default 100%)
// slot 1
UFixed retentionLevel; // amount of collateral held in pool (default 100%)
bool isInterceptingBundleTransfers; // custom logic for bundle nft transfers
bool isProcessingConfirmedClaims; // custom logic for claims confirmation
bool isExternallyManaged; // funding bundles is restricted to book keeping, actual funds may be provided as needed to support payouts
bool isVerifyingApplications; // underwriting requires the pool component checks/confirms the applications
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {DistributorType} from "../../type/DistributorType.sol";
import {NftId} from "../../type/NftId.sol";
import {Seconds} from "../../type/Seconds.sol";
import {Timestamp} from "../../type/Timestamp.sol";
import {UFixed} from "../../type/UFixed.sol";
interface IDistribution {
struct DistributorTypeInfo {
// slot 0
UFixed minDiscountPercentage;
NftId distributionNftId;
// slot 1
UFixed maxDiscountPercentage;
uint32 maxReferralCount;
Seconds maxReferralLifetime;
bool allowSelfReferrals;
bool allowRenewals;
// slot 2
UFixed commissionPercentage;
// slot 3
string name;
// slot 4
bytes data;
}
struct DistributorInfo {
// slot 0
DistributorType distributorType;
bool active;
uint32 numPoliciesSold;
// slot 1
bytes data;
}
struct ReferralInfo {
// slot 0
NftId distributionNftId;
NftId distributorNftId;
uint32 maxReferrals;
uint32 usedReferrals;
// slot 1
UFixed discountPercentage;
Timestamp expiryAt;
// slot 2
string referralCode;
// slot 3
bytes data;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount} from "../../type/Amount.sol";
import {NftId} from "../../type/NftId.sol";
import {ClaimId} from "../../type/ClaimId.sol";
import {ReferralId} from "../../type/Referral.sol";
import {RiskId} from "../../type/RiskId.sol";
import {Seconds} from "../../type/Seconds.sol";
import {Timestamp} from "../../type/Timestamp.sol";
interface IPolicy {
struct PremiumInfo {
// slot 0
// premium splitting per target wallet
Amount productFeeAmount;
Amount distributionFeeAndCommissionAmount;
// slot 1
Amount poolPremiumAndFeeAmount;
// detailed positions
// this is the net premium calculated by the product
Amount netPremiumAmount;
// slot 2
// fullPremium = netPremium + all fixed amounts + all variable amounts (excl commission and minDistribtuionOwnerFee variable part)
Amount fullPremiumAmount;
// effective premium = fullPremium - discount
Amount premiumAmount;
// slot 3
Amount productFeeFixAmount;
Amount poolFeeFixAmount;
// slot 4
Amount bundleFeeFixAmount;
Amount distributionFeeFixAmount;
// slot 5
Amount productFeeVarAmount;
Amount poolFeeVarAmount;
// slot 6
Amount bundleFeeVarAmount;
Amount distributionFeeVarAmount;
// slot 7
Amount distributionOwnerFeeFixAmount;
// this is the remaining amount when the commission and discount are subtracted from the distribution fee variable part (must be at least the minDistributionOwnerFee)
Amount distributionOwnerFeeVarAmount;
// slot 8
// this value is based on distributor type referenced in the referral
Amount commissionAmount;
// this is based on referral used
Amount discountAmount;
}
/// @dev policy data for the full policy lifecycle
struct PolicyInfo {
// slot 0
NftId productNftId;
NftId bundleNftId;
RiskId riskId;
// slot 1
Amount sumInsuredAmount;
Amount premiumAmount; // expected premium at application time
ReferralId referralId;
// slot 2
uint16 claimsCount;
uint16 openClaimsCount;
Amount claimAmount; // sum of confirmed claim amounts (max = sum insured amount)
Amount payoutAmount; // sum of payouts (max = sum confirmed claim amountst)
// slot 3
Timestamp activatedAt; // time of underwriting
Seconds lifetime;
Timestamp expiredAt; // no new claims (activatedAt + lifetime)
Timestamp closedAt; // no locked capital (or declinedAt)
// slot 4
bytes applicationData;
// slot 5
bytes processData;
}
// claimId neeeds to be encoded policyNftId:claimId combination
struct ClaimInfo {
// slot 0
Amount claimAmount;
Amount paidAmount;
Timestamp closedAt; // payment of confirmed claim amount (or declinedAt)
uint24 payoutsCount;
// slot 1
uint24 openPayoutsCount;
// slot 2
bytes submissionData; // use case specific claim submission data, no changes after submitting the claim
// slot 3
bytes processData; // use case specific data that may include information supporting confirm or decline
}
// claimId neeeds to be encoded policyNftId:claimId combination
struct PayoutInfo {
// slot 0
ClaimId claimId;
Amount amount;
Timestamp paidAt; // timestamp for actual payout
// slot 1
address beneficiary; // for address(0) beneficiary is policy nft owner
// slot 2
bytes data; // use case specific supporting data
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {NftId} from "../../type/NftId.sol";
import {Timestamp} from "../../type/Timestamp.sol";
interface IRisk {
struct RiskInfo {
// slot 0
NftId productNftId;
Timestamp createdAt;
// slot 1
bytes data;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {IComponents} from "./module/IComponents.sol";
import {IInstance} from "./IInstance.sol";
import {IPolicy} from "./module/IPolicy.sol";
import {IRisk} from "./module/IRisk.sol";
import {BalanceStore} from "./base/BalanceStore.sol";
import {BaseStore} from "./BaseStore.sol";
import {Blocknumber} from "../type/Blocknumber.sol";
import {ClaimId} from "../type/ClaimId.sol";
import {Key32} from "../type/Key32.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectCounter} from "./base/ObjectCounter.sol";
import {ObjectLifecycle} from "./base/ObjectLifecycle.sol";
import {ObjectType, FEE, POLICY, PREMIUM, PRODUCT} from "../type/ObjectType.sol";
import {PayoutId} from "../type/PayoutId.sol";
import {RiskId} from "../type/RiskId.sol";
import {StateId, KEEP_STATE} from "../type/StateId.sol";
contract ProductStore is
AccessManagedUpgradeable,
BalanceStore,
BaseStore,
ObjectCounter,
ObjectLifecycle
{
event LogProductStoreProductInfoCreated(NftId productNftId, StateId state, address createdBy, address txOrigin);
event LogProductStoreProductInfoUpdated(NftId productNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreFeeInfoCreated(NftId productNftId, StateId state, address createdBy, address txOrigin);
event LogProductStoreFeeInfoUpdated(NftId productNftId, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreRiskInfoCreated(RiskId riskId, StateId state, address createdBy, address txOrigin);
event LogProductStoreRiskInfoUpdated(RiskId riskId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStorePolicyInfoCreated(NftId policyNftId, StateId state, address createdBy, address txOrigin);
event LogProductStorePolicyInfoUpdated(NftId policyNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStorePremiumInfoCreated(NftId policyNftId, StateId state, address createdBy, address txOrigin);
event LogProductStorePremiumInfoUpdated(NftId policyNftId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStoreClaimInfoCreated(NftId policyNftId, ClaimId claimId, StateId state, address createdBy, address txOrigin);
event LogProductStoreClaimInfoUpdated(NftId policyNftId, ClaimId claimId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
event LogProductStorePayoutInfoCreated(NftId policyNftId, PayoutId payoutId, StateId state, address createdBy, address txOrigin);
event LogProductStorePayoutInfoUpdated(NftId policyNftId, PayoutId payoutId, StateId oldState, StateId newState, address updatedBy, address txOrigin, Blocknumber lastUpdatedIn);
mapping(Key32 key32 => IComponents.ProductInfo) private _products;
mapping(Key32 key32 => IComponents.FeeInfo) private _fees;
mapping(Key32 key32 => IRisk.RiskInfo) private _risks;
mapping(Key32 key32 => IPolicy.PolicyInfo) private _policies;
mapping(Key32 key32 => IPolicy.PremiumInfo) private _premiums;
mapping(Key32 key32 => IPolicy.ClaimInfo) private _claims;
mapping(Key32 key32 => IPolicy.PayoutInfo) private _payouts;
/// @dev This initializer needs to be called from the instance itself.
function initialize()
public
initializer()
{
address instance = msg.sender;
address authority = IInstance(instance).authority();
__AccessManaged_init(authority);
// double initialization, safe
_initializeLifecycle();
}
//--- Product -----------------------------------------------------------//
function createProduct(NftId productNftId, IComponents.ProductInfo memory info) external restricted() {
Key32 key = _toNftKey32(productNftId, PRODUCT());
_createMetadata(key);
_products[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreProductInfoCreated(productNftId, getState(key), msg.sender, tx.origin);
}
function updateProduct(NftId productNftId, IComponents.ProductInfo memory info, StateId newState) external restricted() {
Key32 key = _toNftKey32(productNftId, PRODUCT());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_products[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreProductInfoUpdated(productNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function getProductInfo(NftId productNftId) external view returns (IComponents.ProductInfo memory info) {
return _products[_toNftKey32(productNftId, PRODUCT())];
}
//--- Fee -----------------------------------------------------------//
function createFee(NftId productNftId, IComponents.FeeInfo memory info) external restricted() {
Key32 key = _toNftKey32(productNftId, FEE());
_createMetadata(key);
_fees[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreFeeInfoCreated(productNftId, getState(key), msg.sender, tx.origin);
}
// Fee only has one state, so no change change possible
function updateFee(NftId productNftId, IComponents.FeeInfo memory info) external restricted() {
Key32 key = _toNftKey32(productNftId, FEE());
(Blocknumber lastUpdatedIn,) = _updateState(key, KEEP_STATE());
_fees[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreFeeInfoUpdated(productNftId, msg.sender, tx.origin, lastUpdatedIn);
}
function getFeeInfo(NftId productNftId) external view returns (IComponents.FeeInfo memory info) {
return _fees[_toNftKey32(productNftId, FEE())];
}
//--- Risk --------------------------------------------------------------//
function createRisk(RiskId riskId, IRisk.RiskInfo memory info) external restricted() {
Key32 key = riskId.toKey32();
_createMetadata(key);
_risks[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreRiskInfoCreated(riskId, getState(key), msg.sender, tx.origin);
}
function updateRisk(RiskId riskId, IRisk.RiskInfo memory info, StateId newState) external restricted() {
Key32 key = riskId.toKey32();
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_risks[key] = info;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreRiskInfoUpdated(riskId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function updateRiskState(RiskId riskId, StateId newState) external restricted() {
// _updateState(riskId.toKey32(), newState);
Key32 key = riskId.toKey32();
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreRiskInfoUpdated(riskId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function getRiskInfo(RiskId riskId) external view returns (IRisk.RiskInfo memory info) {
return _risks[riskId.toKey32()];
}
//--- Application (Policy) ----------------------------------------------//
function createApplication(NftId applicationNftId, IPolicy.PolicyInfo memory policy) external restricted() {
_registerBalanceTarget(applicationNftId);
Key32 key = _toNftKey32(applicationNftId, POLICY());
_createMetadata(key);
_policies[key] = policy;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePolicyInfoCreated(applicationNftId, getState(key), msg.sender, tx.origin);
}
function updateApplication(NftId applicationNftId, IPolicy.PolicyInfo memory policy, StateId newState) external restricted() {
Key32 key = _toNftKey32(applicationNftId, POLICY());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_policies[key] = policy;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePolicyInfoUpdated(applicationNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function updateApplicationState(NftId applicationNftId, StateId newState) external restricted() {
Key32 key = _toNftKey32(applicationNftId, POLICY());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePolicyInfoUpdated(applicationNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
//--- Policy ------------------------------------------------------------//
function updatePolicy(NftId policyNftId, IPolicy.PolicyInfo memory policy, StateId newState) external restricted() {
Key32 key = _toNftKey32(policyNftId, POLICY());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_policies[key] = policy;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePolicyInfoUpdated(policyNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function updatePolicyClaims(NftId policyNftId, IPolicy.PolicyInfo memory policy, StateId newState) external restricted() {
Key32 key = _toNftKey32(policyNftId, POLICY());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_policies[key] = policy;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePolicyInfoUpdated(policyNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function updatePolicyState(NftId policyNftId, StateId newState) external restricted() {
Key32 key = _toNftKey32(policyNftId, POLICY());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePolicyInfoUpdated(policyNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function getPolicyInfo(NftId policyNftId) external view returns (IPolicy.PolicyInfo memory policy) {
return _policies[_toNftKey32(policyNftId, POLICY())];
}
//--- Premium (Policy) ----------------------------------------------//
function createPremium(NftId policyNftId, IPolicy.PremiumInfo memory premium) external restricted() {
Key32 key = _toNftKey32(policyNftId, PREMIUM());
_createMetadata(key);
_premiums[key] = premium;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePremiumInfoCreated(policyNftId, getState(key), msg.sender, tx.origin);
}
function updatePremiumState(NftId policyNftId, StateId newState) external restricted() {
Key32 key = _toNftKey32(policyNftId, PREMIUM());
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePremiumInfoUpdated(policyNftId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function getPremiumInfo(NftId policyNftId) external view returns (IPolicy.PremiumInfo memory premium) {
return _premiums[_toNftKey32(policyNftId, PREMIUM())];
}
//--- Claim -------------------------------------------------------------//
function createClaim(NftId policyNftId, ClaimId claimId, IPolicy.ClaimInfo memory claim) external restricted() {
Key32 key = _toClaimKey32(policyNftId, claimId);
_createMetadata(key);
_claims[key] = claim;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreClaimInfoCreated(policyNftId, claimId, getState(key), msg.sender, tx.origin);
}
function updateClaim(NftId policyNftId, ClaimId claimId, IPolicy.ClaimInfo memory claim, StateId newState) external restricted() {
Key32 key = _toClaimKey32(policyNftId, claimId);
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_claims[key] = claim;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreClaimInfoUpdated(policyNftId, claimId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function updateClaimState(NftId policyNftId, ClaimId claimId, StateId newState) external restricted() {
Key32 key = _toClaimKey32(policyNftId, claimId);
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStoreClaimInfoUpdated(policyNftId, claimId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function getClaimInfo(NftId policyNftId, ClaimId claimId) external view returns (IPolicy.ClaimInfo memory claim) {
return _claims[_toClaimKey32(policyNftId, claimId)];
}
//--- Payout ------------------------------------------------------------//
function createPayout(NftId policyNftId, PayoutId payoutId, IPolicy.PayoutInfo memory payout) external restricted() {
Key32 key = _toPayoutKey32(policyNftId, payoutId);
_createMetadata(key);
_payouts[key] = payout;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePayoutInfoCreated(policyNftId, payoutId, getState(key), msg.sender, tx.origin);
}
function updatePayout(NftId policyNftId, PayoutId payoutId, IPolicy.PayoutInfo memory payout, StateId newState) external restricted() {
Key32 key = _toPayoutKey32(policyNftId, payoutId);
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
_payouts[key] = payout;
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePayoutInfoUpdated(policyNftId, payoutId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function updatePayoutState(NftId policyNftId, PayoutId payoutId, StateId newState) external restricted() {
Key32 key = _toPayoutKey32(policyNftId, payoutId);
(Blocknumber lastUpdatedIn, StateId oldState) = _updateState(key, newState);
// solhint-disable-next-line avoid-tx-origin
emit LogProductStorePayoutInfoUpdated(policyNftId, payoutId, oldState, newState, msg.sender, tx.origin, lastUpdatedIn);
}
function getPayoutInfo(NftId policyNftId, PayoutId payoutId) external view returns (IPolicy.PayoutInfo memory payout) {
return _payouts[_toPayoutKey32(policyNftId, payoutId)];
}
//--- internal view/pure functions --------------------------------------//
function _toNftKey32(NftId nftId, ObjectType objectType) private pure returns (Key32) {
return nftId.toKey32(objectType);
}
function _toClaimKey32(NftId policyNftId, ClaimId claimId) private pure returns (Key32) {
return claimId.toKey32(policyNftId);
}
function _toPayoutKey32(NftId policyNftId, PayoutId payoutId) private pure returns (Key32) {
return payoutId.toKey32(policyNftId);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32} from "../type/Key32.sol";
import {LibNftIdSet} from "../type/NftIdSet.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectSet} from "./base/ObjectSet.sol";
import {ObjectSetHelperLib} from "./base/ObjectSetHelperLib.sol";
import {RiskIdLib, RiskId} from "../type/RiskId.sol";
/// @dev RiskSet manages the risks and its active policies per product.
contract RiskSet is
ObjectSet
{
event LogRiskSetPolicyLinked(RiskId riskId, NftId policyNftId);
event LogRiskSetPolicyUnlinked(RiskId riskId, NftId policyNftId);
event LogRiskSetRiskAdded(NftId productNftId, RiskId riskId);
event LogRiskSetRiskActive(NftId poolNftId, RiskId riskId);
event LogRiskSetRiskPaused(NftId poolNftId, RiskId riskId);
error ErrorRiskSetRiskLocked(RiskId riskId, NftId policyNftId);
error ErrorRiskSetRiskUnknown(RiskId riskId);
error ErrorRiskSetRiskNotRegistered(RiskId riskId);
mapping(RiskId riskId => LibNftIdSet.Set policies) internal _activePolicies;
/// @dev links a policy to its bundle
function linkPolicy(NftId productNftId, RiskId riskId, NftId policyNftId) external restricted() {
// ensure risk is active (in active set) and registered with this instance
if (!_isActive(productNftId, riskId.toKey32())) {
revert ErrorRiskSetRiskLocked(riskId, policyNftId);
}
LibNftIdSet.add(_activePolicies[riskId], policyNftId);
emit LogRiskSetPolicyLinked(riskId, policyNftId);
}
/// @dev Unlinks a policy from its risk.
function unlinkPolicy(NftId productNftId, RiskId riskId, NftId policyNftId) external restricted() {
// ensure risk is registered with this instance
if (!_contains(productNftId, riskId.toKey32())) {
revert ErrorRiskSetRiskUnknown(riskId);
}
LibNftIdSet.remove(_activePolicies[riskId], policyNftId);
emit LogRiskSetPolicyUnlinked(riskId, policyNftId);
}
/// @dev add a new risk to a product registered with this instance
// the corresponding product is fetched via instance reader
function add(RiskId riskId) external restricted() {
NftId productNftId = ObjectSetHelperLib.getProductNftId(_instanceAddress, riskId);
// ensure product is registered with instance
if(productNftId.eqz()) {
revert ErrorRiskSetRiskNotRegistered(riskId);
}
_add(productNftId, riskId.toKey32());
emit LogRiskSetRiskAdded(productNftId, riskId);
}
/// @dev Applications linked to active risks may be underwritten
function activate(RiskId riskId) external restricted() {
NftId productNftId = ObjectSetHelperLib.getProductNftId(_instanceAddress, riskId);
_activate(productNftId, riskId.toKey32());
emit LogRiskSetRiskActive(productNftId, riskId);
}
/// @dev Applications linked to paused/archived risks may not be underwritten
function deactivate(RiskId riskId) external restricted() {
NftId productNftId = ObjectSetHelperLib.getProductNftId(_instanceAddress, riskId);
_deactivate(productNftId, riskId.toKey32());
emit LogRiskSetRiskPaused(productNftId, riskId);
}
function checkRisk(NftId productNftId, RiskId riskId)
public
view
returns (bool exists, bool active)
{
Key32 riskKey32 = riskId.toKey32();
exists = _contains(productNftId, riskKey32);
if (exists) {
active = _isActive(productNftId, riskKey32);
}
}
function hasRisk(NftId productNftId, RiskId riskId)
public
view
returns (bool)
{
Key32 riskKey32 = riskId.toKey32();
return _contains(productNftId, riskKey32);
}
function risks(NftId productNftId) external view returns(uint256) {
return _objects(productNftId);
}
function getRiskId(NftId productNftId, uint256 idx) external view returns(RiskId riskId) {
return RiskIdLib.toRiskId(_getObject(productNftId, idx).toKeyId());
}
function activeRisks(NftId productNftId) external view returns(uint256) {
return _activeObjs(productNftId);
}
function getActiveRiskId(NftId productNftId, uint256 idx) external view returns(RiskId riskId) {
return RiskIdLib.toRiskId(_getActiveObject(productNftId, idx).toKeyId());
}
function linkedPolicies(RiskId riskId) external view returns(uint256) {
return LibNftIdSet.size(_activePolicies[riskId]);
}
function getLinkedPolicyNftId(RiskId riskId, uint256 idx) external view returns(NftId policyNftId) {
return LibNftIdSet.getElementAt(_activePolicies[riskId], idx);
}
}// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; string constant INSTANCE_TARGET_NAME = "Instance"; string constant INSTANCE_ADMIN_TARGET_NAME = "InstanceAdmin"; string constant INSTANCE_STORE_TARGET_NAME = "InstanceStore"; string constant PRODUCT_STORE_TARGET_NAME = "ProductStore"; string constant BUNDLE_SET_TARGET_NAME = "BundleSet"; string constant RISK_SET_TARGET_NAME = "RiskSet";
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAuthorization} from "../../contracts/authorization/IAuthorization.sol";
import {NftId} from "../../contracts/type/NftId.sol";
import {Oracle} from "../../contracts/oracle/Oracle.sol";
import {RequestId} from "../../contracts/type/RequestId.sol";
contract BasicOracle is
Oracle
{
/// Function to provide reponse data releated to request id.
function respond(
RequestId requestId,
bytes memory responseData
)
external
virtual
restricted()
{
_respond(requestId, responseData);
}
function _initializeBasicOracle(
address registry,
NftId instanceNftId,
IAuthorization authorization,
address initialOwner,
string memory name
)
internal
virtual
onlyInitializing()
{
__Oracle_init(
registry,
instanceNftId,
authorization,
initialOwner,
name);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {NftId} from "../type/NftId.sol";
import {RequestId} from "../type/RequestId.sol";
import {Timestamp} from "../type/Timestamp.sol";
interface IOracle {
struct RequestInfo {
// slot 0
NftId requesterNftId; // originator of the request
NftId oracleNftId; // responsible oracle component
bool isCancelled;
Timestamp respondedAt; // response timestamp
// slot 1
Timestamp expiredAt; // expiry timestamp
// slot 2
string callbackMethodName; // callback function of the requestor to call to provide response data
// slot 3
bytes requestData;
// slot 4
bytes responseData;
}
/// @dev Callback function for oracle service to notify this oracle component to retreive some oracle data.
function request(
RequestId requestId,
NftId requesterId,
bytes calldata requestData,
Timestamp expiryAt
) external;
/// @dev Callback function for oracle service to notify this oracle component that the specified oracle request has ben cancelled by the requestor.
function cancel(
RequestId requestId
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Fee} from "../type/Fee.sol";
import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol";
import {ReferralId, ReferralStatus} from "../type/Referral.sol";
import {NftId} from "../type/NftId.sol";
import {DistributorType} from "../type/DistributorType.sol";
import {RequestId} from "../type/RequestId.sol";
import {UFixed} from "../type/UFixed.sol";
import {Timestamp} from "../type/Timestamp.sol";
interface IOracleComponent is IInstanceLinkedComponent {
error ErrorOracleNotImplemented(string methodName);
/// @dev callback method for requesting some data from the oracle
function request(
RequestId requestId,
NftId requesterNftId,
bytes calldata requestData,
Timestamp expiryAt
) external;
/// @dev callback method for cancelling the specified oracle request
function cancel(
RequestId requestId
) external;
/// @dev returns true iff the component needs to be called when selling/renewing policis
function isVerifying() external view returns (bool verifying);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IService} from "../shared/IService.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RequestId} from "../type/RequestId.sol";
import {StateId} from "../type/StateId.sol";
import {Timestamp} from "../type/Timestamp.sol";
interface IOracleService is IService {
event LogOracleServiceRequestCreated(RequestId requestId, NftId requesterNftId, NftId oracleNftId, Timestamp expiryAt);
event LogOracleServiceResponseProcessed(RequestId requestId, NftId oracleNftId);
event LogOracleServiceDeliveryFailed(RequestId requestId, address requesterAddress, string functionSignature);
event LogOracleServiceResponseResent(RequestId requestId, NftId requesterNftId);
event LogOracleServiceRequestCancelled(RequestId requestId, NftId requesterNftId);
// create request
error ErrorOracleServiceProductMismatch(ObjectType callerObjectType, NftId productNft, NftId oracleParentNftId);
error ErrorOracleServiceExpiryInThePast(Timestamp blockTimestamp, Timestamp expiryAt);
error ErrorOracleServiceCallbackMethodNameEmpty();
// respond
error ErrorOracleServiceNotResponsibleOracle(RequestId requestId, NftId expectedOracleNftId, NftId oracleNftId);
// get request info
error ErrorOracleServiceRequestStateNotActive(RequestId requestId, StateId state);
error ErrorOracleServiceCallerNotResponsibleOracle(RequestId requestId, NftId oracleNftId, NftId callerNftId);
error ErrorOracleServiceCallerNotRequester(RequestId requestId, NftId requesterNftId, NftId callerNftId);
error ErrorOracleServiceRequestExpired(RequestId requestId, Timestamp expiredAt);
/// @dev send an oracle request to the specified oracle component.
/// the function returns the id of the newly created request.
/// permissioned: only registered components may send requests to oracles.
function request(
NftId oracleNftId,
bytes calldata requestData,
Timestamp expiryAt,
string calldata callbackMethodName
) external returns (RequestId requestId);
/// @dev Respond to oracle request by oracle compnent.
/// The response data is amended in the request info stored with the instance.
/// The request state changes to FULFILLED (when calling the callback method of the requester is successful)
/// or to FAILED when calling the requester is not succesful.
/// The function returns true iff the state changes to FULFILLED.
/// Permissioned: only the receiving oracle component may call this method
function respond(
RequestId requestId,
bytes calldata responseData
) external returns (bool success);
/// @dev Resend a failed response to the requester.
/// Only requests in state FAILED may be resent.
/// The request state changes to FULFILLED when calling the callback method of the requester is successful.
/// Permissioned: only the receiving oracle may resend a request
function resend(RequestId requestId) external;
/// @dev Notify the oracle component that the specified request has become invalid.
/// Only requests in state ACTIVE may be cancelled.
/// Permissioned: only the requester may cancel a request
function cancel(RequestId requestId) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount} from "../type/Amount.sol";
import {COMPONENT, PRODUCT, ORACLE} from "../type/ObjectType.sol";
import {IAuthorization} from "../authorization/IAuthorization.sol";
import {IComponentService} from "../shared/IComponentService.sol";
import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol";
import {IOracleComponent} from "./IOracleComponent.sol";
import {IOracleService} from "./IOracleService.sol";
import {NftId} from "../type/NftId.sol";
import {InstanceLinkedComponent} from "../shared/InstanceLinkedComponent.sol";
import {RequestId} from "../type/RequestId.sol";
import {Timestamp} from "../type/Timestamp.sol";
abstract contract Oracle is
InstanceLinkedComponent,
IOracleComponent
{
// keccak256(abi.encode(uint256(keccak256("etherisc.storage.Oracle")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant ORACLE_STORAGE_LOCATION_V1 = 0xaab7c0ea03d290e56d6c060e0733d3ebcbe647f7694616a2ec52738a64b2f900;
struct OracleStorage {
IComponentService _componentService;
IOracleService _oracleService;
}
function request(
RequestId requestId,
NftId requesterId,
bytes calldata requestData,
Timestamp expiryAt
)
external
virtual
restricted()
{
_request(requestId, requesterId, requestData, expiryAt);
}
function cancel(
RequestId requestId
)
external
virtual
restricted()
{
_cancel(requestId);
}
/// @dev Not relevant for oracle components, always returns false.
function isVerifying()
external
virtual
view
returns (bool verifying)
{
return false;
}
/// @dev Not relevant for oracle components
function withdrawFees(Amount amount)
external
virtual
override(IInstanceLinkedComponent, InstanceLinkedComponent)
onlyOwner()
restricted()
returns (Amount)
{
revert ErrorOracleNotImplemented("withdrawFees");
}
function __Oracle_init(
address registry,
NftId productNftId,
IAuthorization authorization,
address initialOwner,
string memory name
)
internal
virtual
onlyInitializing()
{
__InstanceLinkedComponent_init(
registry,
productNftId,
name,
ORACLE(),
authorization,
true,
initialOwner);
OracleStorage storage $ = _getOracleStorage();
$._componentService = IComponentService(_getServiceAddress(COMPONENT()));
$._oracleService = IOracleService(_getServiceAddress(ORACLE()));
_registerInterface(type(IOracleComponent).interfaceId);
}
/// @dev Internal function for handling requests.
/// Empty implementation.
/// Overwrite this function to implement use case specific handling for oracle calls.
function _request(
RequestId requestId,
NftId requesterId,
bytes calldata requestData,
Timestamp expiryAt
)
internal
virtual
{
}
/// @dev Internal function for cancelling requests.
/// Empty implementation.
/// Overwrite this function to implement use case specific cancelling.
function _cancel(
RequestId requestId
)
internal
virtual
{
}
/// @dev Internal function for handling oracle responses.
/// Default implementation sends response back to oracle service.
/// Use this function in use case specific external/public functions to handle use case specific response handling.
function _respond(
RequestId requestId,
bytes memory responseData
)
internal
virtual
{
_getOracleStorage()._oracleService.respond(requestId, responseData);
}
function _getOracleStorage() private pure returns (OracleStorage storage $) {
assembly {
$.slot := ORACLE_STORAGE_LOCATION_V1
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IPolicy} from "../instance/module/IPolicy.sol";
import {IService} from "../shared/IService.sol";
import {Amount} from "../type/Amount.sol";
import {NftId} from "../type/NftId.sol";
import {ReferralId} from "../type/Referral.sol";
import {RiskId} from "../type/RiskId.sol";
import {Seconds} from "../type/Seconds.sol";
/// @dev gif service responsible for creating applications
/// only product components may call transaction functions
interface IApplicationService is IService {
event LogApplicationServiceApplicationCreated(
NftId applicationNftId,
NftId productNftId,
NftId bundleNftId,
RiskId riskId,
ReferralId referralId,
address applicationOwner,
Amount sumInsuredAmount,
Amount premiumAmount,
Seconds lifetime);
event LogApplicationServiceApplicationRenewed(NftId policyNftId, NftId bundleNftId);
event LogApplicationServiceApplicationAdjusted(
NftId applicationNftId,
NftId bundleNftId,
RiskId riskId,
ReferralId referralId,
Amount sumInsuredAmount,
Seconds lifetime);
event LogApplicationServiceApplicationRevoked(NftId applicationNftId);
// _checkLinkedApplicationParameters
error ErrorApplicationServiceRiskProductMismatch(RiskId riskId, NftId riskProductNftId, NftId productNftId);
error ErrorApplicationServiceRiskUnknown(RiskId riskId, NftId productNftId);
error ErrorApplicationServiceRiskLocked(RiskId riskId, NftId productNftId);
error ErrorApplicationServiceBundleUnknown(NftId bundleNftId, NftId poolNftId);
error ErrorApplicationServiceBundleLocked(NftId bundleNftId, NftId poolNftId);
error ErrorApplicationServiceReferralInvalid(NftId productNftId, NftId distributionNftId, ReferralId referralId);
/// @dev creates a new application based on the specified attributes
/// may only be called by a product component
function create(
address applicationOwner,
RiskId riskId,
Amount sumInsuredAmount,
Amount premiumAmount,
Seconds lifetime,
NftId bundleNftId,
ReferralId referralId,
bytes memory applicationData
) external returns (NftId applicationNftId);
/// @dev updates application attributes
/// may only be called while the application is in applied state
/// may only be called by the referenced product related to applicationNftId
function adjust(
NftId applicationNftId,
RiskId riskId,
NftId bundleNftId,
ReferralId referralId,
Amount sumInsuredAmount,
Seconds lifetime,
bytes memory applicationData
) external;
/// @dev creates a new application that extends the provided policy
/// lifetime will seamlessly extend referenced policy, for closed policies
/// lifetime will start at underwriting time
/// product will need to limit the time window for renewal as underwriting
/// will lock the collateral at underwriting time which might be earlier than activation time
/// policyNftId needs to refer to an underwritten (or active or closed) policy
/// may only be called by the referenced product related to policyNftId
function renew(
NftId policyNftId, // policy to be renewd (renewal inherits policy attributes)
NftId bundleNftId // will likely need a newer bundle for underwriting
) external returns (NftId applicationNftId);
/// @dev revokes the application represented by {policyNftId}
/// an application can only be revoked in applied state
/// only the application holder may revoke an application
function revoke(NftId policyNftId) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IInstance} from "../instance/IInstance.sol";
import {InstanceReader} from "../instance/InstanceReader.sol";
import {IService} from "../shared/IService.sol";
import {Amount} from "../type/Amount.sol";
import {ClaimId} from "../type/ClaimId.sol";
import {PayoutId} from "../type/PayoutId.sol";
import {NftId} from "../type/NftId.sol";
import {StateId} from "../type/StateId.sol";
import {Timestamp} from "../type/Timestamp.sol";
import {UFixed} from "../type/UFixed.sol";
import {Fee} from "../type/Fee.sol";
/// @dev gif service responsible for creating claims and payouts
/// only product components may call transaction functions
interface IClaimService is
IService
{
event LogClaimServiceClaimSubmitted(NftId policyNftId, ClaimId claimId, Amount claimAmount);
event LogClaimServiceClaimConfirmed(NftId policyNftId, ClaimId claimId, Amount confirmedAmount);
event LogClaimServiceClaimDeclined(NftId policyNftId, ClaimId claimId);
event LogClaimServiceClaimRevoked(NftId policyNftId, ClaimId claimId);
event LogClaimServiceClaimCancelled(NftId policyNftId, ClaimId claimId);
event LogClaimServicePayoutCreated(NftId policyNftId, PayoutId payoutId, Amount amount, address beneficiary);
event LogClaimServicePayoutProcessed(NftId policyNftId, PayoutId payoutId, Amount amount);
event LogClaimServicePayoutCancelled(NftId policyNftId, PayoutId payoutId);
error ErrorClaimServiceBeneficiarySet(NftId policyNftId, PayoutId payoutId, address beneficiary);
error ErrorClaimServicePolicyProductMismatch(NftId policyNftId, NftId expectedProduct, NftId actualProduct);
error ErrorClaimServicePolicyNotOpen(NftId policyNftId);
error ErrorClaimServiceClaimAmountIsZero(NftId policyNftId);
error ErrorClaimServiceClaimExceedsSumInsured(NftId policyNftId, Amount sumInsured, Amount payoutsIncludingClaimAmount);
error ErrorClaimServiceBeneficiaryIsZero(NftId policyNftId, ClaimId claimId);
error ErrorClaimsServicePayoutAmountIsZero(NftId policyNftId, PayoutId payoutId);
error ErrorClaimServiceClaimWithOpenPayouts(NftId policyNftId, ClaimId claimId, uint24 openPayouts);
error ErrorClaimServiceClaimWithMissingPayouts(NftId policyNftId, ClaimId claimId, Amount claimAmount, Amount paidAmount);
error ErrorClaimServiceClaimNotInExpectedState(NftId policyNftId, ClaimId claimId, StateId expectedState, StateId actualState);
error ErrorClaimServiceClaimNotConfirmed(NftId policyNftId, ClaimId claimId, StateId actualState);
error ErrorClaimServicePayoutExceedsClaimAmount(NftId policyNftId, ClaimId claimId, Amount claimAmount, Amount totalPayoutAmount);
error ErrorClaimServicePayoutNotExpected(NftId policyNftId, PayoutId payoutId, StateId actualState);
/// @dev create a new claim for the specified policy
/// returns the id of the newly created claim
/// function can only be called by product, policy needs to match with calling product
function submit(
NftId policyNftId,
Amount claimAmount,
bytes memory claimData
) external returns (ClaimId claimId);
/// @dev declines the specified claim
/// function can only be called by product, policy needs to match with calling product
function decline(
NftId policyNftId,
ClaimId claimId,
bytes memory data // claim processing data
) external;
/// @dev revokes the specified claim
/// function can only be called by product, policy needs to match with calling product
function revoke(
NftId policyNftId,
ClaimId claimId
) external;
/// @dev confirms the specified claim and specifies the payout amount
/// function can only be called by product, policy needs to match with calling product
function confirm(
NftId policyNftId,
ClaimId claimId,
Amount confirmedAmount,
bytes memory data // claim processing data
) external;
/// @dev cancels a confirmed claim before it has been fully paid out.
/// Can only be called when there are not pending payouts
/// function can only be called by product, policy needs to match with calling product
function cancelConfirmedClaim(
NftId policyNftId,
ClaimId claimId
) external;
/// @dev Creates a new payout for the specified claim.
/// The beneficiary is the holder of the policy NFT
/// returns the id of the newly created payout, this id is unique for the specified policy
/// function can only be called by product, policy needs to match with calling product
function createPayout(
NftId policyNftId,
ClaimId claimId,
Amount amount,
bytes memory data
)
external
returns (PayoutId payoutId);
/// @dev Creates a new payout for the specified claim and beneficiary.
/// returns the id of the newly created payout, this id is unique for the specified policy
/// function can only be called by product, policy needs to match with calling product
function createPayoutForBeneficiary(
NftId policyNftId,
ClaimId claimId,
Amount amount,
address beneficiary,
bytes memory data
)
external
returns (PayoutId payoutId);
/// @dev processes the specified payout
/// this includes moving the payout token to the beneficiary (default: policy holder)
/// function can only be called by product, policy needs to match with calling product
function processPayout(
NftId policyNftId,
PayoutId payoutId
) external returns (Amount netPayoutAmount, Amount processingFeeAmount);
/// @dev cancels the specified payout. no tokens are moved, payout is set to cancelled.
function cancelPayout(
NftId policyNftId,
PayoutId payoutId
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IService} from "../shared/IService.sol";
import {Amount} from "../type/Amount.sol";
import {IInstance} from "../instance/IInstance.sol";
import {NftId} from "../type/NftId.sol";
import {StateId} from "../type/StateId.sol";
import {Timestamp} from "../type/Timestamp.sol";
interface IPolicyService is IService {
event LogPolicyServicePolicyCreated(NftId policyNftId, Amount premiumAmount, Timestamp activatedAt);
event LogPolicyServicePolicyDeclined(NftId policyNftId);
event LogPolicyServicePolicyPremiumCollected(NftId policyNftId, Amount premiumAmount);
event LogPolicyServicePolicyActivated(NftId policyNftId, Timestamp activatedAt);
event LogPolicyServicePolicyActivatedUpdated(NftId policyNftId, Timestamp activatedAt);
event LogPolicyServicePolicyExpirationUpdated(NftId policyNftId, Timestamp expiredAt);
event LogPolicyServicePolicyClosed(NftId policyNftId);
error LogPolicyServiceMaxPremiumAmountExceeded(NftId policyNftId, Amount maxPremiumAmount, Amount premiumAmount);
error ErrorPolicyServicePolicyProductMismatch(NftId applicationNftId, NftId expectedProductNftId, NftId actualProductNftId);
error ErrorPolicyServicePolicyStateNotApplied(NftId applicationNftId);
error ErrorPolicyServicePolicyStateNotCollateralized(NftId applicationNftId);
error ErrorPolicyServicePolicyAlreadyActivated(NftId policyNftId);
error ErrorPolicyServicePolicyNotActivated(NftId policyNftId);
error ErrorPolicyServicePolicyActivationTooEarly(NftId policyNftId, Timestamp lowerLimit, Timestamp activatedAt);
error ErrorPolicyServicePolicyActivationTooLate(NftId policyNftId, Timestamp upperLimit, Timestamp activatedAt);
error ErrorPolicyServiceInsufficientAllowance(address customer, address tokenHandlerAddress, uint256 amount);
error ErrorPolicyServicePremiumAlreadyPaid(NftId policyNftId);
error ErrorPolicyServicePolicyNotCloseable(NftId policyNftId);
error ErrorPolicyServicePolicyNotActive(NftId policyNftId, StateId state);
error ErrorPolicyServicePremiumNotPaid(NftId policyNftId, Amount premiumAmount);
error ErrorPolicyServiceOpenClaims(NftId policyNftId, uint16 openClaimsCount);
error ErrorPolicyServicePolicyHasNotExpired(NftId policyNftId, Timestamp expiredAt);
error ErrorPolicyServicePolicyExpirationTooLate(NftId policyNftId, Timestamp upperLimit, Timestamp expiredAt);
error ErrorPolicyServicePolicyExpirationTooEarly(NftId policyNftId, Timestamp lowerLimit, Timestamp expiredAt);
error ErrorPolicyServicePremiumMismatch(NftId policyNftId, Amount expectedPremiumAmount, Amount recalculatedPremiumAmount);
error ErrorPolicyServiceTransferredPremiumMismatch(NftId policyNftId, Amount expectedPremiumAmount, Amount transferredPremiumAmount);
/// @dev creates the policy from {applicationNftId}.
/// @param applicationNftId the application NftId
/// @param activateAt the timestamp when the policy should be activated
/// @param maxPremiumAmount the maximum premium amount that the policy holder is willing to pay
/// During policy creation, the effective premium amount is calculated based on the provided parameters. If this
/// amount is higher than the maxPremiumAmount, the function will revert.
/// After successful completion of the function the policy can be referenced using the application NftId.
/// Locks the sum insured amount in the pool, but does not transfer tokens. Call collectPremium to transfer tokens.
/// Sets the policy state to collateralized.
/// Optionally activates the policy if activateAt is a non-zero timestamp.
/// only the related product may create a policy from an application
/// @return premiumAmount the effective premium amount
function createPolicy(
NftId applicationNftId,
Timestamp activateAt,
Amount maxPremiumAmount
)
external
returns (Amount premiumAmount);
/// @dev declines an application represented by {policyNftId}
/// an application can only be declined in applied state
/// only the related product may decline an application
function decline(NftId policyNftId) external;
/// @dev collects the premium token for the specified policy (must be in COLLATERALIZED state)
function collectPremium(NftId policyNftId, Timestamp activateAt) external;
/// @dev activates the specified policy and sets the activation date in the policy metadata
/// to activate a policy it needs to be in underwritten state
function activate(NftId policyNftId, Timestamp activateAt) external;
/// @dev adjusts the activation date of the specified policy and sets the new activation date in the policy metadata
/// to adjust the activation date of a policy it needs to have an activation date set.
/// the new activation date must not be before the current block timestamp or after the expiry date
function adjustActivation(NftId policyNftId, Timestamp newActivateAt) external;
/// @dev Expires the specified policy and sets the expiry date in the policy metadata.
/// Function consumers are products.
/// If expiry date is set to 0, then the earliest possible expiry date (current blocktime) is set
/// to expire a policy it must be in active state, policies may be expired even when the predefined expiry date is still in the future
/// a policy can only be closed when it has been expired. in addition, it must not have any open claims
/// this function can only be called by a product. the policy needs to match with the calling product
/// @return expiredAt the effective expiry date
function expire(NftId policyNftId, Timestamp expireAt) external returns (Timestamp expiredAt);
/// @dev Closes the specified policy and sets the closed data in the policy metadata
/// a policy can only be closed when it has been expired. in addition, it must not have any open claims
/// this function can only be called by a product. the policy needs to match with the calling product
function close(NftId policyNftId) external;
/// @dev Expires the specified policy and sets the expiry date in the policy metadata.
/// Function consumers is claim service.
function expirePolicy(IInstance instance, NftId policyNftId, Timestamp expireAt) external returns (Timestamp expiredAt);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Seconds} from "../type/Seconds.sol";
import {NftId} from "../type/NftId.sol";
import {ReferralId} from "../type/Referral.sol";
import {RiskId} from "../type/RiskId.sol";
import {Amount} from "../type/Amount.sol";
import {IService} from "./IApplicationService.sol";
import {IPolicy} from "../instance/module/IPolicy.sol";
interface IPricingService is IService
{
error ErrorPricingServiceTargetWalletAmountsMismatch();
error ErrorPricingServiceRiskProductMismatch(RiskId riskId, NftId riskProductNftId, NftId productNftId);
error ErrorPricingServiceBundlePoolMismatch(NftId bundleNftId, NftId bundlePoolNftId, NftId poolNftId);
error ErrorPricingServiceFeeCalculationMismatch(
Amount distributionFeeFixAmount,
Amount distributionFeeVarAmount,
Amount distributionOwnerFeeFixAmount,
Amount distributionOwnerFeeVarAmount,
Amount commissionAmount,
Amount discountAmount
);
function calculatePremium(
NftId productNftId,
RiskId riskId,
Amount sumInsuredAmount,
Seconds lifetime,
bytes memory applicationData,
NftId bundleNftId,
ReferralId referralId
)
external
view
returns (IPolicy.PremiumInfo memory premium);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount} from "../type/Amount.sol";
import {ClaimId} from "../type/ClaimId.sol";
import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol";
import {IComponents} from "../instance/module/IComponents.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {ReferralId} from "../type/Referral.sol";
import {RiskId} from "../type/RiskId.sol";
import {Seconds} from "../type/Seconds.sol";
interface IProductComponent is
IInstanceLinkedComponent
{
// @dev register a new component for this product cluster.
function registerComponent(address component)
external
returns (NftId componentNftId);
/// @dev Callback function to inform product compnent about arrival of funding for a claim.
/// The callback is called by the pool service after the corresponding pool triggers this function.
/// The callback is only called when the product's property isProcessingFundedClaims is set.
function processFundedClaim(
NftId policyNftId,
ClaimId claimId,
Amount availableAmount
) external;
/// @dev Calculates the premium amount for the provided application data.
/// The returned premium amounts takes into account potential discounts and fees.
function calculatePremium(
Amount sumInsuredAmount,
RiskId riskId,
Seconds lifetime,
bytes memory applicationData,
NftId bundleNftId,
ReferralId referralId
) external view returns (Amount premiumAmount);
/// @dev Calculates the net premium amount for the provided application data.
/// The returned net premium amounts only covers the cost of collateralizing the application.
/// This amount purely depends on the use case specific risk and does not include any fees/commission.
function calculateNetPremium(
Amount sumInsuredAmount,
RiskId riskId,
Seconds lifetime,
bytes memory applicationData
) external view returns (Amount netPremiumAmount);
/// @dev returns initial product specific infos
function getInitialProductInfo() external view returns (IComponents.ProductInfo memory info);
/// @dev returns initial fee infos
function getInitialFeeInfo() external view returns (IComponents.FeeInfo memory info);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IService} from "../shared/IService.sol";
import {NftId} from "../type/NftId.sol";
import {RiskId} from "../type/RiskId.sol";
import {StateId} from "../type/StateId.sol";
interface IRiskService is IService {
event LogRiskServiceRiskCreated(NftId productNftId, RiskId riskId);
event LogRiskServiceRiskUpdated(NftId productNftId, RiskId riskId);
event LogRiskServiceRiskLocked(NftId productNftId, RiskId riskId);
event LogRiskServiceRiskUnlocked(NftId productNftId, RiskId riskId);
event LogRiskServiceRiskClosed(NftId productNftId, RiskId riskId);
error ErrorRiskServiceRiskProductMismatch(RiskId riskId, NftId riskProductNftId, NftId productNftId);
error ErrorRiskServiceRiskNotActive(NftId productNftId, RiskId riskId);
error ErrorRiskServiceUnknownRisk(NftId productNftId, RiskId riskId);
error ErrorRiskServiceRiskNotLocked(NftId productNftId, RiskId riskId);
/// @dev Create a new risk with the given id and provided data.
/// The key of the risk derived from the risk id in comination with the product NftId.
/// Risk data is stored in the instance store.
function createRisk(
bytes32 id,
bytes memory data
) external returns (RiskId riskId);
function updateRisk(
RiskId riskId,
bytes memory data
) external;
/// @dev Locks/unlocks the risk with the given id.
/// No new policies can be underwritten for a locked risk.
function setRiskLocked(
RiskId riskId,
bool locked
) external;
/// @dev Close the risk with the given id.
function closeRisk(
RiskId riskId
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {InstanceReader} from "../instance/InstanceReader.sol";
import {IPolicy} from "../instance/module/IPolicy.sol";
import {IPolicyService} from "../product/IPolicyService.sol";
import {NftId} from "../type/NftId.sol";
import {StateId, CLOSED, COLLATERALIZED} from "../type/StateId.sol";
import {Timestamp, TimestampLib} from "../type/Timestamp.sol";
library PolicyServiceLib {
function policyIsActive(InstanceReader instanceReader, NftId policyNftId)
external
view
returns (bool isActive)
{
// policy not collateralized
if (instanceReader.getPolicyState(policyNftId) != COLLATERALIZED()) {
return false;
}
IPolicy.PolicyInfo memory info = instanceReader.getPolicyInfo(policyNftId);
if (info.productNftId.eqz()) { return false; } // not closeable: policy does not exist (or does not belong to this instance)
if (info.activatedAt.eqz()) { return false; } // not closeable: not yet activated
if (info.activatedAt > TimestampLib.current()) { return false; } // not yet active
if (info.expiredAt <= TimestampLib.current()) { return false; } // already expired
return true;
}
function activate(
NftId policyNftId,
IPolicy.PolicyInfo memory policyInfo,
Timestamp activateAt
)
external
pure
returns (IPolicy.PolicyInfo memory)
{
// fail if policy has already been activated and activateAt is different
if(! policyInfo.activatedAt.eqz() && activateAt != policyInfo.activatedAt) {
revert IPolicyService.ErrorPolicyServicePolicyAlreadyActivated(policyNftId);
}
// ignore if policy has already been activated and activateAt is the same
if (policyInfo.activatedAt == activateAt) {
return policyInfo;
}
policyInfo.activatedAt = activateAt;
policyInfo.expiredAt = activateAt.addSeconds(policyInfo.lifetime);
return policyInfo;
}
function expire(
InstanceReader instanceReader,
NftId policyNftId,
IPolicy.PolicyInfo memory policyInfo,
Timestamp expireAt
)
external
view
returns (IPolicy.PolicyInfo memory)
{
StateId policyState = instanceReader.getPolicyState(policyNftId);
checkExpiration(
expireAt,
policyNftId,
policyState,
policyInfo);
// effects
// update policyInfo with new expiredAt timestamp
if (expireAt.gtz()) {
policyInfo.expiredAt = expireAt;
} else {
policyInfo.expiredAt = TimestampLib.current();
}
return policyInfo;
}
function checkExpiration(
Timestamp newExpiredAt,
NftId policyNftId,
StateId policyState,
IPolicy.PolicyInfo memory policyInfo
)
public
view
{
if (policyState != COLLATERALIZED()) {
revert IPolicyService.ErrorPolicyServicePolicyNotActive(policyNftId, policyState);
}
if (policyInfo.activatedAt.eqz() || TimestampLib.current() < policyInfo.activatedAt) {
revert IPolicyService.ErrorPolicyServicePolicyNotActive(policyNftId, policyState);
}
// check expiredAt represents a valid expiry time
if (newExpiredAt > policyInfo.expiredAt) {
revert IPolicyService.ErrorPolicyServicePolicyExpirationTooLate(policyNftId, policyInfo.expiredAt, newExpiredAt);
}
if (newExpiredAt.gtz() && newExpiredAt < TimestampLib.current()) {
revert IPolicyService.ErrorPolicyServicePolicyExpirationTooEarly(policyNftId, TimestampLib.current(), newExpiredAt);
}
}
function policyIsCloseable(InstanceReader instanceReader, NftId policyNftId)
external
view
returns (bool isCloseable)
{
// policy already closed
if (instanceReader.getPolicyState(policyNftId) == CLOSED()) {
return false;
}
IPolicy.PolicyInfo memory info = instanceReader.getPolicyInfo(policyNftId);
if (info.productNftId.eqz()) { return false; } // not closeable: policy does not exist (or does not belong to this instance)
if (info.activatedAt.eqz()) { return false; } // not closeable: not yet activated
if (info.openClaimsCount > 0) { return false; } // not closeable: has open claims
// closeable: if sum of claims matches sum insured a policy may be closed prior to the expiry date
if (info.claimAmount == info.sumInsuredAmount) { return true; }
// not closeable: not yet expired
if (TimestampLib.current() < info.expiredAt) { return false; }
// all conditions to close the policy are met
return true;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount, AmountLib} from "../type/Amount.sol";
import {ClaimId} from "../type/ClaimId.sol";
import {Fee} from "../type/Fee.sol";
import {IApplicationService} from "./IApplicationService.sol";
import {IAuthorization} from "../authorization/IAuthorization.sol";
import {IComponentService} from "../shared/IComponentService.sol";
import {InstanceLinkedComponent} from "../shared/InstanceLinkedComponent.sol";
import {IPolicyService} from "./IPolicyService.sol";
import {IRiskService} from "./IRiskService.sol";
import {IClaimService} from "./IClaimService.sol";
import {IPricingService} from "./IPricingService.sol";
import {IProductComponent} from "./IProductComponent.sol";
import {NftId} from "../type/NftId.sol";
import {COMPONENT, PRODUCT, BUNDLE, APPLICATION, POLICY, CLAIM, PRICE } from "../type/ObjectType.sol";
import {PayoutId} from "../type/PayoutId.sol";
import {COMPONENT, PRODUCT, APPLICATION, POLICY, CLAIM, PRICE, BUNDLE, RISK } from "../type/ObjectType.sol";
import {ReferralId} from "../type/Referral.sol";
import {RiskId} from "../type/RiskId.sol";
import {Seconds} from "../type/Seconds.sol";
import {StateId} from "../type/StateId.sol";
import {Timestamp} from "../type/Timestamp.sol";
import {IPolicy} from "../instance/module/IPolicy.sol";
import {IComponents} from "../instance/module/IComponents.sol";
abstract contract Product is
InstanceLinkedComponent,
IProductComponent
{
// keccak256(abi.encode(uint256(keccak256("etherisc.storage.Product")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant PRODUCT_STORAGE_LOCATION_V1 = 0x0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6800;
struct ProductStorage {
IComponents.ProductInfo _productInfo;
IComponents.FeeInfo _feeInfo;
IComponentService _componentService;
IRiskService _riskService;
IApplicationService _applicationService;
IPolicyService _policyService;
IClaimService _claimService;
IPricingService _pricingService;
}
function registerComponent(address component)
external
virtual
restricted()
onlyOwner()
returns (NftId componentNftId)
{
return _getProductStorage()._componentService.registerComponent(component);
}
function processFundedClaim(
NftId policyNftId,
ClaimId claimId,
Amount availableAmount
)
external
virtual
restricted() // pool service role
onlyNftOfType(policyNftId, POLICY())
{
// default implementation does nothing
}
function calculatePremium(
Amount sumInsuredAmount,
RiskId riskId,
Seconds lifetime,
bytes memory applicationData,
NftId bundleNftId,
ReferralId referralId
)
public
view
virtual
override
onlyNftOfType(bundleNftId, BUNDLE())
returns (Amount premiumAmount)
{
IPolicy.PremiumInfo memory premium = _getProductStorage()._pricingService.calculatePremium(
getNftId(),
riskId,
sumInsuredAmount,
lifetime,
applicationData,
bundleNftId,
referralId
);
return premium.premiumAmount;
}
function calculateNetPremium(
Amount sumInsuredAmount,
RiskId,
Seconds,
bytes memory
)
external
view
virtual override
returns (Amount netPremiumAmount)
{
// default 10% of sum insured
return AmountLib.toAmount(sumInsuredAmount.toInt() / 10);
}
function getInitialProductInfo()
public
virtual
view
returns (IComponents.ProductInfo memory poolInfo)
{
return _getProductStorage()._productInfo;
}
function getInitialFeeInfo()
public
virtual
view
returns (IComponents.FeeInfo memory feeInfo)
{
return _getProductStorage()._feeInfo;
}
function __Product_init(
address registry,
NftId instanceNftId,
string memory name,
IComponents.ProductInfo memory productInfo,
IComponents.FeeInfo memory feeInfo,
IAuthorization authorization,
address initialOwner
)
internal
virtual
onlyInitializing()
{
__InstanceLinkedComponent_init(
registry,
instanceNftId,
name,
PRODUCT(),
authorization,
productInfo.isInterceptingPolicyTransfers,
initialOwner);
ProductStorage storage $ = _getProductStorage();
$._productInfo = productInfo;
$._feeInfo = feeInfo;
$._riskService = IRiskService(_getServiceAddress(RISK()));
$._applicationService = IApplicationService(_getServiceAddress(APPLICATION()));
$._policyService = IPolicyService(_getServiceAddress(POLICY()));
$._claimService = IClaimService(_getServiceAddress(CLAIM()));
$._pricingService = IPricingService(_getServiceAddress(PRICE()));
$._componentService = IComponentService(_getServiceAddress(COMPONENT()));
_registerInterface(type(IProductComponent).interfaceId);
}
function _setFees(
Fee memory productFee,
Fee memory processingFee
)
internal
virtual
{
_getProductStorage()._componentService.setProductFees(productFee, processingFee);
}
function _createRisk(
bytes32 id,
bytes memory data
)
internal
virtual
returns (RiskId riskId)
{
return _getProductStorage()._riskService.createRisk(
id,
data
);
}
function _updateRisk(
RiskId id,
bytes memory data
)
internal
virtual
{
_getProductStorage()._riskService.updateRisk(
id,
data
);
}
function _setRiskLocked(
RiskId id,
bool locked
)
internal
virtual
{
_getProductStorage()._riskService.setRiskLocked(
id,
locked
);
}
function _closeRisk(
RiskId id
)
internal
virtual
{
_getProductStorage()._riskService.closeRisk(
id
);
}
function _createApplication(
address applicationOwner,
RiskId riskId,
Amount sumInsuredAmount,
Amount premiumAmount,
Seconds lifetime,
NftId bundleNftId,
ReferralId referralId,
bytes memory applicationData
)
internal
virtual
returns (NftId applicationNftId)
{
return _getProductStorage()._applicationService.create(
applicationOwner,
riskId,
sumInsuredAmount,
premiumAmount,
lifetime,
bundleNftId,
referralId,
applicationData
);
}
function _revoke(
NftId applicationNftId
)
internal
virtual
{
_getProductStorage()._applicationService.revoke(
applicationNftId);
}
function _createPolicy(
NftId applicationNftId,
Timestamp activateAt,
Amount maxPremiumAmount
)
internal
virtual
returns (Amount premiumAmount)
{
premiumAmount = _getProductStorage()._policyService.createPolicy(
applicationNftId,
activateAt,
maxPremiumAmount);
}
function _decline(
NftId policyNftId
)
internal
virtual
{
_getProductStorage()._policyService.decline(
policyNftId);
}
function _expire(
NftId policyNftId,
Timestamp expireAt
)
internal
virtual
returns (Timestamp expiredAt)
{
expiredAt = _getProductStorage()._policyService.expire(policyNftId, expireAt);
}
/// @dev adjust the activation date of the policy.
/// The policy must already have an activation date set.
/// Allowed values are from the current blocktime to the expiration date of the policy.
function _adjustActivation(
NftId policyNftId,
Timestamp activateAt
)
internal
virtual
{
_getProductStorage()._policyService.adjustActivation(
policyNftId,
activateAt);
}
function _collectPremium(
NftId policyNftId,
Timestamp activateAt
)
internal
virtual
{
_getProductStorage()._policyService.collectPremium(
policyNftId,
activateAt);
}
function _activate(
NftId policyNftId,
Timestamp activateAt
)
internal
virtual
{
_getProductStorage()._policyService.activate(
policyNftId,
activateAt);
}
function _close(
NftId policyNftId
)
internal
virtual
{
_getProductStorage()._policyService.close(
policyNftId);
}
function _submitClaim(
NftId policyNftId,
Amount claimAmount,
bytes memory claimData
)
internal
virtual
returns(ClaimId)
{
return _getProductStorage()._claimService.submit(
policyNftId,
claimAmount,
claimData);
}
function _revokeClaim(
NftId policyNftId,
ClaimId claimId
)
internal
virtual
{
_getProductStorage()._claimService.revoke(
policyNftId,
claimId);
}
function _confirmClaim(
NftId policyNftId,
ClaimId claimId,
Amount confirmedAmount,
bytes memory data
)
internal
virtual
{
_getProductStorage()._claimService.confirm(
policyNftId,
claimId,
confirmedAmount,
data);
}
function _declineClaim(
NftId policyNftId,
ClaimId claimId,
bytes memory data
)
internal
virtual
{
_getProductStorage()._claimService.decline(
policyNftId,
claimId,
data);
}
function _cancelConfirmedClaim(
NftId policyNftId,
ClaimId claimId
)
internal
virtual
{
_getProductStorage()._claimService.cancelConfirmedClaim(
policyNftId,
claimId);
}
function _createPayout(
NftId policyNftId,
ClaimId claimId,
Amount amount,
bytes memory data
)
internal
virtual
returns (PayoutId)
{
return _getProductStorage()._claimService.createPayout(
policyNftId,
claimId,
amount,
data);
}
function _createPayoutForBeneficiary(
NftId policyNftId,
ClaimId claimId,
Amount amount,
address beneficiary,
bytes memory data
)
internal
virtual
returns (PayoutId)
{
return _getProductStorage()._claimService.createPayoutForBeneficiary(
policyNftId,
claimId,
amount,
beneficiary,
data);
}
function _processPayout(
NftId policyNftId,
PayoutId payoutId
)
internal
virtual
returns (Amount netPayoutAmount, Amount processingFeeAmount)
{
(netPayoutAmount, processingFeeAmount) = _getProductStorage()._claimService.processPayout(
policyNftId,
payoutId);
}
function _cancelPayout(
NftId policyNftId,
PayoutId payoutId
)
internal
virtual
{
_getProductStorage()._claimService.cancelPayout(
policyNftId,
payoutId);
}
function _getProductStorage() internal virtual pure returns (ProductStorage storage $) {
assembly {
$.slot := PRODUCT_STORAGE_LOCATION_V1
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IRelease} from "./IRelease.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {VersionPart} from "../type/Version.sol";
/// @title Chain Registry interface.
/// A chain registry holds all protocol relevant objects with basic metadata.
/// Registered objects include services, instances, products, pools, policies, bundles, stakes and more.
/// Registered objects are represented by NFTs.
/// When on mainnet registry is global and keeps arbitrary number of chain registries residing on different chain ids.
/// When not on mainnet registry keeps the only object residing on different chain id (on mainnet) - global registry.
interface IRegistry is
IERC165
{
event LogRegistryObjectRegistered(NftId nftId, NftId parentNftId, ObjectType objectType, bool isInterceptor, address objectAddress, address initialOwner);
event LogRegistryServiceRegistered(VersionPart majorVersion, ObjectType domain);
event LogRegistryChainRegistryRegistered(NftId nftId, uint256 chainId, address chainRegistryAddress);
// initialize
error ErrorRegistryCallerNotDeployer();
// register()
error ErrorRegistryObjectTypeNotSupported(ObjectType objectType);
// registerRegistry()
error ErrorRegistryNotOnMainnet(uint256 chainId);
error ErrorRegistryChainRegistryChainIdZero(NftId nftId);
error ErrorRegistryChainRegistryAddressZero(NftId nftId, uint256 chainId);
error ErrorRegistryChainRegistryNftIdInvalid(NftId nftId, uint256 chainId);
error ErrorRegistryChainRegistryAlreadyRegistered(NftId nftId, uint256 chainId);
// registerService()
error ErrorRegistryServiceAddressZero();
error ErrorRegistryServiceVersionZero(address service);
error ErrorRegistryServiceDomainZero(address service, VersionPart version);
error ErrorRegistryNotService(address service, ObjectType objectType);
error ErrorRegistryServiceParentNotRegistry(address service, VersionPart version, NftId parentNftId);
error ErrorRegistryServiceDomainAlreadyRegistered(address service, VersionPart version, ObjectType domain);
// registerWithCustomTypes()
error ErrorRegistryCoreTypeRegistration();
// _register()
error ErrorRegistryGlobalRegistryAsParent(address objectAddress, ObjectType objectType);
error ErrorRegistryTypeCombinationInvalid(address objectAddress, ObjectType objectType, ObjectType parentType);
error ErrorRegistryContractAlreadyRegistered(address objectAddress);
struct ObjectInfo {
// slot 0
NftId nftId;
NftId parentNftId;
ObjectType objectType;
bool isInterceptor;
// slot 1
address objectAddress;
// slot 2
address initialOwner;
// slot 3
bytes data;
}
/// @dev Registers a registry contract for a specified chain.
/// Only one chain registry may be registered per chain
function registerRegistry(
NftId nftId,
uint256 chainId,
address chainRegistryAddress
) external;
/// @dev Register a service with using the provided domain and version.
/// The function returns a newly minted service NFT ID.
/// May only be used to register services.
function registerService(
ObjectInfo memory serviceInfo,
VersionPart serviceVersion,
ObjectType serviceDomain
) external returns(NftId nftId);
/// @dev Register an object with a known core type.
/// The function returns a newly minted object NFT ID.
/// May not be used to register services.
function register(ObjectInfo memory info) external returns (NftId nftId);
/// @dev Register an object with a custom type.
/// The function returns a newly minted object NFT ID.
/// This function is reserved for GIF releases > 3.
/// May not be used to register known core types.
function registerWithCustomType(ObjectInfo memory info) external returns (NftId nftId);
function getInitialRelease() external view returns (VersionPart);
function getNextRelease() external view returns (VersionPart);
function getLatestRelease() external view returns (VersionPart);
function getReleaseInfo(VersionPart release) external view returns (IRelease.ReleaseInfo memory);
/// @dev Returns the number of supported chains.
function chainIds() external view returns (uint256);
/// @dev Returns the chain id at the specified index.
function getChainId(uint256 idx) external view returns (uint256);
/// @dev Returns the NFT ID of the registry for the specified chain.
function getRegistryNftId(uint256 chainId) external returns (NftId nftId);
function getObjectCount() external view returns (uint256);
function getNftIdForAddress(address objectAddress) external view returns (NftId nftId);
function ownerOf(NftId nftId) external view returns (address);
function isOwnerOf(NftId nftId, address expectedOwner) external view returns (bool);
function ownerOf(address contractAddress) external view returns (address);
function getObjectInfo(NftId nftId) external view returns (ObjectInfo memory info);
function getParentNftId(NftId nftId) external view returns (NftId parentNftId);
function isObjectType(NftId nftId, ObjectType expectedObjectType) external view returns (bool);
function isObjectType(address contractAddress, ObjectType expectedObjectType) external view returns (bool);
function getObjectAddress(NftId nftId) external view returns (address objectAddress);
/// @dev Returns the object info for the specified object address.
// MUST not be used with chain registry address (resides on different chan id)
function getObjectInfo(address object) external view returns (ObjectInfo memory info);
function isRegistered(NftId nftId) external view returns (bool);
function isRegistered(address contractAddress) external view returns (bool);
function isRegisteredService(address contractAddress) external view returns (bool);
function isRegisteredComponent(address object) external view returns (bool);
function isActiveRelease(VersionPart version) external view returns (bool);
function getServiceAddress(
ObjectType serviceDomain,
VersionPart releaseVersion
) external view returns (address serviceAddress);
function getProtocolNftId() external view returns (NftId protocolNftId);
function getNftId() external view returns (NftId nftId);
function getOwner() external view returns (address);
// TODO refactor the address getters below to contract getters
function getChainNftAddress() external view returns (address);
function getReleaseRegistryAddress() external view returns (address);
function getStakingAddress() external view returns (address);
function getTokenRegistryAddress() external view returns (address);
function getRegistryAdminAddress() external view returns (address);
function getAuthority() external view returns (address);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IServiceAuthorization} from "../authorization/IServiceAuthorization.sol";
import {StateId} from "../type/StateId.sol";
import {Timestamp} from "../type/Timestamp.sol";
import {VersionPart} from "../type/Version.sol";
/// @title Marks contracts that are linked to a specific GIF release version.
interface IRelease {
struct ReleaseInfo {
// slot 0
address releaseAdmin;
StateId state;
VersionPart version;
Timestamp activatedAt;
Timestamp disabledAt;
// slot 1
IServiceAuthorization auth;
// slot 2
bytes32 salt;
}
/// @dev Registers a registry contract for a specified chain.
/// Only one chain registry may be registered per chain
function getRelease() external view returns (VersionPart release);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
interface ITransferInterceptor {
function nftTransferFrom(address from, address to, uint256 tokenId, address operator) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Amount, AmountLib} from "../type/Amount.sol";
import {IComponent} from "./IComponent.sol";
import {IComponents} from "../instance/module/IComponents.sol";
import {IComponentService} from "./IComponentService.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType, COMPONENT} from "../type/ObjectType.sol";
import {Registerable} from "../shared/Registerable.sol";
import {TokenHandler} from "../shared/TokenHandler.sol";
import {Version, VersionLib} from "../type/Version.sol";
abstract contract Component is
Registerable,
IComponent
{
// keccak256(abi.encode(uint256(keccak256("gif-next.contracts.component.Component.sol")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant COMPONENT_LOCATION_V1 = 0xffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f00;
struct ComponentStorage {
string _name; // unique (per instance) component name
bool _isInterceptor;
IComponentService _componentService;
}
modifier onlyChainNft() {
if(msg.sender != getRegistry().getChainNftAddress()) {
revert ErrorComponentNotChainNft(msg.sender);
}
_;
}
function _getComponentStorage() private pure returns (ComponentStorage storage $) {
// solhint-disable-next-line no-inline-assembly
assembly {
$.slot := COMPONENT_LOCATION_V1
}
}
function __Component_init(
address authority,
address registry,
NftId parentNftId,
string memory name,
ObjectType componentType,
bool isInterceptor,
address initialOwner,
bytes memory registryData // writeonly data that will saved in the object info record of the registry
)
internal
virtual
onlyInitializing()
{
if (bytes(name).length == 0) {
revert ErrorComponentNameLengthZero();
}
__Registerable_init(
authority,
registry,
parentNftId,
componentType,
isInterceptor,
initialOwner,
registryData);
// set component state
ComponentStorage storage $ = _getComponentStorage();
$._name = name;
$._isInterceptor = isInterceptor;
$._componentService = IComponentService(_getServiceAddress(COMPONENT()));
_registerInterface(type(IAccessManaged).interfaceId);
_registerInterface(type(IComponent).interfaceId);
}
/// @dev callback function for nft transfers
/// may only be called by chain nft contract.
/// override internal function _nftTransferFrom to implement custom behaviour
function nftTransferFrom(address from, address to, uint256 tokenId, address operator)
external
onlyChainNft
{
_nftTransferFrom(from, to, tokenId, operator);
}
function getWallet() public view virtual returns (address walletAddress) {
return getTokenHandler().getWallet();
}
function getTokenHandler() public virtual view returns (TokenHandler tokenHandler) {
return getComponentInfo().tokenHandler;
}
function getToken() public view virtual returns (IERC20Metadata token) {
return getTokenHandler().TOKEN();
}
function getName() public view override returns(string memory name) {
return getComponentInfo().name;
}
function getVersion() public view virtual returns (Version version) {
return VersionLib.toVersion(1, 0, 0);
}
function getComponentInfo() public virtual view returns (IComponents.ComponentInfo memory info) {
if (isRegistered()) {
return _getComponentInfo();
} else {
return getInitialComponentInfo();
}
}
/// @dev defines initial component specification
/// overwrite this function according to your use case
function getInitialComponentInfo() public virtual view returns (IComponents.ComponentInfo memory info) {
return _getComponentInfo();
}
function isNftInterceptor() public virtual view returns(bool isInterceptor) {
if (isRegistered()) {
return getRegistry().getObjectInfo(address(this)).isInterceptor;
} else {
return _getComponentStorage()._isInterceptor;
}
}
function isRegistered() public virtual view returns (bool) {
return getRegistry().getNftIdForAddress(address(this)).gtz();
}
/// @dev Approves token hanlder to spend up to the specified amount of tokens.
/// Reverts if component wallet is not token handler itself.
/// Only component owner (nft holder) is authorizes to call this function.
function _approveTokenHandler(IERC20Metadata token, Amount amount)
internal
virtual
returns (Amount oldAllowanceAmount)
{
oldAllowanceAmount = AmountLib.toAmount(
token.allowance(address(getTokenHandler()), address(this)));
_getComponentStorage()._componentService.approveTokenHandler(
token,
amount);
}
/// @dev internal function for nft transfers.
/// handling logic that deals with nft transfers need to overwrite this function
function _nftTransferFrom(address from, address to, uint256 tokenId, address operator)
internal
virtual
// solhint-disable-next-line no-empty-blocks
{
// empty default implementation
}
/// @dev Sets the components wallet to the specified address.
/// Depending on the source of the component information this function needs to be overwritten.
/// eg for instance linked components that externally store this information with the instance store contract
function _setWallet(
address newWallet
)
internal
virtual
{
_getComponentStorage()._componentService.setWallet(newWallet);
}
function _setLocked(bool locked)
internal
virtual
{
_getComponentStorage()._componentService.setLocked(locked);
}
/// @dev depending on the source of the component information this function needs to be overwritten.
/// eg for instance linked components that externally store this information with the instance store contract
function _getComponentInfo() internal virtual view returns (IComponents.ComponentInfo memory info) {
ComponentStorage storage $ = _getComponentStorage();
return IComponents.ComponentInfo({
name: $._name,
tokenHandler: TokenHandler(address(0))
});
}
/// @dev returns the service address for the specified domain
/// gets address via lookup from registry using the major version form the linked instance
function _getServiceAddress(ObjectType domain) internal view returns (address) {
return getRegistry().getServiceAddress(domain, getRelease());
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {IPolicyHolder} from "../shared/IPolicyHolder.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IService} from "../shared/IService.sol";
import {ChainId} from "../type/ChainId.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType, INSTANCE, PRODUCT, DISTRIBUTION, ORACLE, POOL} from "../type/ObjectType.sol";
import {VersionPart} from "../type/Version.sol";
interface ITargetHelper {
function isTargetLocked(address target) external view returns (bool);
}
interface IInstanceAdminHelper {
function getInstanceAdmin() external view returns (ITargetHelper);
}
interface ITokenRegistryHelper {
function isActive(ChainId chainId, address token, VersionPart release) external view returns (bool);
}
library ContractLib {
error ErrorContractLibCallerNotRegistered(address target);
error ErrorContractLibCallerNotComponent(NftId componentNftId, ObjectType objectType);
error ErrorContractLibParentNotInstance(NftId componentNftId, NftId parentNftId);
error ErrorContractLibParentNotProduct(NftId componentNftId, NftId parentNftId);
error ErrorContractLibComponentTypeMismatch(NftId componentNftId, ObjectType expectedType, ObjectType actualType);
error ErrorContractLibComponentInactive(NftId componentNftId);
function getInfoAndInstance(
IRegistry registry,
NftId componentNftId,
bool onlyActive
)
external
view
returns (
IRegistry.ObjectInfo memory info,
address instance
)
{
info = registry.getObjectInfo(componentNftId);
return _getAndVerifyComponentAndInstance(registry, info, info.objectType, onlyActive);
}
function getAndVerifyAnyComponent(
IRegistry registry,
address caller,
bool onlyActive
)
external
view
returns (
IRegistry.ObjectInfo memory callerInfo,
address instance
)
{
// check caller is component
callerInfo = _getAndVerifyObjectInfo(registry, caller);
if(!(callerInfo.objectType == PRODUCT()
|| callerInfo.objectType == POOL()
|| callerInfo.objectType == DISTRIBUTION()
|| callerInfo.objectType == ORACLE())
) {
revert ErrorContractLibCallerNotComponent(
callerInfo.nftId,
callerInfo.objectType);
}
return _getAndVerifyComponentAndInstance(registry, callerInfo, callerInfo.objectType, onlyActive);
}
function getAndVerifyComponent(
IRegistry registry,
address caller,
ObjectType expectedType,
bool onlyActive
)
external
view
returns (
IRegistry.ObjectInfo memory info,
address instance
)
{
info = _getAndVerifyObjectInfo(registry, caller);
return _getAndVerifyComponentAndInstance(registry, info, expectedType, onlyActive);
}
function getInstanceForComponent(
IRegistry registry,
NftId componentNftId
)
public
view
returns (address instance)
{
NftId productNftId = registry.getParentNftId(componentNftId);
NftId instanceNftId = registry.getParentNftId(productNftId);
return registry.getObjectInfo(instanceNftId).objectAddress;
}
function isActiveToken(
address tokenRegistryAddress,
ChainId chainId,
address token,
VersionPart release
)
external
view
returns (bool)
{
return ITokenRegistryHelper(
tokenRegistryAddress).isActive(
chainId, token, release);
}
function isPolicyHolder(address target) external view returns (bool) {
return ERC165Checker.supportsInterface(target, type(IPolicyHolder).interfaceId);
}
function isAuthority(address authority) public view returns (bool) {
if (!isContract(authority)) {
return false;
}
return supportsInterface(authority, type(IAccessManager).interfaceId);
}
function isAccessManaged(address target)
public
view
returns (bool)
{
if (!isContract(target)) {
return false;
}
(bool success, ) = target.staticcall(
abi.encodeWithSelector(
IAccessManaged.authority.selector));
return success;
}
function isRegistered(address registry, address caller, ObjectType expectedType) public view returns (bool) {
NftId nftId = IRegistry(registry).getNftIdForAddress(caller);
if (nftId.eqz()) {
return false;
}
return IRegistry(registry).getObjectInfo(nftId).objectType == expectedType;
}
function isService(address service) public view returns (bool) {
if (!isContract(service)) {
return false;
}
return supportsInterface(service, type(IService).interfaceId);
}
function isRegistry(address registry) public view returns (bool) {
if (!isContract(registry)) {
return false;
}
return supportsInterface(registry, type(IRegistry).interfaceId);
}
function isContract(address target) public view returns (bool) {
if (target == address(0)) {
return false;
}
uint256 size;
assembly {
size := extcodesize(target)
}
return size > 0;
}
function supportsInterface(address target, bytes4 interfaceId) public view returns (bool) {
return ERC165Checker.supportsInterface(target, interfaceId);
}
function _getAndVerifyComponentAndInstance(
IRegistry registry,
IRegistry.ObjectInfo memory info,
ObjectType expectedType,
bool onlyActive
)
internal
view
returns (
IRegistry.ObjectInfo memory,
address instance
)
{
if(info.objectType != expectedType) {
revert ErrorContractLibComponentTypeMismatch(
info.nftId,
expectedType,
info.objectType);
}
// get instance and check component is active
instance = getAndVerifyInstance(registry, info);
_checkComponentActive(instance, info.objectAddress, info.nftId, onlyActive);
return (
info,
instance
);
}
function _checkComponentActive(
address instance,
address target,
NftId componentNftId,
bool onlyActive
)
internal
view
{
if (onlyActive) {
if (IInstanceAdminHelper(
instance).getInstanceAdmin().isTargetLocked(
target)
) {
revert ErrorContractLibComponentInactive(componentNftId);
}
}
}
/// @dev Given an object info the function returns the instance address.
/// The info may represent a product or any other component.
/// If the parent of the provided info is not registered with the correct type, the function reverts.
function getAndVerifyInstance(
IRegistry registry,
IRegistry.ObjectInfo memory info
)
public
view
returns (address instance)
{
// get instance for product case
if (info.objectType == PRODUCT()) {
// verify that parent of product is registered instance
IRegistry.ObjectInfo memory instanceInfo = registry.getObjectInfo(info.parentNftId);
if (instanceInfo.objectType != INSTANCE()) {
revert ErrorContractLibParentNotInstance(
info.nftId,
info.parentNftId);
}
// we have verified that parent object is a registerd instance -> we return the instance address
return instanceInfo.objectAddress;
}
// not product: verify parent is registered product
info = registry.getObjectInfo(info.parentNftId);
if (info.objectType != PRODUCT()) {
revert ErrorContractLibParentNotProduct(
info.nftId,
info.parentNftId);
}
// we have verified that parent is registerd product -> we can rely on registry that its parent is an instance
return registry.getObjectAddress(info.parentNftId);
}
function _getAndVerifyObjectInfo(
IRegistry registry,
address caller
)
internal
view
returns (IRegistry.ObjectInfo memory info)
{
NftId componentNftId = registry.getNftIdForAddress(caller);
if (componentNftId.eqz()) {
revert ErrorContractLibCallerNotRegistered(caller);
}
info = registry.getObjectInfo(componentNftId);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IComponent} from "../shared/IComponent.sol";
import {IAuthorization} from "../authorization/IAuthorization.sol";
/// @dev component base class
/// component examples are product, distribution, pool and oracle
interface IAuthorizedComponent is
IComponent
{
/// @dev returns the initial component authorization specification.
function getAuthorization() external view returns (IAuthorization authorization);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Amount} from "../type/Amount.sol";
import {IComponents} from "../instance/module/IComponents.sol";
import {IRegisterable} from "../shared/IRegisterable.sol";
import {ITransferInterceptor} from "../registry/ITransferInterceptor.sol";
import {TokenHandler} from "../shared/TokenHandler.sol";
/// @dev component base class
/// component examples are staking, product, distribution, pool and oracle
interface IComponent is
IRegisterable,
ITransferInterceptor
{
error ErrorComponentProductNftIdZero();
error ErrorComponentProductNftIdNonzero();
error ErrorComponentNameLengthZero();
error ErrorComponentNotChainNft(address caller);
error ErrorComponentWalletAddressZero();
error ErrorComponentWalletAddressIsSameAsCurrent();
error ErrorComponentWalletNotComponent();
event LogComponentWalletAddressChanged(address oldWallet, address newWallet);
event LogComponentWalletTokensTransferred(address from, address to, uint256 amount);
event LogComponentTokenHandlerApproved(address tokenHandler, address token, Amount limit, bool isMaxAmount);
/// @dev returns the name of this component
/// to successfully register the component with an instance the name MUST be unique in the linked instance
function getName() external view returns (string memory name);
/// @dev defines which ERC20 token is used by this component
function getToken() external view returns (IERC20Metadata token);
/// @dev returns token handler for this component
function getTokenHandler() external view returns (TokenHandler tokenHandler);
/// @dev defines the wallet address used to hold the ERC20 tokens related to this component
/// the default address is the token handler address
function getWallet() external view returns (address walletAddress);
/// @dev returns true iff this compoent intercepts nft minting and transfers for objects registered by this component
function isNftInterceptor() external view returns(bool isInterceptor);
/// @dev returns true iff this component is registered with the registry
function isRegistered() external view returns (bool);
/// @dev returns the component infos for this component
/// for a non registered component the function returns getInitialComponentInfo()
function getComponentInfo() external view returns (IComponents.ComponentInfo memory info);
/// @dev returns the iniital component infos for this component
function getInitialComponentInfo() external view returns (IComponents.ComponentInfo memory info);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Amount} from "../type/Amount.sol";
import {Fee} from "../type/Fee.sol";
import {IService} from "../shared/IService.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {UFixed} from "../type/UFixed.sol";
import {VersionPart} from "../type/Version.sol";
/// @dev component base class
/// component examples are staking, product, distribution, pool and oracle
interface IComponentService is
IService
{
// registerProduct
error ErrorComponentServiceCallerNotInstance(address caller);
error ErrorComponentServiceNotProduct(address product);
error ErrorComponentServiceTokenInvalid(address token);
// registerComponent
error ErrorComponentServiceCallerNotProduct(address caller);
error ErrorComponentServiceNotComponent(address component);
error ErrorComponentServiceNotInstanceLinkedComponent(address component);
error ErrorComponentServiceComponentTypeNotSupported(address component, ObjectType invalid);
error ErrorComponentServiceComponentParentInvalid(address component, NftId required, NftId actual);
error ErrorComponentServiceComponentReleaseMismatch(address component, VersionPart serviceRelease, VersionPart componentRelease);
error ErrorComponentServiceComponentAlreadyRegistered(address component);
error ErrorProductServiceNoDistributionExpected(NftId productNftId);
error ErrorProductServiceDistributionAlreadyRegistered(NftId productNftId, NftId distributionNftId);
error ErrorProductServiceNoOraclesExpected(NftId productNftId);
error ErrorProductServiceOraclesAlreadyRegistered(NftId productNftId, uint8 expectedOracles);
error ErrorProductServicePoolAlreadyRegistered(NftId productNftId, NftId poolNftId);
error ErrorComponentServiceNewWalletAddressZero();
error ErrorComponentServiceWalletAddressZero();
error ErrorComponentServiceWalletAddressIsSameAsCurrent();
error ErrorComponentServiceWithdrawAmountIsZero();
error ErrorComponentServiceWithdrawAmountExceedsLimit(Amount withdrawnAmount, Amount withdrawLimit);
error ErrorComponentServiceWalletAllowanceTooSmall(address wallet, address spender, uint256 allowance, uint256 amount);
event LogComponentServiceComponentLocked(address component, bool locked);
event LogComponentServiceRegistered(NftId instanceNftId, NftId componentNftId, ObjectType componentType, address component, address token, address initialOwner);
event LogComponentServiceWalletAddressChanged(NftId componentNftId, address currentWallet, address newWallet);
event LogComponentServiceWalletTokensTransferred(NftId componentNftId, address currentWallet, address newWallet, uint256 currentBalance);
event LogComponentServiceComponentFeesWithdrawn(NftId componentNftId, address recipient, address token, Amount withdrawnAmount);
event LogComponentServiceProductFeesUpdated(NftId productNftId);
event LogComponentServiceDistributionFeesUpdated(NftId distributionNftId);
event LogComponentServicePoolFeesUpdated(NftId poolNftId);
event LogComponentServiceUpdateFee(
NftId nftId,
string feeName,
UFixed previousFractionalFee,
Amount previousFixedFee,
UFixed newFractionalFee,
Amount newFixedFee
);
//-------- component ----------------------------------------------------//
/// @dev Approves the callers token handler to spend up to the specified amount of tokens.
/// Reverts if the component's token handler wallet is not the token handler itself.
function approveTokenHandler(IERC20Metadata token, Amount amount) external;
/// @dev Sets the components associated wallet address.
/// To set the wallet to the token handler contract, use address(0) as the new wallet adress.
function setWallet(address newWallet) external;
/// @dev Locks/Unlocks the calling component.
function setLocked(bool locked) external;
/// @dev Withdraw fees from the distribution component. Only component owner is allowed to withdraw fees.
/// @param withdrawAmount the amount to withdraw
/// @return withdrawnAmount the amount that was actually withdrawn
function withdrawFees(Amount withdrawAmount) external returns (Amount withdrawnAmount);
/// @dev Registers the provided component with the product (sender)
function registerComponent(address component) external returns (NftId componentNftId);
//-------- product ------------------------------------------------------//
/// @dev Registers the specified product component for the instance (sender)
function registerProduct(address product, address token) external returns (NftId productNftId);
function setProductFees(
Fee memory productFee, // product fee on net premium
Fee memory processingFee // product fee on payout amounts
) external;
//-------- distribution -------------------------------------------------//
function setDistributionFees(
Fee memory distributionFee, // distribution fee for sales that do not include commissions
Fee memory minDistributionOwnerFee // min fee required by distribution owner (not including commissions for distributors)
) external;
//-------- pool ---------------------------------------------------------//
function setPoolFees(
Fee memory poolFee, // pool fee on net premium
Fee memory stakingFee, // pool fee on staked capital from investor
Fee memory performanceFee // pool fee on profits from capital investors
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount} from "../type/Amount.sol";
import {IAuthorizedComponent} from "../shared/IAuthorizedComponent.sol";
import {IAuthorization} from "../authorization/IAuthorization.sol";
import {IInstance} from "../instance/IInstance.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
/// @dev component base class
/// component examples are product, distribution, pool and oracle
interface IInstanceLinkedComponent is
IAuthorizedComponent
{
error ErrorInstanceLinkedComponentTypeMismatch(ObjectType requiredType, ObjectType objectType);
error ErrorInstanceLinkedComponentNotProduct(NftId nftId, ObjectType objectType);
/// @dev Withdraw fees from the distribution component. Only component owner is allowed to withdraw fees.
/// @param amount the amount to withdraw
/// @return withdrawnAmount the amount that was actually withdrawn
function withdrawFees(Amount amount) external returns (Amount withdrawnAmount);
/// @dev defines the instance to which this component is linked to
function getInstance() external view returns (IInstance instance);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ObjectType} from "../type/ObjectType.sol";
import {StateId} from "../type/StateId.sol";
interface ILifecycle {
error ErrorNoLifecycle(address contractAddress, ObjectType objectType);
error ErrorFromStateMissmatch(address contractAddress, ObjectType objectType, StateId actual, StateId required);
error ErrorInvalidStateTransition(
address contractAddress,
ObjectType objectType,
StateId fromStateId,
StateId toStateId
);
function hasLifecycle(
ObjectType objectType
) external view returns (bool);
function getInitialState(
ObjectType objectType
) external view returns (StateId);
function isValidTransition(
ObjectType objectType,
StateId fromId,
StateId toId
) external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IRegistryLinked} from "./IRegistryLinked.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
interface INftOwnable is
IERC165,
IRegistryLinked
{
event LogNftOwnableNftLinkedToAddress(NftId nftId, address owner);
error ErrorNftOwnableInitialOwnerZero();
error ErrorNftOwnableNotOwner(address account);
error ErrorNftOwnableInvalidType(NftId nftId, ObjectType expectedObjectType);
error ErrorNftOwnableAlreadyLinked(NftId nftId);
error ErrorNftOwnableContractNotRegistered(address contractAddress);
function linkToRegisteredNftId() external returns (NftId);
function getNftId() external view returns (NftId);
function getOwner() external view returns (address);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract InitializableERC165 is
Initializable,
IERC165
{
mapping(bytes4 => bool) private _isSupported;
// @dev initializes with support for ERC165
function __ERC165_init() internal onlyInitializing() {
_initializeERC165();
}
function _initializeERC165() internal {
_isSupported[type(IERC165).interfaceId] = true;
}
// @dev register support for provided interfaceId
// includes initialization for ERC165_ID if not yet done
function _registerInterface(bytes4 interfaceId) internal onlyInitializing() {
_registerInterfaceNotInitializing(interfaceId);
}
function _registerInterfaceNotInitializing(bytes4 interfaceId) internal{
_isSupported[interfaceId] = true;
}
function supportsInterface(bytes4 interfaceId) external view override returns (bool) {
return _isSupported[interfaceId];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAuthorization} from "../authorization/IAuthorization.sol";
import {IAuthorizedComponent} from "../shared/IAuthorizedComponent.sol";
import {IComponents} from "../instance/module/IComponents.sol";
import {IComponentService} from "./IComponentService.sol";
import {IInstance} from "../instance/IInstance.sol";
import {IInstanceLinkedComponent} from "./IInstanceLinkedComponent.sol";
import {IInstanceService} from "../instance/IInstanceService.sol";
import {IOracleService} from "../oracle/IOracleService.sol";
import {Amount} from "../type/Amount.sol";
import {Component} from "./Component.sol";
import {InstanceReader} from "../instance/InstanceReader.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType, COMPONENT, INSTANCE, ORACLE, PRODUCT} from "../type/ObjectType.sol";
import {RequestId} from "../type/RequestId.sol";
import {RoleId, RoleIdLib} from "../type/RoleId.sol";
import {TokenHandler} from "../shared/TokenHandler.sol";
import {Timestamp} from "../type/Timestamp.sol";
import {VersionPart} from "../type/Version.sol";
// then add (Distribution|Pool|Product)Upradeable that also intherit from Versionable
// same pattern as for Service which is also upgradeable
abstract contract InstanceLinkedComponent is
Component,
IInstanceLinkedComponent
{
// keccak256(abi.encode(uint256(keccak256("gif-next.contracts.component.Component.sol")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant INSTANCE_LINKED_COMPONENT_LOCATION_V1 = 0xffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f00;
struct InstanceLinkedComponentStorage {
IInstance _instance; // instance for this component
InstanceReader _instanceReader; // instance reader for this component
IAuthorization _initialAuthorization;
IComponentService _componentService;
IOracleService _oracleService;
}
//--- view functions ----------------------------------------------------//
/// @inheritdoc IInstanceLinkedComponent
function getInstance() public view virtual override returns (IInstance instance) {
return _getInstanceLinkedComponentStorage()._instance;
}
/// @inheritdoc IAuthorizedComponent
function getAuthorization() external view virtual returns (IAuthorization authorization) {
return _getInstanceLinkedComponentStorage()._initialAuthorization;
}
/// @inheritdoc IInstanceLinkedComponent
function withdrawFees(Amount amount)
external
virtual
restricted()
onlyOwner()
returns (Amount withdrawnAmount)
{
return _withdrawFees(amount);
}
//--- internal functions ------------------------------------------------//
function _sendRequest(
NftId oracleNftId,
bytes memory requestData,
Timestamp expiryAt,
string memory callbackMethod
)
internal
virtual
returns (RequestId requestId)
{
return _getInstanceLinkedComponentStorage()._oracleService.request(
oracleNftId,
requestData,
expiryAt,
callbackMethod);
}
function _cancelRequest(RequestId requestId)
internal
virtual
{
_getInstanceLinkedComponentStorage()._oracleService.cancel(requestId);
}
function _resendRequest(RequestId requestId)
internal
virtual
{
_getInstanceLinkedComponentStorage()._oracleService.resend(requestId);
}
function _getInstanceLinkedComponentStorage() private pure returns (InstanceLinkedComponentStorage storage $) {
assembly {
$.slot := INSTANCE_LINKED_COMPONENT_LOCATION_V1
}
}
function __InstanceLinkedComponent_init(
address registry,
NftId parentNftId,
string memory name,
ObjectType componentType,
IAuthorization authorization,
bool isInterceptor,
address initialOwner
)
internal
virtual
onlyInitializing()
{
// validate registry, nft ids and get parent nft id
NftId instanceNftId = _checkAndGetInstanceNftId(
registry,
parentNftId,
componentType);
// set and check linked instance
InstanceLinkedComponentStorage storage $ = _getInstanceLinkedComponentStorage();
$._instance = IInstance(
IRegistry(registry).getObjectAddress(instanceNftId));
// set component specific parameters
__Component_init(
$._instance.authority(), // instance linked components need to point to instance admin
registry,
parentNftId,
name,
componentType,
isInterceptor,
initialOwner,
""); // registry data
// set instance linked specific parameters
$._instanceReader = $._instance.getInstanceReader();
$._initialAuthorization = authorization;
$._componentService = IComponentService(_getServiceAddress(COMPONENT()));
$._oracleService = IOracleService(_getServiceAddress(ORACLE()));
// register interfaces
_registerInterface(type(IInstanceLinkedComponent).interfaceId);
}
function _checkAndGetInstanceNftId(
address registryAddress,
NftId parentNftId,
ObjectType componentType
)
internal
view
returns (NftId instanceNftId)
{
// if product, then parent is already instance
if (componentType == PRODUCT()) {
_checkAndGetRegistry(registryAddress, parentNftId, INSTANCE());
return parentNftId;
}
// if not product parent is product, and parent of product is instance
IRegistry registry = _checkAndGetRegistry(registryAddress, parentNftId, PRODUCT());
return registry.getParentNftId(parentNftId);
}
/// @dev checks the and gets registry.
/// validates registry using a provided nft id and expected object type.
function _checkAndGetRegistry(
address registryAddress,
NftId objectNftId,
ObjectType requiredType
)
internal
view
returns (IRegistry registry)
{
registry = IRegistry(registryAddress);
IRegistry.ObjectInfo memory info = registry.getObjectInfo(objectNftId);
if (info.objectType != requiredType) {
revert ErrorInstanceLinkedComponentTypeMismatch(requiredType, info.objectType);
}
}
/// @dev for instance linked components the wallet address stored in the instance store.
/// updating needs to go throug component service
function _setWallet(address newWallet) internal virtual override onlyOwner {
IComponentService(_getServiceAddress(COMPONENT())).setWallet(newWallet);
}
function _getComponentInfo() internal virtual override view returns (IComponents.ComponentInfo memory info) {
NftId componentNftId = getRegistry().getNftIdForAddress(address(this));
// if registered, attempt to return component info via instance reader
if (componentNftId.gtz()) {
// component registerd with registry
info = _getInstanceReader().getComponentInfo(getNftId());
// check if also registered with instance
if (address(info.tokenHandler) != address(0)) {
return info;
}
}
// return data from component contract if not yet registered
return super._getComponentInfo();
}
/// @dev returns reader for linked instance
function _getInstanceReader() internal view returns (InstanceReader reader) {
return _getInstanceLinkedComponentStorage()._instanceReader;
}
function _withdrawFees(Amount amount)
internal
returns (Amount withdrawnAmount)
{
return _getInstanceLinkedComponentStorage()._componentService.withdrawFees(amount);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {Amount} from "../type/Amount.sol";
import {ClaimId} from "../type/ClaimId.sol";
import {IRegistryLinked} from "../shared/IRegistryLinked.sol";
import {NftId} from "../type/NftId.sol";
import {PayoutId} from "../type/PayoutId.sol";
import {Timestamp} from "../type/Timestamp.sol";
/// @dev Generic interface for contracts that need to hold policies and receive payouts.
/// The framework notifies policy holder contracts for policy creation/expiry, claim confirmation and payout execution
interface IPolicyHolder is
IERC165,
IERC721Receiver,
IRegistryLinked
{
/// @dev Callback function that will be called after successful policy activation.
/// Active policies may open claims under the activated policy.
function policyActivated(NftId policyNftId, Timestamp activatedAt) external;
/// @dev Callback function to indicate the specified policy has expired.
/// expired policies no longer accept new claims.
function policyExpired(NftId policyNftId, Timestamp expiredAt) external;
/// @dev Callback function to notify the confirmation of the specified claim.
function claimConfirmed(NftId policyNftId, ClaimId claimId, Amount amount) external;
/// @dev Callback function to notify the successful payout.
function payoutExecuted(NftId policyNftId, PayoutId payoutId, Amount amount, address beneficiary) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {INftOwnable} from "./INftOwnable.sol";
import {IRelease} from "../registry/IRelease.sol";
import {IRegistry} from "../registry/IRegistry.sol";
/// @title IRegisterable
/// @dev Marks contracts that are intended to be registered in the registry.
///
interface IRegisterable is
IAccessManaged,
INftOwnable,
IRelease
{
// __Registerable_init
error ErrorAuthorityInvalid(address authority);
// onlyActive()
error ErrorRegisterableNotActive();
/// @dev Returns true iff this contract managed by its authority is active.
/// Queries the IAccessManaged.authority().
function isActive() external view returns (bool active);
/// @dev retuns the object info relevant for registering for this contract
/// IMPORTANT information returned by this function may only be used
/// before the contract is registered in the registry.
/// Once registered this information MUST only be accessed via the registry.
function getInitialInfo()
external
view
returns (IRegistry.ObjectInfo memory);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IRegistry} from "../registry/IRegistry.sol";
interface IRegistryLinked {
error ErrorNotRegistry(address registryAddress);
function getRegistry() external view returns (IRegistry);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {IRegisterable} from "./IRegisterable.sol";
import {IVersionable} from "../upgradeability/IVersionable.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RoleId} from "../type/RoleId.sol";
interface IService is
IAccessManaged,
IRegisterable,
IVersionable
{
/// @dev returns the domain for this service.
/// In any GIF release only one service for any given domain may be deployed.
function getDomain() external pure returns(ObjectType serviceDomain);
/// @dev returns the GIF release specific role id.
/// These role ids are used to authorize service to service communication.
function getRoleId() external view returns(RoleId serviceRoleId);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ObjectType} from "../type/ObjectType.sol";
import {StateId, zeroStateId} from "../type/StateId.sol";
import {ILifecycle} from "./ILifecycle.sol";
abstract contract Lifecycle is
ILifecycle
{
mapping(ObjectType objectType => StateId initialState)
private _initialState;
mapping(ObjectType objectType => mapping(StateId stateFrom => mapping(StateId stateTo => bool isValid)))
private _isValidTransition;
/// @dev child class must implement and CALL setup func at deployment/initializaton time
function _setupLifecycle() internal virtual;
function setInitialState(ObjectType ttype, StateId state) internal virtual {
assert(_initialState[ttype] == zeroStateId());
_initialState[ttype] = state;
}
function setStateTransition(ObjectType ttype, StateId oldState, StateId newState) internal virtual {
assert(_isValidTransition[ttype][oldState][newState] == false);
_isValidTransition[ttype][oldState][newState] = true;
}
function hasLifecycle(
ObjectType objectType
)
public
view
override
returns (bool)
{
return _initialState[objectType].gtz();
}
function getInitialState(
ObjectType objectType
)
public
view
returns (StateId)
{
return _initialState[objectType];
}
function checkTransition(
StateId stateId,
ObjectType objectType,
StateId expectedFromId,
StateId toId
)
public
view
{
// revert if no life cycle support
if (_initialState[objectType].eqz()) {
revert ErrorNoLifecycle(address(this), objectType);
}
// revert if current state is not expected `from` state
if(stateId != expectedFromId) {
revert ErrorFromStateMissmatch(address(this), objectType, stateId, expectedFromId);
}
// enforce valid state transition
if (!_isValidTransition[objectType][stateId][toId]) {
revert ErrorInvalidStateTransition(
address(this),
objectType,
stateId,
toId
);
}
}
function isValidTransition(
ObjectType objectType,
StateId fromId,
StateId toId
) public view returns (bool) {
return _isValidTransition[objectType][fromId][toId];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {InitializableERC165} from "./InitializableERC165.sol";
import {INftOwnable} from "./INftOwnable.sol";
import {NftId} from "../type/NftId.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {RegistryLinked} from "./RegistryLinked.sol";
contract NftOwnable is
InitializableERC165,
RegistryLinked,
INftOwnable
{
// keccak256(abi.encode(uint256(keccak256("etherisc.storage.NftOwnable")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant NFT_OWNABLE_STORAGE_LOCATION_V1 = 0x07ebcf49758b6ed3af50fa146bec0abe157c0218fe65dc0874c286e9d5da4f00;
struct NftOwnableStorage {
NftId _nftId;
address _initialOwner;
}
/// @dev enforces msg.sender is owner of nft (or initial owner of nft ownable)
modifier onlyOwner() {
if (msg.sender != getOwner()) {
revert ErrorNftOwnableNotOwner(msg.sender);
}
_;
}
modifier onlyNftOwner(NftId nftId) {
if(!getRegistry().isOwnerOf(nftId, msg.sender)) {
revert ErrorNftOwnableNotOwner(msg.sender);
}
_;
}
modifier onlyNftOfType(NftId nftId, ObjectType expectedObjectType) {
_checkNftType(nftId, expectedObjectType);
_;
}
function _checkNftType(NftId nftId, ObjectType expectedObjectType) internal view {
if(expectedObjectType.eqz() || !getRegistry().isObjectType(nftId, expectedObjectType)) {
revert ErrorNftOwnableInvalidType(nftId, expectedObjectType);
}
}
/// @dev Initialization for upgradable contracts.
// used in __Registerable_init, ProxyManager._preDeployChecksAndSetup
function __NftOwnable_init(
address registry,
address initialOwner
)
internal
virtual
onlyInitializing()
{
__ERC165_init();
__RegistryLinked_init(registry);
if(initialOwner == address(0)) {
revert ErrorNftOwnableInitialOwnerZero();
}
_getNftOwnableStorage()._initialOwner = initialOwner;
}
/// @dev links this contract to nft after registration
// needs to be done once per registered contract and
// reduces registry calls to check ownership
// does not need any protection as function can only do the "right thing"
function linkToRegisteredNftId()
public
virtual
returns (NftId nftId)
{
return _linkToNftOwnable(address(this));
}
function getNftId() public view virtual override returns (NftId) {
return _getNftOwnableStorage()._nftId;
}
function getOwner() public view virtual override returns (address) {
NftOwnableStorage storage $ = _getNftOwnableStorage();
if ($._nftId.gtz()) {
return getRegistry().ownerOf($._nftId);
}
return $._initialOwner;
}
/// @dev used in constructor of registry service manager
// links ownership of registry service manager ot nft owner of registry service
function _linkToNftOwnable(
address nftOwnableAddress
)
internal
returns (NftId)
{
NftOwnableStorage storage $ = _getNftOwnableStorage();
if ($._nftId.gtz()) {
revert ErrorNftOwnableAlreadyLinked($._nftId);
}
if (!getRegistry().isRegistered(nftOwnableAddress)) {
revert ErrorNftOwnableContractNotRegistered(nftOwnableAddress);
}
$._nftId = getRegistry().getNftIdForAddress(nftOwnableAddress);
emit LogNftOwnableNftLinkedToAddress($._nftId, getOwner());
return $._nftId;
}
function _getNftOwnableStorage() private pure returns (NftOwnableStorage storage $) {
// solhint-disable-next-line no-inline-assembly
assembly {
$.slot := NFT_OWNABLE_STORAGE_LOCATION_V1
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {AccessManagerCloneable} from "../authorization/AccessManagerCloneable.sol";
import {ContractLib} from "../shared/ContractLib.sol";
import {NftId, NftIdLib} from "../type/NftId.sol";
import {NftOwnable} from "../shared/NftOwnable.sol";
import {ObjectType} from "../type/ObjectType.sol";
import {VersionPart, VersionPartLib} from "../type/Version.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IRegisterable} from "./IRegisterable.sol";
import {IRelease} from "../registry/IRelease.sol";
abstract contract Registerable is
AccessManagedUpgradeable,
NftOwnable,
IRegisterable
{
// keccak256(abi.encode(uint256(keccak256("gif-next.contracts.shared.Registerable.sol")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant REGISTERABLE_LOCATION_V1 = 0x6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa300;
struct RegisterableStorage {
NftId _parentNftId;
ObjectType _objectType;
bool _isInterceptor;
bytes _data;
}
modifier onlyActive() {
if (!isActive()) {
revert ErrorRegisterableNotActive();
}
_;
}
function __Registerable_init(
address authority,
address registry,
NftId parentNftId,
ObjectType objectType,
bool isInterceptor,
address initialOwner,
bytes memory data // writeonly data that will saved in the object info record of the registry
)
internal
virtual
onlyInitializing()
{
if (!ContractLib.isAuthority(authority)) {
revert ErrorAuthorityInvalid(authority);
}
__AccessManaged_init(authority);
__NftOwnable_init(registry, initialOwner);
RegisterableStorage storage $ = _getRegisterableStorage();
$._parentNftId = parentNftId;
$._objectType = objectType;
$._isInterceptor = isInterceptor;
$._data = data;
_registerInterface(type(IAccessManaged).interfaceId);
}
/// @inheritdoc IRegisterable
function isActive() public virtual view returns (bool active) {
return !AccessManagerCloneable(authority()).isTargetClosed(address(this));
}
/// @inheritdoc IRelease
function getRelease() public virtual view returns (VersionPart release) {
return AccessManagerCloneable(authority()).getRelease();
}
/// @inheritdoc IRegisterable
function getInitialInfo()
public
view
virtual
returns (IRegistry.ObjectInfo memory info)
{
RegisterableStorage storage $ = _getRegisterableStorage();
return IRegistry.ObjectInfo(
NftIdLib.zero(),
$._parentNftId,
$._objectType,
$._isInterceptor,
address(this),
getOwner(),
$._data);
}
function _getRegisterableStorage() private pure returns (RegisterableStorage storage $) {
assembly {
$.slot := REGISTERABLE_LOCATION_V1
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {ContractLib} from "../shared/ContractLib.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {IRegistryLinked} from "./IRegistryLinked.sol";
contract RegistryLinked is
Initializable,
IRegistryLinked
{
// priorize simplicity and size over using standard upgradeability structs
IRegistry private _registry;
/// @dev initialization for upgradable contracts
// used in _initializeRegisterable
function __RegistryLinked_init(
address registry
)
internal
virtual
onlyInitializing()
{
if (!ContractLib.isRegistry(registry)) {
revert ErrorNotRegistry(registry);
}
_registry = IRegistry(registry);
}
function getRegistry() public view returns (IRegistry) {
return _registry;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Amount, AmountLib} from "../type/Amount.sol";
import {ContractLib} from "../shared/ContractLib.sol";
import {IRegistry} from "../registry/IRegistry.sol";
import {NftId} from "../type/NftId.sol";
import {SERVICE} from "../type/ObjectType.sol";
/// @dev Token specific transfer helper base contract.
/// A default token contract is provided via contract constructor.
/// Relies internally on OpenZeppelin SafeERC20.safeTransferFrom.
/// This base contract simplifies writing tests.
contract TokenHandlerBase {
// _setWallet
event LogTokenHandlerWalletAddressChanged(NftId componentNftId, address oldWallet, address newWallet);
event LogTokenHandlerWalletTokensTransferred(NftId componentNftId, address oldWallet, address newWallet, Amount amount);
// _approveTokenHandler
event LogTokenHandlerTokenApproved(NftId nftId, address tokenHandler, address token, Amount amount, bool isMaxAmount);
// _transfer
event LogTokenHandlerTokenTransfer(address token, address from, address to, Amount amount);
// constructor
error ErrorTokenHandlerNotRegistry(address registry);
error ErrorTokenHandlerComponentNotRegistered(address component);
error ErrorTokenHandlerTokenAddressZero();
// _setWallet
error ErrorTokenHandlerNewWalletAddressZero();
error ErrorTokenHandlerAddressIsSameAsCurrent();
// _approveTokenHandler
error ErrorTokenHandlerNotWallet(NftId nftId, address tokenHandler, address wallet);
// _checkPreconditions
error ErrorTokenHandlerBalanceTooLow(address token, address from, uint256 balance, uint256 expectedBalance);
error ErrorTokenHandlerAllowanceTooSmall(address token, address from, address spender, uint256 allowance, uint256 expectedAllowance);
error ErrorTokenHandlerAmountIsZero();
IRegistry public immutable REGISTRY;
IERC20Metadata public immutable TOKEN;
address public immutable COMPONENT;
NftId public immutable NFT_ID;
address internal _wallet;
constructor(
address registry,
address component,
address token
)
{
if (!ContractLib.isRegistry(registry)) {
revert ErrorTokenHandlerNotRegistry(registry);
}
if (token == address(0)) {
revert ErrorTokenHandlerTokenAddressZero();
}
REGISTRY = IRegistry(registry);
COMPONENT = component;
NFT_ID = REGISTRY.getNftIdForAddress(component);
if (NFT_ID.eqz()) {
revert ErrorTokenHandlerComponentNotRegistered(component);
}
TOKEN = IERC20Metadata(token);
// self approval of token handler to max amount
_approve(TOKEN, AmountLib.max());
}
/// @dev Checks the balance and allowance for the from address and amount.
/// When requiring amount > 0 set checkAmount to true.
function checkBalanceAndAllowance(
address from,
Amount amount,
bool checkAmount
)
external
view
{
_checkBalanceAndAllowance(from, amount, checkAmount);
}
/// @dev Returns the wallet linked to this TokenHandler.
function getWallet()
public
view
returns (address wallet)
{
if (_wallet == address(0)) {
return address(this);
}
return _wallet;
}
/// @dev Approves token handler to spend up to the specified amount of tokens.
/// Sets spending limit to type(uint256).max for AmountLib.max().
/// Reverts if wallet is not token handler itself.
/// Sets approvel using SareERC20.forceApprove internally.
function _approve(
IERC20Metadata token,
Amount amount
)
internal
{
// check that wallet is token handler contract itself
if(_wallet != address(0)) {
revert ErrorTokenHandlerNotWallet(NFT_ID, address(this), _wallet);
}
// update spending limit for AmountLib.max() to type(uint256).max
uint256 amountInt = amount.toInt();
bool isMaxAmount = false;
if (amount == AmountLib.max()) {
amountInt = type(uint256).max;
isMaxAmount = true;
}
emit LogTokenHandlerTokenApproved(NFT_ID, address(this), address(token), amount, isMaxAmount);
// execute approval
SafeERC20.forceApprove(
token,
address(this),
amountInt);
}
function _setWallet(address newWallet)
internal
{
address oldWallet = _wallet;
if (newWallet == oldWallet) {
revert ErrorTokenHandlerAddressIsSameAsCurrent();
}
// effects
address oldWalletForBalance = getWallet();
_wallet = newWallet;
emit LogTokenHandlerWalletAddressChanged(NFT_ID, oldWallet, newWallet);
// interactions
Amount balanceAmount = AmountLib.toAmount(
TOKEN.balanceOf(oldWalletForBalance));
if (balanceAmount.gtz()) {
// move tokens from old to new wallet
emit LogTokenHandlerWalletTokensTransferred(NFT_ID, oldWallet, newWallet, balanceAmount);
if (oldWallet == address(0)) {
// transfer from the component requires an allowance
_transfer(address(this), newWallet, balanceAmount, true);
} else if (newWallet == address(0)) {
_transfer(oldWallet, address(this), balanceAmount, true);
} else {
_transfer(oldWallet, newWallet, balanceAmount, true);
}
}
}
function _pullToken(address from, Amount amount)
internal
{
_transfer(from, getWallet(), amount, true);
}
function _pushToken(address to, Amount amount)
internal
{
_transfer(getWallet(), to, amount, true);
}
function _transfer(
address from,
address to,
Amount amount,
bool checkPreconditions
)
internal
{
if (checkPreconditions) {
bool checkAmount = true;
_checkBalanceAndAllowance(from, amount, checkAmount);
}
// transfer the tokens
emit LogTokenHandlerTokenTransfer(address(TOKEN), from, to, amount);
SafeERC20.safeTransferFrom(
TOKEN,
from,
to,
amount.toInt());
}
function _checkBalanceAndAllowance(
address from,
Amount amount,
bool checkAmount
)
internal
view
{
// amount must be greater than zero
if (checkAmount && amount.eqz()) {
revert ErrorTokenHandlerAmountIsZero();
}
// allowance must be >= amount
uint256 allowance = TOKEN.allowance(from, address(this));
if (allowance < amount.toInt()) {
revert ErrorTokenHandlerAllowanceTooSmall(address(TOKEN), from, address(this), allowance, amount.toInt());
}
// balance must be >= amount
uint256 balance = TOKEN.balanceOf(from);
if (balance < amount.toInt()) {
revert ErrorTokenHandlerBalanceTooLow(address(TOKEN), from, balance, amount.toInt());
}
}
}
/// @dev Token specific transfer helper.
/// Contract is derived from TokenHandlerBase and adds
/// authorization based on OpenZeppelin AccessManaged.
contract TokenHandler is
AccessManaged,
TokenHandlerBase
{
// onlyService
error ErrorTokenHandlerNotService(address service);
modifier onlyService() {
if (!REGISTRY.isObjectType(msg.sender, SERVICE())) {
revert ErrorTokenHandlerNotService(msg.sender);
}
_;
}
constructor(
address registry,
address component,
address token,
address authority
)
TokenHandlerBase(registry, component, token)
AccessManaged(authority)
{ }
/// @dev Sets the wallet address for the component.
/// Seeting the new wallet address to address(0) will set the wallet to the tokenHandler contract itself.
/// If the current wallet has tokens, these will be transferred.
/// If the new wallet address is externally owned, an approval from the
/// owner of the external wallet to the tokenhandler of the component that
/// covers the current component balance must exist.
function setWallet(address newWallet)
external
restricted()
onlyService()
{
_setWallet(newWallet);
}
/// @dev Approves token handler to spend up to the specified amount of tokens.
/// Sets spending limit to type(uint256).max for AmountLib.max().
/// Reverts if component wallet is not component itself.
/// Sets approvel using SareERC20.forceApprove internally.
function approve(
IERC20Metadata token,
Amount amount
)
external
restricted()
onlyService()
{
_approve(token, amount);
}
/// @dev Collect tokens from outside of GIF and transfer them to the wallet.
/// This method also checks balance and allowance and makes sure the amount is greater than zero.
function pullToken(
address from,
Amount amount
)
external
restricted()
onlyService()
{
_pullToken(from, amount);
}
/// @dev Distribute tokens from a wallet within the scope of gif to some address.
function pushToken(
address to,
Amount amount
)
external
restricted()
onlyService()
{
_pushToken(to, amount);
}
/// @dev Distribute fee tokens from a wallet within the scope of gif to some address.
/// Separate push function for component service.
function pushFeeToken(
address to,
Amount amount
)
external
restricted()
onlyService()
{
_pushToken(to, amount);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {UFixed, UFixedLib} from "./UFixed.sol";
/// @dev Targets: 100 trillion (worlds GDP) with 6 decimal places
/// 3 trillion USD (total crypto market cap) with 12 decimal places.
/// 2023 100 trillion USD => 100e12 * 1e6 = 1e20
/// 2024 2 trillion crypto market cap => 2e12 * 1e18 = 2e30
type Amount is uint96;
using {
addAmount as +,
subAmount as -,
eqAmount as ==,
nqAmount as !=,
ltAmount as <,
ltAmount as <=,
gtAmount as >,
gteAmount as >=,
AmountLib.add,
AmountLib.eq,
AmountLib.eqz,
AmountLib.gtz,
AmountLib.gt,
AmountLib.gte,
AmountLib.multiplyWith,
AmountLib.toInt,
AmountLib.toUFixed
} for Amount global;
function addAmount(Amount a, Amount b) pure returns (Amount) {
return AmountLib.add(a, b);
}
function subAmount(Amount a, Amount b) pure returns (Amount) {
return AmountLib.sub(a, b);
}
function eqAmount(Amount a, Amount b) pure returns (bool) {
return AmountLib.eq(a, b);
}
function nqAmount(Amount a, Amount b) pure returns (bool) {
return !AmountLib.eq(a, b);
}
function ltAmount(Amount a, Amount b) pure returns (bool) {
return AmountLib.lt(a, b);
}
function lteAmount(Amount a, Amount b) pure returns (bool) {
return AmountLib.lte(a, b);
}
function gtAmount(Amount a, Amount b) pure returns (bool) {
return AmountLib.gt(a, b);
}
function gteAmount(Amount a, Amount b) pure returns (bool) {
return AmountLib.gte(a, b);
}
library AmountLib {
error ErrorAmountLibValueTooBig(uint256 amount);
function zero() public pure returns (Amount) {
return Amount.wrap(0);
}
function max() public pure returns (Amount) {
return Amount.wrap(_max());
}
/// @dev converts the uint amount into Amount
/// function reverts if value is exceeding max Amount value
function toAmount(uint256 amount) public pure returns (Amount) {
if(amount > _max()) {
revert ErrorAmountLibValueTooBig(amount);
}
return Amount.wrap(uint96(amount));
}
/// @dev return true if amount equals 0
function eqz(Amount amount) public pure returns (bool) {
return Amount.unwrap(amount) == 0;
}
/// @dev return true if amount1 equals amount2
function eq(Amount amount1, Amount amount2) public pure returns (bool) {
return Amount.unwrap(amount1) == Amount.unwrap(amount2);
}
/// @dev return true if amount a1 is less than a2
function lt(Amount a1, Amount a2) public pure returns (bool) {
return Amount.unwrap(a1) < Amount.unwrap(a2);
}
/// @dev return true if amount a1 is less or equal than a2
function lte(Amount a1, Amount a2) public pure returns (bool) {
return Amount.unwrap(a1) <= Amount.unwrap(a2);
}
/// @dev return true if amount a1 is greater than a2
function gt(Amount a1, Amount a2) public pure returns (bool) {
return Amount.unwrap(a1) > Amount.unwrap(a2);
}
/// @dev return true if amount a1 is greater or equal than a2
function gte(Amount a1, Amount a2) public pure returns (bool) {
return Amount.unwrap(a1) >= Amount.unwrap(a2);
}
/// @dev return minimum of a1 and a2.
function min(Amount a1, Amount a2) public pure returns (Amount) {
if (Amount.unwrap(a1) < Amount.unwrap(a2)) {
return a1;
}
return a2;
}
/// @dev return true if amount is larger than 0
function gtz(Amount amount) public pure returns (bool) {
return Amount.unwrap(amount) > 0;
}
function add(Amount a1, Amount a2) public pure returns (Amount) {
return Amount.wrap(Amount.unwrap(a1) + Amount.unwrap(a2));
}
function sub(Amount a1, Amount a2) public pure returns (Amount) {
return Amount.wrap(Amount.unwrap(a1) - Amount.unwrap(a2));
}
function toInt(Amount amount) public pure returns (uint256) {
return uint256(uint96(Amount.unwrap(amount)));
}
function toUFixed(Amount amount) public pure returns (UFixed) {
return UFixedLib.toUFixed(Amount.unwrap(amount));
}
function multiplyWith(Amount amount, UFixed factor) public pure returns (Amount) {
return toAmount((factor * UFixedLib.toUFixed(Amount.unwrap(amount))).toInt());
}
function _max() internal pure returns (uint96) {
// IMPORTANT: type nees to match with actual definition for Amount
return type(uint96).max;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
/// @dev Target: Cover 10 years with 1 ms block times.
/// Typical block times are a few seconds.
type Blocknumber is uint40;
using {
gtBlocknumber as >,
gteBlocknumber as >=,
ltBlocknumber as <,
lteBlocknumber as <=,
eqBlocknumber as ==,
neBlocknumber as !=,
BlocknumberLib.toInt,
BlocknumberLib.eq,
BlocknumberLib.ne,
BlocknumberLib.eqz,
BlocknumberLib.gtz,
BlocknumberLib.gt,
BlocknumberLib.gte,
BlocknumberLib.lt,
BlocknumberLib.lte
} for Blocknumber global;
/// @dev return true if Blocknumber a is greater than Blocknumber b
function gtBlocknumber(Blocknumber a, Blocknumber b) pure returns (bool) {
return Blocknumber.unwrap(a) > Blocknumber.unwrap(b);
}
/// @dev return true if Blocknumber a is greater than or equal to Blocknumber b
function gteBlocknumber(Blocknumber a, Blocknumber b) pure returns (bool) {
return Blocknumber.unwrap(a) >= Blocknumber.unwrap(b);
}
/// @dev return true if Blocknumber a is less than Blocknumber b
function ltBlocknumber(Blocknumber a, Blocknumber b) pure returns (bool) {
return Blocknumber.unwrap(a) < Blocknumber.unwrap(b);
}
/// @dev return true if Blocknumber a is less than or equal to Blocknumber b
function lteBlocknumber(Blocknumber a, Blocknumber b) pure returns (bool) {
return Blocknumber.unwrap(a) <= Blocknumber.unwrap(b);
}
/// @dev return true if Blocknumber a is equal to Blocknumber b
function eqBlocknumber(Blocknumber a, Blocknumber b) pure returns (bool) {
return Blocknumber.unwrap(a) == Blocknumber.unwrap(b);
}
/// @dev return true if Blocknumber a is not equal to Blocknumber b
function neBlocknumber(Blocknumber a, Blocknumber b) pure returns (bool) {
return Blocknumber.unwrap(a) != Blocknumber.unwrap(b);
}
library BlocknumberLib {
function zero() public pure returns (Blocknumber) {
return Blocknumber.wrap(0);
}
function max() public pure returns (Blocknumber) {
return Blocknumber.wrap(type(uint40).max);
}
function current() public view returns (Blocknumber) {
return Blocknumber.wrap(uint40(block.number));
}
function toBlocknumber(uint256 blocknum) public pure returns (Blocknumber) {
return Blocknumber.wrap(uint32(blocknum));
}
/// @dev return true iff blocknumber is 0
function eqz(Blocknumber blocknumber) public pure returns (bool) {
return Blocknumber.unwrap(blocknumber) == 0;
}
/// @dev return true iff blocknumber is > 0
function gtz(Blocknumber blocknumber) public pure returns (bool) {
return Blocknumber.unwrap(blocknumber) > 0;
}
/// @dev return true if Blocknumber a is greater than Blocknumber b
function gt(
Blocknumber a,
Blocknumber b
) public pure returns (bool isAfter) {
return gtBlocknumber(a, b);
}
/// @dev return true if Blocknumber a is greater than or equal to Blocknumber b
function gte(
Blocknumber a,
Blocknumber b
) public pure returns (bool isAfterOrSame) {
return gteBlocknumber(a, b);
}
/// @dev return true if Blocknumber a is less than Blocknumber b
function lt(
Blocknumber a,
Blocknumber b
) public pure returns (bool isBefore) {
return ltBlocknumber(a, b);
}
/// @dev return true if Blocknumber a is less than or equal to Blocknumber b
function lte(
Blocknumber a,
Blocknumber b
) public pure returns (bool isBeforeOrSame) {
return lteBlocknumber(a, b);
}
/// @dev return true if Blocknumber a is equal to Blocknumber b
function eq(
Blocknumber a,
Blocknumber b
) public pure returns (bool isSame) {
return eqBlocknumber(a, b);
}
/// @dev return true if Blocknumber a is not equal to Blocknumber b
function ne(
Blocknumber a,
Blocknumber b
) public pure returns (bool isDifferent) {
return neBlocknumber(a, b);
}
/// @dev converts the Blocknumber to a uint256
function toInt(Blocknumber blocknumber) public pure returns (uint256) {
return uint256(uint32(Blocknumber.unwrap(blocknumber)));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {NftId} from "./NftId.sol";
/// @dev Target: Cover chain IDs up to 26 decimal places.
/// Current longest chain ID seems to be DCHAIN Testnet: 2713017997578000 with 16 decimal places
type ChainId is uint96;
using {
eqChainId as ==,
neChainId as !=,
ChainIdLib.toInt,
ChainIdLib.eqz,
ChainIdLib.gtz
} for ChainId global;
/// @dev return true if ChainId a is equal to ChainId b
function eqChainId(ChainId a, ChainId b) pure returns (bool) {
return ChainId.unwrap(a) == ChainId.unwrap(b);
}
/// @dev return true if ChainId a is not equal to ChainId b
function neChainId(ChainId a, ChainId b) pure returns (bool) {
return ChainId.unwrap(a) != ChainId.unwrap(b);
}
library ChainIdLib {
error ErrorChainIdLibValueTooBig(uint256 chainId);
function zero() public pure returns (ChainId) {
return ChainId.wrap(0);
}
function max() public pure returns (ChainId) {
return ChainId.wrap(_max());
}
function current() public view returns (ChainId) {
return toChainId(block.chainid);
}
/// @dev return true iff chainId is 0
function eqz(ChainId chainId) public pure returns (bool) {
return ChainId.unwrap(chainId) == 0;
}
/// @dev return true iff chainId is > 0
function gtz(ChainId chainId) public pure returns (bool) {
return ChainId.unwrap(chainId) > 0;
}
/// @dev converts the uint into ChainId
/// function reverts if value is exceeding max ChainId value
function toChainId(uint256 chainId) public pure returns (ChainId) {
if(chainId > _max()) {
revert ErrorChainIdLibValueTooBig(chainId);
}
return ChainId.wrap(uint96(chainId));
}
/// @dev returns true iff NFT ID is from the current chain.
function isCurrentChain(NftId nftId) public view returns (bool) {
return _fromNftId(nftId) == block.chainid;
}
function fromNftId(NftId nftId) public pure returns (ChainId) {
return toChainId(_fromNftId(nftId));
}
/// @dev converts the ChainId to a uint256
function toInt(ChainId chainId) public pure returns (uint256) {
return uint256(uint96(ChainId.unwrap(chainId)));
}
function _fromNftId(NftId nftId) internal pure returns (uint256 chainIdInt) {
uint256 nftIdInt = nftId.toInt();
uint256 chainIdDigits = nftIdInt % 100; // Extract the last two digits
chainIdInt = nftIdInt % 10**(chainIdDigits + 2) / 100; // Extract the chainId
}
function _max() internal pure returns (uint96) {
// IMPORTANT: type nees to match with actual definition for Amount
return type(uint96).max;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
// uint16 allows for 65'535 claims per policy
type ClaimId is uint16;
import {CLAIM} from "./ObjectType.sol";
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {NftId} from "./NftId.sol";
// type bindings
using {
eqClaimId as ==,
neClaimId as !=,
ClaimIdLib.eq,
ClaimIdLib.eqz,
ClaimIdLib.gtz,
ClaimIdLib.toInt,
ClaimIdLib.toKey32
} for ClaimId global;
// pure free functions for operators
function eqClaimId(ClaimId a, ClaimId b) pure returns (bool isSame) {
return ClaimIdLib.eq(a, b);
}
function neClaimId(ClaimId a, ClaimId b) pure returns (bool isDifferent) {
return ClaimId.unwrap(a) != ClaimId.unwrap(b);
}
// library functions that operate on user defined type
library ClaimIdLib {
/// @dev claim id min value (0), use only for non-initialized values
function zero() public pure returns (ClaimId) {
return ClaimId.wrap(0);
}
/// @dev claim id max value (2**16-1), use only for non-initialized values
function max() public pure returns (ClaimId) {
return ClaimId.wrap(type(uint16).max);
}
/// @dev Converts an uint into a ClaimId.
function toClaimId(uint256 a) public pure returns (ClaimId) {
return ClaimId.wrap(uint16(a));
}
/// @dev Converts the ClaimId to a uint.
function toInt(ClaimId a) public pure returns (uint16) {
return uint16(ClaimId.unwrap(a));
}
/// @dev Converts the ClaimId and NftId to a Key32.
function toKey32(ClaimId claimId, NftId policyNftId) public pure returns (Key32) {
return Key32Lib.toKey32(CLAIM(), toKeyId(claimId, policyNftId));
}
/// @dev Converts the ClaimId and NftId to a Key32.
function toKeyId(ClaimId claimId, NftId policyNftId) public pure returns (KeyId) {
return KeyId.wrap(
bytes31(
bytes14(
uint112(
NftId.unwrap(policyNftId) << 16 + ClaimId.unwrap(claimId)))));
}
/// @dev Returns true if the value is non-zero (> 0).
function gtz(ClaimId a) public pure returns (bool) {
return ClaimId.unwrap(a) > 0;
}
function eq(ClaimId a, ClaimId b) public pure returns (bool) {
return ClaimId.unwrap(a) == ClaimId.unwrap(b);
}
/// @dev Returns true if the value is zero (== 0).
function eqz(ClaimId a) public pure returns (bool) {
return ClaimId.unwrap(a) == 0;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {NftId} from "./NftId.sol";
import {DISTRIBUTOR_TYPE} from "./ObjectType.sol";
type DistributorType is bytes8;
// type bindings
using {
eqDistributorType as ==,
neDistributorType as !=,
DistributorTypeLib.toKey32
} for DistributorType global;
// general pure free functions
// pure free functions for operators
function eqDistributorType(
DistributorType a,
DistributorType b
) pure returns (bool isSame) {
return DistributorType.unwrap(a) == DistributorType.unwrap(b);
}
function neDistributorType(
DistributorType a,
DistributorType b
) pure returns (bool isDifferent) {
return DistributorType.unwrap(a) != DistributorType.unwrap(b);
}
// library functions that operate on user defined type
library DistributorTypeLib {
function zero() public pure returns (DistributorType) {
return DistributorType.wrap(bytes8(0));
}
// @dev Converts a referral string into an id.
function toDistributorType(NftId distributionNftId, string memory name) public pure returns (DistributorType) {
return DistributorType.wrap(bytes8(keccak256(abi.encode(distributionNftId, name))));
}
/// @dev Returns the key32 value for the specified nft id and object type.
function toKey32(DistributorType id) public pure returns (Key32 key) {
return Key32Lib.toKey32(DISTRIBUTOR_TYPE(), toKeyId(id));
}
/// @dev Returns the key id value for the specified nft id
function toKeyId(DistributorType id) public pure returns (KeyId keyId) {
return KeyId.wrap(bytes31(DistributorType.unwrap(id)));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Amount, AmountLib} from "./Amount.sol";
import {UFixed, UFixedLib} from "./UFixed.sol";
struct Fee {
// slot 0
UFixed fractionalFee;
Amount fixedFee;
}
library FeeLib {
/// @dev Return a zero fee struct (0, 0)
function zero() public pure returns (Fee memory fee) {
return Fee(UFixed.wrap(0), AmountLib.zero());
}
/// @dev Converts the uint256 to a fee struct.
function toFee(
UFixed fractionalFee,
uint256 fixedFee
) public pure returns (Fee memory fee) {
return Fee(fractionalFee, AmountLib.toAmount(fixedFee));
}
/// @dev Calculates fee and net amounts for the provided parameters
function calculateFee(
Fee memory fee,
Amount amount
)
public
pure
returns (
Amount feeAmount,
Amount netAmount
)
{
netAmount = amount;
if(gtz(fee)) {
UFixed fractionalAmount =
amount.toUFixed() * fee.fractionalFee;
feeAmount = AmountLib.toAmount(fractionalAmount.toInt()) + fee.fixedFee;
netAmount = netAmount - feeAmount;
}
}
/// @dev Return the percent fee struct (x%, 0)
function percentageFee(uint8 percent) public pure returns (Fee memory fee) {
return Fee(UFixedLib.toUFixed(percent, -2), AmountLib.zero());
}
// pure free functions for operators
function eq(Fee memory a, Fee memory b) public pure returns (bool isSame) {
return a.fixedFee == b.fixedFee && a.fractionalFee == b.fractionalFee;
}
function gtz(Fee memory fee) public pure returns (bool) {
return UFixed.unwrap(fee.fractionalFee) > 0 || fee.fixedFee.gtz();
}
function eqz(Fee memory fee) public pure returns (bool) {
return fee.fixedFee.eqz() && UFixed.unwrap(fee.fractionalFee) == 0;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ObjectType} from "./ObjectType.sol";
type Key32 is bytes32;
type KeyId is bytes31;
// type bindings
using {
eqKey32 as ==,
neKey32 as !=,
Key32Lib.toKeyId,
Key32Lib.toObjectType
} for Key32 global;
// @dev Returns true iff keys are identical
function eqKey32(Key32 a, Key32 b) pure returns (bool isSame) {
return Key32.unwrap(a) == Key32.unwrap(b);
}
// @dev Returns true iff keys are different
function neKey32(Key32 a, Key32 b) pure returns (bool isDifferent) {
return Key32.unwrap(a) != Key32.unwrap(b);
}
library Key32Lib {
uint8 public constant TYPE_SHIFT = 31 * 8;
uint8 public constant ID_SHIFT = uint8(32 * 8 - TYPE_SHIFT);
bytes32 public constant TYPE_MASK = bytes32(bytes1(type(uint8).max)); // [32] byte in bytes32
bytes32 public constant ID_MASK = bytes32(~TYPE_MASK); // [0..31] bytes in bytes32
function toKey32(ObjectType objectType, KeyId id) public pure returns (Key32) {
uint256 uintObjectType = ObjectType.unwrap(objectType);
uint256 uintId = uint248(KeyId.unwrap(id));
uint256 uintKey = (uintObjectType << TYPE_SHIFT) + uintId;
return Key32.wrap(bytes32(uintKey));
}
function toObjectType(Key32 key) public pure returns (ObjectType objectType) {
bytes32 key32 = Key32.unwrap(key);
objectType = ObjectType.wrap(uint8(uint256(key32 & TYPE_MASK) >> TYPE_SHIFT));
}
function toKeyId(Key32 key) public pure returns (KeyId id) {
bytes32 key32 = Key32.unwrap(key);
id = KeyId.wrap(bytes31((key32 & ID_MASK) << ID_SHIFT));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32} from "../type/Key32.sol";
// based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol
library LibKey32Set {
struct Set {
Key32[] keys;
mapping(Key32 key => uint256 index) at;
}
error ErrorKey32SetAlreadyAdded(Key32 key);
error ErrorKey32SetNotInSet(Key32 key);
function add(Set storage set, Key32 key) external {
if (set.at[key] > 0) {
revert ErrorKey32SetAlreadyAdded(key);
}
set.keys.push(key);
set.at[key] = set.keys.length;
}
function remove(Set storage set, Key32 key) external {
uint256 nftIdIndex = set.at[key];
if (nftIdIndex == 0) {
revert ErrorKey32SetNotInSet(key);
}
uint256 toDeleteIndex = nftIdIndex - 1;
uint256 lastIndex = set.keys.length - 1;
if (lastIndex != toDeleteIndex) {
Key32 lastId = set.keys[lastIndex];
set.keys[toDeleteIndex] = lastId;
set.at[lastId] = nftIdIndex; // Replace lastValue's index to valueIndex
}
set.keys.pop();
delete set.at[key];
}
function isEmpty(Set storage set) external view returns(bool empty) {
return set.keys.length == 0;
}
function contains(Set storage set, Key32 key) external view returns(bool inSet) {
return set.at[key] > 0;
}
function size(Set storage set) external view returns(uint256 length) {
return set.keys.length;
}
function getElementAt(Set storage set, uint256 index) external view returns(Key32 key) {
return set.keys[index];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {ObjectType} from "./ObjectType.sol";
// uint96 allows for chain ids up to 13 digits
type NftId is uint96;
// type bindings
using {
eqNftId as ==,
neNftId as !=,
NftIdLib.toInt,
NftIdLib.gtz,
NftIdLib.eqz,
NftIdLib.eq,
NftIdLib.toKeyId,
NftIdLib.toKey32
} for NftId global;
// pure free functions for operators
function eqNftId(NftId a, NftId b) pure returns (bool isSame) {
return NftIdLib.eq(a, b);
}
function neNftId(NftId a, NftId b) pure returns (bool isDifferent) {
return NftIdLib.ne(a, b);
}
// library functions that operate on user defined type
library NftIdLib {
/// @dev the zero nft id
/// is never a valid nft id and implies a non-initialized value
function zero() public pure returns (NftId) {
return NftId.wrap(0);
}
/// @dev Converts the uint256 to a NftId.
function toNftId(uint256 id) public pure returns (NftId) {
return NftId.wrap(uint96(id));
}
/// @dev Converts the NftId to a uint256.
function toInt(NftId nftId) public pure returns (uint96) {
return uint96(NftId.unwrap(nftId));
}
/// @dev Returns true if the value is non-zero (> 0).
function gtz(NftId a) public pure returns (bool) {
return NftId.unwrap(a) > 0;
}
/// @dev Returns true if the value is zero (== 0).
function eqz(NftId a) public pure returns (bool) {
return NftId.unwrap(a) == 0;
}
/// @dev Returns true if the values are equal (==).
function eq(NftId a, NftId b) public pure returns (bool isSame) {
return NftId.unwrap(a) == NftId.unwrap(b);
}
/// @dev Returns true if the values are not equal (!=).
function ne(NftId a, NftId b) public pure returns (bool isSame) {
return NftId.unwrap(a) != NftId.unwrap(b);
}
/// @dev Returns the key32 value for the specified nft id and object type.
function toKey32(NftId id, ObjectType objectType) public pure returns (Key32 key) {
return Key32Lib.toKey32(objectType, toKeyId(id));
}
/// @dev Returns the key id value for the specified nft id
function toKeyId(NftId id) public pure returns (KeyId keyId) {
return KeyId.wrap(bytes31(uint248(NftId.unwrap(id))));
}
function toNftId(KeyId keyId) public pure returns (NftId nftId) {
uint248 keyIdInt = uint248(bytes31(KeyId.unwrap(keyId)));
assert(keyIdInt < type(uint96).max);
return NftId.wrap(uint96(keyIdInt));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {NftId} from "../type/NftId.sol";
// based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol
library LibNftIdSet {
struct Set {
NftId[] ids;
mapping(NftId nftid => uint256 index) at;
}
error ErrorNftIdSetAlreadyAdded(NftId nftId);
error ErrorNftIdSetNotInSet(NftId nftId);
function add(Set storage set, NftId nftId) external {
if (set.at[nftId] > 0) {
revert ErrorNftIdSetAlreadyAdded(nftId);
}
set.ids.push(nftId);
set.at[nftId] = set.ids.length;
}
function remove(Set storage set, NftId nftId) external {
uint256 nftIdIndex = set.at[nftId];
if (nftIdIndex == 0) {
revert ErrorNftIdSetNotInSet(nftId);
}
uint256 toDeleteIndex = nftIdIndex - 1;
uint256 lastIndex = set.ids.length - 1;
if (lastIndex != toDeleteIndex) {
NftId lastId = set.ids[lastIndex];
set.ids[toDeleteIndex] = lastId;
set.at[lastId] = nftIdIndex; // Replace lastValue's index to valueIndex
}
set.ids.pop();
delete set.at[nftId];
}
function isEmpty(Set storage set) external view returns(bool empty) {
return set.ids.length == 0;
}
function contains(Set storage set, NftId nftId) external view returns(bool inSet) {
return set.at[nftId] > 0;
}
function size(Set storage set) external view returns(uint256 length) {
return set.ids.length;
}
function getElementAt(Set storage set, uint256 index) external view returns(NftId nftId) {
return set.ids[index];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {StrLib} from "./String.sol";
import {VersionPart} from "./Version.sol";
type ObjectType is uint8;
// type bindings
using {
eqObjectType as ==,
neObjectType as !=,
ObjectTypeLib.toInt,
ObjectTypeLib.toName,
ObjectTypeLib.eqz,
ObjectTypeLib.eq,
ObjectTypeLib.gtz
} for ObjectType global;
//--- GIF object types/domains (rage: 1 - 99) -------------------------------//
function PROTOCOL() pure returns (ObjectType) {
return ObjectType.wrap(1);
}
function REGISTRY() pure returns (ObjectType) {
return ObjectType.wrap(2);
}
function STAKING() pure returns (ObjectType) {
return ObjectType.wrap(3);
}
function RELEASE() pure returns (ObjectType) {
return ObjectType.wrap(6);
}
function ROLE() pure returns (ObjectType) {
return ObjectType.wrap(7);
}
function SERVICE() pure returns (ObjectType) {
return ObjectType.wrap(8);
}
function INSTANCE() pure returns (ObjectType) {
return ObjectType.wrap(10);
}
/// @dev Generic component object type.
/// Component role id range is 11-19.
/// Stick to this range for new component object types.
function COMPONENT() pure returns (ObjectType) {
return ObjectType.wrap(11);
}
/// @dev Product object type.
/// IMPORTANT the actual value has an influence on the corresponding role id (RoleIdLib.sol).
/// Do not change this value without updating the corresponding role id calculation.
function PRODUCT() pure returns (ObjectType) {
return ObjectType.wrap(12);
}
function ORACLE() pure returns (ObjectType) {
return ObjectType.wrap(13);
}
function DISTRIBUTION() pure returns (ObjectType) {
return ObjectType.wrap(14);
}
function POOL() pure returns (ObjectType) {
return ObjectType.wrap(15);
}
/// @dev Application object type.
/// Range for NFT objects created thorugh components is 20-29.
function APPLICATION() pure returns (ObjectType) {
return ObjectType.wrap(20);
}
function POLICY() pure returns (ObjectType) {
return ObjectType.wrap(21);
}
function BUNDLE() pure returns (ObjectType) {
return ObjectType.wrap(22);
}
function DISTRIBUTOR() pure returns (ObjectType) {
return ObjectType.wrap(23);
}
/// @dev Stake object type.
/// NFT object type is 30
function STAKE() pure returns (ObjectType) {
return ObjectType.wrap(30);
}
/// @dev Staking target object type.
function TARGET() pure returns (ObjectType) {
return ObjectType.wrap(31);
}
/// @dev Accounting object type.
/// Range for non-NFT types created through components is 40+
function ACCOUNTING() pure returns (ObjectType) {
return ObjectType.wrap(40);
}
function FEE() pure returns (ObjectType) {
return ObjectType.wrap(41);
}
function PRICE() pure returns (ObjectType) {
return ObjectType.wrap(42);
}
function PREMIUM() pure returns (ObjectType) {
return ObjectType.wrap(43);
}
function RISK() pure returns (ObjectType) {
return ObjectType.wrap(44);
}
function CLAIM() pure returns (ObjectType) {
return ObjectType.wrap(45);
}
function PAYOUT() pure returns (ObjectType) {
return ObjectType.wrap(46);
}
function REQUEST() pure returns (ObjectType) {
return ObjectType.wrap(47);
}
function DISTRIBUTOR_TYPE() pure returns (ObjectType) {
return ObjectType.wrap(48);
}
function REFERRAL() pure returns (ObjectType) {
return ObjectType.wrap(49);
}
/// @dev Object type for GIF core target roles.
function CORE() pure returns (ObjectType) {
return ObjectType.wrap(97);
}
/// @dev Object type for target roles of contracts outside the GIF framework.
/// Example: Custom supporting contracts for a product component.
function CUSTOM() pure returns (ObjectType) {
return ObjectType.wrap(98);
}
/// @dev Object type that includes any other object type.
/// Note that eq()/'==' does not take this property into account.
function ALL() pure returns (ObjectType) {
return ObjectType.wrap(99);
}
// other pure free functions for operators
function eqObjectType(ObjectType a, ObjectType b) pure returns (bool isSame) {
return ObjectType.unwrap(a) == ObjectType.unwrap(b);
}
function neObjectType(ObjectType a, ObjectType b) pure returns (bool isSame) {
return ObjectType.unwrap(a) != ObjectType.unwrap(b);
}
// library functions that operate on user defined type
library ObjectTypeLib {
function zero() public pure returns (ObjectType) {
return ObjectType.wrap(0);
}
/// @dev Converts the uint256 into ObjectType.
function toObjectType(uint256 objectType) public pure returns (ObjectType) {
return ObjectType.wrap(uint8(objectType));
}
/// @dev Converts the NftId to a uint256.
function toInt(ObjectType objectType) public pure returns (uint96) {
return uint96(ObjectType.unwrap(objectType));
}
/// @dev Returns true if the value is non-zero (> 0).
function gtz(ObjectType a) public pure returns (bool) {
return ObjectType.unwrap(a) > 0;
}
/// @dev Returns true if the value is zero (== 0).
function eqz(ObjectType a) public pure returns (bool) {
return ObjectType.unwrap(a) == 0;
}
/// @dev Returns true if the values are equal (==).
function eq(ObjectType a, ObjectType b) public pure returns (bool isSame) {
return ObjectType.unwrap(a) == ObjectType.unwrap(b);
}
/// @dev Returns true if the values are not equal (!=).
function ne(ObjectType a, ObjectType b) public pure returns (bool isSame) {
return ObjectType.unwrap(a) != ObjectType.unwrap(b);
}
/// @dev Returns the type/domain name for the provided object type
function toName(ObjectType objectType) public pure returns (string memory name) {
if (objectType == REGISTRY()) {
return "Registry";
} else if (objectType == STAKING()) {
return "Staking";
} else if (objectType == RELEASE()) {
return "Release";
} else if (objectType == INSTANCE()) {
return "Instance";
} else if (objectType == COMPONENT()) {
return "Component";
} else if (objectType == PRODUCT()) {
return "Product";
} else if (objectType == ORACLE()) {
return "Oracle";
} else if (objectType == DISTRIBUTION()) {
return "Distribution";
} else if (objectType == POOL()) {
return "Pool";
} else if (objectType == APPLICATION()) {
return "Application";
} else if (objectType == POLICY()) {
return "Policy";
} else if (objectType == CLAIM()) {
return "Claim";
} else if (objectType == PRICE()) {
return "Price";
} else if (objectType == BUNDLE()) {
return "Bundle";
} else if (objectType == RISK()) {
return "Risk";
} else if (objectType == ACCOUNTING()) {
return "Accounting";
}
// fallback: ObjectType<obect-type-int>
return string(
abi.encodePacked(
"ObjectType",
StrLib.uintToString(
toInt(objectType))));
}
// TODO move to IService
function toVersionedName(
string memory name,
string memory suffix,
VersionPart release
)
external
pure
returns (string memory versionedName)
{
string memory versionName = "V0";
if (release.toInt() >= 10) {
versionName = "V";
}
versionedName = string(
abi.encodePacked(
name,
suffix,
versionName,
release.toString()));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
// uint40 allows for 65'535 claims with 16'777'216 payouts each per policy
type PayoutId is uint40;
import {ClaimId} from "./ClaimId.sol";
import {PAYOUT} from "./ObjectType.sol";
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {NftId} from "./NftId.sol";
// type bindings
using {
eqPayoutId as ==,
nePayoutId as !=,
PayoutIdLib.eqz,
PayoutIdLib.gtz,
PayoutIdLib.toInt,
PayoutIdLib.toClaimId,
PayoutIdLib.toPayoutNo,
PayoutIdLib.toKey32
} for PayoutId global;
// pure free functions for operators
function eqPayoutId(PayoutId a, PayoutId b) pure returns (bool isSame) {
return PayoutId.unwrap(a) == PayoutId.unwrap(b);
}
function nePayoutId(PayoutId a, PayoutId b) pure returns (bool isDifferent) {
return PayoutId.unwrap(a) != PayoutId.unwrap(b);
}
// library functions that operate on user defined type
library PayoutIdLib {
/// @dev Converts the PayoutId to a uint.
function zero() public pure returns (PayoutId) {
return PayoutId.wrap(0);
}
/// @dev Converts an uint into a PayoutId.
function toPayoutId(ClaimId claimId, uint24 payoutNo) public pure returns (PayoutId) {
return PayoutId.wrap((uint40(ClaimId.unwrap(claimId)) << 24) + payoutNo);
}
function toClaimId(PayoutId payoutId) public pure returns (ClaimId) {
return ClaimId.wrap(uint16(PayoutId.unwrap(payoutId) >> 24));
}
function toPayoutNo(PayoutId payoutId) public pure returns (uint24) {
return uint24(PayoutId.unwrap(payoutId) & 16777215);
}
/// @dev Converts the PayoutId to a uint.
function toInt(PayoutId a) public pure returns (uint40) {
return PayoutId.unwrap(a);
}
/// @dev Returns true if the value is non-zero (> 0).
function gtz(PayoutId a) public pure returns (bool) {
return PayoutId.unwrap(a) > 0;
}
/// @dev Returns true if the value is zero (== 0).
function eqz(PayoutId a) public pure returns (bool) {
return PayoutId.unwrap(a) == 0;
}
/// @dev Converts the PayoutId and NftId to a Key32.
function toKey32(PayoutId payoutId, NftId policyNftId) public pure returns (Key32) {
return Key32Lib.toKey32(PAYOUT(), toKeyId(payoutId, policyNftId));
}
/// @dev Converts the PayoutId and NftId to a Key32.
function toKeyId(PayoutId payoutId, NftId policyNftId) public pure returns (KeyId) {
return KeyId.wrap(
bytes31(
bytes15(
uint120(
(NftId.unwrap(policyNftId) << 40) + PayoutId.unwrap(payoutId)))));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {NftId} from "./NftId.sol";
import {REFERRAL} from "./ObjectType.sol";
type ReferralId is bytes8;
type ReferralStatus is uint8;
// type bindings
using {
eqReferralId as ==,
neReferralId as !=,
ReferralLib.eqz,
ReferralLib.toInt,
ReferralLib.toKey32
} for ReferralId global;
using {
eqReferralStatus as ==,
neReferralStatus as !=
} for ReferralStatus global;
// general pure free functions
// @dev Returns true iff a and b are identical
function eqReferralId(ReferralId a, ReferralId b) pure returns (bool isSame) {
return ReferralId.unwrap(a) == ReferralId.unwrap(b);
}
// @dev Returns true iff a and b are different
function neReferralId(ReferralId a, ReferralId b) pure returns (bool isDifferent) {
return ReferralId.unwrap(a) != ReferralId.unwrap(b);
}
// @dev Returns true iff a and b are identical
function eqReferralStatus(ReferralStatus a, ReferralStatus b) pure returns (bool isSame) {
return ReferralStatus.unwrap(a) == ReferralStatus.unwrap(b);
}
// @dev Returns true iff a and b are different
function neReferralStatus(ReferralStatus a, ReferralStatus b) pure returns (bool isDifferent) {
return ReferralStatus.unwrap(a) != ReferralStatus.unwrap(b);
}
function REFERRAL_OK() pure returns (ReferralStatus) {
return ReferralStatus.wrap(10);
}
function REFERRAL_ERROR_UNKNOWN() pure returns (ReferralStatus) {
return ReferralStatus.wrap(100);
}
function REFERRAL_ERROR_EXPIRED() pure returns (ReferralStatus) {
return ReferralStatus.wrap(110);
}
function REFERRAL_ERROR_EXHAUSTED() pure returns (ReferralStatus) {
return ReferralStatus.wrap(120);
}
library ReferralLib {
function zero() public pure returns (ReferralId) {
return ReferralId.wrap(bytes8(0));
}
// @dev Converts a referral string into an id.
function toReferralId(NftId distributionNftId, string memory referral) public pure returns (ReferralId) {
return ReferralId.wrap(bytes8(keccak256(abi.encode(distributionNftId, referral))));
}
function toReferralStatus(uint8 status) public pure returns (ReferralStatus) {
return ReferralStatus.wrap(status);
}
/// @dev Converts a referral id into a uint256.
function toInt(ReferralId referralId) public pure returns (uint256) {
return uint64(ReferralId.unwrap(referralId));
}
/// @dev Returns the key32 value for the specified nft id and object type.
function toKey32(ReferralId id) public pure returns (Key32 key) {
return Key32Lib.toKey32(REFERRAL(), toKeyId(id));
}
/// @dev Returns the key id value for the specified nft id
function toKeyId(ReferralId id) public pure returns (KeyId keyId) {
return KeyId.wrap(bytes31(ReferralId.unwrap(id)));
}
function eqz(ReferralId id) public pure returns (bool) {
return eqReferralId(id, zero());
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {REQUEST} from "./ObjectType.sol";
type RequestId is uint64;
// type bindings
using {
eqRequestId as ==,
neRequestId as !=,
RequestIdLib.eqz,
RequestIdLib.gtz,
RequestIdLib.toInt,
RequestIdLib.toKey32
} for RequestId global;
// general pure free functions
function eqRequestId(RequestId a, RequestId b) pure returns (bool isSame) {
return RequestIdLib.eq(a, b);
}
function neRequestId(RequestId a, RequestId b) pure returns (bool isSame) {
return RequestIdLib.ne(a, b);
}
library RequestIdLib {
// @dev zero element to refer to a non existing/initialized request
function zero() public pure returns (RequestId) {
return RequestId.wrap(0);
}
// @dev Converts an int id into a request id.
function toRequestId(uint256 id) public pure returns (RequestId) {
return RequestId.wrap(uint64(id));
}
// @dev Converts a request id back to an int value.
function toInt(RequestId requestId) public pure returns (uint256) {
return RequestId.unwrap(requestId);
}
// @dev Returns true iff request id a == 0
function eqz(RequestId a) public pure returns (bool) {
return RequestId.unwrap(a) == 0;
}
// @dev Returns true iff request id a > 0
function gtz(RequestId a) public pure returns (bool) {
return RequestId.unwrap(a) > 0;
}
// @dev Returns true iff risk ids a and b are identical
function eq(RequestId a, RequestId b) public pure returns (bool isSame) {
return RequestId.unwrap(a) == RequestId.unwrap(b);
}
// @dev Returns true iff risk ids a and b are different
function ne(RequestId a, RequestId b) public pure returns (bool isSame) {
return RequestId.unwrap(a) != RequestId.unwrap(b);
}
/// @dev Returns the key32 value for the specified nft id and object type.
function toKey32(RequestId id) public pure returns (Key32 key) {
return Key32Lib.toKey32(REQUEST(), toKeyId(id));
}
/// @dev Returns the key id value for the specified nft id
function toKeyId(RequestId id) public pure returns (KeyId keyId) {
return KeyId.wrap(bytes31(uint248(RequestId.unwrap(id))));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {RequestId} from "../type/RequestId.sol";
// based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol
library LibRequestIdSet {
struct Set {
RequestId[] ids;
mapping(RequestId requestId => uint256 index) at;
}
error ErrorRequestIdSetAlreadyAdded(RequestId requestId);
error ErrorRequestIdSetNotInSet(RequestId requestId);
function add(Set storage set, RequestId requestId) external {
if (set.at[requestId] > 0) {
revert ErrorRequestIdSetAlreadyAdded(requestId);
}
set.ids.push(requestId);
set.at[requestId] = set.ids.length;
}
function remove(Set storage set, RequestId requestId) external {
uint256 requestIdIndex = set.at[requestId];
if (requestIdIndex == 0) {
revert ErrorRequestIdSetNotInSet(requestId);
}
uint256 toDeleteIndex = requestIdIndex - 1;
uint256 lastIndex = set.ids.length - 1;
if (lastIndex != toDeleteIndex) {
RequestId lastId = set.ids[lastIndex];
set.ids[toDeleteIndex] = lastId;
set.at[lastId] = requestIdIndex; // Replace lastValue's index to valueIndex
}
set.ids.pop();
delete set.at[requestId];
}
function isEmpty(Set storage set) external view returns(bool empty) {
return set.ids.length == 0;
}
function contains(Set storage set, RequestId requestId) external view returns(bool inSet) {
return set.at[requestId] > 0;
}
function size(Set storage set) external view returns(uint256 length) {
return set.ids.length;
}
function getElementAt(Set storage set, uint256 index) external view returns(RequestId requestId) {
return set.ids[index];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {NftId} from "./NftId.sol";
import {RISK} from "./ObjectType.sol";
type RiskId is bytes8;
// type bindings
using {
eqRiskId as ==,
neRiskId as !=,
RiskIdLib.eq,
RiskIdLib.eqz,
RiskIdLib.gtz,
RiskIdLib.toInt,
RiskIdLib.toKeyId,
RiskIdLib.toKey32
} for RiskId global;
// general pure free functions
// @dev Returns true iff risk ids a and b are identical
function eqRiskId(RiskId a, RiskId b) pure returns (bool isSame) {
return RiskId.unwrap(a) == RiskId.unwrap(b);
}
// @dev Returns true iff risk ids a and b are different
function neRiskId(RiskId a, RiskId b) pure returns (bool isDifferent) {
return RiskId.unwrap(a) != RiskId.unwrap(b);
}
library RiskIdLib {
function zero() public pure returns (RiskId) {
return RiskId.wrap(bytes8(0));
}
// @dev Converts a risk id into a uint256.
function toInt(RiskId riskId) public pure returns (uint256) {
return uint64(RiskId.unwrap(riskId));
}
// @dev Converts a risk id string with a product NftId into a risk id.
function toRiskId(NftId productNftId, bytes32 risk) public pure returns (RiskId) {
return RiskId.wrap(bytes8(keccak256(abi.encode(productNftId, risk))));
}
/// @dev Returns the key32 value for the specified risk id.
function toKey32(RiskId riskId) public pure returns (Key32 key) {
return Key32Lib.toKey32(RISK(), toKeyId(riskId));
}
/// @dev Returns the key id value for the specified nft id
function toKeyId(RiskId id) public pure returns (KeyId keyId) {
return KeyId.wrap(bytes31(RiskId.unwrap(id)));
}
function toRiskId(KeyId keyId) public pure returns (RiskId riskId) {
riskId = RiskId.wrap(bytes8(KeyId.unwrap(keyId)));
assert(toInt(riskId) < 2**64);
}
function eq(RiskId a, RiskId b) public pure returns (bool isSame) {
return eqRiskId(a, b);
}
function eqz(RiskId a) public pure returns (bool isZero) {
return eqRiskId(a, zero());
}
function gtz(RiskId a) public pure returns (bool isZero) {
return uint64(RiskId.unwrap(a)) > 0;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Key32, KeyId, Key32Lib} from "./Key32.sol";
import {ObjectType, ROLE} from "./ObjectType.sol";
import {VersionPart, VersionPartLib} from "./Version.sol";
type RoleId is uint64;
// type bindings
using {
eqRoleId as ==,
neRoleId as !=,
RoleIdLib.toInt,
RoleIdLib.isServiceRole,
RoleIdLib.eqz,
RoleIdLib.gtz
} for RoleId global;
// general pure free functions
// @dev Returns true iff role ids a and b are identical
function eqRoleId(RoleId a, RoleId b) pure returns (bool isSame) {
return RoleId.unwrap(a) == RoleId.unwrap(b);
}
// @dev Returns true iff role ids a and b are different
function neRoleId(RoleId a, RoleId b) pure returns (bool isDifferent) {
return RoleId.unwrap(a) != RoleId.unwrap(b);
}
//--- OpenZeppelin provided roles -------------------------------------------//
/// @dev Role ID needs to match with oz AccessManager.ADMIN_ROLE
function ADMIN_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(type(uint64).min); }
/// @dev Role ID needs to match with oz AccessManager.PUBLIC_ROLE
function PUBLIC_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(type(uint64).max); }
//--- GIF roles (range: 1-99) ----------------------------------------------//
/// @dev cental role for gif release management.
/// this role is necessary to call ReleaseManager.createNextRelease/activateNextRelease
/// the actual deployment of a release requires the GIF_MANAGER_ROLE.
/// GIF_ADMIN_ROLE is the admin of the GIF_MANAGER_ROLE.
/// only a single holder may hold this role at any time
function GIF_ADMIN_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(1); }
/// @dev role for token whith/blacklisting, deploying and registering the services for a new major release
/// registering services for a new major release is only possible after a new initial release has been created by the GIF_ADMIN_ROLE
/// token white/blacklisting is possible for any active release
function GIF_MANAGER_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(2); }
/// @dev role for registering remote staking targets and reporting remote total value locked amounts.
function GIF_REMOTE_MANAGER_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(3); }
// TODO check if/where this is really needed
/// @dev role assigned to release registry, release specfic to lock/unlock a release
function RELEASE_REGISTRY_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(4); }
/// @dev role assigned to every instance owner
function INSTANCE_OWNER_ROLE() pure returns (RoleId) { return RoleIdLib.toRoleId(5); }
// TODO upate role id ranges
//--- GIF core contract roles (range: 200 - 9'900) --------------------------//
// created and assigned during initial deployment for registry and staking
// granting for instances and components in instance service
// object type * 100 + 0, examples:
// - registry contract role: 200
// - staking contract role: 300
// - instance contract role: 1000
//--- GIF service roles (range 201 - 9'9xx) ---------------------------------//
// created and assigned by release manager contract
// object type * 100 + 1/major version, examples:
// - registry service role (any version): 299
// - registry service role (version 3): 203
// - registry service role (any version): 399
// - staking service role: (version 3): 303
// - application service role (version 3): 2003
//--- GIF component contract roles (range 12'001 - 19'099) ------------------//
// the min value of 12'001 is based on the following calculation:
// object type * 1000 + 1 where the lowest object type is 12 (product)
// assigned at component registration time
// object type * 1000 + instane specific component counter
// on any instance a maximum number of 999 components may be deployed
// examples:
// - 1st pool on instance: 15001
// - 1st distribution on instance: 14002
// - 1st product on instance: 12003
// - 2nd pool on instance: 15004
// - 2nd distribution on instance: 14005
// - 2nd product on instance: 12006
//--- Custom roles (range >= 1'000'000) -------------------------------------//
function CUSTOM_ROLE_MIN() pure returns (RoleId) { return RoleIdLib.toRoleId(1000000); }
library RoleIdLib {
error ErrorRoleIdTooBig(uint256 roleId);
// constant values need to match with AccessAdminLib.SERVICE_ROLE_*
uint64 public constant SERVICE_ROLE_MIN = 1000;
uint64 public constant SERVICE_ROLE_MAX = 99099; // 99 (max object type) * 1000 + 99
uint64 public constant SERVICE_ROLE_FACTOR = 1000;
/// @dev Converts the RoleId to a uint.
function zero() public pure returns (RoleId) {
return RoleId.wrap(0);
}
/// @dev Converts an uint into a role id.
function toRoleId(uint256 a) public pure returns (RoleId) {
if (a > type(uint64).max) {
revert ErrorRoleIdTooBig(a);
}
return RoleId.wrap(uint64(a));
}
function isServiceRole(RoleId roleId)
public
pure
returns (bool)
{
uint256 roleIdInt = RoleId.unwrap(roleId);
return roleIdInt >= SERVICE_ROLE_MIN && roleIdInt <= SERVICE_ROLE_MAX;
}
function toGenericServiceRoleId(
ObjectType objectType
)
public
pure
returns (RoleId)
{
return toServiceRoleId(
objectType,
VersionPartLib.releaseMax());
}
function toServiceRoleId(
ObjectType serviceDomain,
VersionPart release
)
public
pure
returns (RoleId serviceRoleId)
{
uint256 serviceRoleIdInt =
SERVICE_ROLE_MIN
+ SERVICE_ROLE_FACTOR * (serviceDomain.toInt() - 1)
+ release.toInt();
return toRoleId(serviceRoleIdInt);
}
/// @dev Converts the role id to a uint.
function toInt(RoleId a) public pure returns (uint64) {
return uint64(RoleId.unwrap(a));
}
/// @dev Returns true if the value is non-zero (> 0).
function gtz(RoleId a) public pure returns (bool) {
return RoleId.unwrap(a) > 0;
}
/// @dev Returns true if the value is zero (== 0).
function eqz(RoleId a) public pure returns (bool) {
return RoleId.unwrap(a) == 0;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
/// @dev Target: Cover durations of 1000 years.
type Seconds is uint40;
using {
SecondsEq as ==,
SecondsLt as <,
SecondsGt as >,
SecondsAdd as +,
SecondsLib.eqz,
SecondsLib.gtz,
SecondsLib.eq,
SecondsLib.gt,
SecondsLib.lt,
SecondsLib.toInt,
SecondsLib.add
} for Seconds global;
function SecondsEq(Seconds duration1, Seconds duration2) pure returns (bool) {
return SecondsLib.eq(duration1, duration2);
}
function SecondsLt(Seconds duration1, Seconds duration2) pure returns (bool) {
return SecondsLib.lt(duration1, duration2);
}
function SecondsGt(Seconds duration1, Seconds duration2) pure returns (bool) {
return SecondsLib.gt(duration1, duration2);
}
function SecondsAdd(Seconds duration1, Seconds duration2) pure returns (Seconds) {
return SecondsLib.add(duration1, duration2);
}
library SecondsLib {
error ErrorSecondsLibDurationTooBig(uint256 duration);
function zero() public pure returns (Seconds) {
return Seconds.wrap(0);
}
function max() public pure returns (Seconds) {
return Seconds.wrap(_max());
}
function fromHours(uint32 numberOfHours) public pure returns (Seconds duration) {
return Seconds.wrap(numberOfHours * 3600);
}
function oneDay() public pure returns (Seconds duration) {
return Seconds.wrap(24 * 3600);
}
function fromDays(uint32 numberOfDays) public pure returns (Seconds duration) {
return Seconds.wrap(numberOfDays * 24 * 3600);
}
function oneYear() public pure returns (Seconds duration) {
return Seconds.wrap(365 * 24 * 3600);
}
/// @dev converts the uint duration into Seconds
/// function reverts if duration is exceeding max Seconds value
function toSeconds(uint256 duration) public pure returns (Seconds) {
// if(duration > type(uint40).max) {
if(duration > _max()) {
revert ErrorSecondsLibDurationTooBig(duration);
}
return Seconds.wrap(uint40(duration));
}
/// @dev return true if duration equals 0
function eqz(Seconds duration) public pure returns (bool) {
return Seconds.unwrap(duration) == 0;
}
/// @dev return true if duration is larger than 0
function gtz(Seconds duration) public pure returns (bool) {
return Seconds.unwrap(duration) > 0;
}
/// @dev return true iff duration1 and duration2 are the same
function eq(Seconds duration1, Seconds duration2) public pure returns (bool) {
return Seconds.unwrap(duration1) == Seconds.unwrap(duration2);
}
/// @dev return true if duration1 is larger than duration2
function gt(Seconds duration1, Seconds duration2) public pure returns (bool) {
return Seconds.unwrap(duration1) > Seconds.unwrap(duration2);
}
/// @dev return true if duration1 is smaller than duration2
function lt(Seconds duration1, Seconds duration2) public pure returns (bool) {
return Seconds.unwrap(duration1) < Seconds.unwrap(duration2);
}
/// @dev returns the smaller of the duration
function min(Seconds duration1, Seconds duration2) public pure returns (Seconds) {
if (Seconds.unwrap(duration1) < Seconds.unwrap(duration2)) {
return duration1;
}
return duration2;
}
/// @dev return add duration1 and duration2
function add(Seconds duration1, Seconds duration2) public pure returns (Seconds) {
return Seconds.wrap(Seconds.unwrap(duration1) + Seconds.unwrap(duration2));
}
function toInt(Seconds duration) public pure returns (uint256) {
return uint256(uint40(Seconds.unwrap(duration)));
}
function _max() internal pure returns (uint40) {
// IMPORTANT: type nees to match with actual definition for Seconds
return type(uint40).max;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
type Selector is bytes4;
// type bindings
using {
eqSelector as ==,
neSelector as !=,
SelectorLib.toBytes4,
SelectorLib.toString,
SelectorLib.eqz
} for Selector global;
// pure free functions for operators
function eqSelector(Selector s1, Selector s2) pure returns (bool isSame) {
return SelectorLib.eq(s1, s2);
}
function neSelector(Selector s1, Selector s2) pure returns (bool isDifferent) {
return SelectorLib.ne(s1, s2);
}
// library functions that operate on user defined type
library SelectorLib {
function zero() public pure returns (Selector) {
return Selector.wrap("");
}
function eqz(Selector s) public pure returns (bool) {
return Selector.unwrap(s) == "";
}
function eq(Selector s1, Selector s2) public pure returns (bool isSame) {
return Selector.unwrap(s1) == Selector.unwrap(s2);
}
function ne(Selector s1, Selector s2) public pure returns (bool isDifferent) {
return Selector.unwrap(s1) != Selector.unwrap(s2);
}
function toSelector(bytes4 selector) public pure returns (Selector) {
return Selector.wrap(selector);
}
function toBytes4(Selector s) public pure returns (bytes4) {
return Selector.unwrap(s);
}
function toString(Selector s) public pure returns (string memory) {
return string(abi.encode(Selector.unwrap(s)));
}
}
// selector specific set library
// based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol
library SelectorSetLib {
struct Set {
Selector[] selectors;
mapping(Selector selector => uint256 index) at;
}
function add(Set storage set, Selector selector) external {
// selector already in set
if (set.at[selector] > 0) { return; }
set.selectors.push(selector);
set.at[selector] = set.selectors.length;
}
function remove(Set storage set, Selector selector) external {
uint256 selectorIndex = set.at[selector];
// selector not in set
if (selectorIndex == 0) {return; }
uint256 toDeleteIndex = selectorIndex - 1;
uint256 lastIndex = set.selectors.length - 1;
if (lastIndex != toDeleteIndex) {
Selector lastSelector = set.selectors[lastIndex];
set.selectors[toDeleteIndex] = lastSelector;
set.at[lastSelector] = selectorIndex; // Replace lastValue's index to valueIndex
}
set.selectors.pop();
delete set.at[selector];
}
function isEmpty(Set storage set) external view returns(bool empty) {
return set.selectors.length == 0;
}
function contains(Set storage set, Selector selector) external view returns(bool inSet) {
return set.at[selector] > 0;
}
function size(Set storage set) external view returns(uint256 length) {
return set.selectors.length;
}
function at(Set storage set, uint256 index) external view returns(Selector selector) {
return set.selectors[index];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
// uint96 allows for chain ids up to 13 digits
type StateId is uint8;
// type bindings
using {
eqStateId as ==,
neStateId as !=,
StateIdLib.eqz,
StateIdLib.eq,
StateIdLib.gtz,
StateIdLib.toInt
} for StateId global;
// general pure free functions
function INITIAL() pure returns (StateId) {
return toStateId(1);
}
function SCHEDULED() pure returns (StateId) {
return toStateId(2);
}
function DEPLOYING() pure returns (StateId) {
return toStateId(3);
}
function DEPLOYED() pure returns (StateId) {
return toStateId(4);
}
function ACTIVE() pure returns (StateId) {
return toStateId(5);
}
function SKIPPED() pure returns (StateId) {
return toStateId(6);
}
function APPLIED() pure returns (StateId) {
return toStateId(10);
}
function REVOKED() pure returns (StateId) {
return toStateId(20);
}
function DECLINED() pure returns (StateId) {
return toStateId(30);
}
function COLLATERALIZED() pure returns (StateId) {
return toStateId(40);
}
function SUBMITTED() pure returns (StateId) {
return toStateId(50);
}
function CONFIRMED() pure returns (StateId) {
return toStateId(51);
}
function EXPECTED() pure returns (StateId) {
return toStateId(60);
}
function FULFILLED() pure returns (StateId) {
return toStateId(70);
}
function FAILED() pure returns (StateId) {
return toStateId(7);
}
function CANCELLED() pure returns (StateId) {
return toStateId(72);
}
function PAUSED() pure returns (StateId) {
return toStateId(110);
}
function CLOSED() pure returns (StateId) {
return toStateId(200);
}
function ARCHIVED() pure returns (StateId) {
return toStateId(210);
}
function PAID() pure returns (StateId) {
return toStateId(220);
}
function KEEP_STATE() pure returns (StateId) {
return toStateId(type(uint8).max);
}
/// @dev Converts the uint8 to a StateId.
function toStateId(uint256 id) pure returns (StateId) {
return StateId.wrap(uint8(id));
}
// TODO move to StateIdLib and rename to zero()
/// @dev Return the StateId zero (0)
function zeroStateId() pure returns (StateId) {
return StateId.wrap(0);
}
// pure free functions for operators
function eqStateId(StateId a, StateId b) pure returns (bool isSame) {
return StateId.unwrap(a) == StateId.unwrap(b);
}
function neStateId(StateId a, StateId b) pure returns (bool isDifferent) {
return StateId.unwrap(a) != StateId.unwrap(b);
}
// library functions that operate on user defined type
library StateIdLib {
function zero() public pure returns (StateId) {
return StateId.wrap(0);
}
/// @dev Converts the NftId to a uint256.
function toInt(StateId stateId) public pure returns (uint96) {
return uint96(StateId.unwrap(stateId));
}
/// @dev Returns true if the value is non-zero (> 0).
function gtz(StateId a) public pure returns (bool) {
return StateId.unwrap(a) > 0;
}
/// @dev Returns true if the value is zero (== 0).
function eqz(StateId a) public pure returns (bool) {
return StateId.unwrap(a) == 0;
}
/// @dev Returns true if the values are equal (==).
function eq(StateId a, StateId b) public pure returns (bool isSame) {
return eqStateId(a, b);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {ShortString, ShortStrings} from "@openzeppelin/contracts/utils/ShortStrings.sol";
type Str is bytes32;
using {
StrEq as ==,
StrNe as !=,
StrLib.toString,
StrLib.length
} for Str global;
// pure free function needed for the operator overloading
function StrEq(Str s1, Str s2) pure returns (bool) {
return StrLib.eq(s1, s2);
}
// pure free function needed for the operator overloading
function StrNe(Str s1, Str s2) pure returns (bool) {
return StrLib.ne(s1, s2);
}
library StrLib {
/// @dev converts the provided string into a short string.
/// uses ShortStrings.toShortString
function toStr(string memory str) public pure returns (Str) {
return Str.wrap(ShortString.unwrap(ShortStrings.toShortString(str)));
}
/// @dev return true iff s1 equals s2
function eq(Str s1, Str s2) public pure returns (bool) {
return Str.unwrap(s1) == Str.unwrap(s2);
}
/// @dev return true iff s1 differs from s2
function ne(Str s1, Str s2) public pure returns (bool) {
return Str.unwrap(s1) != Str.unwrap(s2);
}
/// @dev return true iff s1 equals from s2
function eq(string memory s1, string memory s2) public pure returns (bool) {
return keccak256(bytes(s1)) == keccak256(bytes(s2));
}
/// @dev return true iff s1 differs s2
function ne(string memory s1, string memory s2) public pure returns (bool) {
return !eq(s1, s2);
}
/// @dev converts the provided short string into a string.
/// uses ShortStrings.toString
function toString(Str str) public pure returns (string memory) {
return ShortStrings.toString(ShortString.wrap(Str.unwrap(str)));
}
/// @dev converts the provided short string into a string.
/// uses ShortStrings.byteLength
function length(Str str) public pure returns (uint256 byteLength) {
return ShortStrings.byteLength(ShortString.wrap(Str.unwrap(str)));
}
/// @dev Returns the provied int as a string
function uintToString(uint256 value) public pure returns (string memory name) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits = 0;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
uint256 index = digits - 1;
temp = value;
while (temp != 0) {
buffer[index] = bytes1(uint8(48 + temp % 10));
temp /= 10;
if (index > 0) {
index--;
}
}
return string(buffer);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Seconds} from "./Seconds.sol";
/// @dev Target: Cover 10 years with 1 ms block time resolution.
/// Typical block time resolution is 1s.
type Timestamp is uint40;
using {
gtTimestamp as >,
gteTimestamp as >=,
ltTimestamp as <,
lteTimestamp as <=,
eqTimestamp as ==,
neTimestamp as !=,
TimestampLib.eq,
TimestampLib.ne,
TimestampLib.gt,
TimestampLib.gte,
TimestampLib.lt,
TimestampLib.lte,
TimestampLib.gtz,
TimestampLib.eqz,
TimestampLib.addSeconds,
TimestampLib.subtractSeconds,
TimestampLib.toInt
} for Timestamp global;
/// @dev return true if Timestamp a is after Timestamp b
function gtTimestamp(Timestamp a, Timestamp b) pure returns (bool) {
return Timestamp.unwrap(a) > Timestamp.unwrap(b);
}
/// @dev return true if Timestamp a is after or equal to Timestamp b
function gteTimestamp(Timestamp a, Timestamp b) pure returns (bool) {
return Timestamp.unwrap(a) >= Timestamp.unwrap(b);
}
/// @dev return true if Timestamp a is before Timestamp b
function ltTimestamp(Timestamp a, Timestamp b) pure returns (bool) {
return Timestamp.unwrap(a) < Timestamp.unwrap(b);
}
/// @dev return true if Timestamp a is before or equal to Timestamp b
function lteTimestamp(Timestamp a, Timestamp b) pure returns (bool) {
return Timestamp.unwrap(a) <= Timestamp.unwrap(b);
}
/// @dev return true if Timestamp a is equal to Timestamp b
function eqTimestamp(Timestamp a, Timestamp b) pure returns (bool) {
return Timestamp.unwrap(a) == Timestamp.unwrap(b);
}
/// @dev return true if Timestamp a is not equal to Timestamp b
function neTimestamp(Timestamp a, Timestamp b) pure returns (bool) {
return Timestamp.unwrap(a) != Timestamp.unwrap(b);
}
// TODO move to TimestampLib and rename to zero()
/// @dev Return the Timestamp zero (0)
function zeroTimestamp() pure returns (Timestamp) {
return Timestamp.wrap(0);
}
library TimestampLib {
function zero() public pure returns (Timestamp) {
return Timestamp.wrap(0);
}
function max() public pure returns (Timestamp) {
return Timestamp.wrap(type(uint40).max);
}
function current() public view returns (Timestamp) {
return Timestamp.wrap(uint40(block.timestamp));
}
function toTimestamp(uint256 timestamp) public pure returns (Timestamp) {
return Timestamp.wrap(uint40(timestamp));
}
/// @dev return true if Timestamp a is after Timestamp b
function gt(Timestamp a, Timestamp b) public pure returns (bool isAfter) {
return gtTimestamp(a, b);
}
/// @dev return true if Timestamp a is after or the same than Timestamp b
function gte(
Timestamp a,
Timestamp b
) public pure returns (bool isAfterOrSame) {
return gteTimestamp(a, b);
}
/// @dev return true if Timestamp a is before Timestamp b
function lt(Timestamp a, Timestamp b) public pure returns (bool isBefore) {
return ltTimestamp(a, b);
}
/// @dev return true if Timestamp a is before or the same than Timestamp b
function lte(
Timestamp a,
Timestamp b
) public pure returns (bool isBeforeOrSame) {
return lteTimestamp(a, b);
}
/// @dev return true if Timestamp a is equal to Timestamp b
function eq(Timestamp a, Timestamp b) public pure returns (bool isSame) {
return eqTimestamp(a, b);
}
/// @dev return true if Timestamp a is not equal to Timestamp b
function ne(
Timestamp a,
Timestamp b
) public pure returns (bool isDifferent) {
return neTimestamp(a, b);
}
/// @dev return true if Timestamp equals 0
function eqz(Timestamp timestamp) public pure returns (bool) {
return Timestamp.unwrap(timestamp) == 0;
}
/// @dev return true if Timestamp is larger than 0
function gtz(Timestamp timestamp) public pure returns (bool) {
return Timestamp.unwrap(timestamp) > 0;
}
/// @dev return a new timestamp that is duration seconds later than the provided timestamp.
function addSeconds(
Timestamp timestamp,
Seconds duration
) public pure returns (Timestamp) {
return toTimestamp(Timestamp.unwrap(timestamp) + duration.toInt());
}
/// @dev return a new timestamp that is duration seconds earlier than the provided timestamp.
function subtractSeconds(
Timestamp timestamp,
Seconds duration
) public pure returns (Timestamp) {
return toTimestamp(Timestamp.unwrap(timestamp) - duration.toInt());
}
function toInt(Timestamp timestamp) public pure returns (uint256) {
return uint256(uint40(Timestamp.unwrap(timestamp)));
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
/// @dev UFixed is a 160-bit fixed point number with 15 decimals precision.
type UFixed is uint160;
using {
addUFixed as +,
subUFixed as -,
mulUFixed as *,
divUFixed as /,
gtUFixed as >,
gteUFixed as >=,
ltUFixed as <,
lteUFixed as <=,
eqUFixed as ==,
neUFixed as !=,
UFixedLib.gt,
UFixedLib.eqz,
UFixedLib.gtz,
UFixedLib.toInt,
UFixedLib.toInt1000
} for UFixed global;
// TODO move to UFixedLib and rename to zero()
function zeroUFixed() pure returns (UFixed zero) {
return UFixed.wrap(0);
}
function addUFixed(UFixed a, UFixed b) pure returns (UFixed) {
return UFixed.wrap(UFixed.unwrap(a) + UFixed.unwrap(b));
}
function subUFixed(UFixed a, UFixed b) pure returns (UFixed) {
if (a < b) {
revert UFixedLib.UFixedLibNegativeResult();
}
return UFixed.wrap(UFixed.unwrap(a) - UFixed.unwrap(b));
}
function mulUFixed(UFixed a, UFixed b) pure returns (UFixed) {
return
UFixed.wrap(uint160(Math.mulDiv(UFixed.unwrap(a), UFixed.unwrap(b), 10 ** 15)));
}
function divUFixed(UFixed a, UFixed b) pure returns (UFixed) {
if (UFixed.unwrap(b) == 0) {
revert UFixedLib.UFixedLibDivisionByZero();
}
return
UFixed.wrap(uint160(Math.mulDiv(UFixed.unwrap(a), 10 ** 15, UFixed.unwrap(b))));
}
function gtUFixed(UFixed a, UFixed b) pure returns (bool isGreaterThan) {
return UFixed.unwrap(a) > UFixed.unwrap(b);
}
function gteUFixed(UFixed a, UFixed b) pure returns (bool isGreaterThan) {
return UFixed.unwrap(a) >= UFixed.unwrap(b);
}
function ltUFixed(UFixed a, UFixed b) pure returns (bool isGreaterThan) {
return UFixed.unwrap(a) < UFixed.unwrap(b);
}
function lteUFixed(UFixed a, UFixed b) pure returns (bool isGreaterThan) {
return UFixed.unwrap(a) <= UFixed.unwrap(b);
}
function eqUFixed(UFixed a, UFixed b) pure returns (bool isEqual) {
return UFixed.unwrap(a) == UFixed.unwrap(b);
}
function neUFixed(UFixed a, UFixed b) pure returns (bool isEqual) {
return UFixed.unwrap(a) != UFixed.unwrap(b);
}
function gtzUFixed(UFixed a) pure returns (bool isZero) {
return UFixed.unwrap(a) > 0;
}
function eqzUFixed(UFixed a) pure returns (bool isZero) {
return UFixed.unwrap(a) == 0;
}
function deltaUFixed(UFixed a, UFixed b) pure returns (UFixed) {
if (a > b) {
return a - b;
}
return b - a;
}
library UFixedLib {
error UFixedLibNegativeResult();
error UFixedLibDivisionByZero();
error UFixedLibExponentTooSmall(int8 exp);
error UFixedLibExponentTooLarge(int8 exp);
error UFixedLibNumberTooLarge(uint256 number);
int8 public constant EXP = 15;
uint256 public constant MULTIPLIER = 10 ** uint256(int256(EXP));
uint256 public constant MULTIPLIER_HALF = MULTIPLIER / 2;
/// @dev returns the rounding mode DOWN - 0.4 becomes 0, 0.5 becomes 0, 0.6 becomes 0
function ROUNDING_DOWN() public pure returns (uint8) {
return uint8(0);
}
/// @dev returns the rounding mode UP - 0.4 becomes 1, 0.5 becomes 1, 0.6 becomes 1
function ROUNDING_UP() public pure returns (uint8) {
return uint8(1);
}
/// @dev returns the rounding mode HALF_UP - 0.4 becomes 0, 0.5 becomes 1, 0.6 becomes 1
function ROUNDING_HALF_UP() public pure returns (uint8) {
return uint8(2);
}
/// @dev Converts the uint256 to a uint160 based UFixed.
/// This method reverts if the number is too large to fit in a uint160.
function toUFixed(uint256 a) public pure returns (UFixed) {
uint256 n = a * MULTIPLIER;
if (n > type(uint160).max) {
revert UFixedLibNumberTooLarge(a);
}
return UFixed.wrap(uint160(n));
}
/// @dev Converts the uint256 to a UFixed with given exponent.
function toUFixed(uint256 a, int8 exp) public pure returns (UFixed) {
if (EXP + exp < 0) {
revert UFixedLibExponentTooSmall(exp);
}
if (EXP + exp > 48) {
revert UFixedLibExponentTooLarge(exp);
}
uint256 n = a * 10 ** uint8(EXP + exp);
if (n > type(uint160).max) {
revert UFixedLibNumberTooLarge(n);
}
return UFixed.wrap(uint160(n));
}
/// @dev returns the decimals precision of the UFixed type
function decimals() public pure returns (uint256) {
return uint8(EXP);
}
/// @dev Converts a UFixed to a uint256.
function toInt(UFixed a) public pure returns (uint256) {
return toIntWithRounding(a, ROUNDING_HALF_UP());
}
/// @dev Converts a UFixed to a uint256.
function toInt1000(UFixed a) public pure returns (uint256) {
return toIntWithRounding(toUFixed(1000) * a, ROUNDING_HALF_UP());
}
/// @dev Converts a UFixed to a uint256 with given rounding mode.
function toIntWithRounding(UFixed a, uint8 rounding) public pure returns (uint256) {
if (rounding == ROUNDING_HALF_UP()) {
return
Math.mulDiv(
UFixed.unwrap(a) + MULTIPLIER_HALF,
1,
MULTIPLIER,
Math.Rounding.Floor
);
} else if (rounding == ROUNDING_DOWN()) {
return
Math.mulDiv(
UFixed.unwrap(a),
1,
MULTIPLIER,
Math.Rounding.Floor
);
} else {
return
Math.mulDiv(UFixed.unwrap(a), 1, MULTIPLIER, Math.Rounding.Ceil);
}
}
/// @dev adds two UFixed numbers
function add(UFixed a, UFixed b) public pure returns (UFixed) {
return addUFixed(a, b);
}
/// @dev subtracts two UFixed numbers
function sub(UFixed a, UFixed b) public pure returns (UFixed) {
return subUFixed(a, b);
}
/// @dev multiplies two UFixed numbers
function mul(UFixed a, UFixed b) public pure returns (UFixed) {
return mulUFixed(a, b);
}
/// @dev divides two UFixed numbers
function div(UFixed a, UFixed b) public pure returns (UFixed) {
return divUFixed(a, b);
}
/// @dev return true if UFixed a is greater than UFixed b
function gt(UFixed a, UFixed b) public pure returns (bool isGreaterThan) {
return gtUFixed(a, b);
}
/// @dev return true if UFixed a is greater than or equal to UFixed b
function gte(UFixed a, UFixed b) public pure returns (bool isGreaterThan) {
return gteUFixed(a, b);
}
/// @dev return true if UFixed a is less than UFixed b
function lt(UFixed a, UFixed b) public pure returns (bool isGreaterThan) {
return ltUFixed(a, b);
}
/// @dev return true if UFixed a is less than or equal to UFixed b
function lte(UFixed a, UFixed b) public pure returns (bool isGreaterThan) {
return lteUFixed(a, b);
}
/// @dev return true if UFixed a is equal to UFixed b
function eq(UFixed a, UFixed b) public pure returns (bool isEqual) {
return eqUFixed(a, b);
}
/// @dev return true if UFixed a is not zero
function gtz(UFixed a) public pure returns (bool isZero) {
return gtzUFixed(a);
}
/// @dev return true if UFixed a is zero
function eqz(UFixed a) public pure returns (bool isZero) {
return eqzUFixed(a);
}
function zero() public pure returns (UFixed) {
return UFixed.wrap(0);
}
function one() public pure returns (UFixed) {
return UFixed.wrap(uint160(MULTIPLIER));
}
function max() public pure returns (UFixed) {
return UFixed.wrap(type(uint160).max);
}
/// @dev return the absolute delta between two UFixed numbers
function delta(UFixed a, UFixed b) public pure returns (UFixed) {
return deltaUFixed(a, b);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
type VersionPart is uint8;
using {
versionPartGt as >,
versionPartEq as ==,
versionPartNe as !=,
VersionPartLib.eqz,
VersionPartLib.gtz,
VersionPartLib.toInt,
VersionPartLib.toString,
VersionPartLib.isValidRelease
}
for VersionPart global;
function versionPartGt(VersionPart a, VersionPart b) pure returns(bool isGreaterThan) { return VersionPart.unwrap(a) > VersionPart.unwrap(b); }
function versionPartEq(VersionPart a, VersionPart b) pure returns(bool isSame) { return VersionPart.unwrap(a) == VersionPart.unwrap(b); }
function versionPartNe(VersionPart a, VersionPart b) pure returns(bool isSame) { return VersionPart.unwrap(a) != VersionPart.unwrap(b); }
library VersionPartLib {
error ErrorReleaseTooBig(VersionPart releaseMax, VersionPart release);
function releaseMin() public pure returns (VersionPart) { return toVersionPart(3); }
function releaseMax() public pure returns (VersionPart) { return toVersionPart(99); }
function isValidRelease(VersionPart release) external pure returns(bool) {
uint256 releaseInt = VersionPart.unwrap(release);
return 3 <= releaseInt && releaseInt <= 99;
}
function toString(VersionPart a) external pure returns (string memory) {
if (a > releaseMax()) {
revert ErrorReleaseTooBig(releaseMax(), a);
}
uint256 value = VersionPart.unwrap(a);
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits = 0;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
uint index = digits - 1;
temp = value;
while (temp != 0) {
buffer[index] = bytes1(uint8(48 + temp % 10));
temp /= 10;
if (index > 0) {
index--;
}
}
return string(buffer);
}
function eqz(VersionPart a) external pure returns(bool) { return VersionPart.unwrap(a) == 0; }
function gtz(VersionPart a) external pure returns(bool) { return VersionPart.unwrap(a) > 0; }
function toInt(VersionPart a) external pure returns(uint256) { return VersionPart.unwrap(a); }
function toVersionPart(uint256 a) public pure returns(VersionPart) { return VersionPart.wrap(uint8(a)); }
}
type Version is uint24; // contains major,minor,patch version parts
using {
versionGt as >,
versionEq as ==,
VersionLib.toInt,
VersionLib.toUint64,
VersionLib.toMajorPart,
VersionLib.toVersionParts
}
for Version global;
function versionGt(Version a, Version b) pure returns(bool isGreaterThan) { return Version.unwrap(a) > Version.unwrap(b); }
function versionEq(Version a, Version b) pure returns(bool isSame) { return Version.unwrap(a) == Version.unwrap(b); }
library VersionLib {
function toInt(Version version) external pure returns(uint) { return Version.unwrap(version); }
function toUint64(Version version) external pure returns(uint64) { return Version.unwrap(version); }
function toMajorPart(Version version)
external
pure
returns(VersionPart major)
{
uint24 versionInt = Version.unwrap(version);
uint8 majorInt = uint8(versionInt >> 16);
return VersionPart.wrap(majorInt);
}
function toVersionParts(Version version)
external
pure
returns(
VersionPart major,
VersionPart minor,
VersionPart patch
)
{
uint24 versionInt = Version.unwrap(version);
uint8 majorInt = uint8(versionInt >> 16);
versionInt -= majorInt << 16;
uint8 minorInt = uint8(versionInt >> 8);
uint8 patchInt = uint8(versionInt - (minorInt << 8));
return (
VersionPart.wrap(majorInt),
VersionPart.wrap(minorInt),
VersionPart.wrap(patchInt)
);
}
// function toVersionPart(uint256 versionPart) public pure returns(VersionPart) {
// return VersionPart.wrap(uint8(versionPart));
// }
function toVersion(
uint256 major,
uint256 minor,
uint256 patch
)
external
pure
returns(Version)
{
require(
major < 256 && minor < 256 && patch < 256,
"ERROR:VRS-010:VERSION_PART_TOO_BIG");
return Version.wrap(
uint24(
(major << 16) + (minor << 8) + patch));
}
// TODO check for overflow?
function toVersion(uint64 versionNumber) external pure returns(Version) {
//assert(versionNumber <= type(Version).max);
return Version.wrap(uint24(versionNumber));
}
// TODO rename to zero()
function zeroVersion() external pure returns(Version) {
return Version.wrap(0);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Version} from "../type/Version.sol";
/// IMPORTANT
// Upgradeable contract MUST:
// 1) inherit from Versionable
// 2) implement version() function
// 3) implement internal _initialize() function with onlyInitializing modifier
// 4) implement internal _upgrade() function with onlyInitializing modifier (1st version MUST revert)
// 5) have onlyInitialising modifier for each function callable inside _initialize()/_upgrade() (MUST use different functions for initialization/upgrade and normal operations)
// 6) use default empty constructor -> _disableInitializer() is called from Versionable contructor
// 7) use namespace storage (should this be needed)
// 8) since now inheritance is used for upgradability, contract MUST BE inherited ONLY by the next version
// Upgradeable contract SHOULD:
// 9) define all non private methods as virtual (in order to be able to upgrade them latter)
// otherwise, it is still possible to upgrade contract, but everyone who is using it will have to switch to a new fucntions
// in some cases this ok but not in the others...
//
// IMPORTANT
// If introducting/amending storage related to Versionable version MUST:
// 1) define namespace storage struct if accessing storage
// - DO NOT use structs inside, except
// - CAN use structs ONLY inside mappings
// 2) ALWAYS define private getter if accessing storage
// - MUST use default implementation, CAN change ONLY return type
interface IVersionable {
error ErrorVersionableInitializeNotImplemented();
error ErrorVersionableUpgradeNotImplemented();
/**
* @dev IMPORTANT
* implementation MUST be guarded by initializer modifier
* new version MUST inherit from previous version
*/
function initializeVersionable(address activatedBy, bytes memory activationData) external;
/**
* @dev
* implementation MUST be guarded by reinitializer(version().toUint64()) modifier
* new version MUST inherit from previous version
* the first verion MUST revert
*/
function upgradeVersionable(bytes memory upgradeData) external;
/**
* @dev returns version of this contract
* each new implementation MUST implement this function
* version number MUST increase
*/
function getVersion() external pure returns(Version);
}{
"evmVersion": "cancun",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/shared/ContractLib.sol": {
"ContractLib": "0x0Dca08c2260A16010538655b2894c4d7FeD280fA"
},
"contracts/type/Fee.sol": {
"FeeLib": "0x7344Ca80C9187E40D161c55aa59B68b680ab0b9A"
},
"contracts/examples/flight/FlightLib.sol": {
"FlightLib": "0x08bd2a26fcf141f9244e9f71c3c99249451c89d3"
},
"contracts/type/Amount.sol": {
"AmountLib": "0x82860d6202c009092d0d7507380ba8ef8f4fd567"
},
"contracts/type/NftId.sol": {
"NftIdLib": "0xb6fe977f3e63d01a734dd238ba5fc05bf45bf32c"
},
"contracts/type/ObjectType.sol": {
"ObjectTypeLib": "0xa6b4725b0a1cf143baf5099fdd58abc8d862d34f"
},
"contracts/type/Referral.sol": {
"ReferralLib": "0xf41933c60fdea61085b0ff18b906cddcd547634c"
},
"contracts/type/RequestId.sol": {
"RequestIdLib": "0x6583a0cc1ea5b6841adae78a8ce62f319a028053"
},
"contracts/type/Seconds.sol": {
"SecondsLib": "0x3fb33d6b382d000f1ef0928f8942c56ef3af6c41"
},
"contracts/type/String.sol": {
"StrLib": "0xb7336e875465659bad9659b25d078c6cace41706"
},
"contracts/type/Timestamp.sol": {
"TimestampLib": "0xfdbcee5ffb06ba0f107922a3294110ce43c3112e"
},
"contracts/type/Version.sol": {
"VersionLib": "0x1c7f4780c639cb898b64769694d308a5a363a83e"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"registry","type":"address"},{"internalType":"NftId","name":"instanceNftId","type":"uint96"},{"internalType":"string","name":"componentName","type":"string"},{"internalType":"contract IAuthorization","name":"authorization","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"authority","type":"address"}],"name":"AccessManagedInvalidAuthority","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"uint32","name":"delay","type":"uint32"}],"name":"AccessManagedRequiredDelay","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"AccessManagedUnauthorized","type":"error"},{"inputs":[{"internalType":"address","name":"authority","type":"address"}],"name":"ErrorAuthorityInvalid","type":"error"},{"inputs":[],"name":"ErrorComponentNameLengthZero","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"ErrorComponentNotChainNft","type":"error"},{"inputs":[],"name":"ErrorComponentProductNftIdNonzero","type":"error"},{"inputs":[],"name":"ErrorComponentProductNftIdZero","type":"error"},{"inputs":[],"name":"ErrorComponentWalletAddressIsSameAsCurrent","type":"error"},{"inputs":[],"name":"ErrorComponentWalletAddressZero","type":"error"},{"inputs":[],"name":"ErrorComponentWalletNotComponent","type":"error"},{"inputs":[{"internalType":"NftId","name":"nftId","type":"uint96"},{"internalType":"ObjectType","name":"objectType","type":"uint8"}],"name":"ErrorInstanceLinkedComponentNotProduct","type":"error"},{"inputs":[{"internalType":"ObjectType","name":"requiredType","type":"uint8"},{"internalType":"ObjectType","name":"objectType","type":"uint8"}],"name":"ErrorInstanceLinkedComponentTypeMismatch","type":"error"},{"inputs":[{"internalType":"NftId","name":"nftId","type":"uint96"}],"name":"ErrorNftOwnableAlreadyLinked","type":"error"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"ErrorNftOwnableContractNotRegistered","type":"error"},{"inputs":[],"name":"ErrorNftOwnableInitialOwnerZero","type":"error"},{"inputs":[{"internalType":"NftId","name":"nftId","type":"uint96"},{"internalType":"ObjectType","name":"expectedObjectType","type":"uint8"}],"name":"ErrorNftOwnableInvalidType","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"ErrorNftOwnableNotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"registryAddress","type":"address"}],"name":"ErrorNotRegistry","type":"error"},{"inputs":[],"name":"ErrorRegisterableNotActive","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenHandler","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"Amount","name":"limit","type":"uint96"},{"indexed":false,"internalType":"bool","name":"isMaxAmount","type":"bool"}],"name":"LogComponentTokenHandlerApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldWallet","type":"address"},{"indexed":false,"internalType":"address","name":"newWallet","type":"address"}],"name":"LogComponentWalletAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LogComponentWalletTokensTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"RiskId","name":"riskId","type":"bytes8"},{"indexed":false,"internalType":"uint8","name":"payoutOption","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"policiesProcessed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"policiesRemaining","type":"uint256"}],"name":"LogFlightPoliciesProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"NftId","name":"policyNftId","type":"uint96"},{"indexed":false,"internalType":"Amount","name":"payoutAmount","type":"uint96"}],"name":"LogFlightPolicyClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"NftId","name":"policyNftId","type":"uint96"},{"indexed":false,"internalType":"string","name":"flightData","type":"string"},{"indexed":false,"internalType":"Amount","name":"premiumAmount","type":"uint96"}],"name":"LogFlightPolicyPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"RequestId","name":"requestId","type":"uint64"},{"indexed":false,"internalType":"RiskId","name":"riskId","type":"bytes8"},{"indexed":false,"internalType":"bytes1","name":"status","type":"bytes1"},{"indexed":false,"internalType":"int256","name":"delayMinutes","type":"int256"},{"indexed":false,"internalType":"uint8","name":"payoutOption","type":"uint8"}],"name":"LogFlightStatusProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"NftId","name":"nftId","type":"uint96"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"LogNftOwnableNftLinkedToAddress","type":"event"},{"inputs":[],"name":"COMPONENT_LOCATION_V1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INSTANCE_LINKED_COMPONENT_LOCATION_V1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIFETIME","outputs":[{"internalType":"Seconds","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MARGIN_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FLIGHT_DURATION","outputs":[{"internalType":"Seconds","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PAYOUT","outputs":[{"internalType":"Amount","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POLICIES_TO_PROCESS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PREMIUM","outputs":[{"internalType":"Amount","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TIME_BEFORE_DEPARTURE","outputs":[{"internalType":"Seconds","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TOTAL_PAYOUT","outputs":[{"internalType":"Amount","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_OBSERVATIONS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_PREMIUM","outputs":[{"internalType":"Amount","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TIME_BEFORE_DEPARTURE","outputs":[{"internalType":"Seconds","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NFT_OWNABLE_STORAGE_LOCATION_V1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRODUCT_STORAGE_LOCATION_V1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTERABLE_LOCATION_V1","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"WEIGHT_PATTERN","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"internalType":"Amount","name":"amount","type":"uint96"}],"name":"approveTokenHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Amount","name":"","type":"uint96"},{"internalType":"RiskId","name":"","type":"bytes8"},{"internalType":"Seconds","name":"","type":"uint40"},{"internalType":"bytes","name":"applicationData","type":"bytes"}],"name":"calculateNetPremium","outputs":[{"internalType":"Amount","name":"netPremiumAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FlightProduct","name":"flightProduct","type":"address"},{"internalType":"Amount","name":"premium","type":"uint96"},{"internalType":"uint256[6]","name":"statistics","type":"uint256[6]"}],"name":"calculatePayoutAmounts","outputs":[{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"Amount[5]","name":"payoutAmounts","type":"uint96[5]"},{"internalType":"Amount","name":"sumInsuredAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Amount","name":"sumInsuredAmount","type":"uint96"},{"internalType":"RiskId","name":"riskId","type":"bytes8"},{"internalType":"Seconds","name":"lifetime","type":"uint40"},{"internalType":"bytes","name":"applicationData","type":"bytes"},{"internalType":"NftId","name":"bundleNftId","type":"uint96"},{"internalType":"ReferralId","name":"referralId","type":"bytes8"}],"name":"calculatePremium","outputs":[{"internalType":"Amount","name":"premiumAmount","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct FlightProduct.PermitData","name":"permit","type":"tuple"},{"components":[{"internalType":"string","name":"flightData","type":"string"},{"internalType":"Timestamp","name":"departureTime","type":"uint40"},{"internalType":"string","name":"departureTimeLocal","type":"string"},{"internalType":"Timestamp","name":"arrivalTime","type":"uint40"},{"internalType":"string","name":"arrivalTimeLocal","type":"string"},{"internalType":"Amount","name":"premiumAmount","type":"uint96"},{"internalType":"uint256[6]","name":"statistics","type":"uint256[6]"}],"internalType":"struct FlightProduct.ApplicationData","name":"application","type":"tuple"}],"name":"createPolicyWithPermit","outputs":[{"internalType":"RiskId","name":"riskId","type":"bytes8"},{"internalType":"NftId","name":"policyNftId","type":"uint96"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"decodeFlightRiskData","outputs":[{"components":[{"internalType":"Str","name":"flightData","type":"bytes32"},{"internalType":"Timestamp","name":"departureTime","type":"uint40"},{"internalType":"string","name":"departureTimeLocal","type":"string"},{"internalType":"Timestamp","name":"arrivalTime","type":"uint40"},{"internalType":"string","name":"arrivalTimeLocal","type":"string"},{"internalType":"Amount","name":"sumOfSumInsuredAmounts","type":"uint96"},{"internalType":"bytes1","name":"status","type":"bytes1"},{"internalType":"int256","name":"delayMinutes","type":"int256"},{"internalType":"uint8","name":"payoutOption","type":"uint8"},{"internalType":"Timestamp","name":"statusUpdatedAt","type":"uint40"}],"internalType":"struct FlightProduct.FlightRisk","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"RequestId","name":"requestId","type":"uint64"},{"internalType":"bytes","name":"responseData","type":"bytes"}],"name":"flightStatusCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAuthorization","outputs":[{"internalType":"contract IAuthorization","name":"authorization","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getComponentInfo","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"contract TokenHandler","name":"tokenHandler","type":"address"}],"internalType":"struct IComponents.ComponentInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"RiskId","name":"riskId","type":"bytes8"},{"internalType":"bool","name":"requireRiskExists","type":"bool"}],"name":"getFlightRisk","outputs":[{"internalType":"bool","name":"exists","type":"bool"},{"components":[{"internalType":"Str","name":"flightData","type":"bytes32"},{"internalType":"Timestamp","name":"departureTime","type":"uint40"},{"internalType":"string","name":"departureTimeLocal","type":"string"},{"internalType":"Timestamp","name":"arrivalTime","type":"uint40"},{"internalType":"string","name":"arrivalTimeLocal","type":"string"},{"internalType":"Amount","name":"sumOfSumInsuredAmounts","type":"uint96"},{"internalType":"bytes1","name":"status","type":"bytes1"},{"internalType":"int256","name":"delayMinutes","type":"int256"},{"internalType":"uint8","name":"payoutOption","type":"uint8"},{"internalType":"Timestamp","name":"statusUpdatedAt","type":"uint40"}],"internalType":"struct FlightProduct.FlightRisk","name":"flightRisk","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitialComponentInfo","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"contract TokenHandler","name":"tokenHandler","type":"address"}],"internalType":"struct IComponents.ComponentInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitialFeeInfo","outputs":[{"components":[{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"productFee","type":"tuple"},{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"processingFee","type":"tuple"},{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"distributionFee","type":"tuple"},{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"minDistributionOwnerFee","type":"tuple"},{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"poolFee","type":"tuple"},{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"stakingFee","type":"tuple"},{"components":[{"internalType":"UFixed","name":"fractionalFee","type":"uint160"},{"internalType":"Amount","name":"fixedFee","type":"uint96"}],"internalType":"struct Fee","name":"performanceFee","type":"tuple"}],"internalType":"struct IComponents.FeeInfo","name":"feeInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitialInfo","outputs":[{"components":[{"internalType":"NftId","name":"nftId","type":"uint96"},{"internalType":"NftId","name":"parentNftId","type":"uint96"},{"internalType":"ObjectType","name":"objectType","type":"uint8"},{"internalType":"bool","name":"isInterceptor","type":"bool"},{"internalType":"address","name":"objectAddress","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IRegistry.ObjectInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitialProductInfo","outputs":[{"components":[{"internalType":"bool","name":"isProcessingFundedClaims","type":"bool"},{"internalType":"bool","name":"isInterceptingPolicyTransfers","type":"bool"},{"internalType":"bool","name":"hasDistribution","type":"bool"},{"internalType":"uint8","name":"expectedNumberOfOracles","type":"uint8"},{"internalType":"uint8","name":"numberOfOracles","type":"uint8"},{"internalType":"NftId","name":"poolNftId","type":"uint96"},{"internalType":"NftId","name":"distributionNftId","type":"uint96"},{"internalType":"NftId[]","name":"oracleNftId","type":"uint96[]"}],"internalType":"struct IComponents.ProductInfo","name":"poolInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInstance","outputs":[{"internalType":"contract IInstance","name":"instance","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getName","outputs":[{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNftId","outputs":[{"internalType":"NftId","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleNftId","outputs":[{"internalType":"NftId","name":"oracleNftId","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelease","outputs":[{"internalType":"VersionPart","name":"release","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"RiskId","name":"riskId","type":"bytes8"}],"name":"getRequestForRisk","outputs":[{"internalType":"RequestId","name":"requestId","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getToken","outputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenHandler","outputs":[{"internalType":"contract TokenHandler","name":"tokenHandler","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersion","outputs":[{"internalType":"Version","name":"version","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWallet","outputs":[{"internalType":"address","name":"walletAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isConsumingScheduledOp","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isNftInterceptor","outputs":[{"internalType":"bool","name":"isInterceptor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTestMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkToRegisteredNftId","outputs":[{"internalType":"NftId","name":"nftId","type":"uint96"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"operator","type":"address"}],"name":"nftTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"NftId","name":"policyNftId","type":"uint96"},{"internalType":"ClaimId","name":"claimId","type":"uint16"},{"internalType":"Amount","name":"availableAmount","type":"uint96"}],"name":"processFundedClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"RiskId","name":"riskId","type":"bytes8"},{"internalType":"uint8","name":"maxPoliciesToProcess","type":"uint8"}],"name":"processPayoutsAndClosePolicies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"component","type":"address"}],"name":"registerComponent","outputs":[{"internalType":"NftId","name":"componentNftId","type":"uint96"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"RequestId","name":"requestId","type":"uint64"}],"name":"resendRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Amount","name":"minPremium","type":"uint96"},{"internalType":"Amount","name":"maxPremium","type":"uint96"},{"internalType":"Amount","name":"maxPayout","type":"uint96"},{"internalType":"Amount","name":"maxTotalPayout","type":"uint96"},{"internalType":"Seconds","name":"minTimeBeforeDeparture","type":"uint40"},{"internalType":"Seconds","name":"maxTimeBeforeDeparture","type":"uint40"},{"internalType":"uint8","name":"maxPoliciesToProcess","type":"uint8"}],"name":"setConstants","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"NftId","name":"bundleNftId","type":"uint96"}],"name":"setDefaultBundle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"locked","type":"bool"}],"name":"setLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setOracleNftId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"testMode","type":"bool"}],"name":"setTestMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWallet","type":"address"}],"name":"setWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Amount","name":"amount","type":"uint96"}],"name":"withdrawFees","outputs":[{"internalType":"Amount","name":"withdrawnAmount","type":"uint96"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561000f575f80fd5b5060405161799338038061799383398101604081905261002e91611657565b3361003c8585858585610046565b5050505050611a1c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff1615906001600160401b03165f8115801561008f5750825b90505f826001600160401b031660011480156100aa5750303b155b9050811580156100b8575080155b156100d65760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b0319166001178555831561010457845460ff60401b1916680100000000000000001785555b6105798a8a8a6040518061010001604052805f151581526020015f151581526020015f15158152602001600160ff1681526020015f60ff16815260200173b6fe977f3e63d01a734dd238ba5fc05bf45bf32c63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af4158015610188573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ac91906116dc565b6001600160601b0316815260200173b6fe977f3e63d01a734dd238ba5fc05bf45bf32c63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af4158015610201573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061022591906116dc565b6001600160601b031681526020015f60405190808252806020026020018201604052801561025d578160200160208202803683370190505b508152506040518060e00160405280737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af41580156102b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102d691906116f7565b8152602001737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af4158015610321573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034591906116f7565b8152602001737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af4158015610390573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103b491906116f7565b8152602001737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af41580156103ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042391906116f7565b8152602001737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af415801561046e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049291906116f7565b8152602001737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af41580156104dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061050191906116f7565b8152602001737344ca80c9187e40d161c55aa59b68b680ab0b9a63bc1b392d6040518163ffffffff1660e01b81526004016040805180830381865af415801561054c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061057091906116f7565b90528c8c610741565b6040516209629960e41b815260026004820152733fb33d6b382d000f1ef0928f8942c56ef3af6c41906296299090602401602060405180830381865af41580156105c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e99190611755565b6003805464ffffffffff92909216600160b01b0264ffffffffff60b01b199092169190911790556040516209629960e41b8152601e6004820152733fb33d6b382d000f1ef0928f8942c56ef3af6c41906296299090602401602060405180830381865af415801561065c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106809190611755565b6003805464ffffffffff92909216600160d81b026001600160d81b039092169190911790556040805160c0810182525f8082526020820181905291810191909152601e606082015260326080820181905260a08201526106e490600490600661141c565b50600a600555601e600655831561073557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b610749610a4e565b61075e878787600c6020890151879087610a9e565b5f7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68008551815460208089015160408a015160608b015160808c015160a08d015160c08e015161ffff1990971697151561ff00191697909717610100941515949094029390931763ffff00001916620100009215159290920263ff000000191691909117630100000060ff9283160217600160201b600160881b0319166401000000009190921602600160281b600160881b03191617650100000000006001600160601b039485160217600160881b600160e81b031916600160881b939092169290920217825560e08701518051929350879284926108639260018501929101906114ac565b5050845180516020918201516001600160601b03908116600160a01b9081026001600160a01b03938416176002870155838901518051908501518316820290841617600387015560408901518051908501518316820290841617600487015560608901518051908501518316820290841617600587015560808901518051908501518316820290841617600687015560a08901518051908501518316820290841617600787015560c089015180519401519091160291161760088301555061093161092c602c90565b610cf9565b600a820180546001600160a01b0319166001600160a01b039290921691909117905561095e61092c601490565b600b820180546001600160a01b0319166001600160a01b039290921691909117905561098b61092c601590565b600c820180546001600160a01b0319166001600160a01b03929092169190911790556109b861092c602d90565b600d820180546001600160a01b0319166001600160a01b03929092169190911790556109e561092c602a90565b600e820180546001600160a01b0319166001600160a01b0392909216919091179055610a1261092c600b90565b6009820180546001600160a01b0319166001600160a01b0392909216919091179055610a44630cdf80bd60e31b610d90565b5050505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610a9c57604051631afcd79f60e31b815260040160405180910390fd5b565b610aa6610a4e565b5f610ab2888887610dc3565b90505f7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f0060405163bf8e179760e01b81526001600160601b03841660048201529091506001600160a01b038a169063bf8e179790602401602060405180830381865afa158015610b24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b489190611779565b81546001600160a01b0319166001600160a01b039190911690811782556040805163bf7e214f60e01b81529051610be6929163bf7e214f9160048083019260209291908290030181865afa158015610ba2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc69190611779565b8a8a8a8a898960405180602001604052805f815250610e6e60201b60201c565b8054604080516302cd307160e01b815290516001600160a01b03909216916302cd3071916004808201926020929091908290030181865afa158015610c2d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c519190611779565b6001820180546001600160a01b03199081166001600160a01b0393841617909155600283018054909116918716919091179055610c8f61092c600b90565b6003820180546001600160a01b0319166001600160a01b0392909216919091179055610cbc61092c600d90565b6004820180546001600160a01b0319166001600160a01b0392909216919091179055610cee6330841f2160e21b610d90565b505050505050505050565b5f610d0c6001546001600160a01b031690565b6001600160a01b031663d39e604383610d23610f37565b6040516001600160e01b031960e085901b16815260ff928316600482015291166024820152604401602060405180830381865afa158015610d66573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d8a9190611779565b92915050565b610d98610a4e565b610dc0816001600160e01b0319165f908152602081905260409020805460ff19166001179055565b50565b5f60ff8216600c03610de457610ddb8484600a610fcd565b50829050610e67565b5f610df18585600c610fcd565b60405163677d3feb60e11b81526001600160601b03861660048201529091506001600160a01b0382169063cefa7fd690602401602060405180830381865afa158015610e3f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e6391906116dc565b9150505b9392505050565b610e76610a4e565b84515f03610e975760405163591eebf360e11b815260040160405180910390fd5b610ea688888887878787611097565b7fffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f0080610ed28782611818565b5060018101805460ff1916851515179055610eee61092c600b90565b6001820180546001600160a01b039290921661010002610100600160a81b0319909216919091179055610f27634a531f3360e01b610d90565b610cee6306e9e5ff60e31b610d90565b5f610f697ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00546001600160a01b031690565b6001600160a01b03166376b707b76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fa4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fc891906118eb565b905090565b6040516305247a1760e51b81526001600160601b038316600482015283905f906001600160a01b0383169063a48f42e0906024015f60405180830381865afa15801561101b573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526110429190810190611933565b905061105981604001518460ff9081169116141590565b1561108f57604080820151905163b0c1f6eb60e01b815260ff808616600483015290911660248201526044015b60405180910390fd5b509392505050565b61109f610a4e565b604051632330f24760e01b81526001600160a01b0388166004820152730dca08c2260a16010538655b2894c4d7fed280fa90632330f24790602401602060405180830381865af41580156110f5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111199190611a03565b6111415760405163cf6935e560e01b81526001600160a01b0388166004820152602401611086565b61114a876111e1565b61115486836111f2565b5f7f6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa30080546001600160601b0388166001600160681b0319909116176c0100000000000000000000000060ff8816021760ff60681b19166d0100000000000000000000000000861515021781559050600181016111d08382611818565b50610a44634a531f3360e01b610d90565b6111e9610a4e565b610dc081611284565b6111fa610a4e565b611202611295565b61120b826112dd565b6001600160a01b0381166112325760405163f17ef42d60e01b815260040160405180910390fd5b7f07ebcf49758b6ed3af50fa146bec0abe157c0218fe65dc0874c286e9d5da4f0080546001600160601b03166c010000000000000000000000006001600160a01b039093169290920291909117905550565b61128c610a4e565b610dc0816113a9565b61129d610a4e565b610a9c6301ffc9a760e01b5f9081526020527f67be87c3ff9960ca1e9cfac5cab2ff4747269cf9ed20c9b7306235ac35a491c5805460ff19166001179055565b6112e5610a4e565b604051633334d16b60e01b81526001600160a01b0382166004820152730dca08c2260a16010538655b2894c4d7fed280fa90633334d16b90602401602060405180830381865af415801561133b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135f9190611a03565b6113875760405163fdeac91f60e01b81526001600160a01b0382166004820152602401611086565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b7ff3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a0080546001600160a01b0383166001600160a01b03199091168117825560408051918252517f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9181900360200190a15050565b60018301918390821561149c579160200282015f5b8382111561146e57835183826101000a81548160ff021916908360ff16021790555092602001926001016020815f01049283019260010302611431565b801561149a5782816101000a81549060ff02191690556001016020815f0104928301926001030261146e565b505b506114a892915061154f565b5090565b828054828255905f5260205f209060010160029004810192821561149c579160200282015f5b8382111561151c57835183826101000a8154816001600160601b0302191690836001600160601b031602179055509260200192600c01602081600b010492830192600103026114d2565b801561149a5782816101000a8154906001600160601b030219169055600c01602081600b0104928301926001030261151c565b5b808211156114a8575f8155600101611550565b6001600160a01b0381168114610dc0575f80fd5b805161158281611563565b919050565b6001600160601b0381168114610dc0575f80fd5b805161158281611587565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b03811182821017156115dc576115dc6115a6565b60405290565b5f806001600160401b038411156115fb576115fb6115a6565b50604051601f19601f85018116603f011681018181106001600160401b0382111715611629576116296115a6565b604052838152905080828401851015611640575f80fd5b8383602083015e5f60208583010152509392505050565b5f805f806080858703121561166a575f80fd5b845161167581611563565b602086015190945061168681611587565b60408601519093506001600160401b038111156116a1575f80fd5b8501601f810187136116b1575f80fd5b6116c0878251602084016115e2565b92505060608501516116d181611563565b939692955090935050565b5f602082840312156116ec575f80fd5b8151610e6781611587565b5f6040828403128015611708575f80fd5b50604080519081016001600160401b038111828210171561172b5761172b6115a6565b604052825161173981611563565b8152602083015161174981611587565b60208201529392505050565b5f60208284031215611765575f80fd5b815164ffffffffff81168114610e67575f80fd5b5f60208284031215611789575f80fd5b8151610e6781611563565b600181811c908216806117a857607f821691505b6020821081036117c657634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561181357805f5260205f20601f840160051c810160208510156117f15750805b601f840160051c820191505b81811015611810575f81556001016117fd565b50505b505050565b81516001600160401b03811115611831576118316115a6565b6118458161183f8454611794565b846117cc565b6020601f821160018114611877575f83156118605750848201515b5f19600385901b1c1916600184901b178455611810565b5f84815260208120601f198516915b828110156118a65787850151825560209485019460019092019101611886565b50848210156118c357868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b60ff81168114610dc0575f80fd5b8051611582816118d2565b5f602082840312156118fb575f80fd5b8151610e67816118d2565b80518015158114611582575f80fd5b5f82601f830112611924575f80fd5b610e67838351602085016115e2565b5f60208284031215611943575f80fd5b81516001600160401b03811115611958575f80fd5b820160e08185031215611969575f80fd5b6119716115ba565b61197a8261159b565b81526119886020830161159b565b6020820152611999604083016118e0565b60408201526119aa60608301611906565b60608201526119bb60808301611577565b60808201526119cc60a08301611577565b60a082015260c08201516001600160401b038111156119e9575f80fd5b6119f586828501611915565b60c083015250949350505050565b5f60208284031215611a13575f80fd5b610e6782611906565b615f6a80611a295f395ff3fe608060405234801561000f575f80fd5b50600436106103bf575f3560e01c806360efe48c116101f5578063b277d78011610114578063de7b5d14116100a9578063ea15869f11610079578063ea15869f1461094f578063f0107c1514610963578063f179d0641461097b578063f3e349ae1461098e575f80fd5b8063de7b5d14146108e5578063deaa59df14610915578063e1f216fa14610928578063e9b2460c1461093b575f80fd5b8063bf7e214f116100e4578063bf7e214f14610866578063c108bd4c1461086e578063d11efdfa14610883578063d3c576d8146108cd575f80fd5b8063b277d78014610819578063b423086c1461082c578063b7b357ac14610834578063be5c8f441461084c575f80fd5b8063893d20e81161018a578063972e22eb1161015a578063972e22eb146107ba578063a1794029146107d2578063ad12ad60146107f2578063ada9652e14610805575f80fd5b8063893d20e8146107745780638b0af5d81461077c5780638fb360371461078457806390edbd35146107a5575f80fd5b806376b707b7116101c557806376b707b7146107225780637a9e5e4b1461072a578063844e0f201461073d578063846c9fce14610752575f80fd5b806360efe48c146106c7578063644c45e0146106d75780636bd1c0eb146106df578063768e87771461070f575f80fd5b80632c47e75a116102e15780634cdabb16116102765780635ab1bd53116102465780635ab1bd531461066257806360426af3146106735780636078a3b214610686578063608a5f8d14610699575f80fd5b80634cdabb16146106215780635349d2a81461063457806354d33735146106475780635741e5e91461065a575f80fd5b8063419197fe116102b1578063419197fe146105df57806343d752d3146105f25780634b396c4f146105fa5780634b9ddafe14610607575f80fd5b80632c47e75a146105855780632eb3e6f4146105a65780632f15ce0d146105cd57806339cee407146105d6575f80fd5b80631d0ed70211610357578063211e28b611610327578063211e28b61461055a57806321df0da71461056d578063223668441461057557806322f3e2d41461057d575f80fd5b80631d0ed702146104b25780631e6239c6146104ed5780631eff4b22146105125780631ff1292f14610547575f80fd5b80631329960411610392578063132996041461044a578063138461e01461046a57806317d7de7c1461048a5780631c6b21901461049f575f80fd5b806301ffc9a7146103c35780630b045f60146104045780630d8e6e2c146104195780630fec111c14610435575b5f80fd5b6103ef6103d1366004614322565b6001600160e01b0319165f9081526020819052604090205460ff1690565b60405190151581526020015b60405180910390f35b61041761041236600461436c565b6109a1565b005b6104216109fe565b60405162ffffff90911681526020016103fb565b61043d610a85565b6040516103fb91906143d1565b610452610c3f565b6040516001600160a01b0390911681526020016103fb565b610472610ca7565b6040516001600160601b0390911681526020016103fb565b610492610cb1565b6040516103fb919061445d565b6104726104ad36600461448e565b610cc1565b6104c56104c0366004614779565b610d17565b604080516001600160c01b031990931683526001600160601b039091166020830152016103fb565b6105006104fb36600461482d565b610dd9565b60405160ff90911681526020016103fb565b6105397f6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa30081565b6040519081526020016103fb565b610417610555366004614851565b610e02565b610417610568366004614851565b610e60565b610452610ea7565b6103ef610eeb565b6103ef610fe1565b61059861059336600461486c565b611058565b6040516103fb929190614980565b6105397fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f0081565b61053960065481565b61053960055481565b6104176105ed36600461499a565b611124565b610452611177565b6007546105009060ff1681565b60025461047290600160601b90046001600160601b031681565b600254610472906001600160601b031681565b6104726106423660046149c6565b611189565b610417610655366004614a6f565b61124b565b6103ef61125d565b6001546001600160a01b0316610452565b610417610681366004614a8a565b611313565b610472610694366004614acc565b61134a565b6003546106b190600160881b900464ffffffffff1681565b60405164ffffffffff90911681526020016103fb565b600754610100900460ff166103ef565b61047261141c565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f02546001600160a01b0316610452565b61041761071d366004614ae7565b611437565b610500611521565b610417610738366004614acc565b611589565b61074561160f565b6040516103fb9190614b99565b610765610760366004614c27565b6117e8565b6040516103fb93929190614c98565b61045261187c565b6104176119ad565b61078c611a78565b6040516001600160e01b031990911681526020016103fb565b6107ad611aad565b6040516103fb9190614cc3565b6003546106b190600160b01b900464ffffffffff1681565b6107e56107e0366004614cff565b611ade565b6040516103fb9190614d30565b610417610800366004614d42565b611afa565b6105395f80516020615eb583398151915281565b61041761082736600461448e565b611b9d565b6107ad611c08565b6003546106b190600160601b900464ffffffffff1681565b60015461047290600160a01b90046001600160601b031681565b610452611c24565b610876611c3f565b6040516103fb9190614dd5565b6108b5610891366004614e65565b6001600160c01b0319165f908152600860205260409020546001600160401b031690565b6040516001600160401b0390911681526020016103fb565b6003546106b190600160d81b900464ffffffffff1681565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f00546001600160a01b0316610452565b610417610923366004614acc565b611d93565b610417610936366004614e8f565b611de0565b6105395f80516020615f1583398151915281565b6105395f80516020615ed583398151915281565b600954600160601b90046001600160601b0316610472565b610472610989366004614ed7565b611df6565b600354610472906001600160601b031681565b6109ad335b5f36611e15565b6109b561187c565b6001600160a01b0316336001600160a01b0316146109ed5760405163086391f760e31b81523360048201526024015b60405180910390fd5b6109f78282611f13565b5050505050565b604051632efe011360e01b8152600160048201525f602482018190526044820181905290731c7f4780c639cb898b64769694d308a5a363a83e90632efe011390606401602060405180830381865af4158015610a5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a809190614f47565b905090565b6040805160e0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820152907f6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa30090506040518060e0016040528073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af4158015610b31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b559190614f74565b6001600160601b0390811682528354908116602083015260ff600160601b820481166040840152600160681b909104161515606082015230608082015260a001610b9d61187c565b6001600160a01b03168152602001826001018054610bba90614f8f565b80601f0160208091040260200160405190810160405280929190818152602001828054610be690614f8f565b8015610c315780601f10610c0857610100808354040283529160200191610c31565b820191905f5260205f20905b815481529060010190602001808311610c1457829003601f168201915b505050505081525091505090565b5f610c48611177565b6001600160a01b031663132996046040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c83573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a809190614fd2565b5f610a80306123cc565b6060610cbb611aad565b51919050565b5f610ccb336109a6565b610cd361187c565b6001600160a01b0316336001600160a01b031614610d065760405163086391f760e31b81523360048201526024016109e4565b610d0f82612622565b90505b919050565b5f80610d22336109a6565b610d2b8461267a565b8351835160405163cdc23e6960e01b8152610dcd91839173b7336e875465659bad9659b25d078c6cace417069163cdc23e6991610d6b919060040161445d565b602060405180830381865af4158015610d86573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610daa9190614fed565b86602001518760400151886060015189608001518a60a001518b60c0015161272c565b90969095509350505050565b60048160068110610de8575f80fd5b60209182820401919006915054906101000a900460ff1681565b610e0b336109a6565b610e1361187c565b6001600160a01b0316336001600160a01b031614610e465760405163086391f760e31b81523360048201526024016109e4565b600780549115156101000261ff0019909216919091179055565b610e6861187c565b6001600160a01b0316336001600160a01b031614610e9b5760405163086391f760e31b81523360048201526024016109e4565b610ea481612b86565b50565b5f610eb0611177565b6001600160a01b03166382bfefc86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c83573d5f803e3d5ffd5b5f610efe6001546001600160a01b031690565b604051632f2a35f760e11b81523060048201526001600160a01b039190911690635e546bee90602401602060405180830381865afa158015610f42573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f669190614f74565b6040516330b8415f60e01b81526001600160601b03909116600482015273b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af4158015610fbd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a80919061500f565b5f610fea611c24565b60405163a166aa8960e01b81523060048201526001600160a01b03919091169063a166aa8990602401602060405180830381865afa15801561102e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611052919061500f565b15905090565b5f6110616141d7565b7308bd2a26fcf141f9244e9f71c3c99249451c89d3637bc17425611083612bf0565b61108b61141c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160601b031660248201526001600160c01b03198716604482015285151560648201526084015f60405180830381865af41580156110f2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526111199190810190615193565b909590945092505050565b61112d336109a6565b61113561187c565b6001600160a01b0316336001600160a01b0316146111685760405163086391f760e31b81523360048201526024016109e4565b6111728282612c1e565b505050565b5f611180611aad565b60200151905090565b5f8260166111978282612d9f565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680e545f906001600160a01b031663f4bfe53a6111d161141c565b8b8d8c8c8c8c6040518863ffffffff1660e01b81526004016111f997969594939291906151d6565b61024060405180830381865afa158015611215573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112399190615253565b60a001519a9950505050505050505050565b611254336109a6565b610ea481612ed3565b5f611266610eeb565b156112ea576001546001600160a01b03166040516308b09a5f60e41b81523060048201526001600160a01b039190911690638b09a5f0906024015f60405180830381865afa1580156112ba573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112e191908101906153b5565b60600151905090565b507fffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f015460ff1690565b61131c336109a6565b5f818060200190518101906113319190615490565b905061117283825f015183602001518460400151612f2b565b5f611354336109a6565b61135c61187c565b6001600160a01b0316336001600160a01b03161461138f5760405163086391f760e31b81523360048201526024016109e4565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68095460405163303c51d960e11b81526001600160a01b03848116600483015290911690636078a3b2906024015b6020604051808303815f875af11580156113f8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0f9190614f74565b5f80516020615eb5833981519152546001600160601b031690565b611440336109a6565b61144861187c565b6001600160a01b0316336001600160a01b03161461147b5760405163086391f760e31b81523360048201526024016109e4565b600180546001600160a01b0316600160a01b6001600160601b03998a1602179055600280549688166001600160c01b031990971696909617600160601b958816860217909555600380549390961670ffffffffffffffffffffffffffffffffff199093169290921764ffffffffff9182169093029290921764ffffffffff60881b1916600160881b9190921602179091556007805460ff191660ff909216919091179055565b5f61152a611c24565b6001600160a01b03166376b707b76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611565573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8091906154f8565b33611592611c24565b6001600160a01b0316816001600160a01b0316146115cd5760405162d1953b60e31b81526001600160a01b03821660048201526024016109e4565b816001600160a01b03163b5f03611602576040516361798f2f60e11b81526001600160a01b03831660048201526024016109e4565b61160b826131a7565b5050565b61161761422c565b5060408051610120810182527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6802546001600160a01b0380821660e084019081526001600160601b03600160a01b938490048116610100860152908452845180860186527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6803548084168252849004821660208083019190915280860191909152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680454808516825285900483168183015285870152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68055480851682528590048316818301526060860152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68065480851682528590048316818301526080860152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680754808516825285900483168183015260a086015285518087019096527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680854928316865292909104169083015260c081019190915290565b5f6117f1614304565b6040516355d166e160e01b81525f907308bd2a26fcf141f9244e9f71c3c99249451c89d3906355d166e19061182e90899089908990600401615513565b60e060405180830381865af4158015611849573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061186d91906155b1565b92509250925093509350939050565b5f805f80516020615eb583398151915280546040516330b8415f60e01b81526001600160601b03909116600482015290915073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af41580156118e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190c919061500f565b15611997576001546001600160a01b03168154604051631c5da14d60e11b81526001600160601b0390911660048201526001600160a01b0391909116906338bb429a90602401602060405180830381865afa15801561196d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119919190614fd2565b91505090565b54600160601b90046001600160a01b0316919050565b6119b5612bf0565b6001600160a01b0316630b5d931c6119cb61141c565b6040516001600160e01b031960e084901b1681526001600160601b0390911660048201526024015f60405180830381865afa158015611a0c573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611a33919081019061566c565b60e001515f81518110611a4857611a4861574e565b60200260200101516009600c6101000a8154816001600160601b0302191690836001600160601b03160217905550565b5f80516020615ef583398151915280545f9190600160a01b900460ff16611a9f575f611991565b638fb3603760e01b91505090565b60408051808201909152606081525f6020820152611ac9610eeb565b15611ad657610a80613207565b610a80611c08565b611ae66141d7565b81806020019051810190610d0f9190615762565b6001546001600160a01b03166001600160a01b031663120726c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b41573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b659190614fd2565b6001600160a01b0316336001600160a01b031614611b975760405162f0630960e01b81523360048201526024016109e4565b50505050565b611ba6336109a6565b611bae61187c565b6001600160a01b0316336001600160a01b031614611be15760405163086391f760e31b81523360048201526024016109e4565b600980546bffffffffffffffffffffffff19166001600160601b0392909216919091179055565b60408051808201909152606081525f6020820152610a80613207565b5f80516020615ef5833981519152546001600160a01b031690565b60408051610100810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e08101919091525f80516020615f15833981519152604080516101008082018352835460ff808216151584529181048216151560208085019190915262010000820483161515848601526301000000820483166060850152640100000000820490921660808401526001600160601b03650100000000008204811660a0850152600160881b9091041660c083015260018401805484518184028101840190955280855292949360e08601939092830182828015611d8557602002820191905f5260205f20905f905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b01049283019260010382029150808411611d425790505b505050505081525050905090565b611d9c336109a6565b611da461187c565b6001600160a01b0316336001600160a01b031614611dd75760405163086391f760e31b81523360048201526024016109e4565b610ea4816133c0565b611de9336109a6565b8260156109f78282612d9f565b5f81806020019051810190611e0b9190615793565b5095945050505050565b5f80516020615ef58339815191525f80611e4d611e30611c24565b8730611e3f60045f8a8c6157c7565b611e48916157ee565b613435565b9150915081611f0b5763ffffffff811615611ee857825460ff60a01b1916600160a01b178355611e7b611c24565b6001600160a01b03166394c7d7ee8787876040518463ffffffff1660e01b8152600401611eaa93929190615824565b5f604051808303815f87803b158015611ec1575f80fd5b505af1158015611ed3573d5f803e3d5ffd5b5050845460ff60a01b1916855550611f0b9050565b60405162d1953b60e31b81526001600160a01b03871660048201526024016109e4565b505050505050565b5f805f80611f1f612bf0565b90507308bd2a26fcf141f9244e9f71c3c99249451c89d363bcfba16982611f4461141c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160601b031660248201526001600160c01b031989166044820152606401606060405180830381865af4158015611fa4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fc89190615863565b91955093509150831580611fda575082155b15611fe557506123c5565b604051631954e65360e21b81526001600160c01b0319871660048201525f906001600160a01b03831690636553994c90602401602060405180830381865afa158015612033573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120579190614fed565b90505f8660ff16821061206d578660ff1661206f565b815b90505f816001600160401b0381111561208a5761208a6144a9565b6040519080825280602002602001820160405280156120b3578160200160208202803683370190505b5090505f5b82811015612169576040516325fb9d0d60e11b81526001600160c01b03198b166004820152602481018290526001600160a01b03861690634bf73a1a90604401602060405180830381865afa158015612113573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121379190614f74565b8282815181106121495761214961574e565b6001600160601b03909216602092830291909101909101526001016120b8565b505f5b82811015612361575f8282815181106121875761218761574e565b602002602001015190505f7308bd2a26fcf141f9244e9f71c3c99249451c89d3638a37ab63886001600160a01b031663bd7d9d85856040518263ffffffff1660e01b81526004016121e791906001600160601b0391909116815260200190565b5f60405180830381865afa158015612201573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261222891908101906158ad565b6101c001518a6040518363ffffffff1660e01b815260040161224b929190615a40565b602060405180830381865af4158015612266573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061228a9190614f74565b9050612296828261353d565b61230a8273fdbcee5ffb06ba0f107922a3294110ce43c3112e639fa6a6e36040518163ffffffff1660e01b8152600401602060405180830381865af41580156122e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123059190615a64565b61361d565b50612314826136b5565b604080516001600160601b038085168252831660208201527f1c424341cadf6615bb5fa2a96492cd7ed267c05f7d1dcef2f2229ae26d4d1a7a910160405180910390a1505060010161216c565b507f497e6cfdb1ef3149777822f9e0716eebbeef1264fbc8effc6004e0111ec600818986846123908188615a7f565b604080516001600160c01b0319909516855260ff909316602085015291830152606082015260800160405180910390a1505050505b9250925092565b5f805f80516020615eb583398151915280546040516330b8415f60e01b81526001600160601b03909116600482015290915073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af4158015612438573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061245c919061500f565b156124885780546040516301ab8b6760e21b81526001600160601b0390911660048201526024016109e4565b6001546001600160a01b031660405163c3c5a54760e01b81526001600160a01b038581166004830152919091169063c3c5a54790602401602060405180830381865afa1580156124da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124fe919061500f565b6125265760405163b9304b0d60e01b81526001600160a01b03841660048201526024016109e4565b6001546001600160a01b0316604051632f2a35f760e11b81526001600160a01b0385811660048301529190911690635e546bee90602401602060405180830381865afa158015612578573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061259c9190614f74565b81546bffffffffffffffffffffffff19166001600160601b039190911690811782557f88857b75cbef7f257c9d5a473e28aaf6a91cc28f717f60f2cda3bcf5623d7b54906125e861187c565b604080516001600160601b0390931683526001600160a01b0390911660208301520160405180910390a1546001600160601b031692915050565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f03546040516301c6b21960e41b81526001600160601b03831660048201525f916001600160a01b031690631c6b2190906024016113dc565b612683336109a6565b5f61268c610ea7565b825160208401516040808601516060870151608088015160a089015160c08a0151945163d505accf60e01b81526001600160a01b03978816600482015295871660248701526044860193909352606485019190915260ff16608484015260a483015260c482015291925082169063d505accf9060e4015b5f604051808303815f87803b15801561271a575f80fd5b505af1158015611f0b573d5f803e3d5ffd5b604051634617dc7960e11b81523060048201526024810188905264ffffffffff8088166044830152851660648201526001600160601b03831660848201525f9081907308bd2a26fcf141f9244e9f71c3c99249451c89d390638c2fb8f29060a4015f6040518083038186803b1580156127a3575f80fd5b505af41580156127b5573d5f803e3d5ffd5b505050506127c98a8a8a8a8a8a8a8a61370d565b80925081935050506128468173fdbcee5ffb06ba0f107922a3294110ce43c3112e63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af415801561281c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128409190615a64565b86613806565b5061285181896138a7565b6001600160c01b031982165f908152600860205260409081902054905163015c60ad60e21b81526001600160401b039091166004820152736583a0cc1ea5b6841adae78a8ce62f319a0280539063057182b490602401602060405180830381865af41580156128c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128e6919061500f565b15612ac95760095460408051606080820183526001600160c01b0319861680835260208084018f815264ffffffffff8f81169587019586528651928301939093525194810194909452915190911690820152612a9191600160601b90046001600160601b03169060800160408051601f19818403018152908290526209629960e41b8252601e60048301529073fdbcee5ffb06ba0f107922a3294110ce43c3112e9063a5798b4e9064ffffffffff8c1690733fb33d6b382d000f1ef0928f8942c56ef3af6c41906296299090602401602060405180830381865af41580156129d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129f49190615a64565b6040516001600160e01b031960e085901b16815264ffffffffff928316600482015291166024820152604401602060405180830381865af4158015612a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5f9190615a64565b60405180604001604052806014815260200173666c6967687453746174757343616c6c6261636b60601b81525061390c565b6001600160c01b031983165f908152600860205260409020805467ffffffffffffffff19166001600160401b03929092169190911790555b604051631623433d60e31b8152600481018a90527fb51fd6991e0581f19175f5ef6b8bc59d44dbff4511eb57379f0ce2862228794490829073b7336e875465659bad9659b25d078c6cace417069063b11a19e8906024015f60405180830381865af4158015612b3a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612b619190810190615a9e565b86604051612b7193929190615acf565b60405180910390a19850989650505050505050565b5f80516020615ed58339815191526001015460405163108f145b60e11b815282151560048201526101009091046001600160a01b03169063211e28b6906024015b5f604051808303815f87803b158015612bde575f80fd5b505af11580156109f7573d5f803e3d5ffd5b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f01546001600160a01b031690565b5f7382860d6202c009092d0d7507380ba8ef8f4fd567634c41dd96846001600160a01b031663dd62ed3e612c50611177565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015612c98573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cbc9190614fed565b6040518263ffffffff1660e01b8152600401612cda91815260200190565b602060405180830381865af4158015612cf5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d199190614f74565b90505f80516020615ed5833981519152600101546040516320c8cbff60e11b81526001600160a01b0385811660048301526001600160601b03851660248301526101009092049091169063419197fe906044015f604051808303815f87803b158015612d83575f80fd5b505af1158015612d95573d5f803e3d5ffd5b5050505092915050565b60405163037c8cb160e51b815260ff8216600482015273a6b4725b0a1cf143baf5099fdd58abc8d862d34f90636f91962090602401602060405180830381865af4158015612def573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e13919061500f565b80612ea157506001546001600160a01b0316604051635b12715d60e11b81526001600160601b038416600482015260ff831660248201526001600160a01b03919091169063b624e2ba90604401602060405180830381865afa158015612e7b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e9f919061500f565b155b1561160b5760405163d711af7560e01b81526001600160601b038316600482015260ff821660248201526044016109e4565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f0454604051630b331f6960e21b81526001600160401b03831660048201526001600160a01b0390911690632ccc7da490602401612bc7565b5f612f37846001611058565b61012081015160405163790a38ad60e01b815264ffffffffff909116600482015290925073fdbcee5ffb06ba0f107922a3294110ce43c3112e915063790a38ad90602401602060405180830381865af4158015612f96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fba919061500f565b1561311c5773fdbcee5ffb06ba0f107922a3294110ce43c3112e639fa6a6e36040518163ffffffff1660e01b8152600401602060405180830381865af4158015613006573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061302a9190615a64565b64ffffffffff166101208201526001600160f81b0319831660c0820181905260e08201839052604051621600c960ea1b81526001600160401b03871660048201526001600160c01b0319861660248201526044810191909152606481018390527308bd2a26fcf141f9244e9f71c3c99249451c89d390635803240090608401602060405180830381865af41580156130c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130e891906154f8565b60ff1661010082015260405161311c908590613108908490602001614d30565b6040516020818303038152906040526139aa565b6007545f9061312f90869060ff16611f13565b604080516001600160401b038b1681526001600160c01b03198a1660208201526001600160f81b03198916818301526060810188905260ff8316608082015290519194507f6088f5fc3484ec0fdf466ecfcea487e5566da0db0bda62b4dbeb3ed86fd3ef0b935081900360a0019150a1505050505050565b5f80516020615ef583398151915280546001600160a01b0383166001600160a01b03199091168117825560408051918252517f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9181900360200190a15050565b60408051808201909152606081525f60208201525f61322e6001546001600160a01b031690565b604051632f2a35f760e11b81523060048201526001600160a01b039190911690635e546bee90602401602060405180830381865afa158015613272573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132969190614f74565b6040516330b8415f60e01b81526001600160601b038216600482015290915073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af41580156132ef573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613313919061500f565b156133b857613320612bf0565b6001600160a01b031663f0ea17c361333661141c565b6040516001600160e01b031960e084901b1681526001600160601b0390911660048201526024015f60405180830381865afa158015613377573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261339e9190810190615b09565b60208101519092506001600160a01b0316156133b8575090565b6119916139fb565b6133c861187c565b6001600160a01b0316336001600160a01b0316146133fb5760405163086391f760e31b81523360048201526024016109e4565b613405600b613ac5565b60405163deaa59df60e01b81526001600160a01b038381166004830152919091169063deaa59df90602401612bc7565b6040516001600160a01b03848116602483015283811660448301526001600160e01b0319831660648301525f9182918291829189169060840160408051601f198184030181529181526020820180516001600160e01b031663b700961360e01b179052516134a39190615ba7565b5f60405180830381855afa9150503d805f81146134db576040519150601f19603f3d011682016040523d82523d5f602084013e6134e0565b606091505b5091509150811561353257604081511061351257808060200190518101906135089190615bbd565b9094509250613532565b6020815110613532578080602001905181019061352f919061500f565b93505b505094509492505050565b604051630a4d29dd60e31b81526001600160601b03821660048201527382860d6202c009092d0d7507380ba8ef8f4fd567906352694ee890602401602060405180830381865af4158015613593573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135b7919061500f565b156135c0575050565b5f6135da838360405180602001604052805f815250613b56565b90506135f683828460405180602001604052805f815250613be9565b5f61361184838560405180602001604052805f815250613c71565b9050611f0b8482613d06565b5f5f80516020615f15833981519152600c0154604051637baa9a0b60e01b81526001600160601b038516600482015264ffffffffff841660248201526001600160a01b0390911690637baa9a0b906044016020604051808303815f875af115801561368a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136ae9190615a64565b9392505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680c54604051630155751d60e31b81526001600160601b03831660048201526001600160a01b0390911690630aaba8e890602401612bc7565b5f80613717614304565b5f6137278b8b8b8b8b8b8b613d97565b8093508194508296505050506137f58c8583896003601b9054906101000a900464ffffffffff1660095f9054906101000a90046001600160601b031673f41933c60fdea61085b0ff18b906cddcd547634c63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af41580156137aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137ce9190615bf2565b8d8a6040516020016137e1929190615c0d565b604051602081830303815290604052613e42565b925050509850989650505050505050565b5f5f80516020615f15833981519152600c015460405163d22413e560e01b81526001600160601b03808716600483015264ffffffffff86166024830152841660448201526001600160a01b039091169063d22413e5906064016020604051808303815f875af115801561387b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061389f9190614f74565b949350505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680c54604051635dfddfdd60e11b81526001600160601b038416600482015264ffffffffff831660248201526001600160a01b039091169063bbfbbfba90604401612703565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f045460405163f684566360e01b81525f916001600160a01b03169063f684566390613961908890889088908890600401615c2a565b6020604051808303815f875af115801561397d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139a19190615c75565b95945050505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680a54604051638f997f6d60e01b81526001600160a01b0390911690638f997f6d906127039085908590600401615c90565b60408051808201909152606081525f60208201525f5f80516020615ed583398151915290506040518060400160405280825f018054613a3990614f8f565b80601f0160208091040260200160405190810160405280929190818152602001828054613a6590614f8f565b8015613ab05780601f10613a8757610100808354040283529160200191613ab0565b820191905f5260205f20905b815481529060010190602001808311613a9357829003601f168201915b50505091835250505f60209091015292915050565b5f613ad86001546001600160a01b031690565b6001600160a01b031663d39e604383613aef611521565b6040516001600160e01b031960e085901b16815260ff928316600482015291166024820152604401602060405180830381865afa158015613b32573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0f9190614fd2565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680d546040516374b775eb60e01b81525f916001600160a01b0316906374b775eb90613ba990879087908790600401615cb4565b6020604051808303815f875af1158015613bc5573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061389f9190615ce4565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680d54604051636e2cdce760e01b81526001600160a01b0390911690636e2cdce790613c3e908790879087908790600401615cff565b5f604051808303815f87803b158015613c55575f80fd5b505af1158015613c67573d5f803e3d5ffd5b5050505050505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680d54604051631e2992c760e11b81525f916001600160a01b031690633c53258e90613cc6908890889088908890600401615cff565b6020604051808303815f875af1158015613ce2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139a19190615a64565b5f805f80516020615f15833981519152600d015460405163137a92a760e01b81526001600160601b038616600482015264ffffffffff851660248201526001600160a01b039091169063137a92a79060440160408051808303815f875af1158015613d73573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111199190615d39565b5f613da0614304565b5f807308bd2a26fcf141f9244e9f71c3c99249451c89d36355d166e13088886040518463ffffffff1660e01b8152600401613ddd93929190615513565b60e060405180830381865af4158015613df8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1c91906155b1565b90945092509050613e328b8b8b8b8b8787613eec565b9350509750975097945050505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680b54604051639a83274160e01b81525f916001600160a01b031690639a83274190613e9f908c908c908c908c908c908c908c908c90600401615d66565b6020604051808303815f875af1158015613ebb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613edf9190614f74565b9998505050505050505050565b5f80613ef66141d7565b7308bd2a26fcf141f9244e9f71c3c99249451c89d3634f339f15613f18612bf0565b613f2061141c565b8d8d8d8d8d6040518863ffffffff1660e01b8152600401613f479796959493929190615ddc565b5f60405180830381865af4158015613f61573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613f889190810190615e3d565b9194509250905081613fcc575f613f9e8b61408b565b9050613fc98183604051602001613fb59190614d30565b6040516020818303038152906040526140bc565b50505b60a081015160035460405163586a46dd60e11b81526001600160601b0392831660048201528288166024820152911660448201527308bd2a26fcf141f9244e9f71c3c99249451c89d39063b0d48dba906064015f6040518083038186803b158015614035575f80fd5b505af4158015614047573d5f803e3d5ffd5b505050506140598160a0015186614153565b6001600160601b031660a082015260405161407e908490613108908490602001614d30565b5050979650505050505050565b5f8160405160200161409f91815260200190565b604051602081830303815290604052805190602001209050919050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680a5460405163c3fa12bb60e01b81525f916001600160a01b03169063c3fa12bb9061410d9086908690600401615e9c565b6020604051808303815f875af1158015614129573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136ae9190615bf2565b92915050565b60405163274acb3560e01b81526001600160601b038084166004830152821660248201525f907382860d6202c009092d0d7507380ba8ef8f4fd5679063274acb3590604401602060405180830381865af41580156141b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136ae9190614f74565b60408051610140810182525f808252602082018190526060928201839052828201819052608082019290925260a0810182905260c0810182905260e08101829052610100810182905261012081019190915290565b6040805161012081019091525f60e0820181815261010083019190915281908152602001614269604080518082019091525f808252602082015290565b8152602001614287604080518082019091525f808252602082015290565b81526020016142a5604080518082019091525f808252602082015290565b81526020016142c3604080518082019091525f808252602082015290565b81526020016142e1604080518082019091525f808252602082015290565b81526020016142ff604080518082019091525f808252602082015290565b905290565b6040518060a001604052806005906020820280368337509192915050565b5f60208284031215614332575f80fd5b81356001600160e01b0319811681146136ae575f80fd5b6001600160c01b031981168114610ea4575f80fd5b60ff81168114610ea4575f80fd5b5f806040838503121561437d575f80fd5b823561438881614349565b915060208301356143988161435e565b809150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081526001600160601b0382511660208201526001600160601b03602083015116604082015260ff60408301511660608201525f6060830151614419608084018215159052565b5060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08084015261389f6101008401826143a3565b602081525f6136ae60208301846143a3565b6001600160601b0381168114610ea4575f80fd5b8035610d128161446f565b5f6020828403121561449e575f80fd5b81356136ae8161446f565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b03811182821017156144df576144df6144a9565b60405290565b60405161014081016001600160401b03811182821017156144df576144df6144a9565b60405161024081016001600160401b03811182821017156144df576144df6144a9565b60405161010081016001600160401b03811182821017156144df576144df6144a9565b60405161020081016001600160401b03811182821017156144df576144df6144a9565b604051601f8201601f191681016001600160401b0381118282101715614599576145996144a9565b604052919050565b6001600160a01b0381168114610ea4575f80fd5b5f6001600160401b038211156145cd576145cd6144a9565b50601f01601f191660200190565b5f82601f8301126145ea575f80fd5b8135602083015f6146026145fd846145b5565b614571565b9050828152858383011115614615575f80fd5b828260208301375f92810160200192909252509392505050565b64ffffffffff81168114610ea4575f80fd5b8035610d128161462f565b5f82601f83011261465b575f80fd5b61466560c0614571565b8060c0840185811115614676575f80fd5b845b81811015614690578035845260209384019301614678565b509095945050505050565b5f61018082840312156146ac575f80fd5b6146b46144bd565b905081356001600160401b038111156146cb575f80fd5b6146d7848285016145db565b8252506146e660208301614641565b602082015260408201356001600160401b03811115614703575f80fd5b61470f848285016145db565b60408301525061472160608301614641565b606082015260808201356001600160401b0381111561473e575f80fd5b61474a848285016145db565b60808301525061475c60a08301614483565b60a082015261476e8360c0840161464c565b60c082015292915050565b5f8082840361010081121561478c575f80fd5b60e0811215614799575f80fd5b506147a26144bd565b83356147ad816145a1565b815260208401356147bd816145a1565b6020820152604084810135908201526060808501359082015260808401356147e48161435e565b608082015260a0848101359082015260c08085013590820152915060e08301356001600160401b03811115614817575f80fd5b6148238582860161469b565b9150509250929050565b5f6020828403121561483d575f80fd5b5035919050565b8015158114610ea4575f80fd5b5f60208284031215614861575f80fd5b81356136ae81614844565b5f806040838503121561487d575f80fd5b823561488881614349565b9150602083013561439881614844565b805182525f60208201516148b5602085018264ffffffffff169052565b50604082015161014060408501526148d16101408501826143a3565b905060608301516148eb606086018264ffffffffff169052565b506080830151848203608086015261490382826143a3565b91505060a083015161492060a08601826001600160601b03169052565b5060c083015161493c60c08601826001600160f81b0319169052565b5060e083015160e085015261010083015161495d61010086018260ff169052565b5061012083015161497861012086018264ffffffffff169052565b509392505050565b8215158152604060208201525f61389f6040830184614898565b5f80604083850312156149ab575f80fd5b82356149b6816145a1565b915060208301356143988161446f565b5f805f805f8060c087890312156149db575f80fd5b86356149e68161446f565b955060208701356149f681614349565b94506040870135614a068161462f565b935060608701356001600160401b03811115614a20575f80fd5b614a2c89828a016145db565b9350506080870135614a3d8161446f565b915060a0870135614a4d81614349565b809150509295509295509295565b6001600160401b0381168114610ea4575f80fd5b5f60208284031215614a7f575f80fd5b81356136ae81614a5b565b5f8060408385031215614a9b575f80fd5b8235614aa681614a5b565b915060208301356001600160401b03811115614ac0575f80fd5b614823858286016145db565b5f60208284031215614adc575f80fd5b81356136ae816145a1565b5f805f805f805f60e0888a031215614afd575f80fd5b8735614b088161446f565b96506020880135614b188161446f565b95506040880135614b288161446f565b94506060880135614b388161446f565b93506080880135614b488161462f565b925060a0880135614b588161462f565b915060c0880135614b688161435e565b8091505092959891949750929550565b80516001600160a01b031682526020908101516001600160601b0316910152565b5f6101c082019050614bac828451614b78565b6020830151614bbe6040840182614b78565b506040830151614bd16080840182614b78565b506060830151614be460c0840182614b78565b506080830151614bf8610100840182614b78565b5060a0830151614c0c610140840182614b78565b5060c0830151614c20610180840182614b78565b5092915050565b5f805f6101008486031215614c3a575f80fd5b8335614c45816145a1565b92506020840135614c558161446f565b9150614c64856040860161464c565b90509250925092565b805f5b6005811015611b975781516001600160601b0316845260209384019390910190600101614c70565b83815260e08101614cac6020830185614c6d565b6001600160601b03831660c0830152949350505050565b602081525f825160406020840152614cde60608401826143a3565b602094909401516001600160a01b0316604093909301929092525090919050565b5f60208284031215614d0f575f80fd5b81356001600160401b03811115614d24575f80fd5b61389f848285016145db565b602081525f6136ae6020830184614898565b5f805f8060808587031215614d55575f80fd5b8435614d60816145a1565b93506020850135614d70816145a1565b9250604085013591506060850135614d87816145a1565b939692955090935050565b5f8151808452602084019350602083015f5b82811015614dcb5781516001600160601b0316865260209586019590910190600101614da4565b5093949350505050565b602081528151151560208201526020820151151560408201525f6040830151614e02606084018215159052565b50606083015160ff8116608084015250608083015160ff811660a08401525060a08301516001600160601b03811660c08401525060c08301516001600160601b03811660e08401525060e08301516101008084015261389f610120840182614d92565b5f60208284031215614e75575f80fd5b81356136ae81614349565b61ffff81168114610ea4575f80fd5b5f805f60608486031215614ea1575f80fd5b8335614eac8161446f565b92506020840135614ebc81614e80565b91506040840135614ecc8161446f565b809150509250925092565b5f805f8060808587031215614eea575f80fd5b8435614ef58161446f565b93506020850135614f0581614349565b92506040850135614f158161462f565b915060608501356001600160401b03811115614f2f575f80fd5b614f3b878288016145db565b91505092959194509250565b5f60208284031215614f57575f80fd5b815162ffffff811681146136ae575f80fd5b8051610d128161446f565b5f60208284031215614f84575f80fd5b81516136ae8161446f565b600181811c90821680614fa357607f821691505b602082108103614fc157634e487b7160e01b5f52602260045260245ffd5b50919050565b8051610d12816145a1565b5f60208284031215614fe2575f80fd5b81516136ae816145a1565b5f60208284031215614ffd575f80fd5b5051919050565b8051610d1281614844565b5f6020828403121561501f575f80fd5b81516136ae81614844565b8051610d128161462f565b5f82601f830112615044575f80fd5b8151602083015f6150576145fd846145b5565b905082815285838301111561506a575f80fd5b8282602083015e5f92810160200192909252509392505050565b80516001600160f81b031981168114610d12575f80fd5b8051610d128161435e565b5f61014082840312156150b7575f80fd5b6150bf6144e5565b8251815290506150d16020830161502a565b602082015260408201516001600160401b038111156150ee575f80fd5b6150fa84828501615035565b60408301525061510c6060830161502a565b606082015260808201516001600160401b03811115615129575f80fd5b61513584828501615035565b60808301525061514760a08301614f69565b60a082015261515860c08301615084565b60c082015260e08281015190820152615174610100830161509b565b610100820152615187610120830161502a565b61012082015292915050565b5f80604083850312156151a4575f80fd5b82516151af81614844565b60208401519092506001600160401b038111156151ca575f80fd5b614823858286016150a6565b6001600160601b03881681526001600160401b0360c01b871660208201526001600160601b038616604082015264ffffffffff8516606082015260e060808201525f61522560e08301866143a3565b6001600160601b039490941660a0830152506001600160c01b03199190911660c09091015295945050505050565b5f610240828403128015615265575f80fd5b5061526e614508565b61527783614f69565b815261528560208401614f69565b602082015261529660408401614f69565b60408201526152a760608401614f69565b60608201526152b860808401614f69565b60808201526152c960a08401614f69565b60a08201526152da60c08401614f69565b60c08201526152eb60e08401614f69565b60e08201526152fd6101008401614f69565b6101008201526153106101208401614f69565b6101208201526153236101408401614f69565b6101408201526153366101608401614f69565b6101608201526153496101808401614f69565b61018082015261535c6101a08401614f69565b6101a082015261536f6101c08401614f69565b6101c08201526153826101e08401614f69565b6101e08201526153956102008401614f69565b6102008201526153a86102208401614f69565b6102208201529392505050565b5f602082840312156153c5575f80fd5b81516001600160401b038111156153da575f80fd5b820160e081850312156153eb575f80fd5b6153f36144bd565b6153fc82614f69565b815261540a60208301614f69565b602082015261541b6040830161509b565b604082015261542c60608301615004565b606082015261543d60808301614fc7565b608082015261544e60a08301614fc7565b60a082015260c08201516001600160401b0381111561546b575f80fd5b61547786828501615035565b60c083015250949350505050565b8051610d1281614349565b5f60608284031280156154a1575f80fd5b50604051606081016001600160401b03811182821017156154c4576154c46144a9565b60405282516154d281614349565b81526154e060208401615084565b60208201526040928301519281019290925250919050565b5f60208284031215615508575f80fd5b81516136ae8161435e565b6001600160a01b03841681526001600160601b0383166020820152610100810160408201835f5b600681101561555957815183526020928301929091019060010161553a565b505050949350505050565b5f82601f830112615573575f80fd5b61557d60a0614571565b8060a084018581111561558e575f80fd5b845b818110156146905780516155a38161446f565b845260209384019301615590565b5f805f60e084860312156155c3575f80fd5b835192506155d48560208601615564565b915060c0840151614ecc8161446f565b5f82601f8301126155f3575f80fd5b81516001600160401b0381111561560c5761560c6144a9565b8060051b61561c60208201614571565b91825260208185018101929081019086841115615637575f80fd5b6020860192505b838310156156625782516156518161446f565b82526020928301929091019061563e565b9695505050505050565b5f6020828403121561567c575f80fd5b81516001600160401b03811115615691575f80fd5b820161010081850312156156a3575f80fd5b6156ab61452b565b6156b482615004565b81526156c260208301615004565b60208201526156d360408301615004565b60408201526156e46060830161509b565b60608201526156f56080830161509b565b608082015261570660a08301614f69565b60a082015261571760c08301614f69565b60c082015260e08201516001600160401b03811115615734575f80fd5b615740868285016155e4565b60e083015250949350505050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615772575f80fd5b81516001600160401b03811115615787575f80fd5b61389f848285016150a6565b5f8060c083850312156157a4575f80fd5b82516157af8161446f565b91506157be8460208501615564565b90509250929050565b5f80858511156157d5575f80fd5b838611156157e1575f80fd5b5050820193919092039150565b80356001600160e01b03198116906004841015614c20576001600160e01b031960049490940360031b84901b1690921692915050565b6001600160a01b03841681526040602082018190528101829052818360608301375f818301606090810191909152601f909201601f1916010192915050565b5f805f60608486031215615875575f80fd5b835161588081614844565b602085015190935061589181614844565b6040850151909250614ecc8161435e565b8051610d1281614e80565b5f602082840312156158bd575f80fd5b81516001600160401b038111156158d2575f80fd5b820161020081850312156158e4575f80fd5b6158ec61454e565b6158f582614f69565b815261590360208301614f69565b602082015261591460408301615485565b604082015261592560608301614f69565b606082015261593660808301614f69565b608082015261594760a08301615485565b60a082015261595860c083016158a2565b60c082015261596960e083016158a2565b60e082015261597b6101008301614f69565b61010082015261598e6101208301614f69565b6101208201526159a1610140830161502a565b6101408201526159b4610160830161502a565b6101608201526159c7610180830161502a565b6101808201526159da6101a0830161502a565b6101a08201526101c08201516001600160401b038111156159f9575f80fd5b615a0586828501615035565b6101c0830152506101e08201516001600160401b03811115615a25575f80fd5b615a3186828501615035565b6101e083015250949350505050565b604081525f615a5260408301856143a3565b905060ff831660208301529392505050565b5f60208284031215615a74575f80fd5b81516136ae8161462f565b8181038181111561414d57634e487b7160e01b5f52601160045260245ffd5b5f60208284031215615aae575f80fd5b81516001600160401b03811115615ac3575f80fd5b61389f84828501615035565b6001600160601b0384168152606060208201525f615af060608301856143a3565b90506001600160601b0383166040830152949350505050565b5f60208284031215615b19575f80fd5b81516001600160401b03811115615b2e575f80fd5b820160408185031215615b3f575f80fd5b604080519081016001600160401b0381118282101715615b6157615b616144a9565b60405281516001600160401b03811115615b79575f80fd5b615b8586828501615035565b82525060208201519150615b98826145a1565b60208101919091529392505050565b5f82518060208501845e5f920191825250919050565b5f8060408385031215615bce575f80fd5b8251615bd981614844565b602084015190925063ffffffff81168114614398575f80fd5b5f60208284031215615c02575f80fd5b81516136ae81614349565b6001600160601b038316815260c081016136ae6020830184614c6d565b6001600160601b0385168152608060208201525f615c4b60808301866143a3565b64ffffffffff851660408401528281036060840152615c6a81856143a3565b979650505050505050565b5f60208284031215615c85575f80fd5b81516136ae81614a5b565b6001600160401b0360c01b83168152604060208201525f61389f60408301846143a3565b6001600160601b03841681526001600160601b0383166020820152606060408201525f6139a160608301846143a3565b5f60208284031215615cf4575f80fd5b81516136ae81614e80565b6001600160601b038516815261ffff841660208201526001600160601b0383166040820152608060608201525f61566260808301846143a3565b5f8060408385031215615d4a575f80fd5b8251615d558161446f565b60208401519092506143988161446f565b6001600160a01b03891681526001600160c01b031988811660208301526001600160601b038881166040840152878116606084015264ffffffffff87166080840152851660a0830152831660c082015261010060e082018190525f90615dce908301846143a3565b9a9950505050505050505050565b60018060a01b03881681526001600160601b038716602082015285604082015264ffffffffff8516606082015260e060808201525f615e1e60e08301866143a3565b64ffffffffff851660a084015282810360c0840152615dce81856143a3565b5f805f60608486031215615e4f575f80fd5b8351615e5a81614349565b6020850151909350615e6b81614844565b60408501519092506001600160401b03811115615e86575f80fd5b615e92868287016150a6565b9150509250925092565b828152604060208201525f61389f60408301846143a356fe07ebcf49758b6ed3af50fa146bec0abe157c0218fe65dc0874c286e9d5da4f00ffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f00f3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a000bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6800a2646970667358221220b29fccb899298434e2a76e759e25e71e130d914680df214389448ab53f86026e64736f6c634300081a003300000000000000000000000048b24f2908bba1fd1a7d68395980e4c9eabbb4d300000000000000000000000000000000000000000000000000000000012ed0b80000000000000000000000000000000000000000000000000000000000000080000000000000000000000000893a65351f3cc68d6683af9fe0a1df2a2e1ea7300000000000000000000000000000000000000000000000000000000000000012464450726f647563745f37353263386432310000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106103bf575f3560e01c806360efe48c116101f5578063b277d78011610114578063de7b5d14116100a9578063ea15869f11610079578063ea15869f1461094f578063f0107c1514610963578063f179d0641461097b578063f3e349ae1461098e575f80fd5b8063de7b5d14146108e5578063deaa59df14610915578063e1f216fa14610928578063e9b2460c1461093b575f80fd5b8063bf7e214f116100e4578063bf7e214f14610866578063c108bd4c1461086e578063d11efdfa14610883578063d3c576d8146108cd575f80fd5b8063b277d78014610819578063b423086c1461082c578063b7b357ac14610834578063be5c8f441461084c575f80fd5b8063893d20e81161018a578063972e22eb1161015a578063972e22eb146107ba578063a1794029146107d2578063ad12ad60146107f2578063ada9652e14610805575f80fd5b8063893d20e8146107745780638b0af5d81461077c5780638fb360371461078457806390edbd35146107a5575f80fd5b806376b707b7116101c557806376b707b7146107225780637a9e5e4b1461072a578063844e0f201461073d578063846c9fce14610752575f80fd5b806360efe48c146106c7578063644c45e0146106d75780636bd1c0eb146106df578063768e87771461070f575f80fd5b80632c47e75a116102e15780634cdabb16116102765780635ab1bd53116102465780635ab1bd531461066257806360426af3146106735780636078a3b214610686578063608a5f8d14610699575f80fd5b80634cdabb16146106215780635349d2a81461063457806354d33735146106475780635741e5e91461065a575f80fd5b8063419197fe116102b1578063419197fe146105df57806343d752d3146105f25780634b396c4f146105fa5780634b9ddafe14610607575f80fd5b80632c47e75a146105855780632eb3e6f4146105a65780632f15ce0d146105cd57806339cee407146105d6575f80fd5b80631d0ed70211610357578063211e28b611610327578063211e28b61461055a57806321df0da71461056d578063223668441461057557806322f3e2d41461057d575f80fd5b80631d0ed702146104b25780631e6239c6146104ed5780631eff4b22146105125780631ff1292f14610547575f80fd5b80631329960411610392578063132996041461044a578063138461e01461046a57806317d7de7c1461048a5780631c6b21901461049f575f80fd5b806301ffc9a7146103c35780630b045f60146104045780630d8e6e2c146104195780630fec111c14610435575b5f80fd5b6103ef6103d1366004614322565b6001600160e01b0319165f9081526020819052604090205460ff1690565b60405190151581526020015b60405180910390f35b61041761041236600461436c565b6109a1565b005b6104216109fe565b60405162ffffff90911681526020016103fb565b61043d610a85565b6040516103fb91906143d1565b610452610c3f565b6040516001600160a01b0390911681526020016103fb565b610472610ca7565b6040516001600160601b0390911681526020016103fb565b610492610cb1565b6040516103fb919061445d565b6104726104ad36600461448e565b610cc1565b6104c56104c0366004614779565b610d17565b604080516001600160c01b031990931683526001600160601b039091166020830152016103fb565b6105006104fb36600461482d565b610dd9565b60405160ff90911681526020016103fb565b6105397f6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa30081565b6040519081526020016103fb565b610417610555366004614851565b610e02565b610417610568366004614851565b610e60565b610452610ea7565b6103ef610eeb565b6103ef610fe1565b61059861059336600461486c565b611058565b6040516103fb929190614980565b6105397fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f0081565b61053960065481565b61053960055481565b6104176105ed36600461499a565b611124565b610452611177565b6007546105009060ff1681565b60025461047290600160601b90046001600160601b031681565b600254610472906001600160601b031681565b6104726106423660046149c6565b611189565b610417610655366004614a6f565b61124b565b6103ef61125d565b6001546001600160a01b0316610452565b610417610681366004614a8a565b611313565b610472610694366004614acc565b61134a565b6003546106b190600160881b900464ffffffffff1681565b60405164ffffffffff90911681526020016103fb565b600754610100900460ff166103ef565b61047261141c565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f02546001600160a01b0316610452565b61041761071d366004614ae7565b611437565b610500611521565b610417610738366004614acc565b611589565b61074561160f565b6040516103fb9190614b99565b610765610760366004614c27565b6117e8565b6040516103fb93929190614c98565b61045261187c565b6104176119ad565b61078c611a78565b6040516001600160e01b031990911681526020016103fb565b6107ad611aad565b6040516103fb9190614cc3565b6003546106b190600160b01b900464ffffffffff1681565b6107e56107e0366004614cff565b611ade565b6040516103fb9190614d30565b610417610800366004614d42565b611afa565b6105395f80516020615eb583398151915281565b61041761082736600461448e565b611b9d565b6107ad611c08565b6003546106b190600160601b900464ffffffffff1681565b60015461047290600160a01b90046001600160601b031681565b610452611c24565b610876611c3f565b6040516103fb9190614dd5565b6108b5610891366004614e65565b6001600160c01b0319165f908152600860205260409020546001600160401b031690565b6040516001600160401b0390911681526020016103fb565b6003546106b190600160d81b900464ffffffffff1681565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f00546001600160a01b0316610452565b610417610923366004614acc565b611d93565b610417610936366004614e8f565b611de0565b6105395f80516020615f1583398151915281565b6105395f80516020615ed583398151915281565b600954600160601b90046001600160601b0316610472565b610472610989366004614ed7565b611df6565b600354610472906001600160601b031681565b6109ad335b5f36611e15565b6109b561187c565b6001600160a01b0316336001600160a01b0316146109ed5760405163086391f760e31b81523360048201526024015b60405180910390fd5b6109f78282611f13565b5050505050565b604051632efe011360e01b8152600160048201525f602482018190526044820181905290731c7f4780c639cb898b64769694d308a5a363a83e90632efe011390606401602060405180830381865af4158015610a5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a809190614f47565b905090565b6040805160e0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820152907f6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa30090506040518060e0016040528073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af4158015610b31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b559190614f74565b6001600160601b0390811682528354908116602083015260ff600160601b820481166040840152600160681b909104161515606082015230608082015260a001610b9d61187c565b6001600160a01b03168152602001826001018054610bba90614f8f565b80601f0160208091040260200160405190810160405280929190818152602001828054610be690614f8f565b8015610c315780601f10610c0857610100808354040283529160200191610c31565b820191905f5260205f20905b815481529060010190602001808311610c1457829003601f168201915b505050505081525091505090565b5f610c48611177565b6001600160a01b031663132996046040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c83573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a809190614fd2565b5f610a80306123cc565b6060610cbb611aad565b51919050565b5f610ccb336109a6565b610cd361187c565b6001600160a01b0316336001600160a01b031614610d065760405163086391f760e31b81523360048201526024016109e4565b610d0f82612622565b90505b919050565b5f80610d22336109a6565b610d2b8461267a565b8351835160405163cdc23e6960e01b8152610dcd91839173b7336e875465659bad9659b25d078c6cace417069163cdc23e6991610d6b919060040161445d565b602060405180830381865af4158015610d86573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610daa9190614fed565b86602001518760400151886060015189608001518a60a001518b60c0015161272c565b90969095509350505050565b60048160068110610de8575f80fd5b60209182820401919006915054906101000a900460ff1681565b610e0b336109a6565b610e1361187c565b6001600160a01b0316336001600160a01b031614610e465760405163086391f760e31b81523360048201526024016109e4565b600780549115156101000261ff0019909216919091179055565b610e6861187c565b6001600160a01b0316336001600160a01b031614610e9b5760405163086391f760e31b81523360048201526024016109e4565b610ea481612b86565b50565b5f610eb0611177565b6001600160a01b03166382bfefc86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c83573d5f803e3d5ffd5b5f610efe6001546001600160a01b031690565b604051632f2a35f760e11b81523060048201526001600160a01b039190911690635e546bee90602401602060405180830381865afa158015610f42573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f669190614f74565b6040516330b8415f60e01b81526001600160601b03909116600482015273b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af4158015610fbd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a80919061500f565b5f610fea611c24565b60405163a166aa8960e01b81523060048201526001600160a01b03919091169063a166aa8990602401602060405180830381865afa15801561102e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611052919061500f565b15905090565b5f6110616141d7565b7308bd2a26fcf141f9244e9f71c3c99249451c89d3637bc17425611083612bf0565b61108b61141c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160601b031660248201526001600160c01b03198716604482015285151560648201526084015f60405180830381865af41580156110f2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526111199190810190615193565b909590945092505050565b61112d336109a6565b61113561187c565b6001600160a01b0316336001600160a01b0316146111685760405163086391f760e31b81523360048201526024016109e4565b6111728282612c1e565b505050565b5f611180611aad565b60200151905090565b5f8260166111978282612d9f565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680e545f906001600160a01b031663f4bfe53a6111d161141c565b8b8d8c8c8c8c6040518863ffffffff1660e01b81526004016111f997969594939291906151d6565b61024060405180830381865afa158015611215573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112399190615253565b60a001519a9950505050505050505050565b611254336109a6565b610ea481612ed3565b5f611266610eeb565b156112ea576001546001600160a01b03166040516308b09a5f60e41b81523060048201526001600160a01b039190911690638b09a5f0906024015f60405180830381865afa1580156112ba573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112e191908101906153b5565b60600151905090565b507fffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f015460ff1690565b61131c336109a6565b5f818060200190518101906113319190615490565b905061117283825f015183602001518460400151612f2b565b5f611354336109a6565b61135c61187c565b6001600160a01b0316336001600160a01b03161461138f5760405163086391f760e31b81523360048201526024016109e4565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68095460405163303c51d960e11b81526001600160a01b03848116600483015290911690636078a3b2906024015b6020604051808303815f875af11580156113f8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0f9190614f74565b5f80516020615eb5833981519152546001600160601b031690565b611440336109a6565b61144861187c565b6001600160a01b0316336001600160a01b03161461147b5760405163086391f760e31b81523360048201526024016109e4565b600180546001600160a01b0316600160a01b6001600160601b03998a1602179055600280549688166001600160c01b031990971696909617600160601b958816860217909555600380549390961670ffffffffffffffffffffffffffffffffff199093169290921764ffffffffff9182169093029290921764ffffffffff60881b1916600160881b9190921602179091556007805460ff191660ff909216919091179055565b5f61152a611c24565b6001600160a01b03166376b707b76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611565573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8091906154f8565b33611592611c24565b6001600160a01b0316816001600160a01b0316146115cd5760405162d1953b60e31b81526001600160a01b03821660048201526024016109e4565b816001600160a01b03163b5f03611602576040516361798f2f60e11b81526001600160a01b03831660048201526024016109e4565b61160b826131a7565b5050565b61161761422c565b5060408051610120810182527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6802546001600160a01b0380821660e084019081526001600160601b03600160a01b938490048116610100860152908452845180860186527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6803548084168252849004821660208083019190915280860191909152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680454808516825285900483168183015285870152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68055480851682528590048316818301526060860152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d68065480851682528590048316818301526080860152855180870187527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680754808516825285900483168183015260a086015285518087019096527f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680854928316865292909104169083015260c081019190915290565b5f6117f1614304565b6040516355d166e160e01b81525f907308bd2a26fcf141f9244e9f71c3c99249451c89d3906355d166e19061182e90899089908990600401615513565b60e060405180830381865af4158015611849573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061186d91906155b1565b92509250925093509350939050565b5f805f80516020615eb583398151915280546040516330b8415f60e01b81526001600160601b03909116600482015290915073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af41580156118e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190c919061500f565b15611997576001546001600160a01b03168154604051631c5da14d60e11b81526001600160601b0390911660048201526001600160a01b0391909116906338bb429a90602401602060405180830381865afa15801561196d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119919190614fd2565b91505090565b54600160601b90046001600160a01b0316919050565b6119b5612bf0565b6001600160a01b0316630b5d931c6119cb61141c565b6040516001600160e01b031960e084901b1681526001600160601b0390911660048201526024015f60405180830381865afa158015611a0c573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611a33919081019061566c565b60e001515f81518110611a4857611a4861574e565b60200260200101516009600c6101000a8154816001600160601b0302191690836001600160601b03160217905550565b5f80516020615ef583398151915280545f9190600160a01b900460ff16611a9f575f611991565b638fb3603760e01b91505090565b60408051808201909152606081525f6020820152611ac9610eeb565b15611ad657610a80613207565b610a80611c08565b611ae66141d7565b81806020019051810190610d0f9190615762565b6001546001600160a01b03166001600160a01b031663120726c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b41573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b659190614fd2565b6001600160a01b0316336001600160a01b031614611b975760405162f0630960e01b81523360048201526024016109e4565b50505050565b611ba6336109a6565b611bae61187c565b6001600160a01b0316336001600160a01b031614611be15760405163086391f760e31b81523360048201526024016109e4565b600980546bffffffffffffffffffffffff19166001600160601b0392909216919091179055565b60408051808201909152606081525f6020820152610a80613207565b5f80516020615ef5833981519152546001600160a01b031690565b60408051610100810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e08101919091525f80516020615f15833981519152604080516101008082018352835460ff808216151584529181048216151560208085019190915262010000820483161515848601526301000000820483166060850152640100000000820490921660808401526001600160601b03650100000000008204811660a0850152600160881b9091041660c083015260018401805484518184028101840190955280855292949360e08601939092830182828015611d8557602002820191905f5260205f20905f905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b01049283019260010382029150808411611d425790505b505050505081525050905090565b611d9c336109a6565b611da461187c565b6001600160a01b0316336001600160a01b031614611dd75760405163086391f760e31b81523360048201526024016109e4565b610ea4816133c0565b611de9336109a6565b8260156109f78282612d9f565b5f81806020019051810190611e0b9190615793565b5095945050505050565b5f80516020615ef58339815191525f80611e4d611e30611c24565b8730611e3f60045f8a8c6157c7565b611e48916157ee565b613435565b9150915081611f0b5763ffffffff811615611ee857825460ff60a01b1916600160a01b178355611e7b611c24565b6001600160a01b03166394c7d7ee8787876040518463ffffffff1660e01b8152600401611eaa93929190615824565b5f604051808303815f87803b158015611ec1575f80fd5b505af1158015611ed3573d5f803e3d5ffd5b5050845460ff60a01b1916855550611f0b9050565b60405162d1953b60e31b81526001600160a01b03871660048201526024016109e4565b505050505050565b5f805f80611f1f612bf0565b90507308bd2a26fcf141f9244e9f71c3c99249451c89d363bcfba16982611f4461141c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160601b031660248201526001600160c01b031989166044820152606401606060405180830381865af4158015611fa4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fc89190615863565b91955093509150831580611fda575082155b15611fe557506123c5565b604051631954e65360e21b81526001600160c01b0319871660048201525f906001600160a01b03831690636553994c90602401602060405180830381865afa158015612033573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120579190614fed565b90505f8660ff16821061206d578660ff1661206f565b815b90505f816001600160401b0381111561208a5761208a6144a9565b6040519080825280602002602001820160405280156120b3578160200160208202803683370190505b5090505f5b82811015612169576040516325fb9d0d60e11b81526001600160c01b03198b166004820152602481018290526001600160a01b03861690634bf73a1a90604401602060405180830381865afa158015612113573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121379190614f74565b8282815181106121495761214961574e565b6001600160601b03909216602092830291909101909101526001016120b8565b505f5b82811015612361575f8282815181106121875761218761574e565b602002602001015190505f7308bd2a26fcf141f9244e9f71c3c99249451c89d3638a37ab63886001600160a01b031663bd7d9d85856040518263ffffffff1660e01b81526004016121e791906001600160601b0391909116815260200190565b5f60405180830381865afa158015612201573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261222891908101906158ad565b6101c001518a6040518363ffffffff1660e01b815260040161224b929190615a40565b602060405180830381865af4158015612266573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061228a9190614f74565b9050612296828261353d565b61230a8273fdbcee5ffb06ba0f107922a3294110ce43c3112e639fa6a6e36040518163ffffffff1660e01b8152600401602060405180830381865af41580156122e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123059190615a64565b61361d565b50612314826136b5565b604080516001600160601b038085168252831660208201527f1c424341cadf6615bb5fa2a96492cd7ed267c05f7d1dcef2f2229ae26d4d1a7a910160405180910390a1505060010161216c565b507f497e6cfdb1ef3149777822f9e0716eebbeef1264fbc8effc6004e0111ec600818986846123908188615a7f565b604080516001600160c01b0319909516855260ff909316602085015291830152606082015260800160405180910390a1505050505b9250925092565b5f805f80516020615eb583398151915280546040516330b8415f60e01b81526001600160601b03909116600482015290915073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af4158015612438573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061245c919061500f565b156124885780546040516301ab8b6760e21b81526001600160601b0390911660048201526024016109e4565b6001546001600160a01b031660405163c3c5a54760e01b81526001600160a01b038581166004830152919091169063c3c5a54790602401602060405180830381865afa1580156124da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124fe919061500f565b6125265760405163b9304b0d60e01b81526001600160a01b03841660048201526024016109e4565b6001546001600160a01b0316604051632f2a35f760e11b81526001600160a01b0385811660048301529190911690635e546bee90602401602060405180830381865afa158015612578573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061259c9190614f74565b81546bffffffffffffffffffffffff19166001600160601b039190911690811782557f88857b75cbef7f257c9d5a473e28aaf6a91cc28f717f60f2cda3bcf5623d7b54906125e861187c565b604080516001600160601b0390931683526001600160a01b0390911660208301520160405180910390a1546001600160601b031692915050565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f03546040516301c6b21960e41b81526001600160601b03831660048201525f916001600160a01b031690631c6b2190906024016113dc565b612683336109a6565b5f61268c610ea7565b825160208401516040808601516060870151608088015160a089015160c08a0151945163d505accf60e01b81526001600160a01b03978816600482015295871660248701526044860193909352606485019190915260ff16608484015260a483015260c482015291925082169063d505accf9060e4015b5f604051808303815f87803b15801561271a575f80fd5b505af1158015611f0b573d5f803e3d5ffd5b604051634617dc7960e11b81523060048201526024810188905264ffffffffff8088166044830152851660648201526001600160601b03831660848201525f9081907308bd2a26fcf141f9244e9f71c3c99249451c89d390638c2fb8f29060a4015f6040518083038186803b1580156127a3575f80fd5b505af41580156127b5573d5f803e3d5ffd5b505050506127c98a8a8a8a8a8a8a8a61370d565b80925081935050506128468173fdbcee5ffb06ba0f107922a3294110ce43c3112e63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af415801561281c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128409190615a64565b86613806565b5061285181896138a7565b6001600160c01b031982165f908152600860205260409081902054905163015c60ad60e21b81526001600160401b039091166004820152736583a0cc1ea5b6841adae78a8ce62f319a0280539063057182b490602401602060405180830381865af41580156128c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128e6919061500f565b15612ac95760095460408051606080820183526001600160c01b0319861680835260208084018f815264ffffffffff8f81169587019586528651928301939093525194810194909452915190911690820152612a9191600160601b90046001600160601b03169060800160408051601f19818403018152908290526209629960e41b8252601e60048301529073fdbcee5ffb06ba0f107922a3294110ce43c3112e9063a5798b4e9064ffffffffff8c1690733fb33d6b382d000f1ef0928f8942c56ef3af6c41906296299090602401602060405180830381865af41580156129d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129f49190615a64565b6040516001600160e01b031960e085901b16815264ffffffffff928316600482015291166024820152604401602060405180830381865af4158015612a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5f9190615a64565b60405180604001604052806014815260200173666c6967687453746174757343616c6c6261636b60601b81525061390c565b6001600160c01b031983165f908152600860205260409020805467ffffffffffffffff19166001600160401b03929092169190911790555b604051631623433d60e31b8152600481018a90527fb51fd6991e0581f19175f5ef6b8bc59d44dbff4511eb57379f0ce2862228794490829073b7336e875465659bad9659b25d078c6cace417069063b11a19e8906024015f60405180830381865af4158015612b3a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612b619190810190615a9e565b86604051612b7193929190615acf565b60405180910390a19850989650505050505050565b5f80516020615ed58339815191526001015460405163108f145b60e11b815282151560048201526101009091046001600160a01b03169063211e28b6906024015b5f604051808303815f87803b158015612bde575f80fd5b505af11580156109f7573d5f803e3d5ffd5b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f01546001600160a01b031690565b5f7382860d6202c009092d0d7507380ba8ef8f4fd567634c41dd96846001600160a01b031663dd62ed3e612c50611177565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015612c98573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cbc9190614fed565b6040518263ffffffff1660e01b8152600401612cda91815260200190565b602060405180830381865af4158015612cf5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d199190614f74565b90505f80516020615ed5833981519152600101546040516320c8cbff60e11b81526001600160a01b0385811660048301526001600160601b03851660248301526101009092049091169063419197fe906044015f604051808303815f87803b158015612d83575f80fd5b505af1158015612d95573d5f803e3d5ffd5b5050505092915050565b60405163037c8cb160e51b815260ff8216600482015273a6b4725b0a1cf143baf5099fdd58abc8d862d34f90636f91962090602401602060405180830381865af4158015612def573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e13919061500f565b80612ea157506001546001600160a01b0316604051635b12715d60e11b81526001600160601b038416600482015260ff831660248201526001600160a01b03919091169063b624e2ba90604401602060405180830381865afa158015612e7b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e9f919061500f565b155b1561160b5760405163d711af7560e01b81526001600160601b038316600482015260ff821660248201526044016109e4565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f0454604051630b331f6960e21b81526001600160401b03831660048201526001600160a01b0390911690632ccc7da490602401612bc7565b5f612f37846001611058565b61012081015160405163790a38ad60e01b815264ffffffffff909116600482015290925073fdbcee5ffb06ba0f107922a3294110ce43c3112e915063790a38ad90602401602060405180830381865af4158015612f96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fba919061500f565b1561311c5773fdbcee5ffb06ba0f107922a3294110ce43c3112e639fa6a6e36040518163ffffffff1660e01b8152600401602060405180830381865af4158015613006573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061302a9190615a64565b64ffffffffff166101208201526001600160f81b0319831660c0820181905260e08201839052604051621600c960ea1b81526001600160401b03871660048201526001600160c01b0319861660248201526044810191909152606481018390527308bd2a26fcf141f9244e9f71c3c99249451c89d390635803240090608401602060405180830381865af41580156130c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130e891906154f8565b60ff1661010082015260405161311c908590613108908490602001614d30565b6040516020818303038152906040526139aa565b6007545f9061312f90869060ff16611f13565b604080516001600160401b038b1681526001600160c01b03198a1660208201526001600160f81b03198916818301526060810188905260ff8316608082015290519194507f6088f5fc3484ec0fdf466ecfcea487e5566da0db0bda62b4dbeb3ed86fd3ef0b935081900360a0019150a1505050505050565b5f80516020615ef583398151915280546001600160a01b0383166001600160a01b03199091168117825560408051918252517f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9181900360200190a15050565b60408051808201909152606081525f60208201525f61322e6001546001600160a01b031690565b604051632f2a35f760e11b81523060048201526001600160a01b039190911690635e546bee90602401602060405180830381865afa158015613272573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132969190614f74565b6040516330b8415f60e01b81526001600160601b038216600482015290915073b6fe977f3e63d01a734dd238ba5fc05bf45bf32c906330b8415f90602401602060405180830381865af41580156132ef573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613313919061500f565b156133b857613320612bf0565b6001600160a01b031663f0ea17c361333661141c565b6040516001600160e01b031960e084901b1681526001600160601b0390911660048201526024015f60405180830381865afa158015613377573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261339e9190810190615b09565b60208101519092506001600160a01b0316156133b8575090565b6119916139fb565b6133c861187c565b6001600160a01b0316336001600160a01b0316146133fb5760405163086391f760e31b81523360048201526024016109e4565b613405600b613ac5565b60405163deaa59df60e01b81526001600160a01b038381166004830152919091169063deaa59df90602401612bc7565b6040516001600160a01b03848116602483015283811660448301526001600160e01b0319831660648301525f9182918291829189169060840160408051601f198184030181529181526020820180516001600160e01b031663b700961360e01b179052516134a39190615ba7565b5f60405180830381855afa9150503d805f81146134db576040519150601f19603f3d011682016040523d82523d5f602084013e6134e0565b606091505b5091509150811561353257604081511061351257808060200190518101906135089190615bbd565b9094509250613532565b6020815110613532578080602001905181019061352f919061500f565b93505b505094509492505050565b604051630a4d29dd60e31b81526001600160601b03821660048201527382860d6202c009092d0d7507380ba8ef8f4fd567906352694ee890602401602060405180830381865af4158015613593573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135b7919061500f565b156135c0575050565b5f6135da838360405180602001604052805f815250613b56565b90506135f683828460405180602001604052805f815250613be9565b5f61361184838560405180602001604052805f815250613c71565b9050611f0b8482613d06565b5f5f80516020615f15833981519152600c0154604051637baa9a0b60e01b81526001600160601b038516600482015264ffffffffff841660248201526001600160a01b0390911690637baa9a0b906044016020604051808303815f875af115801561368a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136ae9190615a64565b9392505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680c54604051630155751d60e31b81526001600160601b03831660048201526001600160a01b0390911690630aaba8e890602401612bc7565b5f80613717614304565b5f6137278b8b8b8b8b8b8b613d97565b8093508194508296505050506137f58c8583896003601b9054906101000a900464ffffffffff1660095f9054906101000a90046001600160601b031673f41933c60fdea61085b0ff18b906cddcd547634c63bc1b392d6040518163ffffffff1660e01b8152600401602060405180830381865af41580156137aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137ce9190615bf2565b8d8a6040516020016137e1929190615c0d565b604051602081830303815290604052613e42565b925050509850989650505050505050565b5f5f80516020615f15833981519152600c015460405163d22413e560e01b81526001600160601b03808716600483015264ffffffffff86166024830152841660448201526001600160a01b039091169063d22413e5906064016020604051808303815f875af115801561387b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061389f9190614f74565b949350505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680c54604051635dfddfdd60e11b81526001600160601b038416600482015264ffffffffff831660248201526001600160a01b039091169063bbfbbfba90604401612703565b7fffe3d4462bded26a47154f4b8f6db494d2f772496965791d25bd456e342b7f045460405163f684566360e01b81525f916001600160a01b03169063f684566390613961908890889088908890600401615c2a565b6020604051808303815f875af115801561397d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139a19190615c75565b95945050505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680a54604051638f997f6d60e01b81526001600160a01b0390911690638f997f6d906127039085908590600401615c90565b60408051808201909152606081525f60208201525f5f80516020615ed583398151915290506040518060400160405280825f018054613a3990614f8f565b80601f0160208091040260200160405190810160405280929190818152602001828054613a6590614f8f565b8015613ab05780601f10613a8757610100808354040283529160200191613ab0565b820191905f5260205f20905b815481529060010190602001808311613a9357829003601f168201915b50505091835250505f60209091015292915050565b5f613ad86001546001600160a01b031690565b6001600160a01b031663d39e604383613aef611521565b6040516001600160e01b031960e085901b16815260ff928316600482015291166024820152604401602060405180830381865afa158015613b32573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d0f9190614fd2565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680d546040516374b775eb60e01b81525f916001600160a01b0316906374b775eb90613ba990879087908790600401615cb4565b6020604051808303815f875af1158015613bc5573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061389f9190615ce4565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680d54604051636e2cdce760e01b81526001600160a01b0390911690636e2cdce790613c3e908790879087908790600401615cff565b5f604051808303815f87803b158015613c55575f80fd5b505af1158015613c67573d5f803e3d5ffd5b5050505050505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680d54604051631e2992c760e11b81525f916001600160a01b031690633c53258e90613cc6908890889088908890600401615cff565b6020604051808303815f875af1158015613ce2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139a19190615a64565b5f805f80516020615f15833981519152600d015460405163137a92a760e01b81526001600160601b038616600482015264ffffffffff851660248201526001600160a01b039091169063137a92a79060440160408051808303815f875af1158015613d73573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111199190615d39565b5f613da0614304565b5f807308bd2a26fcf141f9244e9f71c3c99249451c89d36355d166e13088886040518463ffffffff1660e01b8152600401613ddd93929190615513565b60e060405180830381865af4158015613df8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1c91906155b1565b90945092509050613e328b8b8b8b8b8787613eec565b9350509750975097945050505050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680b54604051639a83274160e01b81525f916001600160a01b031690639a83274190613e9f908c908c908c908c908c908c908c908c90600401615d66565b6020604051808303815f875af1158015613ebb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613edf9190614f74565b9998505050505050505050565b5f80613ef66141d7565b7308bd2a26fcf141f9244e9f71c3c99249451c89d3634f339f15613f18612bf0565b613f2061141c565b8d8d8d8d8d6040518863ffffffff1660e01b8152600401613f479796959493929190615ddc565b5f60405180830381865af4158015613f61573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613f889190810190615e3d565b9194509250905081613fcc575f613f9e8b61408b565b9050613fc98183604051602001613fb59190614d30565b6040516020818303038152906040526140bc565b50505b60a081015160035460405163586a46dd60e11b81526001600160601b0392831660048201528288166024820152911660448201527308bd2a26fcf141f9244e9f71c3c99249451c89d39063b0d48dba906064015f6040518083038186803b158015614035575f80fd5b505af4158015614047573d5f803e3d5ffd5b505050506140598160a0015186614153565b6001600160601b031660a082015260405161407e908490613108908490602001614d30565b5050979650505050505050565b5f8160405160200161409f91815260200190565b604051602081830303815290604052805190602001209050919050565b7f0bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d680a5460405163c3fa12bb60e01b81525f916001600160a01b03169063c3fa12bb9061410d9086908690600401615e9c565b6020604051808303815f875af1158015614129573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136ae9190615bf2565b92915050565b60405163274acb3560e01b81526001600160601b038084166004830152821660248201525f907382860d6202c009092d0d7507380ba8ef8f4fd5679063274acb3590604401602060405180830381865af41580156141b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136ae9190614f74565b60408051610140810182525f808252602082018190526060928201839052828201819052608082019290925260a0810182905260c0810182905260e08101829052610100810182905261012081019190915290565b6040805161012081019091525f60e0820181815261010083019190915281908152602001614269604080518082019091525f808252602082015290565b8152602001614287604080518082019091525f808252602082015290565b81526020016142a5604080518082019091525f808252602082015290565b81526020016142c3604080518082019091525f808252602082015290565b81526020016142e1604080518082019091525f808252602082015290565b81526020016142ff604080518082019091525f808252602082015290565b905290565b6040518060a001604052806005906020820280368337509192915050565b5f60208284031215614332575f80fd5b81356001600160e01b0319811681146136ae575f80fd5b6001600160c01b031981168114610ea4575f80fd5b60ff81168114610ea4575f80fd5b5f806040838503121561437d575f80fd5b823561438881614349565b915060208301356143988161435e565b809150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081526001600160601b0382511660208201526001600160601b03602083015116604082015260ff60408301511660608201525f6060830151614419608084018215159052565b5060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08084015261389f6101008401826143a3565b602081525f6136ae60208301846143a3565b6001600160601b0381168114610ea4575f80fd5b8035610d128161446f565b5f6020828403121561449e575f80fd5b81356136ae8161446f565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b03811182821017156144df576144df6144a9565b60405290565b60405161014081016001600160401b03811182821017156144df576144df6144a9565b60405161024081016001600160401b03811182821017156144df576144df6144a9565b60405161010081016001600160401b03811182821017156144df576144df6144a9565b60405161020081016001600160401b03811182821017156144df576144df6144a9565b604051601f8201601f191681016001600160401b0381118282101715614599576145996144a9565b604052919050565b6001600160a01b0381168114610ea4575f80fd5b5f6001600160401b038211156145cd576145cd6144a9565b50601f01601f191660200190565b5f82601f8301126145ea575f80fd5b8135602083015f6146026145fd846145b5565b614571565b9050828152858383011115614615575f80fd5b828260208301375f92810160200192909252509392505050565b64ffffffffff81168114610ea4575f80fd5b8035610d128161462f565b5f82601f83011261465b575f80fd5b61466560c0614571565b8060c0840185811115614676575f80fd5b845b81811015614690578035845260209384019301614678565b509095945050505050565b5f61018082840312156146ac575f80fd5b6146b46144bd565b905081356001600160401b038111156146cb575f80fd5b6146d7848285016145db565b8252506146e660208301614641565b602082015260408201356001600160401b03811115614703575f80fd5b61470f848285016145db565b60408301525061472160608301614641565b606082015260808201356001600160401b0381111561473e575f80fd5b61474a848285016145db565b60808301525061475c60a08301614483565b60a082015261476e8360c0840161464c565b60c082015292915050565b5f8082840361010081121561478c575f80fd5b60e0811215614799575f80fd5b506147a26144bd565b83356147ad816145a1565b815260208401356147bd816145a1565b6020820152604084810135908201526060808501359082015260808401356147e48161435e565b608082015260a0848101359082015260c08085013590820152915060e08301356001600160401b03811115614817575f80fd5b6148238582860161469b565b9150509250929050565b5f6020828403121561483d575f80fd5b5035919050565b8015158114610ea4575f80fd5b5f60208284031215614861575f80fd5b81356136ae81614844565b5f806040838503121561487d575f80fd5b823561488881614349565b9150602083013561439881614844565b805182525f60208201516148b5602085018264ffffffffff169052565b50604082015161014060408501526148d16101408501826143a3565b905060608301516148eb606086018264ffffffffff169052565b506080830151848203608086015261490382826143a3565b91505060a083015161492060a08601826001600160601b03169052565b5060c083015161493c60c08601826001600160f81b0319169052565b5060e083015160e085015261010083015161495d61010086018260ff169052565b5061012083015161497861012086018264ffffffffff169052565b509392505050565b8215158152604060208201525f61389f6040830184614898565b5f80604083850312156149ab575f80fd5b82356149b6816145a1565b915060208301356143988161446f565b5f805f805f8060c087890312156149db575f80fd5b86356149e68161446f565b955060208701356149f681614349565b94506040870135614a068161462f565b935060608701356001600160401b03811115614a20575f80fd5b614a2c89828a016145db565b9350506080870135614a3d8161446f565b915060a0870135614a4d81614349565b809150509295509295509295565b6001600160401b0381168114610ea4575f80fd5b5f60208284031215614a7f575f80fd5b81356136ae81614a5b565b5f8060408385031215614a9b575f80fd5b8235614aa681614a5b565b915060208301356001600160401b03811115614ac0575f80fd5b614823858286016145db565b5f60208284031215614adc575f80fd5b81356136ae816145a1565b5f805f805f805f60e0888a031215614afd575f80fd5b8735614b088161446f565b96506020880135614b188161446f565b95506040880135614b288161446f565b94506060880135614b388161446f565b93506080880135614b488161462f565b925060a0880135614b588161462f565b915060c0880135614b688161435e565b8091505092959891949750929550565b80516001600160a01b031682526020908101516001600160601b0316910152565b5f6101c082019050614bac828451614b78565b6020830151614bbe6040840182614b78565b506040830151614bd16080840182614b78565b506060830151614be460c0840182614b78565b506080830151614bf8610100840182614b78565b5060a0830151614c0c610140840182614b78565b5060c0830151614c20610180840182614b78565b5092915050565b5f805f6101008486031215614c3a575f80fd5b8335614c45816145a1565b92506020840135614c558161446f565b9150614c64856040860161464c565b90509250925092565b805f5b6005811015611b975781516001600160601b0316845260209384019390910190600101614c70565b83815260e08101614cac6020830185614c6d565b6001600160601b03831660c0830152949350505050565b602081525f825160406020840152614cde60608401826143a3565b602094909401516001600160a01b0316604093909301929092525090919050565b5f60208284031215614d0f575f80fd5b81356001600160401b03811115614d24575f80fd5b61389f848285016145db565b602081525f6136ae6020830184614898565b5f805f8060808587031215614d55575f80fd5b8435614d60816145a1565b93506020850135614d70816145a1565b9250604085013591506060850135614d87816145a1565b939692955090935050565b5f8151808452602084019350602083015f5b82811015614dcb5781516001600160601b0316865260209586019590910190600101614da4565b5093949350505050565b602081528151151560208201526020820151151560408201525f6040830151614e02606084018215159052565b50606083015160ff8116608084015250608083015160ff811660a08401525060a08301516001600160601b03811660c08401525060c08301516001600160601b03811660e08401525060e08301516101008084015261389f610120840182614d92565b5f60208284031215614e75575f80fd5b81356136ae81614349565b61ffff81168114610ea4575f80fd5b5f805f60608486031215614ea1575f80fd5b8335614eac8161446f565b92506020840135614ebc81614e80565b91506040840135614ecc8161446f565b809150509250925092565b5f805f8060808587031215614eea575f80fd5b8435614ef58161446f565b93506020850135614f0581614349565b92506040850135614f158161462f565b915060608501356001600160401b03811115614f2f575f80fd5b614f3b878288016145db565b91505092959194509250565b5f60208284031215614f57575f80fd5b815162ffffff811681146136ae575f80fd5b8051610d128161446f565b5f60208284031215614f84575f80fd5b81516136ae8161446f565b600181811c90821680614fa357607f821691505b602082108103614fc157634e487b7160e01b5f52602260045260245ffd5b50919050565b8051610d12816145a1565b5f60208284031215614fe2575f80fd5b81516136ae816145a1565b5f60208284031215614ffd575f80fd5b5051919050565b8051610d1281614844565b5f6020828403121561501f575f80fd5b81516136ae81614844565b8051610d128161462f565b5f82601f830112615044575f80fd5b8151602083015f6150576145fd846145b5565b905082815285838301111561506a575f80fd5b8282602083015e5f92810160200192909252509392505050565b80516001600160f81b031981168114610d12575f80fd5b8051610d128161435e565b5f61014082840312156150b7575f80fd5b6150bf6144e5565b8251815290506150d16020830161502a565b602082015260408201516001600160401b038111156150ee575f80fd5b6150fa84828501615035565b60408301525061510c6060830161502a565b606082015260808201516001600160401b03811115615129575f80fd5b61513584828501615035565b60808301525061514760a08301614f69565b60a082015261515860c08301615084565b60c082015260e08281015190820152615174610100830161509b565b610100820152615187610120830161502a565b61012082015292915050565b5f80604083850312156151a4575f80fd5b82516151af81614844565b60208401519092506001600160401b038111156151ca575f80fd5b614823858286016150a6565b6001600160601b03881681526001600160401b0360c01b871660208201526001600160601b038616604082015264ffffffffff8516606082015260e060808201525f61522560e08301866143a3565b6001600160601b039490941660a0830152506001600160c01b03199190911660c09091015295945050505050565b5f610240828403128015615265575f80fd5b5061526e614508565b61527783614f69565b815261528560208401614f69565b602082015261529660408401614f69565b60408201526152a760608401614f69565b60608201526152b860808401614f69565b60808201526152c960a08401614f69565b60a08201526152da60c08401614f69565b60c08201526152eb60e08401614f69565b60e08201526152fd6101008401614f69565b6101008201526153106101208401614f69565b6101208201526153236101408401614f69565b6101408201526153366101608401614f69565b6101608201526153496101808401614f69565b61018082015261535c6101a08401614f69565b6101a082015261536f6101c08401614f69565b6101c08201526153826101e08401614f69565b6101e08201526153956102008401614f69565b6102008201526153a86102208401614f69565b6102208201529392505050565b5f602082840312156153c5575f80fd5b81516001600160401b038111156153da575f80fd5b820160e081850312156153eb575f80fd5b6153f36144bd565b6153fc82614f69565b815261540a60208301614f69565b602082015261541b6040830161509b565b604082015261542c60608301615004565b606082015261543d60808301614fc7565b608082015261544e60a08301614fc7565b60a082015260c08201516001600160401b0381111561546b575f80fd5b61547786828501615035565b60c083015250949350505050565b8051610d1281614349565b5f60608284031280156154a1575f80fd5b50604051606081016001600160401b03811182821017156154c4576154c46144a9565b60405282516154d281614349565b81526154e060208401615084565b60208201526040928301519281019290925250919050565b5f60208284031215615508575f80fd5b81516136ae8161435e565b6001600160a01b03841681526001600160601b0383166020820152610100810160408201835f5b600681101561555957815183526020928301929091019060010161553a565b505050949350505050565b5f82601f830112615573575f80fd5b61557d60a0614571565b8060a084018581111561558e575f80fd5b845b818110156146905780516155a38161446f565b845260209384019301615590565b5f805f60e084860312156155c3575f80fd5b835192506155d48560208601615564565b915060c0840151614ecc8161446f565b5f82601f8301126155f3575f80fd5b81516001600160401b0381111561560c5761560c6144a9565b8060051b61561c60208201614571565b91825260208185018101929081019086841115615637575f80fd5b6020860192505b838310156156625782516156518161446f565b82526020928301929091019061563e565b9695505050505050565b5f6020828403121561567c575f80fd5b81516001600160401b03811115615691575f80fd5b820161010081850312156156a3575f80fd5b6156ab61452b565b6156b482615004565b81526156c260208301615004565b60208201526156d360408301615004565b60408201526156e46060830161509b565b60608201526156f56080830161509b565b608082015261570660a08301614f69565b60a082015261571760c08301614f69565b60c082015260e08201516001600160401b03811115615734575f80fd5b615740868285016155e4565b60e083015250949350505050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215615772575f80fd5b81516001600160401b03811115615787575f80fd5b61389f848285016150a6565b5f8060c083850312156157a4575f80fd5b82516157af8161446f565b91506157be8460208501615564565b90509250929050565b5f80858511156157d5575f80fd5b838611156157e1575f80fd5b5050820193919092039150565b80356001600160e01b03198116906004841015614c20576001600160e01b031960049490940360031b84901b1690921692915050565b6001600160a01b03841681526040602082018190528101829052818360608301375f818301606090810191909152601f909201601f1916010192915050565b5f805f60608486031215615875575f80fd5b835161588081614844565b602085015190935061589181614844565b6040850151909250614ecc8161435e565b8051610d1281614e80565b5f602082840312156158bd575f80fd5b81516001600160401b038111156158d2575f80fd5b820161020081850312156158e4575f80fd5b6158ec61454e565b6158f582614f69565b815261590360208301614f69565b602082015261591460408301615485565b604082015261592560608301614f69565b606082015261593660808301614f69565b608082015261594760a08301615485565b60a082015261595860c083016158a2565b60c082015261596960e083016158a2565b60e082015261597b6101008301614f69565b61010082015261598e6101208301614f69565b6101208201526159a1610140830161502a565b6101408201526159b4610160830161502a565b6101608201526159c7610180830161502a565b6101808201526159da6101a0830161502a565b6101a08201526101c08201516001600160401b038111156159f9575f80fd5b615a0586828501615035565b6101c0830152506101e08201516001600160401b03811115615a25575f80fd5b615a3186828501615035565b6101e083015250949350505050565b604081525f615a5260408301856143a3565b905060ff831660208301529392505050565b5f60208284031215615a74575f80fd5b81516136ae8161462f565b8181038181111561414d57634e487b7160e01b5f52601160045260245ffd5b5f60208284031215615aae575f80fd5b81516001600160401b03811115615ac3575f80fd5b61389f84828501615035565b6001600160601b0384168152606060208201525f615af060608301856143a3565b90506001600160601b0383166040830152949350505050565b5f60208284031215615b19575f80fd5b81516001600160401b03811115615b2e575f80fd5b820160408185031215615b3f575f80fd5b604080519081016001600160401b0381118282101715615b6157615b616144a9565b60405281516001600160401b03811115615b79575f80fd5b615b8586828501615035565b82525060208201519150615b98826145a1565b60208101919091529392505050565b5f82518060208501845e5f920191825250919050565b5f8060408385031215615bce575f80fd5b8251615bd981614844565b602084015190925063ffffffff81168114614398575f80fd5b5f60208284031215615c02575f80fd5b81516136ae81614349565b6001600160601b038316815260c081016136ae6020830184614c6d565b6001600160601b0385168152608060208201525f615c4b60808301866143a3565b64ffffffffff851660408401528281036060840152615c6a81856143a3565b979650505050505050565b5f60208284031215615c85575f80fd5b81516136ae81614a5b565b6001600160401b0360c01b83168152604060208201525f61389f60408301846143a3565b6001600160601b03841681526001600160601b0383166020820152606060408201525f6139a160608301846143a3565b5f60208284031215615cf4575f80fd5b81516136ae81614e80565b6001600160601b038516815261ffff841660208201526001600160601b0383166040820152608060608201525f61566260808301846143a3565b5f8060408385031215615d4a575f80fd5b8251615d558161446f565b60208401519092506143988161446f565b6001600160a01b03891681526001600160c01b031988811660208301526001600160601b038881166040840152878116606084015264ffffffffff87166080840152851660a0830152831660c082015261010060e082018190525f90615dce908301846143a3565b9a9950505050505050505050565b60018060a01b03881681526001600160601b038716602082015285604082015264ffffffffff8516606082015260e060808201525f615e1e60e08301866143a3565b64ffffffffff851660a084015282810360c0840152615dce81856143a3565b5f805f60608486031215615e4f575f80fd5b8351615e5a81614349565b6020850151909350615e6b81614844565b60408501519092506001600160401b03811115615e86575f80fd5b615e92868287016150a6565b9150509250925092565b828152604060208201525f61389f60408301846143a356fe07ebcf49758b6ed3af50fa146bec0abe157c0218fe65dc0874c286e9d5da4f00ffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f00f3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a000bb7aafdb8e380f81267337bc5b5dfdf76e6d3a380ecadb51ec665246d9d6800a2646970667358221220b29fccb899298434e2a76e759e25e71e130d914680df214389448ab53f86026e64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000048b24f2908bba1fd1a7d68395980e4c9eabbb4d300000000000000000000000000000000000000000000000000000000012ed0b80000000000000000000000000000000000000000000000000000000000000080000000000000000000000000893a65351f3cc68d6683af9fe0a1df2a2e1ea7300000000000000000000000000000000000000000000000000000000000000012464450726f647563745f37353263386432310000000000000000000000000000
-----Decoded View---------------
Arg [0] : registry (address): 0x48b24f2908Bba1fD1a7d68395980e4C9eAbBB4D3
Arg [1] : instanceNftId (uint96): 19845304
Arg [2] : componentName (string): FDProduct_752c8d21
Arg [3] : authorization (address): 0x893A65351f3cC68D6683af9FE0A1dF2A2e1EA730
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 00000000000000000000000048b24f2908bba1fd1a7d68395980e4c9eabbb4d3
Arg [1] : 00000000000000000000000000000000000000000000000000000000012ed0b8
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 000000000000000000000000893a65351f3cc68d6683af9fe0a1df2a2e1ea730
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [5] : 464450726f647563745f37353263386432310000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.