Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
3059710 | 11 days ago | Contract Creation | 0 ETH |
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 Name:
FairSideNetwork
Compiler Version
v0.8.22-1.0.1
ZkSolc Version
v1.5.11
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.22; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../dependencies/FairSideFormula2.sol"; import "../dependencies/ABDKMathQuadUInt256.sol"; import "../interfaces/network/IFairSideClaims.sol"; import "../interfaces/network/IFairSideNetwork.sol"; import "../interfaces/token/IFair.sol"; import "../admin/IFairsideAdmin.sol"; interface IFairSideNetworkErrors { /** * @dev FairSideNetwork-related custom errors */ error FSNetwork_ActiveMembershipRequired(); error FSNetwork_ChainlinkPriceStale(); error FSNetwork_ChainlinkMalfunction(); error FSNetwork_ExceedsCSBLimitPerAccount(); error FSNetwork_InvalidCostShareBenefitSpecified(); error FSNetwork_MembershipTopupDisabled(); error FSNetwork_ExceedsCostShareBenefitLimitPerAccount(); error FSNetwork_MembershipNotExpired(); error FSNetwork_MembershipExpired(); error FSNetwork_PremiumFeeSentIsLessThanRequired(); error FSNetwork_NotEnoughFair(); error FSNetwork_InsufficientApproval(); error FSNetwork_InvalidCoverIdForAccount(); error FSNetwork_IncorrectValueSpecified(); error FSNetwork_CannotChange(); error FSNetwork_IncorrectSlippageSpecified(); error FSNetwork_InsufficientPrivileges(); error FSNetwork_CurveIsClosedUseETH(); error FSNetwork_OnlyPremiumPoolCanCall(); error FSNetwork_OnlyFairSideClaimsCanCall(); error FSNetwork_ExceedsMaxCostShareBenefitLimit(); error FSNetwork_IncorrectLossRatioSpecified(); error FSNetwork_OnlyMembershipPurchaseProxyCanCall(); error FSNetwork_FairPurchaseDisabled(); error FSNetwork_InsufficientPrivilegesOnlyGuardian(); error FSNetwork_InsufficientPrivilegesOnlyAdmin(); error FSNetwork_MembershipBlocked(); error FSNetwork_OnlyFairSideBountyPoolCanCall(); error FSNetwork_MembershipTypeDisabled(); } /** * @dev Implementation of {FairSideNetwork}. * * The FairSideNetwork contract allows purchasing of network membership using * ETH/Fair. The Fair tokens collected in fees are distribute among the contract, * staking tribute, governance tribute and funding pool in specific percentages. * * Allows opening, updating and processing of Cross Share Requests. * * Attributes: * - Supports the full workflow of a cost share request * - Handles Fair membership * - Handles governance rewards * - Retrieves ETH price via Chainlink * - Calculates Fair price via Uniswap using Time-Weighted Price Averages (TWAP) */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract FairSideNetwork is IFairSideNetwork, IFairSideNetworkErrors, Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable { /* ========== LIBRARIES ========== */ using AddressUpgradeable for address payable; using ABDKMathQuadUInt256 for uint256; uint256 private constant MAXIMUM_GRACE_PERIOD = 100 * 365 days; // 100 years struct MembershipType { uint256 duration; uint256 gracePeriod; uint256 topupDisabledPeriod; uint256 minimumPurchaseAmount; uint256 maximumBenefitPerUser; uint256 cost; bool active; } /* ========== STATE VARIABLES ========== */ //mapping of id -> Memberships mapping(uint256 => Membership) private membership; //mapping of account (address) -> memberships mapping(address => uint256[]) internal userMembership; //mapping of addresses covered by an address / account mapping(address => address[]) internal userCoveredAddress; mapping(uint256 => MembershipType) public membershipTypes; uint256 public numMembershipTypes; // Tracking the number of cover ids uint256 public membershipCount; // Cost share benefits of the entire personal wallet protection cover in ETH uint256 public totalPWPCSB; // total cover cost received from users uint256 public totalCoverCost; //network gearing factor used for membership calculation uint256 public networkGearingFactor; // Risk based capital uint256 public riskBasedCapital; // estimated loss ratio uint256 public lossRatio; // Supported tokens for membership purchase, top up enum TokenType { ETH, Fair } // Fair Token contract Address IFair private fair; //Fair Network IFairSideClaims public fairSideClaims; // Funding Pool Address address public override FUNDING_POOL; // Premiums Pool Address address public PREMIUMS_POOL; //patners pool address address address public PARTNERS_ADDRESS; // Premium Reward multisign Address address public override PREMIUM_REWARD_ADDRESS; // membership purchase proxy address public membershipPurchaseProxy; // Bountry pool contract address address public FairSIDE_BOUNTY_POOL; // Timelock Address, owned by Governance address public TIMELOCK; // 20% as staking rewards uint256 public STAKING_REWARDS; // 15% patner pool rewards uint256 public PARTNERS_POOL_ALLOCATION; //7.5% as funding pool uint256 public FUNDING_POOL_ALLOCATION; bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); // enable or disable Fair purchase bool public fairPurchaseEnabled; // Admin contract IFairsideAdmin private fairsideAdmin; /* ========== EVENTS ========== */ // An event emitted when a membership is purchased (either new or an extension) event NewMembership( address indexed member, uint256 coverId, uint256 costshareBenefit, address indexed coverAddress, TokenType tokenType, uint256 membershipTypeId ); // An event emitted when a membership is topped up event TopUpCover( address indexed member, uint256 coverId, uint256 costshareBenefit, TokenType tokenType ); // An event for setting Fair Premium Reward contract address event SetFairPremiumReward(address indexed premiumRewardContract); // An event for setting ETH Premium Reward contract address event SetETHPremiumReward(address indexed premiumRewardContract); // An event for setting Network gearing factor event SetNetworkGearingFactor(uint256 networkGearingFactor); // An event for setting Risk based capital event SetRiskBasedCapital(uint256 riskBasedCapital); // An event for setting Loss ratio event SetLossRatio(uint256 lossRatio); event SetFeeDistributionPercenages( uint256 fundingPoolAllocation, uint256 partnersPoolAllocation, uint256 stakingRewards, uint256 lossRatio ); // An event for sending Staking rewards on Fair event PremiumFairDistributed( uint256 fundingPremium, uint256 parntersPremium, uint256 stakingRewards, uint256 curveReserve ); // An event for sending Staking rewards on ETH event PremiumEthDistributed( uint256 fundingPremium, uint256 parntersPremium, uint256 stakingRewards, uint256 curveReserve ); // An event for setting the token gearing factor event TokenGearingFactorSet(uint256 tokenGearingFactor); // An event for setting the Fair purchase enabled event SetFairPurchaseEnabled(bool fairPurchaseEnabled); constructor() { _disableInitializers(); } /** * @dev Initialises the contract's state setting fair, FUNDING_POOL * and TIMELOCK addresses. */ function initialize( IFair _fair, address fundingPool, address premiumsPool, IFairsideAdmin _fairsideAdmin, address timelock, address patnersPool, address premiumReward ) public initializer { __UUPSUpgradeable_init(); __ReentrancyGuard_init(); fair = _fair; FUNDING_POOL = fundingPool; PREMIUMS_POOL = premiumsPool; fairsideAdmin = _fairsideAdmin; TIMELOCK = timelock; PARTNERS_ADDRESS = patnersPool; PREMIUM_REWARD_ADDRESS = premiumReward; membershipPurchaseProxy = msg.sender; fairPurchaseEnabled = false; // 20% staking rewards STAKING_REWARDS = 0.20 ether; // 15% patner pool rewards PARTNERS_POOL_ALLOCATION = 0.15 ether; // 7.5% as funding pool FUNDING_POOL_ALLOCATION = 0.075 ether; riskBasedCapital = 100 ether; lossRatio = 0.575 ether; //57.5% networkGearingFactor = 50; _addMembershipType( 365 days, 60 days, 182 days, 0.25 ether, 10 ether, 0.0195 ether ); } function addMembershipType( uint256 duration, uint256 gracePeriod, uint256 topupDisabledPeriod, uint256 minimumPurchaseAmount, uint256 maximumBenefitPerUser, uint256 cost ) external onlyAdmin { _addMembershipType( duration, gracePeriod, topupDisabledPeriod, minimumPurchaseAmount, maximumBenefitPerUser, cost ); } function _addMembershipType( uint256 duration, uint256 gracePeriod, uint256 topupDisabledPeriod, uint256 minimumPurchaseAmount, uint256 maximumBenefitPerUser, uint256 cost ) private { // duration should be divisible by 1 day if ( duration == 0 || (duration % 1 days != 0) || cost == 0 || topupDisabledPeriod > duration || gracePeriod > MAXIMUM_GRACE_PERIOD || maximumBenefitPerUser == 0 || maximumBenefitPerUser < minimumPurchaseAmount ) { revert FSNetwork_IncorrectValueSpecified(); } membershipTypes[numMembershipTypes] = MembershipType({ duration: duration, gracePeriod: gracePeriod, topupDisabledPeriod: topupDisabledPeriod, minimumPurchaseAmount: minimumPurchaseAmount, maximumBenefitPerUser: maximumBenefitPerUser, cost: cost, active: true }); unchecked { numMembershipTypes += 1; } } function disableMembershipType(uint256 index) external onlyAdmin { membershipTypes[index].active = false; } /** * @dev Setting the fairside claims contract */ function setFairSideClaims( IFairSideClaims _fairSideClaims ) external onlyAdmin { fairSideClaims = _fairSideClaims; } /* * @dev Setting the fairside bounty pool contract */ function setFairSideBountyPool( address _fairSideBountyPool ) external onlyAdmin { FairSIDE_BOUNTY_POOL = _fairSideBountyPool; } /** * @dev returns the list of cover ids purchased by an address */ function getAccountMembership( address account ) external view returns (uint256[] memory) { return userMembership[account]; } /** * @dev returns the list of covered addresses covered by an address */ function getAccountCoveredWallets( address account ) external view returns (address[] memory) { return userCoveredAddress[account]; } /** * @notice returns Membership state containing * (availableCostShareBenefits, duration, creation, owner account, covered wallet) */ function getMembership( uint256 coverId ) external view override returns (Membership memory) { return membership[coverId]; } /** * @dev Token price evaluated as spot price directly on curve */ function getFairPrice() public view override returns (uint256) { uint256 fShare = getNetworkFShare(); uint256 capitalPool = getCapitalPool(); return FairSideFormula2.f(capitalPool, fShare); } /** * @dev : checks if membership still valid using grace period */ function hasPassedGracePeriod( uint256 coverId ) external view override returns (bool) { Membership memory _membership = membership[coverId]; if (_membership.availableCostShareBenefits <= 0) { revert FSNetwork_ActiveMembershipRequired(); } return block.timestamp > _membership.expirationDate + membershipTypes[_membership.membershipTypeId].gracePeriod; } /** * @notice : returns the maximum CSB based on RSB and network gearing factor */ function getMaxTotalCostShareBenefits() public view returns (uint256) { return riskBasedCapital * networkGearingFactor; } /** * @notice get amount in capital pool (ETH) * @dev : Capital Pool = Total Funds held in ETH – Open Cost Share Requests * Open Cost Share Request = Cost share request awaiting assessor consensus */ function getCapitalPool() public view override returns (uint256) { return address(fair).balance - getTotalOpenRequests(); } /** * @notice : returns cover cost of a cover */ function getCoverCost( uint256 membershipTypeId ) external view override returns (uint256 coverCost) { return membershipTypes[membershipTypeId].cost; } /** * @notice Allows purchasing of membership of Fair Network with ETH and Fair * * @dev It accepts ETH to allocate the available cross share benefits * for a member and also determines membership purchase cost. * * The membership is purchased using ETH, 57.5% of which remains in the curve, * 20% is allocated with staking rewards, 7.5% is allocated for the {PREMIUMS_POOL} * and 7.5% is sent to {FUNDING_POOL}. * */ function purchaseMembership( uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external payable validateOpenCurve(TokenType.ETH) { _purchaseMembership( msg.sender, costShareBenefit, coverAddress, membershipType, TokenType.ETH ); } /* * @notice : Allows purchasing of membership of Fair Network with ETH from a membershipPurchaseProxy */ function purchaseMembershipFromProxy( address primaryAddress, uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external payable validateOpenCurve(TokenType.ETH) onlyMembershipPurchaseProxy { _purchaseMembership( primaryAddress, costShareBenefit, coverAddress, membershipType, TokenType.ETH ); } /** * @notice Allows purchasing of membership with Fair */ function purchaseMembershipWithFair( uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external onlyFairPurchaseEnabled validateOpenCurve(TokenType.Fair) { _purchaseMembership( msg.sender, costShareBenefit, coverAddress, membershipType, TokenType.Fair ); } /* * @notice : Allows purchasing of membership of Fair Network with Fair from a membershipPurchaseProxy */ function purchaseMembershipWithFairFromProxy( address primaryAddress, uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external onlyFairPurchaseEnabled validateOpenCurve(TokenType.Fair) onlyMembershipPurchaseProxy { _purchaseMembership( primaryAddress, costShareBenefit, coverAddress, membershipType, TokenType.Fair ); } /** * @notice : Top up a current exisiting purchased cover with ETH * @dev : the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function topupMembership( uint256 coverId, uint256 costshareBenefit ) external payable validateOpenCurve(TokenType.ETH) { _topupMembership(coverId, costshareBenefit, TokenType.ETH); } /** * @notice : Top up a current exisiting purchased cover with Fair * @dev : the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function topupMembershipWithFair( uint256 coverId, uint256 costshareBenefit ) external onlyFairPurchaseEnabled validateOpenCurve(TokenType.Fair) { _topupMembership(coverId, costshareBenefit, TokenType.Fair); } /** * @dev : handles premium membership purchase, for PWP applies the PWP gearing factor {PWPGearing} and PWPfshareRation for PWP cover purchase * and uses the default fshare and fshareRatio for other covers * the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function _purchaseMembership( address primaryAddress, uint256 costShareBenefit, address coverAddress, uint256 membershipTypeId, TokenType tokenType ) private nonReentrant { validateCapitalPool(costShareBenefit, membershipTypeId); MembershipType memory membershipType = membershipTypes[ membershipTypeId ]; if (!membershipType.active) { revert FSNetwork_MembershipTypeDisabled(); } if (costShareBenefit > _getMaximumBenefitPerUser(membershipTypeId)) { revert FSNetwork_ExceedsCSBLimitPerAccount(); } //calculate membership cost uint256 coverCostETH = calculateCoverCost( costShareBenefit, 0, membershipType.duration, membershipType.cost ); distributePremium(coverCostETH, tokenType); unchecked { membershipCount += 1; } uint256 coverId = membershipCount; Membership storage membershipId = membership[coverId]; //update storages totalPWPCSB += costShareBenefit; totalCoverCost += coverCostETH; membershipId.availableCostShareBenefits = costShareBenefit; membershipId.creation = uint80(block.timestamp); membershipId.expirationDate = uint80( block.timestamp + membershipType.duration ); membershipId.owner = primaryAddress; membershipId.wallet = coverAddress; membershipId.membershipTypeId = membershipTypeId; membershipId.coverCost += coverCostETH; userMembership[primaryAddress].push(coverId); userCoveredAddress[primaryAddress].push(coverAddress); emit NewMembership( primaryAddress, coverId, costShareBenefit, coverAddress, tokenType, membershipTypeId ); } /** * @dev : validate if the cost share benefit meets the required threshold * and the capital pool has enough funds to cover the membership */ function validateCapitalPool( uint256 costShareBenefit, uint256 membershipTypeId ) private view { //mimimun CSB if ( costShareBenefit < membershipTypes[membershipTypeId].minimumPurchaseAmount ) { revert FSNetwork_InvalidCostShareBenefitSpecified(); } if (totalPWPCSB + costShareBenefit > getMaxTotalCostShareBenefits()) { revert FSNetwork_ExceedsMaxCostShareBenefitLimit(); } } /** * @dev : handles premium membership purchase, for PWP applies the PWP gearing factor {PWPGearing} and PWPfshareRation for PWP cover purchase * and uses the default fshare and fshareRatio for other covers * the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function _topupMembership( uint256 coverId, uint256 costShareBenefit, TokenType tokenType ) private onlyNotBlocked(coverId) nonReentrant { Membership storage membershipId = membership[coverId]; validateCapitalPool(costShareBenefit, membershipId.membershipTypeId); MembershipType memory membershipType = membershipTypes[ membershipId.membershipTypeId ]; uint256 membershipExpirationDate = membershipId.expirationDate; if ( block.timestamp >= membershipExpirationDate - membershipType.topupDisabledPeriod ) { revert FSNetwork_MembershipTopupDisabled(); } uint256 userMembershipCSB = membershipId.availableCostShareBenefits + costShareBenefit; if ( userMembershipCSB > _getMaximumBenefitPerUser(membershipId.membershipTypeId) ) { revert FSNetwork_ExceedsCostShareBenefitLimitPerAccount(); } uint256 coverCostETH = calculateCoverCost( costShareBenefit, membershipExpirationDate, membershipType.duration, membershipType.cost ); distributePremium(coverCostETH, tokenType); totalPWPCSB += costShareBenefit; totalCoverCost += coverCostETH; membershipId.availableCostShareBenefits = userMembershipCSB; membershipId.coverCost += coverCostETH; emit TopUpCover( membershipId.wallet, coverId, costShareBenefit, tokenType ); } /** * @dev : checks if the cover cost is sufficient * and distributes premiums to pools based on the token type provided */ function distributePremium( uint256 membershipFeeETH, TokenType tokenType ) internal { if (tokenType == TokenType.ETH) { if (msg.value < membershipFeeETH) { revert FSNetwork_PremiumFeeSentIsLessThanRequired(); } premiumDistributionETH(membershipFeeETH); } else { //convert to Fair uint256 membershipFeeFair = membershipFeeETH.div(getFairPrice()); IERC20 _fairToken = IERC20(address(fair)); if (_fairToken.balanceOf(msg.sender) < membershipFeeFair) { revert FSNetwork_NotEnoughFair(); } //receive fair from user _fairToken.transferFrom( msg.sender, address(this), membershipFeeFair ); //distribute premium premiumDistributionFair(membershipFeeFair); } } /* * @dev : remove expired membership's csb from the network */ function removeExpiredMembershipCSB( uint256 coverId ) external override onlyFairSideBountyPool { Membership storage membershipId = membership[coverId]; if (membershipId.availableCostShareBenefits <= 0) { revert FSNetwork_ActiveMembershipRequired(); } MembershipType memory membershipType = membershipTypes[ membershipId.membershipTypeId ]; uint256 gracePeriod = membershipId.expirationDate + membershipType.gracePeriod; if (block.timestamp < gracePeriod) { revert FSNetwork_MembershipNotExpired(); } totalPWPCSB -= membershipId.availableCostShareBenefits; totalCoverCost -= membershipId.coverCost; membershipId.availableCostShareBenefits = 0; membershipId.coverCost = 0; } /** * @dev : estimates the cost of a cover with given amount */ function estimateCost( uint256 costShareBenefit, uint256 expirationDate, uint256 membershipTypeId ) external view returns (uint256) { MembershipType memory membershipType = membershipTypes[ membershipTypeId ]; return calculateCoverCost( costShareBenefit, expirationDate, membershipType.duration, membershipType.cost ); } /** * @dev changes the premiums pool address to a new address */ function setPremiumsPool(address _newPremiumsPool) external onlyAdmin { PREMIUMS_POOL = _newPremiumsPool; } /* * @dev changes the funding pool address to a new address */ function setFundingPool( address payable _newFundingPool ) external onlyAdmin { FUNDING_POOL = _newFundingPool; } /** * @dev changes the partners pool address to a new address */ function setPartnersPool(address _newPartnersPool) external onlyAdmin { PARTNERS_ADDRESS = _newPartnersPool; } /** * @dev changes the premium reward address to a new address */ function setPremiumRewardAddress( address _newPremiumRewardAddress ) external onlyAdmin { PREMIUM_REWARD_ADDRESS = _newPremiumRewardAddress; } /** * @dev changes the membership purchase proxy address to a new address */ function setMembershipPurchaseProxy( address _newMembershipPurchaseProxy ) external onlyAdmin { membershipPurchaseProxy = _newMembershipPurchaseProxy; } /** * @notice This method handles the distribution of Fair to different pools * @dev it's called after a membership is purchased, topped up by Fair * Once the Fair is recieved smart staking calculation is done * DISTRIBUTION IS HANDLED AS * Staking Rewards 20% sent to rewardsContract * Gov. 7.5% = sent to funding pool * Partners Pool 15% sent to Premiums Pool * 57.5% burnt */ function premiumDistributionFair(uint256 fairToDistribute) private { if (IERC20(address(fair)).balanceOf(address(this)) < fairToDistribute) { revert FSNetwork_NotEnoughFair(); } //Calculate funding pool rewards uint256 fundingPremium = fairToDistribute.mul(FUNDING_POOL_ALLOCATION); uint256 parntersPremium = fairToDistribute.mul( PARTNERS_POOL_ALLOCATION ); uint256 stakingRewards = fairToDistribute.mul(STAKING_REWARDS); uint256 curveReserve = fairToDistribute.mul(lossRatio); ERC20Burnable _fairToken = ERC20Burnable(address(fair)); // 7,5% sent to governance _fairToken.transfer(FUNDING_POOL, fundingPremium); //patners pool 15% _fairToken.transfer(PARTNERS_ADDRESS, parntersPremium); // 20% staking rewards _fairToken.transfer(PREMIUM_REWARD_ADDRESS, stakingRewards); // burn remaining 57.5% _fairToken.burn(curveReserve); //register premium distribution in Fair emit PremiumFairDistributed( fundingPremium, parntersPremium, stakingRewards, curveReserve ); } /** * @notice This method handles the distribution of ETH to different pools * @dev it's called after a membership is purchased, topped up by ETH * Once the ETH is recieved smart staking calculation is done * DISTRIBUTION IS HANDLED AS * Staking Rewards 20% sent to rewardsContract * Gov. 7.5% = sent to funding pool * Partners Pool 15% sent to Premiums Pool * 57.5% sent to curve with no emission of FS */ function premiumDistributionETH(uint256 ethToDistribute) private { //Calculate funding pool rewards uint256 fundingPremium = ethToDistribute.mul(FUNDING_POOL_ALLOCATION); uint256 parntersPremium = ethToDistribute.mul(PARTNERS_POOL_ALLOCATION); uint256 stakingRewards = ethToDistribute.mul(STAKING_REWARDS); uint256 curveReserve = ethToDistribute.mul(lossRatio); // 7,5% sent to governance payable(FUNDING_POOL).sendValue(fundingPremium); //patners pool 15% payable(PARTNERS_ADDRESS).sendValue(parntersPremium); //add staking reward in ETH to be distributed payable(PREMIUM_REWARD_ADDRESS).sendValue(stakingRewards); //send remaining 57.5% to the curve fair.bondNoEmission{value: curveReserve}(); //register premium distribution in ETH emit PremiumEthDistributed( fundingPremium, parntersPremium, stakingRewards, curveReserve ); // send back excess ETH if (msg.value > ethToDistribute) { payable(msg.sender).sendValue(msg.value - ethToDistribute); } } /* ========== RESTRICTED FUNCTIONS ========== */ /** * @notice : increases or decreases the CSB when a claims requested is created. * @dev Can only be called by the fairside claims contract */ function increaseOrDecreaseCSB( uint256 amount, address account, uint256 coverId, bool increase ) external override onlyFairSideClaims { Membership storage membershipId = membership[coverId]; if (membershipId.owner != account) { revert FSNetwork_InvalidCoverIdForAccount(); } if (increase) { membershipId.availableCostShareBenefits += amount; } else { membershipId.availableCostShareBenefits -= amount; } } /** * @notice : block cover when a claim is created, unblock when claim is resolved * @dev Can only be called by the fairside claims contract */ function blockMembership( uint256 coverId, bool blocked ) external override onlyFairSideClaims { Membership storage membershipId = membership[coverId]; membershipId.blocked = blocked; } /** * @notice This method flushes out assets mistakenly sent to the contract * @dev Can only be called by the premium pool multisig */ function flushAsset( address tokenContractAddress, address payable destination ) external payable onlyPremiumPool { if (tokenContractAddress == address(0)) { destination.sendValue(address(this).balance); } else { IERC20 tokenContract = ERC20(tokenContractAddress); tokenContract.transfer( destination, tokenContract.balanceOf(address(this)) ); } } /** * @dev Sets the gearing factor used for signing new memberships * * Requirements: * - only callable by governance or timelock contracts. */ function setNetworkGearingFactor( uint256 _gearingFactor ) external onlyTimelock { if (_gearingFactor == 0) { revert FSNetwork_IncorrectValueSpecified(); } networkGearingFactor = _gearingFactor; emit SetNetworkGearingFactor(_gearingFactor); } /** * @dev Sets the risk based capital used for calculating the network FSHARE * * Requirements: * - only callable by governance or timelock contracts. */ function setRiskBasedCapital( uint256 _riskBasedCapital ) external onlyTimelock { riskBasedCapital = _riskBasedCapital; emit SetRiskBasedCapital(_riskBasedCapital); } /** * @dev Sets the distribution percentages * * Requirements: * - only callable by governance or timelock contracts. */ function setFeeDistributionPercentages( uint256 _fundingPoolAllocation, uint256 _partnersPoolAllocation, uint256 _stakingRewards, uint256 _lossRatio ) external onlyTimelock { if ( _fundingPoolAllocation + _partnersPoolAllocation + _stakingRewards + _lossRatio != 1 ether ) { revert FSNetwork_IncorrectValueSpecified(); } FUNDING_POOL_ALLOCATION = _fundingPoolAllocation; PARTNERS_POOL_ALLOCATION = _partnersPoolAllocation; STAKING_REWARDS = _stakingRewards; lossRatio = _lossRatio; emit SetFeeDistributionPercenages( _fundingPoolAllocation, _partnersPoolAllocation, _stakingRewards, _lossRatio ); } /** * @dev Set flag for enabling or disabling Fair purchase * * Requirements: * - only callable by governance or timelock contracts. */ function setEnableFairPurchase( bool _fairPurchaseEnabled ) external onlyTimelock { fairPurchaseEnabled = _fairPurchaseEnabled; emit SetFairPurchaseEnabled(_fairPurchaseEnabled); } /* ========== INTERNAL FUNCTIONS ========== */ /* * @dev : decrement total cost share benefits after a claim is paid out */ function decrementTotalPWPCSB( uint256 costShareBenefit ) external override onlyFairSideClaims { totalPWPCSB -= costShareBenefit; } /** * @dev Calculates the prorated cover cost of a given cover * @return cover cost (uint) */ function calculateCoverCost( uint256 costShareBenefit, uint256 coverPeriod, uint256 duration, uint256 coverCost ) internal view returns (uint256) { uint256 fee = costShareBenefit.mul(coverCost); if (block.timestamp > coverPeriod) { return fee; } else { uint256 dailycost = coverCost / (duration / 1 days); uint256 coverDuration = coverPeriod - block.timestamp; uint256 daysRemaining = coverDuration / 1 days; // round up to the nearest day if (coverDuration % 1 days != 0) { daysRemaining += 1; } uint256 rate = daysRemaining * dailycost; uint256 proratedCostETH = costShareBenefit.mul(rate); return proratedCostETH; } } function _authorizeUpgrade( address newImplementation ) internal override onlyGuardian {} /** * @notice Return Open cost share requests in ETH */ function getTotalOpenRequests() public view returns (uint256) { return fairSideClaims.totalOpenRequests(); } function isOpenCurve() public view returns (bool) { return fair.currentPhase() == IFair.Phase.Final; } /** * @notice : calculates FSHARE risk based capital and loss ratio over * the total cost share benefits */ function getNetworkFShare() public view override returns (uint256) { return riskBasedCapital + lossRatio.mul(totalCoverCost); } /** * @dev Returns maximum cross share benefit allowed per user. */ function _getMaximumBenefitPerUser( uint256 membershipTypeId ) internal view returns (uint256) { return membershipTypes[membershipTypeId].maximumBenefitPerUser; } /** * @notice shows the version of the contract being used * @dev the value represents the current version of the contract should be updated and overriden with new implementations * @return version -the current version of the contract */ function version() external pure virtual returns (string memory) { return "1.0.0"; } /* ========== MODIFIERS ========== */ modifier onlyTimelock() { if (msg.sender != TIMELOCK) { revert FSNetwork_InsufficientPrivileges(); } _; } modifier validateOpenCurve(TokenType tokenType) { if (tokenType != TokenType.ETH) { if (!isOpenCurve()) { revert FSNetwork_CurveIsClosedUseETH(); } } _; } modifier onlyPremiumPool() { if (msg.sender != PREMIUMS_POOL) { revert FSNetwork_OnlyPremiumPoolCanCall(); } _; } modifier onlyFairSideClaims() { if (msg.sender != address(fairSideClaims)) { revert FSNetwork_OnlyFairSideClaimsCanCall(); } _; } modifier onlyNetworkOrClaims() { if ( msg.sender != address(fairSideClaims) && msg.sender != address(this) ) revert FSNetwork_OnlyFairSideClaimsCanCall(); _; } modifier onlyFairSideBountyPool() { if (msg.sender != FairSIDE_BOUNTY_POOL) { revert FSNetwork_OnlyFairSideBountyPoolCanCall(); } _; } modifier onlyMembershipPurchaseProxy() { if (msg.sender != membershipPurchaseProxy) { revert FSNetwork_OnlyMembershipPurchaseProxyCanCall(); } _; } modifier onlyFairPurchaseEnabled() { if (!fairPurchaseEnabled) { revert FSNetwork_FairPurchaseDisabled(); } _; } modifier onlyGuardian() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_NETWORK_GUARDIAN_ROLE, msg.sender ) ) { revert FSNetwork_InsufficientPrivilegesOnlyGuardian(); } _; } modifier onlyAdmin() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_ADMIN_ROLE, msg.sender ) ) { revert FSNetwork_InsufficientPrivilegesOnlyAdmin(); } _; } modifier onlyNotBlocked(uint256 coverId) { if (membership[coverId].blocked) { revert FSNetwork_MembershipBlocked(); } _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.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. * * By default, the owner account will be the one that deploys the contract. 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 OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @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 { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @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 { require(newOwner != address(0), "Ownable: new owner is the zero address"); _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); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967Upgradeable { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267Upgradeable { /** * @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 v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/IERC1967Upgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import {Initializable} from "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ */ abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { AddressUpgradeable.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require( !_initializing && _initialized < version, "Initializable: contract is already initialized" ); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @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 { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeTo(address newImplementation) public virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.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}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * 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. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => 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. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override 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 override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override 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 `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` 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 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); 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 `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `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. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` 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. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-ERC20Permit.sol) pragma solidity ^0.8.0; // EIP-2612 is Final as of 2022-11-01. This file is deprecated. import "./ERC20PermitUpgradeable.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../../../utils/ContextUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable { function __ERC20Burnable_init() internal onlyInitializing { } function __ERC20Burnable_init_unchained() internal onlyInitializing { } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.0; import "./IERC20PermitUpgradeable.sol"; import "../ERC20Upgradeable.sol"; import "../../../utils/cryptography/ECDSAUpgradeable.sol"; import "../../../utils/cryptography/EIP712Upgradeable.sol"; import "../../../utils/CountersUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.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. * * _Available since v3.4._ * * @custom:storage-size 51 */ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; mapping(address => CountersUpgradeable.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private constant _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. * However, to ensure consistency with the upgradeable transpiler, we will continue * to reserve a slot. * @custom:oz-renamed-from _PERMIT_TYPEHASH */ // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; /** * @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. */ function __ERC20Permit_init(string memory name) internal onlyInitializing { __EIP712_init_unchained(name, "1"); } function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {} /** * @inheritdoc IERC20PermitUpgradeable */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSAUpgradeable.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @inheritdoc IERC20PermitUpgradeable */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @inheritdoc IERC20PermitUpgradeable */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { CountersUpgradeable.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @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 v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @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 IERC20PermitUpgradeable { /** * @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 v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; 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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @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 ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode 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 {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] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { 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); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode 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 {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); 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] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); 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. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // 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); } // 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); } return (signer, RecoverError.NoError); } /** * @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) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSAUpgradeable.sol"; import "../../interfaces/IERC5267Upgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic 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 their contracts 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. * * _Available since v3.4._ * * @custom:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:oz-renamed-from _HASHED_NAME bytes32 private _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 private _hashedVersion; string private _name; string private _version; /** * @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]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { _name = name; _version = version; // Reset prior values in storage if upgrading _hashedName = 0; _hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), 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 ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal virtual view returns (string memory) { return _name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal virtual view returns (string memory) { return _version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = _hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = _hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[48] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @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 IERC165Upgradeable { /** * @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 v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @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 up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (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; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) 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. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 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. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); 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 (rounding == Rounding.Up && 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 down. * * 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @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 v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @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(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlotUpgradeable { 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 v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.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), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.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, MathUpgradeable.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) { 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] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); 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 keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../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. * * By default, the owner account will be the one that deploys the contract. 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; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @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 { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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 { require(newOwner != address(0), "Ownable: new owner is the zero address"); _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 v4.7.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.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}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * 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. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * 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 override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override 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 value {ERC20} uses, unless this function is * 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 override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override 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 `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` 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 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); 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 `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `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. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` 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. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @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. */ 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]. */ 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 v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.0; import "../ERC20.sol"; import "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ 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 v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // 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(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract Multicall { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, 'STE'); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManaged.sol) pragma solidity ^0.8.22; import {AuthorityUtils} from "./AuthorityUtils.sol"; import {IAccessManager} from "./IAccessManager.sol"; import {IAccessManaged} from "./IAccessManaged.sol"; import {Context} from "@openzeppelin/contracts/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.22/contracts.html#receive-ether-function[`receive()`] * function or the https://docs.soliditylang.org/en/v0.8.22/contracts.html#fallback-function[`fallback()`]. These * functions are the only execution paths where a function selector cannot be unambiguously determined from the calldata * since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function * if no calldata is provided. (See {_checkCanCall}). * * The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length. * ==== */ modifier restricted() { _checkCanCall(_msgSender(), _msgData()); _; } /// @inheritdoc IAccessManaged function authority() public view virtual returns (address) { return _authority; } /// @inheritdoc IAccessManaged function setAuthority(address newAuthority) public virtual { address caller = _msgSender(); if (caller != authority()) { revert AccessManagedUnauthorized(caller); } if (newAuthority.code.length == 0) { revert AccessManagedInvalidAuthority(newAuthority); } _setAuthority(newAuthority); } /// @inheritdoc IAccessManaged function isConsumingScheduledOp() public view returns (bytes4) { return _consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0); } /** * @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the * permissions set by the current authority. */ function _setAuthority(address newAuthority) internal virtual { _authority = newAuthority; emit AuthorityUpdated(newAuthority); } /** * @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata * is less than 4 bytes long. */ function _checkCanCall( address caller, bytes calldata data ) internal virtual { (bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay( authority(), caller, address(this), bytes4(data[0:4]) ); if (!immediate) { if (delay > 0) { _consumingSchedule = true; IAccessManager(authority()).consumeScheduledOp(caller, data); _consumingSchedule = false; } else { revert AccessManagedUnauthorized(caller); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManager.sol) pragma solidity ^0.8.22; import {IAccessManager} from "./IAccessManager.sol"; import {IAccessManaged} from "./IAccessManaged.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol"; import {Address} from "./utils/Address.sol"; import {Math} from "./utils/math/Math.sol"; import {Time} from "./utils/types/Time.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 AccessManager is Context, Multicall, 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 mapping(address target => TargetConfig mode) private _targets; mapping(uint64 roleId => Role) private _roles; mapping(bytes32 operationId => Schedule) private _schedules; // Used to identify operations that are currently being executed via {execute}. // This should be transient storage when supported by the EVM. bytes32 private _executionId; /** * @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in * {_getAdminRestrictions}. */ modifier onlyAuthorized() { _checkAuthorized(); _; } constructor(address initialAdmin) { 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) { return _targets[target].closed; } /// @inheritdoc IAccessManager function getTargetFunctionRole( address target, bytes4 selector ) public view virtual returns (uint64) { return _targets[target].allowedRoles[selector]; } /// @inheritdoc IAccessManager function getTargetAdminDelay( address target ) public view virtual returns (uint32) { return _targets[target].adminDelay.get(); } /// @inheritdoc IAccessManager function getRoleAdmin(uint64 roleId) public view virtual returns (uint64) { return _roles[roleId].admin; } /// @inheritdoc IAccessManager function getRoleGuardian( uint64 roleId ) public view virtual returns (uint64) { return _roles[roleId].guardian; } /// @inheritdoc IAccessManager function getRoleGrantDelay( uint64 roleId ) public view virtual returns (uint32) { 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 ) { 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) { 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) { 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 { 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 { 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 { 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 { _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 { 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 { 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) { uint48 timepoint = _schedules[id].timepoint; return _isExpired(timepoint) ? 0 : timepoint; } /// @inheritdoc IAccessManager function getNonce(bytes32 id) public view virtual returns (uint32) { return _schedules[id].nonce; } /// @inheritdoc IAccessManager function schedule( address target, bytes calldata data, uint48 when ) public virtual returns (bytes32 operationId, uint32 nonce) { 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, revert 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 { 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) { address caller = _msgSender(); // Fetch restrictions that apply to the caller on the targeted function (bool immediate, uint32 setback) = _canCallExtended( caller, target, data ); // If call is not authorized, 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) { 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) { 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) { 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) (access/manager/AuthorityUtils.sol) pragma solidity ^0.8.22; 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.22; 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.22; 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 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect ); /** * @dev Check if a given account currently has the permission level corresponding to a given role. Note that this * permission might be associated with an execution delay. {getAccess} can provide more details. */ function hasRole( uint64 roleId, address account ) external view returns (bool isMember, uint32 executionDelay); /** * @dev Give a label to a role, for improved role discoverability by UIs. * * Requirements: * * - the caller must be a global admin * * Emits a {RoleLabel} event. */ function labelRole(uint64 roleId, string calldata label) external; /** * @dev Add `account` to `roleId`, or change its execution delay. * * This gives the account the authorization to call any function that is restricted to this role. An optional * execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation * that is restricted to members of this role. The user will only be able to execute the operation after the delay has * passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}). * * If the account has already been granted this role, the execution delay will be updated. This update is not * immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is * called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any * operation executed in the 3 hours that follows this update was indeed scheduled before this update. * * Requirements: * * - the caller must be an admin for the role (see {getRoleAdmin}) * - granted role must not be the `PUBLIC_ROLE` * * Emits a {RoleGranted} event. */ function grantRole( uint64 roleId, address account, uint32 executionDelay ) external; /** * @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has * no effect. * * Requirements: * * - the caller must be an admin for the role (see {getRoleAdmin}) * - revoked role must not be the `PUBLIC_ROLE` * * Emits a {RoleRevoked} event if the account had the role. */ function revokeRole(uint64 roleId, address account) external; /** * @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in * the role this call has no effect. * * Requirements: * * - the caller must be `callerConfirmation`. * * Emits a {RoleRevoked} event if the account had the role. */ function renounceRole(uint64 roleId, address callerConfirmation) external; /** * @dev Change admin role for a given role. * * Requirements: * * - the caller must be a global admin * * Emits a {RoleAdminChanged} event */ function setRoleAdmin(uint64 roleId, uint64 admin) external; /** * @dev Change guardian role for a given role. * * Requirements: * * - the caller must be a global admin * * Emits a {RoleGuardianChanged} event */ function setRoleGuardian(uint64 roleId, uint64 guardian) external; /** * @dev Update the delay for granting a `roleId`. * * Requirements: * * - the caller must be a global admin * * Emits a {RoleGrantDelayChanged} event. */ function setGrantDelay(uint64 roleId, uint32 newDelay) external; /** * @dev Set the role required to call functions identified by the `selectors` in the `target` contract. * * Requirements: * * - the caller must be a global admin * * Emits a {TargetFunctionRoleUpdated} event per selector. */ function setTargetFunctionRole( address target, bytes4[] calldata selectors, uint64 roleId ) external; /** * @dev Set the delay for changing the configuration of a given target contract. * * Requirements: * * - the caller must be a global admin * * Emits a {TargetAdminDelayUpdated} event. */ function setTargetAdminDelay(address target, uint32 newDelay) external; /** * @dev Set the closed flag for a contract. * * Requirements: * * - the caller must be a global admin * * Emits a {TargetClosed} event. */ function setTargetClosed(address target, bool closed) external; /** * @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the * operation is not yet scheduled, has expired, was executed, or was canceled. */ function getSchedule(bytes32 id) external view returns (uint48); /** * @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never * been scheduled. */ function getNonce(bytes32 id) external view returns (uint32); /** * @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to * choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays * required for the caller. The special value zero will automatically set the earliest possible time. * * Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when * the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this * scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}. * * Emits a {OperationScheduled} event. * * NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If * this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target * contract if it is using standard Solidity ABI encoding. */ function schedule( address target, bytes calldata data, uint48 when ) external returns (bytes32 operationId, uint32 nonce); /** * @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the * execution delay is 0. * * Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the * operation wasn't previously scheduled (if the caller doesn't have an execution delay). * * Emits an {OperationExecuted} event only if the call was scheduled and delayed. */ function execute( address target, bytes calldata data ) external payable returns (uint32); /** * @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled * operation that is cancelled. * * Requirements: * * - the caller must be the proposer, a guardian of the targeted function, or a global admin * * Emits a {OperationCanceled} event. */ function cancel( address caller, address target, bytes calldata data ) external returns (uint32); /** * @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed * (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error. * * This is useful for contract that want to enforce that calls targeting them were scheduled on the manager, * with all the verifications that it implies. * * Emit a {OperationExecuted} event. */ function consumeScheduledOp(address caller, bytes calldata data) external; /** * @dev Hashing function for delayed operations. */ function hashOperation( address caller, address target, bytes calldata data ) external view returns (bytes32); /** * @dev Changes the authority of a target managed by this manager instance. * * Requirements: * * - the caller must be a global admin */ function updateAuthority(address target, address newAuthority) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAuthority.sol) pragma solidity ^0.8.22; /** * @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) (utils/Address.sol) pragma solidity ^0.8.22; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall( address target, bytes memory data ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, 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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. */ 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 Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.22; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd( uint256 a, uint256 b ) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub( uint256 a, uint256 b ) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul( uint256 a, uint256 b ) internal pure returns (bool success, uint256 result) { 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 success flag (no division by zero). */ function tryDiv( uint256 a, uint256 b ) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod( uint256 a, uint256 b ) internal pure returns (bool success, uint256 result) { unchecked { 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. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return a == 0 ? 0 : (a - 1) / b + 1; } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 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²⁵⁶ + 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²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic( denominator == 0 ? Panic.DIVISION_BY_ZERO : Panic.UNDER_OVERFLOW ); } /////////////////////////////////////////////// // 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²⁵⁶ / 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²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint( unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0 ); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, expect 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Ferma's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return x < 0 ? (n - uint256(-x)) : uint256(x); // Wrap the result if it's negative. } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp( uint256 b, uint256 e, uint256 m ) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked has failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp( uint256 b, uint256 e, uint256 m ) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); /// @solidity memory-safe-assembly assembly { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall( gas(), 0x05, dataPtr, mload(result), dataPtr, mLen ) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt( uint256 a, Rounding rounding ) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint( unsignedRoundsUp(rounding) && result * result < a ); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 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 + SafeCast.toUint( unsignedRoundsUp(rounding) && 1 << result < value ); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10( uint256 value, Rounding rounding ) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint( unsignedRoundsUp(rounding) && 10 ** result < value ); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 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 + SafeCast.toUint( unsignedRoundsUp(rounding) && 1 << (result << 3) < value ); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// 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.22; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { /// @solidity memory-safe-assembly assembly { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) pragma solidity ^0.8.22; 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: MIT pragma solidity ^0.8.22; import "../AccessManager/AccessManager.sol"; import "./IFairsideAdmin.sol"; contract FairSideAdmin is AccessManager, IFairsideAdmin { constructor() AccessManager(msg.sender) { _grantRole(uint64(FSRoles.FS_ADMIN_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_CLAIMS_OWNER_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_FAIR_OWNER_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_CLAIMS_GUARDIAN_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_NETWORK_GUARDIAN_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_FAIR_GUARDIAN_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_NETWORK_OWNER_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_CLAIMS_ISSUER), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_BOUNTY_POOL_OWNER_ROLE), msg.sender, 0, 0); _grantRole(uint64(FSRoles.FS_CLAIMS_VERIFIER), msg.sender, 0, 0); } function hasFSRole( FSRoles role, address account ) external view returns (bool) { (bool isMember, ) = AccessManager.hasRole(uint64(role), account); return isMember; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; interface IFairsideAdmin { enum FSRoles { VOID, FS_ADMIN_ROLE, FS_CLAIMS_GUARDIAN_ROLE, FS_CLAIMS_OWNER_ROLE, FS_NETWORK_GUARDIAN_ROLE, FS_NETWORK_OWNER_ROLE, FS_FAIR_GUARDIAN_ROLE, FS_FAIR_OWNER_ROLE, FS_CLAIMS_ISSUER, FS_BOUNTY_POOL_OWNER_ROLE, FS_CLAIMS_VERIFIER } function hasFSRole( FSRoles role, address account ) external view returns (bool); }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math Quad Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity ^0.8.22; /** * Smart contract library of mathematical functions operating with IEEE 754 * quadruple-precision binary floating-point numbers (quadruple precision * numbers). As long as quadruple precision numbers are 16-bytes long, they are * represented by bytes16 type. */ library ABDKMathQuad { /* * 0. */ bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000; /* * -0. */ bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000; /* * +Infinity. */ bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000; /* * -Infinity. */ bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000; /* * Canonical NaN value. */ bytes16 private constant NaN = 0x7FFF8000000000000000000000000000; /** * Convert signed 256-bit integer number into quadruple precision number. * * @param x signed 256-bit integer number * @return quadruple precision number */ function fromInt(int256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { // We rely on overflow behavior here // we get the absolute value of x to put into signifier uint256 result = uint256(x > 0 ? x : -x); uint256 msb = mostSignificantBit(result); // multiplied by 2^n to put most significant bit to the position 112 if (msb < 112) result <<= 112 - msb; // if the signifier is too large then we cut off the least significant bits after 112 else if (msb > 112) result >>= msb - 112; // 16383 = 0x3FFF // based of this table of precedence of operators https://docs.soliditylang.org/en/latest/cheatsheet.html // then +, <<, &, | // to calculate the exponent we use the offset 16383, i.e. numbers greater than 16383 represent positive exponents // numbers lesser than 16383 represent negative exponents result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16383 + msb) << 112); // if x is negative then we put the first bit of the 16bytes to be 1 if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into signed 256-bit integer number * rounding towards zero. Revert on overflow. * * @param x quadruple precision number * @return signed 256-bit integer number */ function toInt(bytes16 x) internal pure returns (int256) { unchecked { // first we cut off the last 112 bits representing the significand // then we cut off the first bit representing the sign // we are then left with the exponent uint256 exponent = (uint128(x) >> 112) & 0x7FFF; // 16638 = 0x40fe // if exponent is at least 16638, then the real exponent is at least 16638 - 16383 = 255, which exceeds the range for int256 require(exponent <= 16638); // Overflow // if the exponent is less than 16383, then the resulting number is less than 1, so rounded to 0, since the result is an integer if (exponent < 16383) return 0; // Underflow // we get the significand then append the 1 from the left // reminder that for a number 1.00101 * 2^8, significand is 00101 // and the result below in this example would be 1.00101 * 2^112 uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; // if the exponent is less than 16495, i.e. the real exponent is less than 16495 - 16383 = 112 // then we need to trim out some digits from the result calculated above if (exponent < 16495) result >>= 16495 - exponent; // else we need to add more zeros else if (exponent > 16495) result <<= exponent - 16495; // we add the negative sign if necessary if (uint128(x) >= 0x80000000000000000000000000000000) { // Negative // in the negative case we require that the esult is at most 2^255 require( result <= 0x8000000000000000000000000000000000000000000000000000000000000000 ); return -int256(result); // We rely on overflow behavior here } else { // in the positive case we require that the result is at most 2^256 - 1 require( result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); return int256(result); } } } /** * Convert unsigned 256-bit integer number into quadruple precision number. * * @param x unsigned 256-bit integer number * @return quadruple precision number */ function fromUInt(uint256 x) internal pure returns (bytes16) { unchecked { // the process is similar to fromInt if (x == 0) return bytes16(0); else { uint256 result = x; uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16383 + msb) << 112); return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into unsigned 256-bit integer number * rounding towards zero. Revert on underflow. Note, that negative floating * point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer * without error, because they are rounded to zero. * * @param x quadruple precision number * @return unsigned 256-bit integer number */ function toUInt(bytes16 x) internal pure returns (uint256) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; if (exponent < 16383) return 0; // Underflow require(uint128(x) < 0x80000000000000000000000000000000); // Negative require(exponent <= 16638); // Overflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16495) result >>= 16495 - exponent; else if (exponent > 16495) result <<= exponent - 16495; return result; } } /** * Convert signed 128.128 bit fixed point number into quadruple precision * number. * * @param x signed 128.128 bit fixed point number * @return quadruple precision number */ function from128x128(int256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { // We rely on overflow behavior here uint256 result = uint256(x > 0 ? x : -x); uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16255 + msb) << 112); if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into signed 128.128 bit fixed point * number. Revert on overflow. * * @param x quadruple precision number * @return signed 128.128 bit fixed point number */ function to128x128(bytes16 x) internal pure returns (int256) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; require(exponent <= 16510); // Overflow if (exponent < 16255) return 0; // Underflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16367) result >>= 16367 - exponent; else if (exponent > 16367) result <<= exponent - 16367; if (uint128(x) >= 0x80000000000000000000000000000000) { // Negative require( result <= 0x8000000000000000000000000000000000000000000000000000000000000000 ); return -int256(result); // We rely on overflow behavior here } else { require( result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); return int256(result); } } } /** * Convert signed 64.64 bit fixed point number into quadruple precision * number. * * @param x signed 64.64 bit fixed point number * @return quadruple precision number */ function from64x64(int128 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { // We rely on overflow behavior here uint256 result = uint128(x > 0 ? x : -x); uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16319 + msb) << 112); if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into signed 64.64 bit fixed point * number. Revert on overflow. * * @param x quadruple precision number * @return signed 64.64 bit fixed point number */ function to64x64(bytes16 x) internal pure returns (int128) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; require(exponent <= 16446); // Overflow if (exponent < 16319) return 0; // Underflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16431) result >>= 16431 - exponent; else if (exponent > 16431) result <<= exponent - 16431; if (uint128(x) >= 0x80000000000000000000000000000000) { // Negative require(result <= 0x80000000000000000000000000000000); return -int128(int256(result)); // We rely on overflow behavior here } else { require(result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128(int256(result)); } } } /** * Convert octuple precision number into quadruple precision number. * * @param x octuple precision number * @return quadruple precision number */ function fromOctuple(bytes32 x) internal pure returns (bytes16) { unchecked { bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0; uint256 exponent = (uint256(x) >> 236) & 0x7FFFF; uint256 significand = uint256(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFFF) { if (significand > 0) return NaN; else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; } if (exponent > 278526) return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else if (exponent < 245649) return negative ? NEGATIVE_ZERO : POSITIVE_ZERO; else if (exponent < 245761) { significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> (245885 - exponent); exponent = 0; } else { significand >>= 124; exponent -= 245760; } uint128 result = uint128(significand | (exponent << 112)); if (negative) result |= 0x80000000000000000000000000000000; return bytes16(result); } } /** * Convert quadruple precision number into octuple precision number. * * @param x quadruple precision number * @return octuple precision number */ function toOctuple(bytes16 x) internal pure returns (bytes32) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; uint256 result = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN else if (exponent == 0) { if (result > 0) { uint256 msb = mostSignificantBit(result); result = (result << (236 - msb)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; exponent = 245649 + msb; } } else { result <<= 124; exponent += 245760; } result |= exponent << 236; if (uint128(x) >= 0x80000000000000000000000000000000) result |= 0x8000000000000000000000000000000000000000000000000000000000000000; return bytes32(result); } } /** * Convert double precision number into quadruple precision number. * * @param x double precision number * @return quadruple precision number */ function fromDouble(bytes8 x) internal pure returns (bytes16) { unchecked { uint256 exponent = (uint64(x) >> 52) & 0x7FF; uint256 result = uint64(x) & 0xFFFFFFFFFFFFF; if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN else if (exponent == 0) { if (result > 0) { uint256 msb = mostSignificantBit(result); result = (result << (112 - msb)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; exponent = 15309 + msb; } } else { result <<= 60; exponent += 15360; } result |= exponent << 112; if (x & 0x8000000000000000 > 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } /** * Convert quadruple precision number into double precision number. * * @param x quadruple precision number * @return double precision number */ function toDouble(bytes16 x) internal pure returns (bytes8) { unchecked { bool negative = uint128(x) >= 0x80000000000000000000000000000000; uint256 exponent = (uint128(x) >> 112) & 0x7FFF; uint256 significand = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFF) { if (significand > 0) return 0x7FF8000000000000; // NaN else return negative ? bytes8(0xFFF0000000000000) // -Infinity : bytes8(0x7FF0000000000000); // Infinity } if (exponent > 17406) return negative ? bytes8(0xFFF0000000000000) // -Infinity : bytes8(0x7FF0000000000000); // Infinity else if (exponent < 15309) return negative ? bytes8(0x8000000000000000) // -0 : bytes8(0x0000000000000000); // 0 else if (exponent < 15361) { significand = (significand | 0x10000000000000000000000000000) >> (15421 - exponent); exponent = 0; } else { significand >>= 60; exponent -= 15360; } uint64 result = uint64(significand | (exponent << 52)); if (negative) result |= 0x8000000000000000; return bytes8(result); } } /** * Test whether given quadruple precision number is NaN. * * @param x quadruple precision number * @return true if x is NaN, false otherwise */ function isNaN(bytes16 x) internal pure returns (bool) { unchecked { return uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF > 0x7FFF0000000000000000000000000000; } } /** * Test whether given quadruple precision number is positive or negative * infinity. * * @param x quadruple precision number * @return true if x is positive or negative infinity, false otherwise */ function isInfinity(bytes16 x) internal pure returns (bool) { unchecked { return uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x7FFF0000000000000000000000000000; } } /** * Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x * is positive. Note that sign (-0) is zero. Revert if x is NaN. * * @param x quadruple precision number * @return sign of x */ function sign(bytes16 x) internal pure returns (int8) { unchecked { uint128 absoluteX = uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require(absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN if (absoluteX == 0) return 0; else if (uint128(x) >= 0x80000000000000000000000000000000) return -1; else return 1; } } /** * Calculate sign (x - y). Revert if either argument is NaN, or both * arguments are infinities of the same sign. * * @param x quadruple precision number * @param y quadruple precision number * @return sign (x - y) */ function cmp(bytes16 x, bytes16 y) internal pure returns (int8) { unchecked { uint128 absoluteX = uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require(absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN uint128 absoluteY = uint128(y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require(absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN // Not infinities of the same sign require(x != y || absoluteX < 0x7FFF0000000000000000000000000000); if (x == y) return 0; else { bool negativeX = uint128(x) >= 0x80000000000000000000000000000000; bool negativeY = uint128(y) >= 0x80000000000000000000000000000000; if (negativeX) { if (negativeY) return absoluteX > absoluteY ? -1 : int8(1); else return -1; } else { if (negativeY) return 1; else return absoluteX > absoluteY ? int8(1) : -1; } } } } /** * Test whether x equals y. NaN, infinity, and -infinity are not equal to * anything. * * @param x quadruple precision number * @param y quadruple precision number * @return true if x equals to y, false otherwise */ function eq(bytes16 x, bytes16 y) internal pure returns (bool) { unchecked { if (x == y) { return uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF < 0x7FFF0000000000000000000000000000; } else return false; } } /** * Calculate x + y. Special values behave in the following way: * * NaN + x = NaN for any x. * Infinity + x = Infinity for any finite x. * -Infinity + x = -Infinity for any finite x. * Infinity + Infinity = Infinity. * -Infinity + -Infinity = -Infinity. * Infinity + -Infinity = -Infinity + Infinity = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function add(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { // we get rid of the last 112 bits (significand) and the first bit (sign) to get the exponent uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 yExponent = (uint128(y) >> 112) & 0x7FFF; // if the xExponent is 0x7FFF then x is positive infinity, negative infinity or NaN if (xExponent == 0x7FFF) { // if yExponent is 0x7FFF then y is positive infinity, negative of NaN if (yExponent == 0x7FFF) { // if they are equal then they are both infinity of the same sign or NaN and their addition keeps the value if (x == y) return x; // else the addition gives undefined else return NaN; // else if y is a normal number, then their addition keeps the value of x } else return x; // else if x is a normal number and y is an edge case, then their addition keeps the value of y } else if (yExponent == 0x7FFF) return y; // now we deal with the case when x and y are both normal numbers else { // the sign of x is its first bit bool xSign = uint128(x) >= 0x80000000000000000000000000000000; // the significand (or signifier) is the last 112 bits uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // if the exponent is 0 then the number should already be 0 (can the significand be anything other than 0 if the exponent is 0?). What is the purpose of setting the exponent to 1 here? // If the exponent is 0 then the number doesn't necessarily be 0, they are called subnormal numbers. In this case the exponent is 1, because the real exponent is -16382, and we don't need to append 1 to the front if (xExponent == 0) xExponent = 1; // we add 1 to the front of the significand else xSignifier |= 0x10000000000000000000000000000; bool ySign = uint128(y) >= 0x80000000000000000000000000000000; uint256 ySignifier = uint128(y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; // if the xSignificand is 0, can only happen when the xExponent was 0 // then the result is equal to y if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y; else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x; // now we deal with the case when both x and y are two normal nonzero numbers else { int256 delta = int256(xExponent) - int256(yExponent); if (xSign == ySign) { // y is too small compared to x so considered precision error if (delta > 112) return x; // we shift y accordingly, the common exponent is xExponent else if (delta > 0) ySignifier >>= uint256(delta); // x is too small compared to y so considered precision error else if (delta < -112) return y; // we shift x accordingly, the common exponent is yExponent else if (delta < 0) { xSignifier >>= uint256(-delta); xExponent = yExponent; } // we add the two significand together xSignifier += ySignifier; // we the addition creates one additional bit then we shift to the right by 1 then increase the exponent by 1 if (xSignifier >= 0x20000000000000000000000000000) { xSignifier >>= 1; xExponent += 1; } // overflowing makes the result become infinity if (xExponent == 0x7FFF) return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else { // I fail to see when this case can ever happen if (xSignifier < 0x10000000000000000000000000000) xExponent = 0; // we get rid of the bit one in the beginning else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; return bytes16( uint128( ( xSign ? 0x80000000000000000000000000000000 : 0 ) | (xExponent << 112) | xSignifier ) ); } } else { // case when x and y have different signs if (delta > 0) { xSignifier <<= 1; xExponent -= 1; } else if (delta < 0) { ySignifier <<= 1; xExponent = yExponent - 1; } // if y is too small compared to x then the effect of the subtraction after rounding is the same as subtraction of 1 if (delta > 112) ySignifier = 1; // if delta is at least 2 then y can only reduce the most significant bit of x by 1, so here we shift ySignifier accordingly else if (delta > 1) ySignifier = ((ySignifier - 1) >> uint256(delta - 1)) + 1; else if (delta < -112) xSignifier = 1; else if (delta < -1) xSignifier = ((xSignifier - 1) >> uint256(-delta - 1)) + 1; if (xSignifier >= ySignifier) xSignifier -= ySignifier; else { xSignifier = ySignifier - xSignifier; xSign = ySign; } if (xSignifier == 0) return POSITIVE_ZERO; uint256 msb = mostSignificantBit(xSignifier); if (msb == 113) { // if the difference is represented by 113 bit then we cut off the last bit and increase the exponent accordingly // we also get rid of the number one in the beginning xSignifier = (xSignifier >> 1) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent += 1; } else if (msb < 112) { // if there are less than 112 precision bits then we shift accordingly uint256 shift = 112 - msb; if (xExponent > shift) { xSignifier = (xSignifier << shift) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent -= shift; } else { xSignifier <<= xExponent - 1; xExponent = 0; } } else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // returns infinity for overflow/underflow if (xExponent == 0x7FFF) return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else return bytes16( uint128( ( xSign ? 0x80000000000000000000000000000000 : 0 ) | (xExponent << 112) | xSignifier ) ); } } } } } /** * Calculate x - y. Special values behave in the following way: * * NaN - x = NaN for any x. * Infinity - x = Infinity for any finite x. * -Infinity - x = -Infinity for any finite x. * Infinity - -Infinity = Infinity. * -Infinity - Infinity = -Infinity. * Infinity - Infinity = -Infinity - -Infinity = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function sub(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { // x + y.neg() return add(x, y ^ 0x80000000000000000000000000000000); } } /** * Calculate x * y. Special values behave in the following way: * * NaN * x = NaN for any x. * Infinity * x = Infinity for any finite positive x. * Infinity * x = -Infinity for any finite negative x. * -Infinity * x = -Infinity for any finite positive x. * -Infinity * x = Infinity for any finite negative x. * Infinity * 0 = NaN. * -Infinity * 0 = NaN. * Infinity * Infinity = Infinity. * Infinity * -Infinity = -Infinity. * -Infinity * Infinity = -Infinity. * -Infinity * -Infinity = Infinity. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function mul(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 yExponent = (uint128(y) >> 112) & 0x7FFF; // firts we deal with edge cases if (xExponent == 0x7FFF) { // when both x and y are special numbers if (yExponent == 0x7FFF) { // & has higher priority than ^ https://docs.soliditylang.org/en/latest/cheatsheet.html // if x and y are both equal then the product is either infinity or Nan if (x == y) return x ^ (y & 0x80000000000000000000000000000000); // if x and y are infinities of different signs then return minus infinity else if (x ^ y == 0x80000000000000000000000000000000) return x | y; else return NaN; } else { // if y is 0 then its product with infinity is undefined if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; // else return the infinity or Nan accordingly else return x ^ (y & 0x80000000000000000000000000000000); } // the case when y is a special number and x is a normal number } else if (yExponent == 0x7FFF) { if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return y ^ (x & 0x80000000000000000000000000000000); // the case when both x and y are normal numbers } else { // we get rid of the sign and exponent uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // still not sure what the purpose of this line is if (xExponent == 0) xExponent = 1; // we add 1 to the front else xSignifier |= 0x10000000000000000000000000000; uint256 ySignifier = uint128(y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; // we multiply the significand together xSignifier *= ySignifier; if (xSignifier == 0) return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? NEGATIVE_ZERO : POSITIVE_ZERO; // we add the exponent together xExponent += yExponent; // why don't we just simply use the function mostSignificantBit // but it seems to me that xSignifier always has either 224 or 225 bits, so the last branch is not needed? uint256 msb = xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 : xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 : mostSignificantBit(xSignifier); // why is 16496 chosen? if (xExponent + msb < 16496) { // Underflow xExponent = 0; xSignifier = 0; } else if (xExponent + msb < 16608) { // Subnormal if (xExponent < 16496) xSignifier >>= 16496 - xExponent; else if (xExponent > 16496) xSignifier <<= xExponent - 16496; xExponent = 0; } else if (xExponent + msb > 49373) { xExponent = 0x7FFF; xSignifier = 0; } else { if (msb > 112) xSignifier >>= msb - 112; else if (msb < 112) xSignifier <<= 112 - msb; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent = xExponent + msb - 16607; } return bytes16( uint128( uint128( (x ^ y) & 0x80000000000000000000000000000000 ) | (xExponent << 112) | xSignifier ) ); } } } /** * Calculate x / y. Special values behave in the following way: * * NaN / x = NaN for any x. * x / NaN = NaN for any x. * Infinity / x = Infinity for any finite non-negative x. * Infinity / x = -Infinity for any finite negative x including -0. * -Infinity / x = -Infinity for any finite non-negative x. * -Infinity / x = Infinity for any finite negative x including -0. * x / Infinity = 0 for any finite non-negative x. * x / -Infinity = -0 for any finite non-negative x. * x / Infinity = -0 for any finite non-negative x including -0. * x / -Infinity = 0 for any finite non-negative x including -0. * * Infinity / Infinity = NaN. * Infinity / -Infinity = -NaN. * -Infinity / Infinity = -NaN. * -Infinity / -Infinity = NaN. * * Division by zero behaves in the following way: * * x / 0 = Infinity for any finite positive x. * x / -0 = -Infinity for any finite positive x. * x / 0 = -Infinity for any finite negative x. * x / -0 = Infinity for any finite negative x. * 0 / 0 = NaN. * 0 / -0 = NaN. * -0 / 0 = NaN. * -0 / -0 = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function div(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 yExponent = (uint128(y) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) return NaN; else return x ^ (y & 0x80000000000000000000000000000000); } else if (yExponent == 0x7FFF) { if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN; else return POSITIVE_ZERO | ((x ^ y) & 0x80000000000000000000000000000000); } else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) { if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return POSITIVE_INFINITY | ((x ^ y) & 0x80000000000000000000000000000000); } else { uint256 ySignifier = uint128(y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) { if (xSignifier != 0) { uint256 shift = 226 - mostSignificantBit(xSignifier); xSignifier <<= shift; xExponent = 1; yExponent += shift - 114; } } else { xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114; } xSignifier = xSignifier / ySignifier; if (xSignifier == 0) return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? NEGATIVE_ZERO : POSITIVE_ZERO; assert(xSignifier >= 0x1000000000000000000000000000); uint256 msb = xSignifier >= 0x80000000000000000000000000000 ? mostSignificantBit(xSignifier) : xSignifier >= 0x40000000000000000000000000000 ? 114 : xSignifier >= 0x20000000000000000000000000000 ? 113 : 112; if (xExponent + msb > yExponent + 16497) { // Overflow xExponent = 0x7FFF; xSignifier = 0; } else if (xExponent + msb + 16380 < yExponent) { // Underflow xExponent = 0; xSignifier = 0; } else if (xExponent + msb + 16268 < yExponent) { // Subnormal if (xExponent + 16380 > yExponent) xSignifier <<= xExponent + 16380 - yExponent; else if (xExponent + 16380 < yExponent) xSignifier >>= yExponent - xExponent - 16380; xExponent = 0; } else { // Normal if (msb > 112) xSignifier >>= msb - 112; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent = xExponent + msb + 16269 - yExponent; } return bytes16( uint128( uint128( (x ^ y) & 0x80000000000000000000000000000000 ) | (xExponent << 112) | xSignifier ) ); } } } /** * Calculate -x. * * @param x quadruple precision number * @return quadruple precision number */ function neg(bytes16 x) internal pure returns (bytes16) { unchecked { // using xor to switch the bit representing sign return x ^ 0x80000000000000000000000000000000; } } /** * Calculate |x|. * * @param x quadruple precision number * @return quadruple precision number */ function abs(bytes16 x) internal pure returns (bytes16) { unchecked { return x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; } } /** * Calculate square root of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function sqrt(bytes16 x) internal pure returns (bytes16) { unchecked { if (uint128(x) > 0x80000000000000000000000000000000) return NaN; else { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) return x; else { uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return POSITIVE_ZERO; bool oddExponent = xExponent & 0x1 == 0; xExponent = (xExponent + 16383) >> 1; if (oddExponent) { if (xSignifier >= 0x10000000000000000000000000000) xSignifier <<= 113; else { uint256 msb = mostSignificantBit(xSignifier); uint256 shift = (226 - msb) & 0xFE; xSignifier <<= shift; xExponent -= (shift - 112) >> 1; } } else { if (xSignifier >= 0x10000000000000000000000000000) xSignifier <<= 112; else { uint256 msb = mostSignificantBit(xSignifier); uint256 shift = (225 - msb) & 0xFE; xSignifier <<= shift; xExponent -= (shift - 112) >> 1; } } uint256 r = 0x10000000000000000000000000000; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; // Seven iterations should be enough uint256 r1 = xSignifier / r; if (r1 < r) r = r1; return bytes16( uint128( (xExponent << 112) | (r & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) ) ); } } } } /** * Calculate binary logarithm of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function log_2(bytes16 x) internal pure returns (bytes16) { unchecked { if (uint128(x) > 0x80000000000000000000000000000000) return NaN; else if (x == 0x3FFF0000000000000000000000000000) return POSITIVE_ZERO; else { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) return x; else { uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return NEGATIVE_INFINITY; bool resultNegative; uint256 resultExponent = 16495; uint256 resultSignifier; if (xExponent >= 0x3FFF) { resultNegative = false; resultSignifier = xExponent - 0x3FFF; xSignifier <<= 15; } else { resultNegative = true; if (xSignifier >= 0x10000000000000000000000000000) { resultSignifier = 0x3FFE - xExponent; xSignifier <<= 15; } else { uint256 msb = mostSignificantBit(xSignifier); resultSignifier = 16493 - msb; xSignifier <<= 127 - msb; } } if (xSignifier == 0x80000000000000000000000000000000) { if (resultNegative) resultSignifier += 1; uint256 shift = 112 - mostSignificantBit(resultSignifier); resultSignifier <<= shift; resultExponent -= shift; } else { uint256 bb = resultNegative ? 1 : 0; while ( resultSignifier < 0x10000000000000000000000000000 ) { resultSignifier <<= 1; resultExponent -= 1; xSignifier *= xSignifier; uint256 b = xSignifier >> 255; resultSignifier += b ^ bb; xSignifier >>= 127 + b; } } return bytes16( uint128( ( resultNegative ? 0x80000000000000000000000000000000 : 0 ) | (resultExponent << 112) | (resultSignifier & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) ) ); } } } } /** * Calculate natural logarithm of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function ln(bytes16 x) internal pure returns (bytes16) { unchecked { return mul(log_2(x), 0x3FFE62E42FEFA39EF35793C7673007E5); } } /** * Calculate 2^x. * * @param x quadruple precision number * @return quadruple precision number */ function pow_2(bytes16 x) internal pure returns (bytes16) { unchecked { bool xNegative = uint128(x) > 0x80000000000000000000000000000000; uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0x7FFF && xSignifier != 0) return NaN; else if (xExponent > 16397) return xNegative ? POSITIVE_ZERO : POSITIVE_INFINITY; else if (xExponent < 16255) return 0x3FFF0000000000000000000000000000; else { if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xExponent > 16367) xSignifier <<= xExponent - 16367; else if (xExponent < 16367) xSignifier >>= 16367 - xExponent; if ( xNegative && xSignifier > 0x406E00000000000000000000000000000000 ) return POSITIVE_ZERO; if ( !xNegative && xSignifier > 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ) return POSITIVE_INFINITY; uint256 resultExponent = xSignifier >> 128; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xNegative && xSignifier != 0) { xSignifier = ~xSignifier; resultExponent += 1; } uint256 resultSignifier = 0x80000000000000000000000000000000; if (xSignifier & 0x80000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128; if (xSignifier & 0x40000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128; if (xSignifier & 0x20000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128; if (xSignifier & 0x10000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10B5586CF9890F6298B92B71842A98363) >> 128; if (xSignifier & 0x8000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128; if (xSignifier & 0x4000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128; if (xSignifier & 0x2000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128; if (xSignifier & 0x1000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128; if (xSignifier & 0x800000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128; if (xSignifier & 0x400000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128; if (xSignifier & 0x200000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128; if (xSignifier & 0x100000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000B175EFFDC76BA38E31671CA939725) >> 128; if (xSignifier & 0x80000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128; if (xSignifier & 0x40000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128; if (xSignifier & 0x20000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000162E525EE054754457D5995292026) >> 128; if (xSignifier & 0x10000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000B17255775C040618BF4A4ADE83FC) >> 128; if (xSignifier & 0x8000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128; if (xSignifier & 0x4000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128; if (xSignifier & 0x2000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000162E43F4F831060E02D839A9D16D) >> 128; if (xSignifier & 0x1000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000B1721BCFC99D9F890EA06911763) >> 128; if (xSignifier & 0x800000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128; if (xSignifier & 0x400000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128; if (xSignifier & 0x200000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000162E430E5A18F6119E3C02282A5) >> 128; if (xSignifier & 0x100000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128; if (xSignifier & 0x80000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128; if (xSignifier & 0x40000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000002C5C8601CC6B9E94213C72737A) >> 128; if (xSignifier & 0x20000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000162E42FFF037DF38AA2B219F06) >> 128; if (xSignifier & 0x10000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000B17217FBA9C739AA5819F44F9) >> 128; if (xSignifier & 0x8000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128; if (xSignifier & 0x4000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128; if (xSignifier & 0x2000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128; if (xSignifier & 0x1000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000B17217F80F4EF5AADDA45554) >> 128; if (xSignifier & 0x800000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128; if (xSignifier & 0x400000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128; if (xSignifier & 0x200000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000162E42FEFB2FED257559BDAA) >> 128; if (xSignifier & 0x100000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128; if (xSignifier & 0x80000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128; if (xSignifier & 0x40000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128; if (xSignifier & 0x20000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000162E42FEFA494F1478FDE05) >> 128; if (xSignifier & 0x10000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000B17217F7D20CF927C8E94C) >> 128; if (xSignifier & 0x8000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128; if (xSignifier & 0x4000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000002C5C85FDF477B662B26945) >> 128; if (xSignifier & 0x2000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000162E42FEFA3AE53369388C) >> 128; if (xSignifier & 0x1000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000B17217F7D1D351A389D40) >> 128; if (xSignifier & 0x800000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128; if (xSignifier & 0x400000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128; if (xSignifier & 0x200000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000162E42FEFA39FE95583C2) >> 128; if (xSignifier & 0x100000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000B17217F7D1CFB72B45E1) >> 128; if (xSignifier & 0x80000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128; if (xSignifier & 0x40000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000002C5C85FDF473E242EA38) >> 128; if (xSignifier & 0x20000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000162E42FEFA39F02B772C) >> 128; if (xSignifier & 0x10000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000B17217F7D1CF7D83C1A) >> 128; if (xSignifier & 0x8000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128; if (xSignifier & 0x4000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000002C5C85FDF473DEA871F) >> 128; if (xSignifier & 0x2000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000162E42FEFA39EF44D91) >> 128; if (xSignifier & 0x1000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000B17217F7D1CF79E949) >> 128; if (xSignifier & 0x800000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000058B90BFBE8E7BCE544) >> 128; if (xSignifier & 0x400000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000002C5C85FDF473DE6ECA) >> 128; if (xSignifier & 0x200000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000162E42FEFA39EF366F) >> 128; if (xSignifier & 0x100000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000B17217F7D1CF79AFA) >> 128; if (xSignifier & 0x80000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000058B90BFBE8E7BCD6D) >> 128; if (xSignifier & 0x40000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000002C5C85FDF473DE6B2) >> 128; if (xSignifier & 0x20000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000162E42FEFA39EF358) >> 128; if (xSignifier & 0x10000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000B17217F7D1CF79AB) >> 128; if (xSignifier & 0x8000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000058B90BFBE8E7BCD5) >> 128; if (xSignifier & 0x4000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000002C5C85FDF473DE6A) >> 128; if (xSignifier & 0x2000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000162E42FEFA39EF34) >> 128; if (xSignifier & 0x1000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000B17217F7D1CF799) >> 128; if (xSignifier & 0x800000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000058B90BFBE8E7BCC) >> 128; if (xSignifier & 0x400000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000002C5C85FDF473DE5) >> 128; if (xSignifier & 0x200000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000162E42FEFA39EF2) >> 128; if (xSignifier & 0x100000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000B17217F7D1CF78) >> 128; if (xSignifier & 0x80000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000058B90BFBE8E7BB) >> 128; if (xSignifier & 0x40000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000002C5C85FDF473DD) >> 128; if (xSignifier & 0x20000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000162E42FEFA39EE) >> 128; if (xSignifier & 0x10000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000B17217F7D1CF6) >> 128; if (xSignifier & 0x8000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000058B90BFBE8E7A) >> 128; if (xSignifier & 0x4000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000002C5C85FDF473C) >> 128; if (xSignifier & 0x2000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000162E42FEFA39D) >> 128; if (xSignifier & 0x1000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000B17217F7D1CE) >> 128; if (xSignifier & 0x800000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000058B90BFBE8E6) >> 128; if (xSignifier & 0x400000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000002C5C85FDF472) >> 128; if (xSignifier & 0x200000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000162E42FEFA38) >> 128; if (xSignifier & 0x100000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000B17217F7D1B) >> 128; if (xSignifier & 0x80000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000058B90BFBE8D) >> 128; if (xSignifier & 0x40000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000002C5C85FDF46) >> 128; if (xSignifier & 0x20000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000162E42FEFA2) >> 128; if (xSignifier & 0x10000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000B17217F7D0) >> 128; if (xSignifier & 0x8000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000058B90BFBE7) >> 128; if (xSignifier & 0x4000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000002C5C85FDF3) >> 128; if (xSignifier & 0x2000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000162E42FEF9) >> 128; if (xSignifier & 0x1000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000B17217F7C) >> 128; if (xSignifier & 0x800000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000058B90BFBD) >> 128; if (xSignifier & 0x400000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000002C5C85FDE) >> 128; if (xSignifier & 0x200000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000162E42FEE) >> 128; if (xSignifier & 0x100000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000B17217F6) >> 128; if (xSignifier & 0x80000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000058B90BFA) >> 128; if (xSignifier & 0x40000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000002C5C85FC) >> 128; if (xSignifier & 0x20000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000162E42FD) >> 128; if (xSignifier & 0x10000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000B17217E) >> 128; if (xSignifier & 0x8000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000058B90BE) >> 128; if (xSignifier & 0x4000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000002C5C85E) >> 128; if (xSignifier & 0x2000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000162E42E) >> 128; if (xSignifier & 0x1000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000B17216) >> 128; if (xSignifier & 0x800000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000058B90A) >> 128; if (xSignifier & 0x400000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000002C5C84) >> 128; if (xSignifier & 0x200000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000162E41) >> 128; if (xSignifier & 0x100000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000B1720) >> 128; if (xSignifier & 0x80000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000058B8F) >> 128; if (xSignifier & 0x40000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000002C5C7) >> 128; if (xSignifier & 0x20000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000162E3) >> 128; if (xSignifier & 0x10000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000B171) >> 128; if (xSignifier & 0x8000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000058B8) >> 128; if (xSignifier & 0x4000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000002C5B) >> 128; if (xSignifier & 0x2000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000162D) >> 128; if (xSignifier & 0x1000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000B16) >> 128; if (xSignifier & 0x800 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000058A) >> 128; if (xSignifier & 0x400 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000002C4) >> 128; if (xSignifier & 0x200 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000161) >> 128; if (xSignifier & 0x100 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000000B0) >> 128; if (xSignifier & 0x80 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000057) >> 128; if (xSignifier & 0x40 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000002B) >> 128; if (xSignifier & 0x20 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000015) >> 128; if (xSignifier & 0x10 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000000A) >> 128; if (xSignifier & 0x8 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000004) >> 128; if (xSignifier & 0x4 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000001) >> 128; if (!xNegative) { resultSignifier = (resultSignifier >> 15) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; resultExponent += 0x3FFF; } else if (resultExponent <= 0x3FFE) { resultSignifier = (resultSignifier >> 15) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; resultExponent = 0x3FFF - resultExponent; } else { resultSignifier = resultSignifier >> (resultExponent - 16367); resultExponent = 0; } return bytes16(uint128((resultExponent << 112) | resultSignifier)); } } } /** * Calculate e^x. * * @param x quadruple precision number * @return quadruple precision number */ function exp(bytes16 x) internal pure returns (bytes16) { unchecked { return pow_2(mul(x, 0x3FFF71547652B82FE1777D0FFDA0D23A)); } } /** * Get index of the most significant non-zero bit in binary representation of * x. Reverts if x is zero. * * @return index of the most significant non-zero bit in binary representation * of x */ function mostSignificantBit(uint256 x) internal pure returns (uint256) { unchecked { require(x > 0); uint256 result = 0; if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; } if (x >= 0x10000000000000000) { x >>= 64; result += 64; } if (x >= 0x100000000) { x >>= 32; result += 32; } if (x >= 0x10000) { x >>= 16; result += 16; } if (x >= 0x100) { x >>= 8; result += 8; } if (x >= 0x10) { x >>= 4; result += 4; } if (x >= 0x4) { x >>= 2; result += 2; } if (x >= 0x2) result += 1; // No need to shift x anymore return result; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "./ABDKMathQuad.sol"; library ABDKMathQuadUInt256 { function mul(uint256 x, uint256 y) internal pure returns (uint256) { return ABDKMathQuad.toUInt( ABDKMathQuad.mul( ABDKMathQuad.fromUInt(x), ABDKMathQuad.fromUInt(y) ) ) / 1e18; } function div(uint256 x, uint256 y) internal pure returns (uint256) { return ABDKMathQuad.toUInt( ABDKMathQuad.div( ABDKMathQuad.fromUInt(x * 1e18), ABDKMathQuad.fromUInt(y) ) ); } }
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.22; import "./ABDKMathQuadUInt256.sol"; import "./FairSideFormula2.sol"; import "../interfaces/token/IFair.sol"; // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* library EstimateEthInputLib { using ABDKMathQuadUInt256 for uint256; // estimate eth search iteration uint256 private constant SEARCH_ITERATION = 200; // estimate eth deviation uint256 private constant ESTIMATION_DEVIATION = 0.00001 ether; // 0.001% /** * @dev : estimates the amount of eth to be received */ function estimateReceivedEth( IFair fair, uint256 capitalPool, uint256 networkFShare, uint256 fairAmount ) external view returns (uint256 fairInput, uint256 ethOut) { ethOut = _estimateReceivedEth(capitalPool, networkFShare, fairAmount); fairInput = fair.getTokensBurned(ethOut); } // @dev : estimates the amount of eth to be received, using binary search // @param capitalPool : capital pool // @param fShare : fshare // @param fairAmount : fair amount function _estimateReceivedEth( uint256 capitalPool, uint256 fShare, uint256 fairAmount ) private pure returns (uint256) { uint256 approximatePrice = FairSideFormula2.f(capitalPool, fShare); uint256 ethOut = fairAmount.mul(approximatePrice); // half decay to reduce search scope uint256 decay = ethOut / 2; uint256 fairInput = 0; uint256 count = 0; // max iteration to 200 due to gas limit while (count < SEARCH_ITERATION) { fairInput = FairSideFormula2.getMintedAmount( capitalPool - ethOut, ethOut, fShare ); // ESTIMATION_DEVIATION is due to the approximation of the curve, and it should be below the fairAmount // to prevent overestimate if ( fairAmount > fairInput && fairAmount - fairInput < fairAmount.mul(ESTIMATION_DEVIATION) ) { return ethOut; } if (fairInput > fairAmount) { ethOut -= decay; } else if (fairInput < fairAmount) { ethOut += decay; } decay /= 2; count += 1; } return ethOut; } }
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.22; import "./ABDKMathQuad.sol"; // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* library FairSideFormula2 { using ABDKMathQuad for bytes16; // A constant (adjusted before launch, in precalculated values below assumed to be 0.00015) bytes16 public constant A = 0x3ff23a92a305532617c1bda5119ce075; // C constant (adjusted before launch, in precalculated values below assumed to be 55,000,000) bytes16 public constant C = 0x4018a39de00000000000000000000000; // 0: in quadruple precision form bytes16 public constant ZERO = 0x00000000000000000000000000000000; // 1: in quadruple precision form bytes16 public constant ONE = 0x3fff0000000000000000000000000000; // 2: in quadruple precision form bytes16 public constant TWO = 0x40000000000000000000000000000000; // 3: in quadruple precision form bytes16 public constant THREE = 0x40008000000000000000000000000000; // 1e18 bytes16 private constant NORMALIZER = 0x403abc16d674ec800000000000000000; function _pow3(bytes16 x) private pure returns (bytes16) { return x.mul(x).mul(x); } function _f(bytes16 x, bytes16 fShare) private pure returns (bytes16) { return A.add(_pow3(x).mul(x).div(_pow3(fShare).mul(C))); } // f represents the relation between capital and token price function f(uint256 x, uint256 fShare) public pure returns (uint256) { bytes16 _x = denormalize(x); bytes16 _fShare = denormalize(fShare); return normalize(_f(_x, _fShare)); } // calculate the integral hypothetically assuming A is 0 function _gAdjusted( bytes16 x, bytes16 fShare ) private pure returns (bytes16) { bytes16 fraction = fShare.div(x); return C.neg().mul(fraction).mul(fraction).mul(fraction).div(THREE); } // calculate the average price hypothetically assuming A is 0 function _getAdjustedPrice( bytes16 x, bytes16 deposit, bytes16 fShare ) private pure returns (bytes16) { bytes16 initialSupply = _gAdjusted(x, fShare); bytes16 finalSupply = _gAdjusted(x.add(deposit), fShare); return deposit.div(finalSupply.sub(initialSupply)); } // calculate the minted amount by dividing the deposit by the approximated price, i.e. adding A back to the adjusted price function _getMintedAmount( bytes16 x, bytes16 deposit, bytes16 fShare ) private pure returns (bytes16) { bytes16 approximatedPrice = _getAdjustedPrice(x, deposit, fShare).add( A ); return deposit.div(approximatedPrice); } function getMintedAmount( uint256 x, uint256 deposit, uint256 fShare ) public pure returns (uint256) { return normalize( _getMintedAmount( denormalize(x), denormalize(deposit), denormalize(fShare) ) ); } function normalize(bytes16 x) public pure returns (uint256) { return x.mul(NORMALIZER).toUInt(); } function denormalize(uint256 a) public pure returns (bytes16) { return ABDKMathQuad.fromUInt(a).div(NORMALIZER); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /** * @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. * * By default, the owner account will be the one that deploys the contract. 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. */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* abstract contract FSOwnable { /* ========== STATE VARIABLES ========== */ address private _owner; /* ========== EVENTS ========== */ event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /* ========== ERRORS ========== */ error CallerNotOwner(); error NewOwnerAddressZero(); /* ========== CONSTRUCTOR ========== */ /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } /* ========== VIEWS ========== */ /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /* ========== MUTATIVE FUNCTIONS ========== */ /** * @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 NewOwnerAddressZero(); } emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { if (owner() != msg.sender) { revert CallerNotOwner(); } _; } }
// SPDX-License-Identifier: Unlicense import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; pragma solidity ^0.8.22; interface IERC20ConvictionScore is IERC20 { function governanceConvictionThreshold() external view returns (uint256); function getConvictionForDuration() external view returns (uint256); function minimumBalance() external view returns (uint256); function tokenizeConviction( uint256 tokensToBeLocked, uint256 convictionToBeLocked ) external returns (uint256); function getGovernanceMinimumBalance() external view returns (uint256); function getVestingAmount(address account) external view returns (uint256); } interface ConvictionScore { function getConvictionScore(address user) external view returns (uint256); function isGovernance(address member) external view returns (bool); function getTotalAvailableConviction() external view returns (uint256); } interface ConvictionScorePoints { function burn(address from, uint256 amount) external; function mint(address from, uint256 amount) external; function transfer(address from, address to, uint256 amount) external; function syncConviction(address account) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
pragma solidity ^0.8.22; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface I1inchAggregatorV5 { struct SwapDescription { IERC20 srcToken; IERC20 dstToken; address payable srcReceiver; address payable dstReceiver; uint256 amount; uint256 minReturnAmount; uint256 flags; bytes permit; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface ITributeAccrual is IERC20 { function totalAvailableReward() external view returns (uint256, uint256, uint256); }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./IFairSideSchema.sol"; interface IFairSideClaims is IFairSideSchema { /** * @dev {CostShareRequest} struct contains parameters representing a Cross Share Request (CSR). * creation: CSR creation date. * initiator: Creator of CSR. * coverId: Cover ID associated with the claim. * csrType: CSR type. * availableBenefits: Available benefits of the membership locked during the claim, its also the maximum amount that can be paid. * claimAmount: Claim amount of CSR in ETH. * payoutAmount: payout amount of CSR in ETH set by Guardian. * evidence: Evidence associated with CSR. * originalClaimId: original claim ID associated with an appeal, if its bigger than 0 then its an appeal. * fairBounty: Bounty associated with CSR (0.4 % of the member's available cross share benefits). * status: Status of CSR. */ struct CostShareRequest { uint80 creation; address initiator; uint256 coverId; uint256 csrType; uint256 availableBenefits; uint256 claimAmount; uint256 payoutAmount; bytes32 evidence; uint256 originalClaimId; uint256 appealId; ClaimStatus status; } /** * @dev Actions to perform on Cost Share Request (CSR). * ApproveClaim: Action for acceptance of CSR. * DenyClaim: Action for rejection of CSR. */ enum Action { APPROVE_CLAIM, DENY_CLAIM } /** * @dev Claim status on Cost Share Request (CSR). * IN_PROGRESS: in progress * Approved: approved * DENIED: denied * PAID: paid * VERIFICATION_APPROVED: verification approved * VERIFICATION_DENIED: verification denied */ enum ClaimStatus { VOID, IN_PROGRESS, APPROVED, DENIED, PAID, VERIFICATION_APPROVED, VERIFICATION_DENIED } struct ClaimCheck { uint256 claimId; uint256 count; } struct ClaimStatistics { uint256 opened; uint256 claimed; } function totalOpenRequests() external view returns (uint256); /* ========== EVENTS ========== */ // An event emitted when a CSR is submitted event CreateCSR( uint256 id, address beneficiary, uint256 availableBenefit, uint256 payoutAmount, uint256 csrType, uint256 timestamp, uint256 orignalClaimId ); // An event emitted when a CSR is accepted event ApproveCSR( uint256 indexed id, uint256 indexed csrType, address assessor, uint256 timestamp ); // An event emitted when a CSR is rejected event DenyCSR( uint256 indexed id, uint256 indexed csrType, address assessor, bytes reason, uint256 timestamp ); // An event emitted when a CSR is verified event VerifyCSR(uint256 indexed id, bool appoved, uint256 timestamp); //An event emitted when a new csrType is approved or disabled event Event(uint256 indexed csrType, bool status); //An event emitted when a new csrType is approved or disabled event PaidCSR( uint256 indexed claimId, uint256 indexed amount, address indexed payoutAddress ); }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./IFairSideSchema.sol"; interface IFairSideNetwork is IFairSideSchema { function PREMIUM_REWARD_ADDRESS() external view returns (address); function FUNDING_POOL() external view returns (address); function getCapitalPool() external view returns (uint256); function getTotalOpenRequests() external view returns (uint256); function getFairPrice() external view returns (uint256); function getNetworkFShare() external view returns (uint256); function hasPassedGracePeriod(uint256 coverId) external view returns (bool); function getCoverCost( uint256 membershipTypeId ) external view returns (uint256); function getMembership( uint256 coverId ) external view returns (Membership memory); function increaseOrDecreaseCSB( uint256 amount, address account, uint256 coverId, bool increase ) external; function blockMembership(uint256 coverId, bool blocked) external; function decrementTotalPWPCSB(uint256 amount) external; function removeExpiredMembershipCSB(uint256 coverId) external; }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; interface IFairSideSchema { /** * @dev CoverTypes in the Fairside Network ecosystem * - Personal wallet protection * - Defi Cover * - Exchange cover */ struct Membership { address wallet; uint80 creation; bool blocked; address owner; uint80 expirationDate; uint256 availableCostShareBenefits; uint256 paidCostShareBenefits; uint256 membershipTypeId; uint256 coverCost; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; interface IFair { /** * @dev Phases of the Fair token. * Premine: Token pre-mine * KOL: KOL token pre-mine * VCWL: Venture Capital white-list * CWL: Community white-list ( Deprecated) * Final: Curve indefinitely open */ enum Phase { Premine, KOL, VCWL, Final } struct AccountUnbonding { uint256 lastUnbondTimestamp; uint256 amountUnbonded; } function currentPhase() external view returns (Phase); function getTokensMinted( uint256 investment ) external view returns (uint256); function payClaim(address beneficiary, uint256 amount) external; function bond(uint256 tokenMinimum) external payable returns (uint256); function bondTo( address to, uint256 tokenMinimum ) external payable returns (uint256); function bondAndBurn() external payable; function bondNoEmission() external payable; function mintPremineAdmin( address[] calldata adminMultisigs, uint256[] calldata amounts ) external; function currentDailyUnbondableAmount() external view returns (uint256); function capitalPoolAvailableFund() external view returns (uint256); function getAvailableETHForWithdraw() external view returns (uint256); function getTokensBurned( uint256 investment ) external view returns (uint256); function estimateReceivedEth( uint256 fairAmount ) external view returns (uint256 fairInput, uint256 ethOut); }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; interface IFairVestingFactory { function createVestingPRE( address beneficiary, uint256 amount ) external returns (address); function createVestingVC( address beneficiary, uint256 amount ) external returns (address); function createVestingKOL( address beneficiary, uint256 amount ) external returns (address); }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; interface IFairVesting { function claimVestedTokens() external; function createVesting(address account, uint256 _amount) external; function increaseAccountVesting(address account, uint256 amount) external; function decreaseAccountVesting(address account, uint256 amount) external; function getCurrentVestingAmount( address account ) external view returns (uint256); function getVestedAmount(address account) external view returns (uint256); function batchCreateVesting( address[] calldata accounts, uint256[] calldata _amounts ) external; function getTotalVestedTokens() external view returns (uint256); function getTotalClaimedTokens() external view returns (uint256); function getUnclaimedTokens() external view returns (int256); }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; interface IFairVestingRegistry { function getCurrentVesting(address account) external view returns (uint256); function getTotalVestedAmount( address account ) external view returns (uint256); function getTotalUnclaimedVesting() external view returns (int256); function getTotalVested() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; interface AggregatorV3Interface { function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } contract DummyPriceOracle is AggregatorV3Interface { int256 public value = 300000000000; constructor() { set(value); } function set(int256 _value) public { value = _value; } function latestRoundData() external view override returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ) { return ( 110680464442257314889, value, 1693886147, 1693886147, 110680464442257314889 ); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.22; interface IWETH { function deposit() external payable; function withdraw(uint256) external; function approve(address, uint256) external returns (bool); function transfer(address, uint256) external returns (bool); function transferFrom(address, address, uint256) external returns (bool); function balanceOf(address) external view returns (uint256); }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract CharlesToken is ERC20, Ownable { constructor() ERC20("CharlesToken", "MTK") { _mint(msg.sender, 100_000_000 * 10 ** decimals()); } function mint(address to, uint256 amount) public onlyOwner { _mint(to, amount); } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MockToken is ERC20, Ownable { constructor( string memory _symbol, string memory _name, uint8 _decimals ) ERC20(_symbol, _name) {} function mint(address account, uint256 amount) public onlyOwner { _mint(account, amount); } function burn(address account, uint256 amount) public onlyOwner { _burn(account, amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "../../network/FairSideClaims.sol"; contract FairSideClaimsV2 is FairSideClaims { /** * @notice shows the version of the contract being used * @dev the value represents the curreent version of the contract should be updated and overriden with new implementations * @return version -the current version of the contract */ function version() external pure override returns (string memory) { return "1.1.0"; } }
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.22; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../../dependencies/FairSideFormula2.sol"; import "../../dependencies/ABDKMathQuadUInt256.sol"; import "../../interfaces/network/IFairSideClaims.sol"; import "../../interfaces/network/IFairSideNetwork.sol"; import "../../interfaces/token/IFair.sol"; import "../../admin/IFairsideAdmin.sol"; interface IFairSideNetworkErrors { /** * @dev FairSideNetwork-related custom errors */ error FSNetwork_ActiveMembershipRequired(); error FSNetwork_ChainlinkPriceStale(); error FSNetwork_ChainlinkMalfunction(); error FSNetwork_ExceedsCSBLimitPerAccount(); error FSNetwork_InvalidCostShareBenefitSpecified(); error FSNetwork_MembershipTopupDisabled(); error FSNetwork_ExceedsCostShareBenefitLimitPerAccount(); error FSNetwork_MembershipNotExpired(); error FSNetwork_MembershipExpired(); error FSNetwork_PremiumFeeSentIsLessThanRequired(); error FSNetwork_NotEnoughFair(); error FSNetwork_InsufficientApproval(); error FSNetwork_InvalidCoverIdForAccount(); error FSNetwork_IncorrectValueSpecified(); error FSNetwork_CannotChange(); error FSNetwork_IncorrectSlippageSpecified(); error FSNetwork_InsufficientPrivileges(); error FSNetwork_CurveIsClosedUseETH(); error FSNetwork_OnlyPremiumPoolCanCall(); error FSNetwork_OnlyFairSideClaimsCanCall(); error FSNetwork_ExceedsMaxCostShareBenefitLimit(); error FSNetwork_IncorrectLossRatioSpecified(); error FSNetwork_OnlyMembershipPurchaseProxyCanCall(); error FSNetwork_FairPurchaseDisabled(); error FSNetwork_InsufficientPrivilegesOnlyGuardian(); error FSNetwork_InsufficientPrivilegesOnlyAdmin(); error FSNetwork_MembershipBlocked(); error FSNetwork_OnlyFairSideBountyPoolCanCall(); error FSNetwork_MembershipTypeDisabled(); } /** * @dev Implementation of {FairSideNetwork}. * * The FairSideNetwork contract allows purchasing of network membership using * ETH/Fair. The Fair tokens collected in fees are distribute among the contract, * staking tribute, governance tribute and funding pool in specific percentages. * * Allows opening, updating and processing of Cross Share Requests. * * Attributes: * - Supports the full workflow of a cost share request * - Handles Fair membership * - Handles governance rewards * - Retrieves ETH price via Chainlink * - Calculates Fair price via Uniswap using Time-Weighted Price Averages (TWAP) */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract FairSideNetworkV2 is IFairSideNetwork, IFairSideNetworkErrors, Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable { /* ========== LIBRARIES ========== */ using AddressUpgradeable for address payable; using ABDKMathQuadUInt256 for uint256; uint256 private constant MAXIMUM_GRACE_PERIOD = 100 * 365 days; // 100 years struct MembershipType { uint256 duration; uint256 gracePeriod; uint256 topupDisabledPeriod; uint256 minimumPurchaseAmount; uint256 maximumBenefitPerUser; uint256 cost; bool active; } /* ========== STATE VARIABLES ========== */ //mapping of id -> Memberships mapping(uint256 => Membership) private membership; //mapping of account (address) -> memberships mapping(address => uint256[]) internal userMembership; //mapping of addresses covered by an address / account mapping(address => address[]) internal userCoveredAddress; mapping(uint256 => MembershipType) public membershipTypes; uint256 public numMembershipTypes; // Tracking the number of cover ids uint256 public membershipCount; // Cost share benefits of the entire personal wallet protection cover in ETH uint256 public totalPWPCSB; // total cover cost received from users uint256 public totalCoverCost; //network gearing factor used for membership calculation uint256 public networkGearingFactor; // Risk based capital uint256 public riskBasedCapital; // estimated loss ratio uint256 public lossRatio; // Supported tokens for membership purchase, top up enum TokenType { ETH, Fair } // Fair Token contract Address IFair private fair; //Fair Network IFairSideClaims public fairSideClaims; // Funding Pool Address address public override FUNDING_POOL; // Premiums Pool Address address public PREMIUMS_POOL; //patners pool address address address public PARTNERS_ADDRESS; // Premium Reward multisign Address address public override PREMIUM_REWARD_ADDRESS; // membership purchase proxy address public membershipPurchaseProxy; // Bountry pool contract address address public FairSIDE_BOUNTY_POOL; // Timelock Address, owned by Governance address public TIMELOCK; // 20% as staking rewards uint256 public STAKING_REWARDS; // 15% patner pool rewards uint256 public PARTNERS_POOL_ALLOCATION; //7.5% as funding pool uint256 public FUNDING_POOL_ALLOCATION; bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); // enable or disable Fair purchase bool public fairPurchaseEnabled; // Admin contract IFairsideAdmin private fairsideAdmin; /* ========== EVENTS ========== */ // An event emitted when a membership is purchased (either new or an extension) event NewMembership( address indexed member, uint256 coverId, uint256 costshareBenefit, address indexed coverAddress, TokenType tokenType, uint256 membershipTypeId ); // An event emitted when a membership is topped up event TopUpCover( address indexed member, uint256 coverId, uint256 costshareBenefit, TokenType tokenType ); // An event for setting Fair Premium Reward contract address event SetFairPremiumReward(address indexed premiumRewardContract); // An event for setting ETH Premium Reward contract address event SetETHPremiumReward(address indexed premiumRewardContract); // An event for setting Network gearing factor event SetNetworkGearingFactor(uint256 networkGearingFactor); // An event for setting Risk based capital event SetRiskBasedCapital(uint256 riskBasedCapital); // An event for setting Loss ratio event SetLossRatio(uint256 lossRatio); event SetFeeDistributionPercenages( uint256 fundingPoolAllocation, uint256 partnersPoolAllocation, uint256 stakingRewards, uint256 lossRatio ); // An event for sending Staking rewards on Fair event PremiumFairDistributed( uint256 fundingPremium, uint256 parntersPremium, uint256 stakingRewards, uint256 curveReserve ); // An event for sending Staking rewards on ETH event PremiumEthDistributed( uint256 fundingPremium, uint256 parntersPremium, uint256 stakingRewards, uint256 curveReserve ); // An event for setting the token gearing factor event TokenGearingFactorSet(uint256 tokenGearingFactor); // An event for setting the Fair purchase enabled event SetFairPurchaseEnabled(bool fairPurchaseEnabled); constructor() { _disableInitializers(); } /** * @dev Initialises the contract's state setting fair, FUNDING_POOL * and TIMELOCK addresses. */ function initialize( IFair _fair, address fundingPool, address premiumsPool, IFairsideAdmin _fairsideAdmin, address timelock, address patnersPool, address premiumReward ) public initializer { __UUPSUpgradeable_init(); __ReentrancyGuard_init(); fair = _fair; FUNDING_POOL = fundingPool; PREMIUMS_POOL = premiumsPool; fairsideAdmin = _fairsideAdmin; TIMELOCK = timelock; PARTNERS_ADDRESS = patnersPool; PREMIUM_REWARD_ADDRESS = premiumReward; membershipPurchaseProxy = msg.sender; fairPurchaseEnabled = false; // 20% staking rewards STAKING_REWARDS = 0.20 ether; // 15% patner pool rewards PARTNERS_POOL_ALLOCATION = 0.15 ether; // 7.5% as funding pool FUNDING_POOL_ALLOCATION = 0.075 ether; riskBasedCapital = 2500 ether; lossRatio = 0.575 ether; //57.5% networkGearingFactor = 50; _addMembershipType( 365 days, 60 days, 182 days, 1 ether, 100 ether, 0.0195 ether ); } function addMembershipType( uint256 duration, uint256 gracePeriod, uint256 topupDisabledPeriod, uint256 minimumPurchaseAmount, uint256 maximumBenefitPerUser, uint256 cost ) external onlyAdmin { _addMembershipType( duration, gracePeriod, topupDisabledPeriod, minimumPurchaseAmount, maximumBenefitPerUser, cost ); } function _addMembershipType( uint256 duration, uint256 gracePeriod, uint256 topupDisabledPeriod, uint256 minimumPurchaseAmount, uint256 maximumBenefitPerUser, uint256 cost ) private { // duration should be divisible by 1 day if ( duration == 0 || (duration % 1 days != 0) || cost == 0 || topupDisabledPeriod > duration || gracePeriod > MAXIMUM_GRACE_PERIOD ) { revert FSNetwork_IncorrectValueSpecified(); } membershipTypes[numMembershipTypes] = MembershipType({ duration: duration, gracePeriod: gracePeriod, topupDisabledPeriod: topupDisabledPeriod, minimumPurchaseAmount: minimumPurchaseAmount, maximumBenefitPerUser: maximumBenefitPerUser, cost: cost, active: true }); unchecked { numMembershipTypes += 1; } } function disableMembershipType(uint256 index) external onlyAdmin { membershipTypes[index].active = false; } /** * @dev Setting the fairside claims contract */ function setFairSideClaims( IFairSideClaims _fairSideClaims ) external onlyAdmin { fairSideClaims = _fairSideClaims; } /* * @dev Setting the fairside bounty pool contract */ function setFairSideBountyPool( address _fairSideBountyPool ) external onlyAdmin { FairSIDE_BOUNTY_POOL = _fairSideBountyPool; } /** * @dev returns the list of cover ids purchased by an address */ function getAccountMembership( address account ) external view returns (uint256[] memory) { return userMembership[account]; } /** * @dev returns the list of covered addresses covered by an address */ function getAccountCoveredWallets( address account ) external view returns (address[] memory) { return userCoveredAddress[account]; } /** * @notice returns Membership state containing * (availableCostShareBenefits, duration, creation, owner account, covered wallet) */ function getMembership( uint256 coverId ) external view override returns (Membership memory) { return membership[coverId]; } /** * @dev Token price evaluated as spot price directly on curve */ function getFairPrice() public view override returns (uint256) { uint256 fShare = getNetworkFShare(); uint256 capitalPool = getCapitalPool(); return FairSideFormula2.f(capitalPool, fShare); } /** * @dev : checks if membership still valid using grace period */ function hasPassedGracePeriod( uint256 coverId ) external view override returns (bool) { Membership memory _membership = membership[coverId]; if (_membership.availableCostShareBenefits <= 0) { revert FSNetwork_ActiveMembershipRequired(); } return block.timestamp > _membership.expirationDate + membershipTypes[_membership.membershipTypeId].gracePeriod; } /** * @notice : returns the maximum CSB based on RSB and network gearing factor */ function getMaxTotalCostShareBenefits() public view returns (uint256) { return riskBasedCapital * networkGearingFactor; } /** * @notice get amount in capital pool (ETH) * @dev : Capital Pool = Total Funds held in ETH – Open Cost Share Requests * Open Cost Share Request = Cost share request awaiting assessor consensus */ function getCapitalPool() public view override returns (uint256) { return address(fair).balance - getTotalOpenRequests(); } /** * @notice : returns cover cost of a cover */ function getCoverCost( uint256 membershipTypeId ) external view override returns (uint256 coverCost) { return membershipTypes[membershipTypeId].cost; } /** * @notice Allows purchasing of membership of Fair Network with ETH and Fair * * @dev It accepts ETH to allocate the available cross share benefits * for a member and also determines membership purchase cost. * * The membership is purchased using ETH, 57.5% of which remains in the curve, * 20% is allocated with staking rewards, 7.5% is allocated for the {PREMIUMS_POOL} * and 7.5% is sent to {FUNDING_POOL}. * */ function purchaseMembership( uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external payable validateOpenCurve(TokenType.ETH) { _purchaseMembership( msg.sender, costShareBenefit, coverAddress, membershipType, TokenType.ETH ); } /* * @notice : Allows purchasing of membership of Fair Network with ETH from a membershipPurchaseProxy */ function purchaseMembershipFromProxy( address primaryAddress, uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external payable validateOpenCurve(TokenType.ETH) onlyMembershipPurchaseProxy { _purchaseMembership( primaryAddress, costShareBenefit, coverAddress, membershipType, TokenType.ETH ); } /** * @notice Allows purchasing of membership with Fair */ function purchaseMembershipWithFair( uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external onlyFairPurchaseEnabled validateOpenCurve(TokenType.Fair) { _purchaseMembership( msg.sender, costShareBenefit, coverAddress, membershipType, TokenType.Fair ); } /* * @notice : Allows purchasing of membership of Fair Network with Fair from a membershipPurchaseProxy */ function purchaseMembershipWithFairFromProxy( address primaryAddress, uint256 costShareBenefit, address coverAddress, uint256 membershipType ) external onlyFairPurchaseEnabled validateOpenCurve(TokenType.Fair) onlyMembershipPurchaseProxy { _purchaseMembership( primaryAddress, costShareBenefit, coverAddress, membershipType, TokenType.Fair ); } /** * @notice : Top up a current exisiting purchased cover with ETH * @dev : the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function topupMembership( uint256 coverId, uint256 costshareBenefit ) external payable validateOpenCurve(TokenType.ETH) { _topupMembership(coverId, costshareBenefit, TokenType.ETH); } /** * @notice : Top up a current exisiting purchased cover with Fair * @dev : the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function topupMembershipWithFair( uint256 coverId, uint256 costshareBenefit ) external onlyFairPurchaseEnabled validateOpenCurve(TokenType.Fair) { _topupMembership(coverId, costshareBenefit, TokenType.Fair); } /** * @dev : handles premium membership purchase, for PWP applies the PWP gearing factor {PWPGearing} and PWPfshareRation for PWP cover purchase * and uses the default fshare and fshareRatio for other covers * the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function _purchaseMembership( address primaryAddress, uint256 costShareBenefit, address coverAddress, uint256 membershipTypeId, TokenType tokenType ) private nonReentrant { validateCapitalPool(costShareBenefit, membershipTypeId); MembershipType memory membershipType = membershipTypes[ membershipTypeId ]; if (!membershipType.active) { revert FSNetwork_MembershipTypeDisabled(); } if (costShareBenefit > _getMaximumBenefitPerUser(membershipTypeId)) { revert FSNetwork_ExceedsCSBLimitPerAccount(); } //calculate membership cost uint256 coverCostETH = calculateCoverCost( costShareBenefit, 0, membershipType.duration, membershipType.cost ); distributePremium(coverCostETH, tokenType); unchecked { membershipCount += 1; } uint256 coverId = membershipCount; Membership storage membershipId = membership[coverId]; //update storages totalPWPCSB += costShareBenefit; totalCoverCost += coverCostETH; membershipId.availableCostShareBenefits = costShareBenefit; membershipId.creation = uint80(block.timestamp); membershipId.expirationDate = uint80( block.timestamp + membershipType.duration ); membershipId.owner = primaryAddress; membershipId.wallet = coverAddress; membershipId.membershipTypeId = membershipTypeId; membershipId.coverCost += coverCostETH; userMembership[primaryAddress].push(coverId); userCoveredAddress[primaryAddress].push(coverAddress); emit NewMembership( primaryAddress, coverId, costShareBenefit, coverAddress, tokenType, membershipTypeId ); } /** * @dev : validate if the cost share benefit meets the required threshold * and the capital pool has enough funds to cover the membership */ function validateCapitalPool( uint256 costShareBenefit, uint256 membershipTypeId ) private view { //mimimun CSB if ( costShareBenefit < membershipTypes[membershipTypeId].minimumPurchaseAmount ) { revert FSNetwork_InvalidCostShareBenefitSpecified(); } if (totalPWPCSB + costShareBenefit > getMaxTotalCostShareBenefits()) { revert FSNetwork_ExceedsMaxCostShareBenefitLimit(); } } /** * @dev : handles premium membership purchase, for PWP applies the PWP gearing factor {PWPGearing} and PWPfshareRation for PWP cover purchase * and uses the default fshare and fshareRatio for other covers * the prorated cost is charged { cost on time of purchase 360 days = full % of cover} */ function _topupMembership( uint256 coverId, uint256 costShareBenefit, TokenType tokenType ) private onlyNotBlocked(coverId) nonReentrant { Membership storage membershipId = membership[coverId]; validateCapitalPool(costShareBenefit, membershipId.membershipTypeId); MembershipType memory membershipType = membershipTypes[ membershipId.membershipTypeId ]; uint256 membershipExpirationDate = membershipId.expirationDate; if ( block.timestamp >= membershipExpirationDate - membershipType.topupDisabledPeriod ) { revert FSNetwork_MembershipTopupDisabled(); } uint256 userMembershipCSB = membershipId.availableCostShareBenefits + costShareBenefit; if ( userMembershipCSB > _getMaximumBenefitPerUser(membershipId.membershipTypeId) ) { revert FSNetwork_ExceedsCostShareBenefitLimitPerAccount(); } uint256 coverCostETH = calculateCoverCost( costShareBenefit, membershipExpirationDate, membershipType.duration, membershipType.cost ); distributePremium(coverCostETH, tokenType); totalPWPCSB += costShareBenefit; totalCoverCost += coverCostETH; membershipId.availableCostShareBenefits = userMembershipCSB; membershipId.coverCost += coverCostETH; emit TopUpCover( membershipId.wallet, coverId, costShareBenefit, tokenType ); } /** * @dev : checks if the cover cost is sufficient * and distributes premiums to pools based on the token type provided */ function distributePremium( uint256 membershipFeeETH, TokenType tokenType ) internal { if (tokenType == TokenType.ETH) { if (msg.value < membershipFeeETH) { revert FSNetwork_PremiumFeeSentIsLessThanRequired(); } premiumDistributionETH(membershipFeeETH); } else { //convert to Fair uint256 membershipFeeFair = membershipFeeETH.div(getFairPrice()); IERC20 _fairToken = IERC20(address(fair)); if (_fairToken.balanceOf(msg.sender) < membershipFeeFair) { revert FSNetwork_NotEnoughFair(); } //receive fair from user _fairToken.transferFrom( msg.sender, address(this), membershipFeeFair ); //distribute premium premiumDistributionFair(membershipFeeFair); } } /* * @dev : remove expired membership's csb from the network */ function removeExpiredMembershipCSB( uint256 coverId ) external override onlyFairSideBountyPool { Membership storage membershipId = membership[coverId]; if (membershipId.availableCostShareBenefits <= 0) { revert FSNetwork_ActiveMembershipRequired(); } MembershipType memory membershipType = membershipTypes[ membershipId.membershipTypeId ]; uint256 gracePeriod = membershipId.expirationDate + membershipType.gracePeriod; if (block.timestamp < gracePeriod) { revert FSNetwork_MembershipNotExpired(); } totalPWPCSB -= membershipId.availableCostShareBenefits; totalCoverCost -= membershipId.coverCost; membershipId.availableCostShareBenefits = 0; membershipId.coverCost = 0; } /** * @dev : estimates the cost of a cover with given amount */ function estimateCost( uint256 costShareBenefit, uint256 expirationDate, uint256 membershipTypeId ) external view returns (uint256) { MembershipType memory membershipType = membershipTypes[ membershipTypeId ]; return calculateCoverCost( costShareBenefit, expirationDate, membershipType.duration, membershipType.cost ); } /** * @dev changes the premiums pool address to a new address */ function setPremiumsPool(address _newPremiumsPool) external onlyAdmin { PREMIUMS_POOL = _newPremiumsPool; } /* * @dev changes the funding pool address to a new address */ function setFundingPool( address payable _newFundingPool ) external onlyAdmin { FUNDING_POOL = _newFundingPool; } /** * @dev changes the partners pool address to a new address */ function setPartnersPool(address _newPartnersPool) external onlyAdmin { PARTNERS_ADDRESS = _newPartnersPool; } /** * @dev changes the premium reward address to a new address */ function setPremiumRewardAddress( address _newPremiumRewardAddress ) external onlyAdmin { PREMIUM_REWARD_ADDRESS = _newPremiumRewardAddress; } /** * @dev changes the membership purchase proxy address to a new address */ function setMembershipPurchaseProxy( address _newMembershipPurchaseProxy ) external onlyAdmin { membershipPurchaseProxy = _newMembershipPurchaseProxy; } /** * @notice This method handles the distribution of Fair to different pools * @dev it's called after a membership is purchased, topped up by Fair * Once the Fair is recieved smart staking calculation is done * DISTRIBUTION IS HANDLED AS * Staking Rewards 20% sent to rewardsContract * Gov. 7.5% = sent to funding pool * Partners Pool 15% sent to Premiums Pool * 57.5% burnt */ function premiumDistributionFair(uint256 fairToDistribute) private { if (IERC20(address(fair)).balanceOf(address(this)) < fairToDistribute) { revert FSNetwork_NotEnoughFair(); } //Calculate funding pool rewards uint256 fundingPremium = fairToDistribute.mul(FUNDING_POOL_ALLOCATION); uint256 parntersPremium = fairToDistribute.mul( PARTNERS_POOL_ALLOCATION ); uint256 stakingRewards = fairToDistribute.mul(STAKING_REWARDS); uint256 curveReserve = fairToDistribute.mul(lossRatio); ERC20Burnable _fairToken = ERC20Burnable(address(fair)); // 7,5% sent to governance _fairToken.transfer(FUNDING_POOL, fundingPremium); //patners pool 15% _fairToken.transfer(PARTNERS_ADDRESS, parntersPremium); // 20% staking rewards _fairToken.transfer(PREMIUM_REWARD_ADDRESS, stakingRewards); // burn remaining 57.5% _fairToken.burn(curveReserve); //register premium distribution in Fair emit PremiumFairDistributed( fundingPremium, parntersPremium, stakingRewards, curveReserve ); } /** * @notice This method handles the distribution of ETH to different pools * @dev it's called after a membership is purchased, topped up by ETH * Once the ETH is recieved smart staking calculation is done * DISTRIBUTION IS HANDLED AS * Staking Rewards 20% sent to rewardsContract * Gov. 7.5% = sent to funding pool * Partners Pool 15% sent to Premiums Pool * 57.5% sent to curve with no emission of FS */ function premiumDistributionETH(uint256 ethToDistribute) private { //Calculate funding pool rewards uint256 fundingPremium = ethToDistribute.mul(FUNDING_POOL_ALLOCATION); uint256 parntersPremium = ethToDistribute.mul(PARTNERS_POOL_ALLOCATION); uint256 stakingRewards = ethToDistribute.mul(STAKING_REWARDS); uint256 curveReserve = ethToDistribute.mul(lossRatio); // 7,5% sent to governance payable(FUNDING_POOL).sendValue(fundingPremium); //patners pool 15% payable(PARTNERS_ADDRESS).sendValue(parntersPremium); //add staking reward in ETH to be distributed payable(PREMIUM_REWARD_ADDRESS).sendValue(stakingRewards); //send remaining 57.5% to the curve fair.bondNoEmission{value: curveReserve}(); //register premium distribution in ETH emit PremiumEthDistributed( fundingPremium, parntersPremium, stakingRewards, curveReserve ); // send back excess ETH if (msg.value > ethToDistribute) { payable(msg.sender).sendValue(msg.value - ethToDistribute); } } /* ========== RESTRICTED FUNCTIONS ========== */ /** * @notice : increases or decreases the CSB when a claims requested is created. * @dev Can only be called by the fairside claims contract */ function increaseOrDecreaseCSB( uint256 amount, address account, uint256 coverId, bool increase ) external override onlyFairSideClaims { Membership storage membershipId = membership[coverId]; if (membershipId.owner != account) { revert FSNetwork_InvalidCoverIdForAccount(); } if (increase) { membershipId.availableCostShareBenefits += amount; } else { membershipId.availableCostShareBenefits -= amount; } } /** * @notice : block cover when a claim is created, unblock when claim is resolved * @dev Can only be called by the fairside claims contract */ function blockMembership( uint256 coverId, bool blocked ) external override onlyFairSideClaims { Membership storage membershipId = membership[coverId]; membershipId.blocked = blocked; } /** * @notice This method flushes out assets mistakenly sent to the contract * @dev Can only be called by the premium pool multisig */ function flushAsset( address tokenContractAddress, address payable destination ) external payable onlyPremiumPool { if (tokenContractAddress == address(0)) { destination.sendValue(address(this).balance); } else { IERC20 tokenContract = ERC20(tokenContractAddress); tokenContract.transfer( destination, tokenContract.balanceOf(address(this)) ); } } /** * @dev Sets the gearing factor used for signing new memberships * * Requirements: * - only callable by governance or timelock contracts. */ function setNetworkGearingFactor( uint256 _gearingFactor ) external onlyTimelock { if (_gearingFactor == 0) { revert FSNetwork_IncorrectValueSpecified(); } networkGearingFactor = _gearingFactor; emit SetNetworkGearingFactor(_gearingFactor); } /** * @dev Sets the risk based capital used for calculating the network FSHARE * * Requirements: * - only callable by governance or timelock contracts. */ function setRiskBasedCapital( uint256 _riskBasedCapital ) external onlyTimelock { riskBasedCapital = _riskBasedCapital; emit SetRiskBasedCapital(_riskBasedCapital); } /** * @dev Sets the distribution percentages * * Requirements: * - only callable by governance or timelock contracts. */ function setFeeDistributionPercentages( uint256 _fundingPoolAllocation, uint256 _partnersPoolAllocation, uint256 _stakingRewards, uint256 _lossRatio ) external onlyTimelock { if ( _fundingPoolAllocation + _partnersPoolAllocation + _stakingRewards + _lossRatio != 1 ether ) { revert FSNetwork_IncorrectValueSpecified(); } FUNDING_POOL_ALLOCATION = _fundingPoolAllocation; PARTNERS_POOL_ALLOCATION = _partnersPoolAllocation; STAKING_REWARDS = _stakingRewards; lossRatio = _lossRatio; emit SetFeeDistributionPercenages( _fundingPoolAllocation, _partnersPoolAllocation, _stakingRewards, _lossRatio ); } /** * @dev Set flag for enabling or disabling Fair purchase * * Requirements: * - only callable by governance or timelock contracts. */ function setEnableFairPurchase( bool _fairPurchaseEnabled ) external onlyTimelock { fairPurchaseEnabled = _fairPurchaseEnabled; emit SetFairPurchaseEnabled(_fairPurchaseEnabled); } /* ========== INTERNAL FUNCTIONS ========== */ /* * @dev : decrement total cost share benefits after a claim is paid out */ function decrementTotalPWPCSB( uint256 costShareBenefit ) external override onlyFairSideClaims { totalPWPCSB -= costShareBenefit; } /** * @dev Calculates the prorated cover cost of a given cover * @return cover cost (uint) */ function calculateCoverCost( uint256 costShareBenefit, uint256 coverPeriod, uint256 duration, uint256 coverCost ) internal view returns (uint256) { uint256 fee = costShareBenefit.mul(coverCost); if (block.timestamp > coverPeriod) { return fee; } else { uint256 dailycost = coverCost / (duration / 1 days); uint256 coverDuration = coverPeriod - block.timestamp; uint256 daysRemaining = coverDuration / 1 days; // round up to the nearest day if (coverDuration % 1 days != 0) { daysRemaining += 1; } uint256 rate = daysRemaining * dailycost; uint256 proratedCostETH = costShareBenefit.mul(rate); return proratedCostETH; } } function _authorizeUpgrade( address newImplementation ) internal override onlyGuardian {} /** * @notice Return Open cost share requests in ETH */ function getTotalOpenRequests() public view returns (uint256) { return fairSideClaims.totalOpenRequests(); } function isOpenCurve() public view returns (bool) { return fair.currentPhase() == IFair.Phase.Final; } /** * @notice : calculates FSHARE risk based capital and loss ratio over * the total cost share benefits */ function getNetworkFShare() public view override returns (uint256) { return riskBasedCapital + lossRatio.mul(totalCoverCost); } /** * @dev Returns maximum cross share benefit allowed per user. */ function _getMaximumBenefitPerUser( uint256 membershipTypeId ) internal view returns (uint256) { return membershipTypes[membershipTypeId].maximumBenefitPerUser; } /** * @notice shows the version of the contract being used * @dev the value represents the current version of the contract should be updated and overriden with new implementations * @return version -the current version of the contract */ function version() external pure virtual returns (string memory) { return "1.1.0"; } /* ========== MODIFIERS ========== */ modifier onlyTimelock() { if (msg.sender != TIMELOCK) { revert FSNetwork_InsufficientPrivileges(); } _; } modifier validateOpenCurve(TokenType tokenType) { if (tokenType != TokenType.ETH) { if (!isOpenCurve()) { revert FSNetwork_CurveIsClosedUseETH(); } } _; } modifier onlyPremiumPool() { if (msg.sender != PREMIUMS_POOL) { revert FSNetwork_OnlyPremiumPoolCanCall(); } _; } modifier onlyFairSideClaims() { if (msg.sender != address(fairSideClaims)) { revert FSNetwork_OnlyFairSideClaimsCanCall(); } _; } modifier onlyNetworkOrClaims() { if ( msg.sender != address(fairSideClaims) && msg.sender != address(this) ) revert FSNetwork_OnlyFairSideClaimsCanCall(); _; } modifier onlyFairSideBountyPool() { if (msg.sender != FairSIDE_BOUNTY_POOL) { revert FSNetwork_OnlyFairSideBountyPoolCanCall(); } _; } modifier onlyMembershipPurchaseProxy() { if (msg.sender != membershipPurchaseProxy) { revert FSNetwork_OnlyMembershipPurchaseProxyCanCall(); } _; } modifier onlyFairPurchaseEnabled() { if (!fairPurchaseEnabled) { revert FSNetwork_FairPurchaseDisabled(); } _; } modifier onlyGuardian() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_NETWORK_GUARDIAN_ROLE, msg.sender ) ) { revert FSNetwork_InsufficientPrivilegesOnlyGuardian(); } _; } modifier onlyAdmin() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_ADMIN_ROLE, msg.sender ) ) { revert FSNetwork_InsufficientPrivilegesOnlyAdmin(); } _; } modifier onlyNotBlocked(uint256 coverId) { if (membership[coverId].blocked) { revert FSNetwork_MembershipBlocked(); } _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "../../vesting/FairVestingRegistry.sol"; contract FairVestingRegistryV2 is FairVestingRegistry { /** * @notice shows the version of the contract being used * @dev the value represents the curreent version of the contract should be updated and overriden with new implementations * @return version -the current version of the contract */ function version() external pure override returns (string memory) { return "1.1.0"; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../interfaces/network/IFairSideNetwork.sol"; import "../interfaces/network/IFairSideClaims.sol"; import "../dependencies/ABDKMathQuadUInt256.sol"; import "../token/Fair.sol"; import "../admin/IFairsideAdmin.sol"; interface IFairSideBountyPoolErrors { /** * @dev FairSideBountyPool-related custom errors */ error FSBountyPool_InsufficientPrivilegesOnlyGuardian(); error FSBountyPool_InsufficientPrivilegesOnlyAdmin(); } /** * @dev Bounty pool contract to handle expired membership by network participants providing an incentive */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract FairSideBountyPool is IFairSideBountyPoolErrors, Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable { /* ========== LIBRARIES ========== */ using AddressUpgradeable for address payable; /* ========== STATE VARIABLES ========== */ uint256 bountyAmount; // fairNetwork contract address IFairSideNetwork private fairSideNetwork; // Admin contract IFairsideAdmin private fairsideAdmin; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } receive() external payable {} /** * @dev Set bounty amount */ function setBountyAmount(uint256 _bountyAmount) external onlyAdmin { bountyAmount = _bountyAmount; } /** * @dev Initialises the contract's upgrade state setting fair, FUNDING_POOL and GOVERNANCE_ADDRESS */ function initialize( IFairSideNetwork _fairSideNetwork, IFairsideAdmin _fairsideAdmin ) public initializer { __UUPSUpgradeable_init(); __ReentrancyGuard_init(); __Pausable_init(); fairSideNetwork = _fairSideNetwork; fairsideAdmin = _fairsideAdmin; } /** * @notice ETH amount of total open requests in the network */ function removeExpiredMembershipCSB( uint256 coverId ) external whenNotPaused nonReentrant { fairSideNetwork.removeExpiredMembershipCSB(coverId); if (bountyAmount > 0) { payable(msg.sender).sendValue(bountyAmount); } } function pause() external onlyAdmin { _pause(); } function unpause() external onlyAdmin { _unpause(); } function withdrawFund(uint256 amount) external onlyAdmin { payable(msg.sender).sendValue(amount); } modifier onlyGuardian() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_BOUNTY_POOL_OWNER_ROLE, msg.sender ) ) { revert FSBountyPool_InsufficientPrivilegesOnlyGuardian(); } _; } modifier onlyAdmin() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_ADMIN_ROLE, msg.sender ) ) { revert FSBountyPool_InsufficientPrivilegesOnlyAdmin(); } _; } function _authorizeUpgrade( address newImplementation ) internal override onlyGuardian {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../interfaces/network/IFairSideNetwork.sol"; import "../interfaces/network/IFairSideClaims.sol"; import "../interfaces/token/IFair.sol"; import "../dependencies/ABDKMathQuadUInt256.sol"; import "../admin/IFairsideAdmin.sol"; interface IFairSideClaimsErrors { /** * @dev FairSideClaims-related custom errors */ error FSClaims_CSRAlreadyProcessed(); error FSClaims_ActiveMembershipRequired(); error FSClaims_ClaimNotApproved(); error FSClaims_FairNotEnoughForBounty(); error FSClaims_ETHNotEnoughForBounty(); error FSClaims_IneligibleForCostShareRequest(); error FSClaims_GracePeriodPassed(); error FSClaims_CostRequestExceedsAvailableCostShareBenefits(); error FSClaims_InvalidMembershipOwner(); error FSClaims_InsufficientPrivilegesOnlyGuardian(); error FSClaims_EthRequired(); error FSClaims_InsufficientPrivilegesOnlyAdmin(); error FSClaims_ClaimAlreadyProcessed(); error FairAssessmentFeePaymentDisabled(); error FSClaims_InsufficientPrivilegesOnlyClaimIssuer(); error FSClaims_CSRAppealAlreadyCreated(); error FSClaims_CSRStatesNotFinal(); error FSClaims_CoverIdMismatch(); error FSClaims_PayoutAmountExceedsAvailableCostShareBenefits(); error FSClaims_CostshareBenefitsNotAvailable(); error FSClaims_AppealToAppealNotAllowed(); error FSClaims_CSRVerdictAlreadySeeded(); error FSClaims_InsufficientPrivilegesOnlyClaimVerifier(); error FSClaims_CSRNotCreated(); error FSClaims_CSRNotVerified(); } /** * @dev Handles everything relating to claims / costshare Requests */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract FairSideClaims is IFairSideClaims, IFairSideClaimsErrors, Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable { /* ========== LIBRARIES ========== */ using AddressUpgradeable for address payable; using ABDKMathQuadUInt256 for uint256; /* ========== STATE VARIABLES ========== */ // Cost Share Requests mapps claimId -> request mapping(uint256 => CostShareRequest) public costShareRequests; // member address - open cost share benefits opened by the account / claimed by the account mapping(address => ClaimStatistics) public openCostShareBenefits; // Data entry proposed by the DAO mapping(uint256 => bool) public approvedCsrTypes; // claimID -> reasons by assesor mapping(uint256 => bytes) public claimsVerdict; // all cost share request created by a user mapping(address => uint256[]) internal accountCSRs; // csrType -> count ( can only open with approvedCsrTypes max of twice) mapping(uint256 => mapping(address => ClaimCheck)) internal requestCount; CostShareRequest[] internal allCSRs; uint256[] internal totalPWPRequests; // Cost Share Request IDs ( claim Id) uint256 public claimID; // Cost share benefits of the entire personal wallet protection cover in ETH uint256 public openPWPRequestAmount; // % cost of assement when opening CSR uint256 public assesmentCostPercentage; // assesment wait time; uint256 public assesmentWaitTime; // is Fair assesment fee enabled bool public isFairAssesmentFeeEnabled; // Fair Token contract Address IFair private fair; // fairNetwork contract address IFairSideNetwork private fairSideNetwork; address public CLAIMS_ISSUER; IFairsideAdmin private fairsideAdmin; // Structure that stores claim votes info struct ClaimPoll { uint256 claimId; uint256 forVotes; uint256 againstVotes; } // Claim poll data associated with claim ID mapping(uint256 => ClaimPoll) public claimPolls; event ClaimVoteCast( uint256 claimId, uint256 forVotes, uint256 againstVotes ); event ETHAssessmentFeePaid( address indexed user, address to, uint256 bounty ); event FairAssessmentFeePaid( address indexed user, address to, uint256 bounty ); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /** * @dev Initialises the contract's upgrade state setting fair, FUNDING_POOL and GOVERNANCE_ADDRESS */ function initialize( IFair _fair, IFairSideNetwork _fairSideNetwork, IFairsideAdmin _fairsideAdmin, address claimPayer ) public initializer { __UUPSUpgradeable_init(); __ReentrancyGuard_init(); fair = _fair; fairSideNetwork = _fairSideNetwork; CLAIMS_ISSUER = claimPayer; assesmentCostPercentage = 0.1e18; // 10% assesmentWaitTime = 10 hours; fairsideAdmin = _fairsideAdmin; } /** * @notice ETH amount of total open requests in the network */ function totalOpenRequests() external view override returns (uint256) { return openPWPRequestAmount; } /** * @notice Returns count of all CSRs */ function getAllCSRCount() external view returns (uint256) { return allCSRs.length; } /** * @notice Returns all costshare request by index */ function getCostshareByIndex( uint256 index ) external view returns (CostShareRequest memory) { return allCSRs[index]; } /** * @notice Returns all Claims with claimId performed by a user */ function getAllClaimsByAddress( address _member ) external view returns (uint256[] memory) { return accountCSRs[_member]; } /** * @dev . Returns ClaimIds awaiting payment from multisig * @return uint256[] . */ function getClaims() external view returns (uint256[] memory) { return totalPWPRequests; } /** * @dev Allows the Governance Guardian to move the PWP votes and reasons on chain * only works for PWP requests * @param _claimId claim id * @param payoutAmount final payment amount * @param action action to perform, approve or deny * @param _csrTypeCore core type of the claim * @param reason reason for the rejectionapproval/approval/ */ function seedPWPVerdict( uint256 _claimId, uint256 payoutAmount, Action action, uint256 _csrTypeCore, bytes calldata reason ) external onlyGuardian { CostShareRequest storage csr = costShareRequests[_claimId]; if (csr.status != ClaimStatus.VERIFICATION_APPROVED) { revert FSClaims_CSRNotVerified(); } if (action == Action.DENY_CLAIM) { csr.status = ClaimStatus.DENIED; csr.csrType = _csrTypeCore; setVerdict(_claimId, reason); decrementCounts(csr.availableBenefits); blockMembership(csr.coverId, false); openCostShareBenefits[csr.initiator].opened -= csr .availableBenefits; setAvailableBenefits( csr.availableBenefits, csr.initiator, csr.coverId, true ); emit DenyCSR( _claimId, csr.csrType, msg.sender, reason, block.timestamp ); } else { if (payoutAmount > csr.availableBenefits) { revert FSClaims_PayoutAmountExceedsAvailableCostShareBenefits(); } csr.status = ClaimStatus.APPROVED; csr.csrType = _csrTypeCore; csr.payoutAmount = payoutAmount; setVerdict(_claimId, reason); emit ApproveCSR(_claimId, csr.csrType, msg.sender, block.timestamp); } } /** * @dev Allows opening of PWP Cross Share Request (CSR) by a member. * * It accepts parameter {claimAmount} representing claim amount * * Updates the {totalOpenRequests} (if the payout is in ETH) and {openCostShareBenefits} of the member. * block membership for topup * * Determines {bounty} as 10% of the user's available cross share benefits, of which * is sent to the funding pool. * if referenceClaimId is specified, the claim is then a appeal. */ function openPWPRequest( uint256 claimAmount, uint256 coverId, bool inETH, uint256 referenceClaimId ) external payable onlyFairAssessmentFeeEnabled(inETH) onlyCoverIdOwner(coverId) nonReentrant { Membership memory membership = fairSideNetwork.getMembership(coverId); if (membership.availableCostShareBenefits <= 0) { revert FSClaims_ActiveMembershipRequired(); } uint256 cost = fairSideNetwork.getCoverCost( membership.membershipTypeId ); uint256 availableCostShareBenefits = validateCSR(coverId); if (referenceClaimId == 0) { // if its a new claim we charge the assesment fee if (isOpenCurve()) { if (inETH) { chargeAssesmentETH(availableCostShareBenefits, cost); } else { chargeAssesment(availableCostShareBenefits, cost); } } else { if (!inETH) { revert FSClaims_EthRequired(); } // closed bonding chargeAssesmentETH(availableCostShareBenefits, cost); } } createCostshareRequest( availableCostShareBenefits, claimAmount, 0, coverId, referenceClaimId ); } /** * @dev Processes a CSR associated with parameter {id}. * * It performs the payout to user in ETH if CSR is approved. * unblock membership for topup if the claim is denied * * Updates the available and open cross share benefits of the user. */ function processCostShareRequest( uint256 _claimId, address payoutAddress ) external onlyClaimIssuer { CostShareRequest storage csr = costShareRequests[_claimId]; if (csr.status != ClaimStatus.APPROVED) { revert FSClaims_ClaimNotApproved(); } csr.status = ClaimStatus.PAID; // update user CSR openCostShareBenefits[csr.initiator].opened -= csr.availableBenefits; openCostShareBenefits[csr.initiator].claimed += csr.payoutAmount; decrementCounts(csr.availableBenefits); // if its approved, the difference between the payout amount and the available benefits is added to the available benefits setAvailableBenefits( csr.availableBenefits - csr.payoutAmount, csr.initiator, csr.coverId, true ); blockMembership(csr.coverId, false); //pay claims fair.payClaim(payoutAddress, csr.payoutAmount); // reduce the total csb from the network decrementTotalPWPCSB(csr.payoutAmount); emit PaidCSR(_claimId, csr.payoutAmount, payoutAddress); } /** * @dev creates the costsharerequest for all covers emits {CreatCSR} event */ function createCostshareRequest( uint256 availableBenefits, uint256 claimAmount, uint256 _csrType, uint256 coverId, uint256 referenceClaimId ) private { unchecked { claimID += 1; } uint256 nextClaimId = claimID; // ClaimStatus status = ClaimStatus.IN_PROGRESS; CostShareRequest memory csr = CostShareRequest( uint80(block.timestamp), msg.sender, coverId, _csrType, availableBenefits, claimAmount, 0, bytes32(0), referenceClaimId, 0, ClaimStatus.IN_PROGRESS ); // if its an appeal we set the appeal id to the original claim if (referenceClaimId != 0) { // validation for appeal creation CostShareRequest storage originalCsr = costShareRequests[ referenceClaimId ]; if (originalCsr.appealId > 0) { revert FSClaims_CSRAppealAlreadyCreated(); } if ( originalCsr.status != ClaimStatus.VERIFICATION_DENIED && originalCsr.status != ClaimStatus.DENIED && originalCsr.status != ClaimStatus.PAID ) { revert FSClaims_CSRStatesNotFinal(); } if (originalCsr.coverId != coverId) { revert FSClaims_CoverIdMismatch(); } if (originalCsr.originalClaimId > 0) { revert FSClaims_AppealToAppealNotAllowed(); } originalCsr.appealId = nextClaimId; } costShareRequests[nextClaimId] = csr; allCSRs.push(csr); accountCSRs[msg.sender].push(nextClaimId); totalPWPRequests.push(nextClaimId); requestCount[_csrType][msg.sender].count += 1; requestCount[_csrType][msg.sender].claimId = nextClaimId; openCostShareBenefits[msg.sender].opened += availableBenefits; setAvailableBenefits(availableBenefits, msg.sender, coverId, false); blockMembership(coverId, true); // set appeal id to original claim emit CreateCSR( nextClaimId, msg.sender, availableBenefits, claimAmount, _csrType, block.timestamp, referenceClaimId ); } function approveCostShareRequest( uint256 claimId, bool approved ) external onlyClaimVerifier { CostShareRequest storage csr = costShareRequests[claimId]; if (csr.status != ClaimStatus.IN_PROGRESS) { revert FSClaims_CSRNotCreated(); } if (approved) { csr.status = ClaimStatus.VERIFICATION_APPROVED; incrementCounts(csr.availableBenefits); } else { csr.status = ClaimStatus.VERIFICATION_DENIED; blockMembership(csr.coverId, false); openCostShareBenefits[csr.initiator].opened -= csr .availableBenefits; setAvailableBenefits( csr.availableBenefits, csr.initiator, csr.coverId, true ); } emit VerifyCSR(claimId, approved, block.timestamp); } /** * @dev : handles charging the assesment cost for opening a request {10% of cover cost} */ function chargeAssesment(uint256 availableCSB, uint256 cost) internal { uint256 fairSpotPrice = fairSideNetwork.getFairPrice(); // We want 10% of cover cost fee as bounty uint256 bounty = availableCSB .mul(cost.mul(assesmentCostPercentage)) .div(fairSpotPrice); IERC20 _fairToken = IERC20(address(fair)); if (_fairToken.allowance(msg.sender, address(this)) <= bounty) { revert FSClaims_FairNotEnoughForBounty(); } address fundingPoolAddress = fairSideNetwork.FUNDING_POOL(); // 100% sent to Fair to funding pool _fairToken.transferFrom(msg.sender, fundingPoolAddress, bounty); emit FairAssessmentFeePaid(msg.sender, fundingPoolAddress, bounty); } /** * @dev Allows an admin to cast a vote for a specific claim. * @param claimId The ID of the claim. * @param totalForVotes The total number of votes in favor of the claim. * @param totalAgainstVotes The total number of votes against the claim. */ function castClaimVote( uint256 claimId, uint256 totalForVotes, uint256 totalAgainstVotes ) external onlyAdmin { CostShareRequest storage claim = costShareRequests[claimId]; ClaimPoll storage claimPoll = claimPolls[claimId]; if ( claim.status == ClaimStatus.PAID || claim.status == ClaimStatus.VERIFICATION_DENIED || claim.status == ClaimStatus.DENIED ) { revert FSClaims_ClaimAlreadyProcessed(); } claimPoll.claimId = claimId; claimPoll.forVotes = totalForVotes; claimPoll.againstVotes = totalAgainstVotes; emit ClaimVoteCast(claimId, totalForVotes, totalAgainstVotes); } /** * @dev : handles charging the assesment cost for opening a request {10% of cover cost} in ETH */ function chargeAssesmentETH(uint256 availableCSB, uint256 cost) internal { //10% of cover cost as bounty fees uint256 bounty = availableCSB.mul(cost.mul(assesmentCostPercentage)); if (msg.value < bounty) { revert FSClaims_ETHNotEnoughForBounty(); } //sending 100% fee to funding pool address fundingPoolAddress = fairSideNetwork.FUNDING_POOL(); payable(fundingPoolAddress).sendValue(bounty); if (msg.value > bounty) { payable(msg.sender).sendValue(msg.value - bounty); } emit ETHAssessmentFeePaid(msg.sender, fundingPoolAddress, bounty); } /** * @notice calculate the bounty cost in Fair or ETH * @param availableCSB available costshare benefits * @param inETH if the bounty is in ETH * @return bounty cost of assesment bounty */ function calculateBountyCost( uint256 availableCSB, bool inETH, uint256 membershipTypeId ) external view returns (uint256 bounty) { uint256 cost = fairSideNetwork.getCoverCost(membershipTypeId); if (inETH) { bounty = availableCSB.mul(cost.mul(assesmentCostPercentage)); } else { uint256 fairSpotPrice = fairSideNetwork.getFairPrice(); bounty = availableCSB.mul(cost.mul(assesmentCostPercentage)).div( fairSpotPrice ); } } function isOpenCurve() internal view returns (bool curveState) { curveState = fair.currentPhase() == IFair.Phase.Final; } /** * @notice : increment counts on the data for CSB */ function incrementCounts(uint256 avaialbleBenefits) internal { openPWPRequestAmount += avaialbleBenefits; } /** * @notice : decrements counts on the data for CSB */ function decrementCounts(uint256 avaialbleBenefits) internal { openPWPRequestAmount -= avaialbleBenefits; } /* * @dev : decrements the total costshare benefits in the network */ function decrementTotalPWPCSB(uint256 avaialbleBenefits) internal { fairSideNetwork.decrementTotalPWPCSB(avaialbleBenefits); } /** * @dev Validates the costshareRequest reverts if conditions not met * - if cover is created too soon to be claimed * - if the grace period has passed * - if the account has no available costshare benefits */ function validateCSR(uint256 coverId) private view returns (uint256) { Membership memory account = fairSideNetwork.getMembership(coverId); if ((account.creation + assesmentWaitTime) > block.timestamp) { revert FSClaims_IneligibleForCostShareRequest(); } if (fairSideNetwork.hasPassedGracePeriod(coverId)) { revert FSClaims_GracePeriodPassed(); } if (account.availableCostShareBenefits == 0) { revert FSClaims_CostshareBenefitsNotAvailable(); } return account.availableCostShareBenefits; } /** * @dev : updates the membership available CSB in network contract */ function setAvailableBenefits( uint256 availableBenefits, address account, uint256 coverId, bool increase ) internal { if (increase) { fairSideNetwork.increaseOrDecreaseCSB( availableBenefits, account, coverId, true ); } else { fairSideNetwork.increaseOrDecreaseCSB( availableBenefits, account, coverId, false ); } } /** * @dev block membership from topup if a claim is in progress */ function blockMembership(uint256 coverId, bool blocked) internal { fairSideNetwork.blockMembership(coverId, blocked); } /** * @notice Sets cost share data entry. * @dev - only callable by governance. */ function setCsrTypes( uint256 _csrType, bool _isApproved ) external onlyGuardian { approvedCsrTypes[_csrType] = _isApproved; emit Event(_csrType, _isApproved); } /** * @notice shows the version of the contract being used * @dev the value represents the current version of the contract should be updated and overriden with new implementations * @return version the current version of the contract */ function version() external pure virtual returns (string memory) { return "1.0.0"; } function setClaimsIssuer(address newIssuer) external onlyGuardian { CLAIMS_ISSUER = newIssuer; } /** * @dev Changes the cost of assement { default 10%} */ function setAssesmentCostPercentage(uint256 newCost) external onlyAdmin { assesmentCostPercentage = newCost; } /** * @dev assesment wait time in {hours} */ function setAssesmentWaitTime(uint256 durationInHour) external onlyAdmin { assesmentWaitTime = durationInHour * 60 * 60; } /** * @dev sets the verdict { decision } of a claim with reason */ function setVerdict(uint256 _claimId, bytes calldata reason) internal { claimsVerdict[_claimId] = reason; } /** * @dev : sets the Fair assesment fee enabled status */ function setFairAssesmentFeeEnabled(bool status) external onlyAdmin { isFairAssesmentFeeEnabled = status; } /** * @dev Handles upgrading of contract */ function _authorizeUpgrade( address newImplementation ) internal override onlyGuardian {} /* ========== MODIFIERS ========== */ modifier onlyCoverIdOwner(uint256 coverId) { if (fairSideNetwork.getMembership(coverId).owner != msg.sender) { revert FSClaims_InvalidMembershipOwner(); } _; } modifier onlyGuardian() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_CLAIMS_GUARDIAN_ROLE, msg.sender ) ) { revert FSClaims_InsufficientPrivilegesOnlyGuardian(); } _; } modifier onlyAdmin() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_ADMIN_ROLE, msg.sender ) ) { revert FSClaims_InsufficientPrivilegesOnlyAdmin(); } _; } modifier onlyClaimIssuer() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_CLAIMS_ISSUER, msg.sender ) ) { revert FSClaims_InsufficientPrivilegesOnlyClaimIssuer(); } _; } modifier onlyClaimVerifier() { if ( !fairsideAdmin.hasFSRole( IFairsideAdmin.FSRoles.FS_CLAIMS_VERIFIER, msg.sender ) ) { revert FSClaims_InsufficientPrivilegesOnlyClaimVerifier(); } _; } modifier onlyFairAssessmentFeeEnabled(bool inETH) { if (!inETH && !isFairAssesmentFeeEnabled) { revert FairAssessmentFeePaymentDisabled(); } _; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "../dependencies/ABDKMathQuadUInt256.sol"; interface IFSTimeLockErrors { /** * @dev FSTimeLock-related custom errors */ error FSTimeLock_DelayMustExceedMinimumDelay(); error FSTimeLock_DelayMustNotExceedMaximumDelay(); error FSTimeLock_CallMustComeFromAdmin(); error FSTimeLock_CallMustComeFromPendingAdmin(); error FSTimeLock_EstimatedExecutionBlockMustSatisfyDelay(); error FSTimeLock_TransactionHasNotSurpassedTimeLock(); error FSTimeLock_TransactionIsStale(); error FSTimeLock_TransactionHasNotBeenQueued(); error FSTimeLock_TransactionExecutionReverted(); } /** * @dev Implementation of {Timelock} contract. * * It allows queueing, execution and cancellation of transactions by the * {admin}. A queued transaction can be executed after the cool-time represented * by {delay} has elapsed and grace period has not passed since the queuing * of transaction. * * It allows changing of contract's admin through a queued transaction by the * prior admin. The new admin the calls {acceptAdmin} to accept its role. */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract Timelock is IFSTimeLockErrors { using ABDKMathQuadUInt256 for uint256; /* ========== STATE VARIABLES ========== */ // Time period a tx is valid for execution after eta has elapsed. uint256 public constant GRACE_PERIOD = 14 days; // The minimum delay required for execution after a tx is queued uint256 public constant MINIMUM_DELAY = 2 days; // The maxium delay required for execution after a tx is queued uint256 public constant MAXIMUM_DELAY = 30 days; // Current admin of the contract address public admin; // Pending admin of the contract address public pendingAdmin; // Cool-off before a queued transaction is executed uint256 public delay; // Queued status of a transaction (txHash => tx status). mapping(bytes32 => bool) public queuedTransactions; /* ========== EVENTS ========== */ // Emitted when a new admin is set event NewAdmin(address indexed newAdmin); // Emitted when a new pending admin is set event NewPendingAdmin(address indexed newPendingAdmin); // Emitted when a new delay/cool-off time is set event NewDelay(uint256 indexed newDelay); // Emitted when a tx is cancelled event CancelTransaction( bytes32 indexed txHash, address indexed target, uint256 value, string signature, bytes data, uint256 eta ); // Emitted when a tx is executed event ExecuteTransaction( bytes32 indexed txHash, address indexed target, uint256 value, string signature, bytes data, uint256 eta ); // Emitted when a tx is queued event QueueTransaction( bytes32 indexed txHash, address indexed target, uint256 value, string signature, bytes data, uint256 eta ); // Emitted when a tx is cancelled for No Contract-Based Proposal event EvCancelTransaction( bytes32 indexed txHash, uint256 proposalId, uint256 eta ); // Emitted when a tx is executed for No Contract-Based Proposal event EvExecuteTransaction( bytes32 indexed txHash, uint256 proposalId, uint256 eta ); // Emitted when a tx is queued for No Contract-Based Proposal event EvQueueTransaction( bytes32 indexed txHash, uint256 proposalId, uint256 eta ); /* ========== CONSTRUCTOR ========== */ /** * @dev Sets contract's state variable of {admin} and {delay} * * Requirements: * - `delay_` param must be within range or min and max delay */ constructor(address admin_, uint256 delay_) { if (delay_ < MINIMUM_DELAY) { revert FSTimeLock_DelayMustExceedMinimumDelay(); } if (delay_ > MAXIMUM_DELAY) { revert FSTimeLock_DelayMustNotExceedMaximumDelay(); } admin = admin_; delay = delay_; } /* ========== VIEWS ========== */ /* ========== MUTATIVE FUNCTIONS ========== */ /** * @dev Allows of receiving of ether beforehand or in bulk, so the sending * ether is optional at the time of tx execution. */ // solhint-disable-next-line receive() external payable {} /* ========== RESTRICTED FUNCTIONS ========== */ /** * @dev Sets the the new value of {delay}. * It allows setting of new delay value through queued tx by the admin * * Requirements: * - only current contract can call it * - `delay_` param must be within the min and max delay range */ function setDelay(uint256 delay_) public { if (msg.sender != admin) { revert FSTimeLock_CallMustComeFromAdmin(); } if (delay_ < MINIMUM_DELAY) { revert FSTimeLock_DelayMustExceedMinimumDelay(); } if (delay_ > MAXIMUM_DELAY) { revert FSTimeLock_DelayMustNotExceedMaximumDelay(); } delay = delay_; emit NewDelay(delay); } /** * @dev Sets {pendingAdmin} to admin of current contract. * A {GovernorAlpha} contract which is already set as {pendingAdmin} * of this contract calls this function to set itself as new admin. * * Requirements: * - only callable by {pendingAdmin} */ function acceptAdmin() public { if (msg.sender != pendingAdmin) { revert FSTimeLock_CallMustComeFromPendingAdmin(); } admin = msg.sender; pendingAdmin = address(0); emit NewAdmin(admin); } /** * @dev Sets the the new value of {pendingAdmin_}. * It allows setting of new pendingAdmin value through queued tx by the admin * * Requirements: * - only current contract can call it */ function setPendingAdmin(address pendingAdmin_) public { if (msg.sender != admin) { revert FSTimeLock_CallMustComeFromAdmin(); } pendingAdmin = pendingAdmin_; emit NewPendingAdmin(pendingAdmin); } /** * @dev Queues a transaction by setting its status in {queuedTransactions} mapping. * * Requirements: * - only callable by {admin} * - `eta` must lie in future compared to delay referenced from current block */ function queueTransaction( address target, uint256 value, string memory signature, bytes memory data, uint256 eta ) public { if (msg.sender != admin) { revert FSTimeLock_CallMustComeFromAdmin(); } if (eta < getBlockTimestamp() + delay) { revert FSTimeLock_EstimatedExecutionBlockMustSatisfyDelay(); } bytes32 txHash = keccak256( abi.encode(target, value, signature, data, eta) ); queuedTransactions[txHash] = true; emit QueueTransaction(txHash, target, value, signature, data, eta); } /** * @dev Cancels a transaction by setting its status in {queuedTransactions} mapping. * * Requirements: * - only callable by {admin} */ function cancelTransaction( address target, uint256 value, string memory signature, bytes memory data, uint256 eta ) public { if (msg.sender != admin) { revert FSTimeLock_CallMustComeFromAdmin(); } bytes32 txHash = keccak256( abi.encode(target, value, signature, data, eta) ); queuedTransactions[txHash] = false; emit CancelTransaction(txHash, target, value, signature, data, eta); } /** * @dev Modifier to check if a transaction can be executed. * * Requirements: * The caller should be the admin * The current timestamp should NOT be ahead of the tx's eta * The grace period associated with the tx should be valid */ modifier canExecuteOnly(uint256 eta) { if (msg.sender != admin) { revert FSTimeLock_CallMustComeFromAdmin(); } if (getBlockTimestamp() < eta) { revert FSTimeLock_TransactionHasNotSurpassedTimeLock(); } if (getBlockTimestamp() > eta + GRACE_PERIOD) { revert FSTimeLock_TransactionIsStale(); } _; } /** * @dev Executes a transaction by making a low level call to its `target`. * The call reverts if the low-level call made to `target` reverts. * * Requirements: * - only callable by {admin} * - tx must already be queued * - current timestamp is ahead of tx's eta * - grace period associated with the tx must not have passed * - the low-level call to tx's `target` must not revert */ function executeTransaction( address target, uint256 value, string memory signature, bytes memory data, uint256 eta ) public payable canExecuteOnly(eta) returns (bytes memory) { bytes32 txHash = keccak256( abi.encode(target, value, signature, data, eta) ); if (!queuedTransactions[txHash]) { revert FSTimeLock_TransactionHasNotBeenQueued(); } queuedTransactions[txHash] = false; bytes memory callData; if (bytes(signature).length == 0) { callData = data; } else { callData = abi.encodePacked( bytes4(keccak256(bytes(signature))), data ); } (bool success, bytes memory returnData) = target.call{value: value}( callData ); if (!success) { revert FSTimeLock_TransactionExecutionReverted(); } emit ExecuteTransaction(txHash, target, value, signature, data, eta); return returnData; } /* ========== INTERNAL FUNCTIONS ========== */ /** * @dev Gets timestamp from the current block. */ function getBlockTimestamp() public view returns (uint256) { // solium-disable-next-line security/no-block-members return block.timestamp; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "../dependencies/ABDKMathQuadUInt256.sol"; import "../dependencies/FairSideFormula2.sol"; interface IABCErrors { /** * @dev ABC-related custom errors */ error ABC_InsufficientCapitalToWithdraw(); } /** * @dev Implementation of Augmented Bonding Curve (ABC) contract. * * Attributes: * - Calculates amount of Fair to be minted given a particular token supply and an amount of reserve * - Calculates amount of reserve to be unlocked given a particular token supply and an amount of Fair tokens * - Tracks creations and timestamps */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract ABC is IABCErrors { using ABDKMathQuadUInt256 for uint256; // Returns absolute value of the parameter {a}. function _abs(int256 a) internal pure returns (uint256) { return uint256(a < 0 ? -a : a); } /** * @dev Returns the delta amount representing change in the supply of Fair token * supply after the change in reserve amount is considered. * * Requirement: * - the reserve amount should not go below {Fshare}. */ function _calculateDeltaOfFair( uint256 reserve, int256 reserveDelta, uint256 openRequests, uint256 fShare ) internal pure returns (uint256 supplyDelta) { // Capital Pool = Total Funds held in ETH – Open Cost Share Requests // Open Cost Share Request = Cost share request awaiting assessor consensus uint256 capitalPool = reserve - openRequests; if (reserveDelta < 0) { uint256 capitalPostWithdrawal = capitalPool - (_abs(reserveDelta)); if (capitalPostWithdrawal < fShare) { revert ABC_InsufficientCapitalToWithdraw(); } supplyDelta = FairSideFormula2.getMintedAmount( capitalPostWithdrawal, _abs(reserveDelta), fShare ); } else { supplyDelta = FairSideFormula2.getMintedAmount( capitalPool, uint256(reserveDelta), fShare ); } return supplyDelta; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../admin/IFairsideAdmin.sol"; import "../interfaces/network/IFairSideNetwork.sol"; import "../interfaces/token/IFair.sol"; import "../dependencies/ABDKMathQuadUInt256.sol"; import "../dependencies/EstimateEthInputLib.sol"; import "./ABC.sol"; interface IFairErrors { /** * @dev Fair-related custom errors */ error Fair_DepositAmountCannotBeZero(); error Fair_NothingToBurn(); error Fair_HighSlippage(); error Fair_AlreadyAtFinalPhase(); error Fair_FeeShouldBeLessThanOneEther(); error Fair_DifferentSizedArrays(); error Fair_AlreadySet(); error Fair_CanOnlySyncConvictionInFinalPhase(); error Fair_OnlyTimelockCanCall(); error Fair_OnlyFairSideClaimsCanCall(); error Fair_OnlyFairSideNetworkCanCall(); error Fair_InvalidPhase(); error Fair_Paused(); error Fair_InvalidCaller(); error Fair_AddressZero(); error Fair_ExceedsCapitalPoolWithdrawLimit(); error Fair_DailyUnBondedPercentageShouldBeLessThan100Percent(); error Fair_DepositAmountTooLarge(); } /** * @dev Implementation {Fair} ERC20 Token contract. * * The Fair contract allows depositing of ETH for bonding to curve and minting * Fair in return. Only 70% of the deposit is bonded to curve during VCWL phase * and the rest 30% is deposited to `fundingPool`. * * It also allows burning of Fair tokens to withdraw ETH. A portion of withdrawing ETH * reserve is taken as tribute fee which is distributed to existing network users * * Has utility functions to modify the contract's state. * * Attributes: * - Mintable via an Augmented Bonding Curve * - Burnable via an Agumented Bonding Curve * - Tracks creations and timestamps */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract Fair is IFair, ABC, IFairErrors, Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable, ERC20PermitUpgradeable, ERC20BurnableUpgradeable { /* ========== LIBRARIES ========== */ using ABDKMathQuadUInt256 for uint256; using AddressUpgradeable for address payable; /* ========== STATE VARIABLES ========== */ // 70% bonding curve ratio uint256 private constant BONDING_CURVE_RATIO = 0.7 ether; // Funding pool needs to achieve 500 ether address public FUNDING_POOL; // Timelock address address public TIME_LOCK; // tribute pool multisign address address public tributePool; // Fair Network address IFairSideNetwork public fairSideNetwork; //FairsideClaims Contract address address public fairSideClaims; // Fairside admin address address public fairSideAdmin; // currect phase of the Fair token Phase public override currentPhase; // Indicator of pause bool public paused; // 3.5% tribute fee on exit uint256 public tributeFee; // 500 ether uint256 public FUNDING_POOL_THRESHOLD; //Fair set to be burnt or reallocated uint256 public toBeBurntFair; // counter for total ETH staked by an address mapping(address => uint256) public amountBonded; uint256 public dailyUnbondedAmount; uint256 public dailyUnbondedPercentageLimit; uint256 public dailyUnbondedDate; uint256 public maxDepositPerTransaction; /* ========== EVENTS ========== */ /** * @dev Emitted when a unbonded from Curve. */ event Unbond( address indexed user, uint256 capitalDesired, uint256 amount, uint256 toDistribute ); /** * @dev Emitted when bonded to Curve. */ event Bond( address indexed user, uint256 ethAmountBonded, uint256 fairIssued ); /** * @dev Emitted when bonded without tokens to be burnt, {fairIssued: is Fair that wasnt minted} */ event BondWithoutMint( address indexed user, uint256 ethAmountBonded, uint256 fairIssued ); /** * @dev Emitted when bonded and burned, {fairIssued: is Fair that wasnt minted} */ event BondAndBurn( address indexed user, uint256 ethAmountBonded, uint256 tokensToBurn ); /** * @dev Emitted when tributes are distributed */ event TributesDistributed(uint256 distributedAmount); /** * @dev Emitted when the pause functionality is triggered. */ event PauseToggled(); /** * @dev Emitted when the phase is advanced. */ event PhaseAdvanced(uint8 newPhase); /** * @dev Emitted when the phase is updated. */ event PhaseUpdated(uint8 newPhase); /** * @dev Emitted when the tribute fee is set. */ event TributeFeeSet(uint256 newTributeFee); /** * @dev Initialises the contract's state with {fundingPool} and {timelock} addresses. * It also passes token name and symbol to ERC20 contract and * the name to the Permit extension. */ function initialize( address _fundingPool, address _timelock, address _tributePool, address _fairSideAdmin ) public virtual initializer { __ERC20_init("Fair", "Fair"); __ERC20Burnable_init(); __ERC20Permit_init("Fair"); __ReentrancyGuard_init(); if ( _fundingPool == address(0) || _timelock == address(0) || _tributePool == address(0) || _fairSideAdmin == address(0) ) { revert Fair_AddressZero(); } FUNDING_POOL = _fundingPool; TIME_LOCK = _timelock; tributePool = _tributePool; fairSideAdmin = _fairSideAdmin; tributeFee = 0.035 ether; dailyUnbondedPercentageLimit = 0.01 ether; // 1% maxDepositPerTransaction = 50 ether; FUNDING_POOL_THRESHOLD = 500 ether; } /** * @dev Returns available ETH balance in the curve. */ function getReserveBalance() internal view returns (uint256) { return address(this).balance; } /** * @dev Returns the amount of Fair available for minting after * reserve is increased by delta. * @param investment The reserve delta - Amount of tokens to be added to the reserve */ function getTokensMinted( uint256 investment ) external view override returns (uint256) { return calculateDeltaOfFair(getReserveBalance(), int256(investment)); } /** * @dev Returns the amount of Fair available for burning after * reserve is decreased by delta. * @param withdrawal The reserve delta - Amount of tokens to be removed from the reserve */ function getTokensBurned( uint256 withdrawal ) public view override returns (uint256) { return calculateDeltaOfFair(getReserveBalance(), -int256(withdrawal)); } /* ========== MUTATIVE FUNCTIONS ========== */ /** * @dev Allows minting of Fair tokens by depositing ETH for bonding in the contract on behalf of an address. * During the Final phase, 100% of the deposited ETH are bonded. * @param to The account receiving the Fair tokens * @param tokenMinimum The minimum amount of tokens to be minted * * Requirements: * - bonding ETH amount MUST NOT be zero * - the minted Fair amount MUST NOT be less than parameter {tokenMinimum} */ function bondTo( address to, uint256 tokenMinimum ) external payable override onlyValidPhase(IFair.Phase.Final) returns (uint256) { return _bondInternal(to, tokenMinimum, true); } /** * @dev Allows minting of Fair tokens by depositing ETH for bonding in the contract. * During the Final phase, 100% of the deposited ETH are bonded. * @param tokenMinimum The minimum amount of tokens to be minted * * Requirements: * - bonding ETH amount MUST NOT be zero * - the minted Fair amount MUST NOT be less than parameter {tokenMinimum} */ function bond( uint256 tokenMinimum ) external payable override onlyValidPhase(IFair.Phase.Final) returns (uint256) { return _bondInternal(msg.sender, tokenMinimum, true); } /** * @notice Bond and preserve Fair to be burnt or redistributed later * @dev Allows minting of Fair tokens by depositing ETH for bonding in the contract. * * Requirements: * - bonding ETH amount MUST NOT be zero * - SHOULD NOT mint Fair */ function bondAndBurn() external payable override onlyOwnerOrNetworkOrClaims { uint256 tokensToBurn = _bondInternal(address(this), 0, true); toBeBurntFair += tokensToBurn; emit BondAndBurn(msg.sender, msg.value, tokensToBurn); } /** * @notice Burn Fair allocated for burning * @dev Owner function to burn Fair allocated for burning * * Requirements: * - MUST be called the owner * - Allocated tokens to be burnt {tobeBurntFair} MUST NOT be zero **/ function burnAllocatedFair() external onlyOwner { if (toBeBurntFair == 0) { revert Fair_NothingToBurn(); } super._burn(address(this), toBeBurntFair); toBeBurntFair = 0; } /** * @notice Burning / Repositioning of burnable amount either to pay claims and etc * @dev transfer the amount allocated burned Fair to reposition for claims * @param to The account to receive the allocated tokens for burning * * Requirements: * - MUST be called by the owner * - Allocated tokens to be burnt {tobeBurntFair} MUST NOT be zero **/ function transferAllocatedFair(address to) external onlyOwner { if (toBeBurntFair == 0) { revert Fair_NothingToBurn(); } _transfer(address(this), to, toBeBurntFair); toBeBurntFair = 0; } /** * @dev Allows minting of Fair tokens by depositing ETH for bonding in the contract. * * Requirements: * - bonding ETH amount MUST NOT be zero * - SHOULD NOT mint Fair */ function bondNoEmission() external payable override onlyOwnerOrNetwork { uint256 notMinted = _bondInternal(msg.sender, 0, false); emit BondWithoutMint(msg.sender, msg.value, notMinted); } // @dev view function to check the remaining amount of ETH that can be unbonded from the daily limit function currentDailyUnbondableAmount() public view override returns (uint256) { return getCapitalPool().mul(dailyUnbondedPercentageLimit) - dailyUnbondedAmount; } // @dev view function to get the amount of ETH that can be unbonded from available capital pool function capitalPoolAvailableFund() public view override returns (uint256) { uint256 fShare = _getNetworkFShare(); uint256 capitalPool = getCapitalPool(); return capitalPool <= fShare ? 0 : capitalPool - fShare; } function _getNetworkFShare() internal view returns (uint256) { return fairSideNetwork.getNetworkFShare(); } // @dev view function for frontend to check the amount of ETH that can be unbonded function getAvailableETHForWithdraw() external view override returns (uint256) { uint256 availableAmountFromCapitalPool = capitalPoolAvailableFund(); uint256 availableAmountFromDailyLimit = currentDailyUnbondableAmount(); return availableAmountFromCapitalPool < availableAmountFromDailyLimit ? availableAmountFromCapitalPool : availableAmountFromDailyLimit; } /** * @dev Allows burning of Fair tokens for ETH * It also takes cut of {tributeFee} and adds it as tribute which is distributed * to the existing users of the network. currently hold in the tribute wallet * @param capitalDesired the desired amount of ETH to distribute * @param tokenMaximum the maximum acceptable amount of Fair tokens for burning * * Requirements: * - the Fair token amount being burned MUST NOT exceed parameter {tokenMaximum} * - the supply SHOULD reduce after the token burn * - MUST be called in open bonding curve */ function unbond( uint256 capitalDesired, uint256 tokenMaximum ) external virtual nonReentrant onlyValidPhase(IFair.Phase.Final) { uint256 curveCapital = getReserveBalance(); uint256 tokenAmount = calculateDeltaOfFair( curveCapital, -int256(capitalDesired) ); if (tokenAmount > tokenMaximum) { revert Fair_HighSlippage(); } uint256 tribute = capitalDesired.mul(tributeFee); uint256 reserveWithdrawn = capitalDesired - tribute; uint256 curDate = getCurrentDate(); uint256 _dailyUnbondedAmount = dailyUnbondedAmount; if (curDate != dailyUnbondedDate) { dailyUnbondedDate = curDate; _dailyUnbondedAmount = 0; } if ( _dailyUnbondedAmount + reserveWithdrawn > getCapitalPool().mul(dailyUnbondedPercentageLimit) ) { revert Fair_ExceedsCapitalPoolWithdrawLimit(); } dailyUnbondedAmount += reserveWithdrawn; uint256 mintTribute = calculateDeltaOfFair( curveCapital - capitalDesired, int256(tribute) ); _burn(msg.sender, tokenAmount); _mint(address(this), mintTribute); _transfer(address(this), tributePool, mintTribute); emit TributesDistributed(mintTribute); payable(msg.sender).sendValue(reserveWithdrawn); emit Unbond(msg.sender, capitalDesired, reserveWithdrawn, mintTribute); } /** * @notice Get ETH amount and convert it to equivalent Fair tokens to be minted * @dev Returns the amount of Fair tokens to be minted after considering the reserve and reserve delta * @param ethAmount the amount of ETH to be converted into Fair tokens */ function estimateMintAmount( uint256 ethAmount ) external view returns (uint256) { return calculateDeltaOfFair( getReserveBalance() - ethAmount, int256(ethAmount) ); } /* ========== RESTRICTED FUNCTIONS ========== */ /** * @notice Advances the current bonding curve to the next phase * @dev Admin function to move the current phase to the next phase. * * Requirements: * - MUST be called by the owner * - The current phase MUST NOT be in Final phase(open curve) */ function phaseAdvance() external onlyOwner { if (currentPhase == Phase.Final) { revert Fair_AlreadyAtFinalPhase(); } unchecked { currentPhase = Phase(uint8(currentPhase) + 1); } emit PhaseAdvanced(uint8(currentPhase)); } /** * * @notice updates the currentPhase based on the passed Phase Enum value * @param newPhase - Phase enumeration values 0 - 4 * @dev only Admin owner can call method * * Requirements * - MUST be called by the owner */ function updateCurrentPhase(Phase newPhase) external onlyOwner { currentPhase = Phase(newPhase); emit PhaseUpdated(uint8(newPhase)); } /** * @dev Allows paying of claims upon processing of Cost Share Requests. * It pays claims by performing account for later withdrawal of ETH by the {beneficiary}. * @param beneficiary The address of the account to receive to receive payout * @param amount The amount of ETH to pay * * Requirements: * - MUST be called only by the {Claims} contract. */ function payClaim( address beneficiary, uint256 amount ) external onlyClaims onlyNonPaused { payable(beneficiary).sendValue(amount); } /** * @dev Sets tribute fee. The fee is expressed in percentage, * being 1 ether = 100% * * Requirements: * - Tribute fee SHOULD be less than 1 ether * - MUST be called only by {owner}, {governance} or {timelock} contracts. */ function setTributeFee(uint256 _tributeFee) external onlyTimelock { if (_tributeFee >= 1 ether) { revert Fair_FeeShouldBeLessThanOneEther(); } tributeFee = _tributeFee; emit TributeFeeSet(_tributeFee); } function setMaxDepositPerTransaction( uint256 _maxDepositPerTransaction ) external onlyTimelock { maxDepositPerTransaction = _maxDepositPerTransaction; } function setDailyUnbondedPercentageLimit( uint256 _dailyUnboondedPercentageLimit ) external onlyTimelock { if (_dailyUnboondedPercentageLimit >= 1 ether) { revert Fair_DailyUnBondedPercentageShouldBeLessThan100Percent(); } dailyUnbondedPercentageLimit = _dailyUnboondedPercentageLimit; } /** * @dev Allows updating of {tributePool} address. * @param _tributePool the new address of the {tributePool} contract * * Requirements: * - MUST be called only by {timelock} contract * - {_tributePool} MUST NOT be a zero address value */ function setTributePool(address _tributePool) external onlyTimelock { if (_tributePool == address(0)) { revert Fair_AddressZero(); } tributePool = _tributePool; } function setFundingPoolThreshold( uint256 _fundingPoolThreshold ) external onlyTimelock { FUNDING_POOL_THRESHOLD = _fundingPoolThreshold; } /** * @dev Allows updating of {_fairSideNetwork} address. Invocable only once. * @param _fairSideNetwork the new address of the {Network} contract * * Requirements: * - MUST be called only by {owner} contract * - {_fairSideNetwork} MUST NOT be a zero address value */ function setFairSideNetwork( IFairSideNetwork _fairSideNetwork ) external onlyOwner { if (address(_fairSideNetwork) == address(0)) { revert Fair_AddressZero(); } fairSideNetwork = _fairSideNetwork; } /** * @dev Allows minting of Fair tokens by depositing ETH for bonding in the contract. * During the Premine phase, 100% of the deposited ETH are bonded. The bonded amount is * immediately vested according to the Fair vesting schedule. * * @param adminMultisigs list of addresses to receive tokens * @param amounts list of numbers to send to {adminMultisigs} * * Requirements: * - during Premine phase, only the token owner can mint to a group of users * - during Premine phase, depositing any ether for bonding is disallowed * - during Premine phase, the tokens that are minted are immediately vested * - the size of {adminMultisigs} and {amounts} MUST be equal */ function mintPremineAdmin( address[] calldata adminMultisigs, uint256[] calldata amounts ) external override onlyOwner onlyValidPhase(IFair.Phase.Premine) { uint256 length = adminMultisigs.length; if (length != amounts.length) { revert Fair_DifferentSizedArrays(); } for (uint8 i; i < length; ++i) { _mint(adminMultisigs[i], amounts[i]); } } /** * @dev Allows updating of {_fairSideClaims} address. Invocable only once. * @param _fairSideClaims the new address of the {claims} contract * * Requirements: * - MUST be called only by {owner} contract * - {_fairSideClaims} MUST NOT be a zero address value */ function setFairSideClaims(address _fairSideClaims) external onlyOwner { if (fairSideClaims != address(0)) { revert Fair_AlreadySet(); } fairSideClaims = _fairSideClaims; } /** * @notice Get amount in capital pool (ETH) * @dev : Capital Pool = Total Funds held in ETH – Open Cost Share Requests * Open Cost Share Request = Cost share request awaiting assessor consensus * @return uint256 */ function getCapitalPool() public view returns (uint256) { uint256 totalOpenRequests = fairSideNetwork.getTotalOpenRequests(); return getReserveBalance() - totalOpenRequests; } /** * @dev Allows pausing fair contract. * * Requirements: * - MUST be called only by {owner} contract */ function togglePause() external onlyOwner { paused = !paused; emit PauseToggled(); } /* ========== INTERNAL FUNCTIONS ========== */ /** * @notice ABC wrapper, returns the change in Fair supply upon * the total reserves and change in reserves. * * @param _reserve The amount of tokens * @param _reserveDelta The amount of tokens to change * * @return uint256 */ function calculateDeltaOfFair( uint256 _reserve, int256 _reserveDelta ) internal view returns (uint256) { uint256 openRequestsInEth = fairSideNetwork.getTotalOpenRequests(); uint256 fshare = _getNetworkFShare(); return _calculateDeltaOfFair( _reserve, _reserveDelta, openRequestsInEth, fshare ); } /** * @notice returns current date starting from unix epoch time * */ function getCurrentDate() internal view returns (uint256) { return block.timestamp / 1 days; } /** * @dev Bond tokens to the curve * * @param to the address of the account to receive tokens * @param tokenMinimum the minimum tokens to bond * @param mintFair states whether {_mint} should be invoked or not * * @return uint256 the amount of tokens minted * * Requirements: * - {tokenMinimum} MUST be greater than the tokens to be minted */ function _bondInternal( address to, uint256 tokenMinimum, bool mintFair ) private nonReentrant returns (uint256) { if (msg.value == 0) { revert Fair_DepositAmountCannotBeZero(); } uint256 amountToBond = msg.value; if (amountToBond > maxDepositPerTransaction) { revert Fair_DepositAmountTooLarge(); } uint256 tokensToBeMinted = calculateDeltaOfFair( getReserveBalance() - msg.value, int256(amountToBond) ); if (tokensToBeMinted < tokenMinimum) { revert Fair_HighSlippage(); } uint256 fundingPoolBalance = FUNDING_POOL.balance; //maintain a 500ETH on funding pool and bond the rest to the curve if (fundingPoolBalance < FUNDING_POOL_THRESHOLD) { amountToBond = amountToBond.mul(BONDING_CURVE_RATIO); uint256 maxAllowedInFundingPool; unchecked { maxAllowedInFundingPool = FUNDING_POOL_THRESHOLD - fundingPoolBalance; } uint256 amountAfterBonding = msg.value - amountToBond; uint256 toFundingPool = amountAfterBonding > maxAllowedInFundingPool ? maxAllowedInFundingPool : amountAfterBonding; payable(FUNDING_POOL).sendValue(toFundingPool); } if (mintFair) { _mint(to, tokensToBeMinted); } //mint Fair if mintFair = true amountBonded[to] += msg.value; emit Bond(msg.sender, msg.value, tokensToBeMinted); return tokensToBeMinted; } function estimateReceivedEth( uint256 fairAmount ) external view override returns (uint256 fairInput, uint256 ethOut) { return EstimateEthInputLib.estimateReceivedEth( this, getCapitalPool(), _getNetworkFShare(), fairAmount ); } /** * @dev See {ERC20-_beforeTokenTransfer}. * * Requirements: * * - the contract MUST NOT be paused. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override onlyNonPaused { ERC20Upgradeable._beforeTokenTransfer(from, to, amount); } /* ========== MODIFIERS ========== */ modifier onlyTimelock() { if (msg.sender != TIME_LOCK) { revert Fair_OnlyTimelockCanCall(); } _; } modifier onlyClaims() { if (msg.sender != fairSideClaims) { revert Fair_OnlyFairSideClaimsCanCall(); } _; } modifier onlyFairNetwork() { if (msg.sender != address(fairSideNetwork)) { revert Fair_OnlyFairSideNetworkCanCall(); } _; } modifier onlyOwner() { if ( !IFairsideAdmin(fairSideAdmin).hasFSRole( IFairsideAdmin.FSRoles.FS_FAIR_OWNER_ROLE, msg.sender ) ) { revert Fair_InvalidCaller(); } _; } modifier onlyOwnerOrNetwork() { if (msg.sender != address(fairSideNetwork)) { if ( !IFairsideAdmin(fairSideAdmin).hasFSRole( IFairsideAdmin.FSRoles.FS_FAIR_OWNER_ROLE, msg.sender ) ) { revert Fair_InvalidCaller(); } } _; } modifier onlyOwnerOrNetworkOrClaims() { if (msg.sender != address(fairSideNetwork)) { if (msg.sender != fairSideClaims) { if ( !IFairsideAdmin(fairSideAdmin).hasFSRole( IFairsideAdmin.FSRoles.FS_FAIR_OWNER_ROLE, msg.sender ) ) { revert Fair_InvalidCaller(); } } } _; } modifier onlyValidPhase(IFair.Phase _phase) { if (currentPhase != _phase) { revert Fair_InvalidPhase(); } _; } modifier onlyNonPaused() { if (paused) { revert Fair_Paused(); } _; } function _authorizeUpgrade( address newImplementation ) internal virtual override onlyOwner {} }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./Fair.sol"; interface IFairTestnetErrors { /** * @dev FairTestnet-related custom errors */ error FairTestnet_OnlyForSepoliaTestnet(); } contract FairTestnet is Fair, IFairTestnetErrors { using ABDKMathQuadUInt256 for uint256; using AddressUpgradeable for address payable; function initialize( address _fundingPool, address _timelock, address _tributePool, address _fairSideAdmin ) public override initializer { // NOTE: not using super.initialize() because due to that if it is used, the contract size will be increased by 0.391KB __ERC20_init("FairSide Token", "Fair"); __ERC20Burnable_init(); __ERC20Permit_init("Fair"); __ReentrancyGuard_init(); if ( _fundingPool == address(0) || _timelock == address(0) || _tributePool == address(0) || _fairSideAdmin == address(0) ) { revert Fair_AddressZero(); } FUNDING_POOL = _fundingPool; TIME_LOCK = _timelock; tributePool = _tributePool; fairSideAdmin = _fairSideAdmin; tributeFee = 0.035 ether; dailyUnbondedPercentageLimit = 0.01 ether; // 1% maxDepositPerTransaction = 50 ether; FUNDING_POOL_THRESHOLD = 500 ether; //@dev: This wrapper it's only for testnet or hardhat chain if (block.chainid != 11155111 && block.chainid != 31337) { revert FairTestnet_OnlyForSepoliaTestnet(); } } function withdrawFromCurve( uint256 amount, address destination ) external onlyTimelock { payable(destination).sendValue(amount); } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./FairVestingBase.sol"; interface IFairSidePausableVestingErrors { /** * @dev FairSidePausableVesting-related custom errors */ error FSPausableVesting_VestingIsAlreadyPaused(); error FSPausableVesting_VestingIsNotPaused(); } /** * Fair Vesting for VC * * Attributes: * - Fair token vesting over a period of time with a cliff * - Allow users to vote with vested tokens * - Vesting duration of 30 months with a 12-month cliff * - 5% unlocked after the cliff period */ contract FairPausableVesting is FairVestingBase, IFairSidePausableVestingErrors { struct PausableVestingPeriod { bool isPaused; uint256 pauseStartTime; uint256 totalPausedDuration; } mapping(address => PausableVestingPeriod) public pausableVestedAccount; // An event emitted when a vesting is paused or unpaused for an account event VestingPausedStateChanged(address indexed account, bool state); constructor( Fair _token ) FairVestingBase( _token, 12 * 30 days, 30 * 30 days, 5, 18 * 30 days, IFair.Phase.Premine ) {} function calculateVestingClaim( address account ) public view override returns (uint256) { VestingPeriod storage vesting = vestedAccount[account]; PausableVestingPeriod storage pausableVesting = pausableVestedAccount[ account ]; uint256 vestedAmount; if (!pausableVesting.isPaused) { uint256 effectiveTime = block.timestamp - pausableVesting.totalPausedDuration; if (effectiveTime >= vesting.startTime + DURATION) { vestedAmount = vesting.amountVested; } else if (effectiveTime >= vesting.startTime + CLIFF) { uint256 initialUnlockAmount = (vesting.amountVested * INITIAL_UNLOCK) / 100; uint256 timeAfterCliff = effectiveTime - (vesting.startTime + CLIFF); uint256 linearVestAmount = ((vesting.amountVested - initialUnlockAmount) * timeAfterCliff) / LINEAR_VEST_AFTER_CLIFF; vestedAmount = initialUnlockAmount + linearVestAmount; } else { return 0; } } uint256 claimableAmount = vestedAmount > vesting.claimed ? vestedAmount - vesting.claimed : 0; return claimableAmount; } /** * @dev Triggers pausing of a vesting for an account * @param account Address of the account to pause the vesting for */ function pauseVesting(address account) external onlyOwner { PausableVestingPeriod storage pausableVesting = pausableVestedAccount[ account ]; if (pausableVesting.isPaused) { revert FSPausableVesting_VestingIsAlreadyPaused(); } pausableVesting.isPaused = true; pausableVesting.pauseStartTime = block.timestamp; emit VestingPausedStateChanged(account, true); } /** * @dev Triggers unpausing of a vesting for an account * @param account Address of the account to pause the vesting for */ function unpauseVesting(address account) external onlyOwner { PausableVestingPeriod storage pausableVesting = pausableVestedAccount[ account ]; if (!pausableVesting.isPaused) { revert FSPausableVesting_VestingIsNotPaused(); } pausableVesting.isPaused = false; pausableVesting.totalPausedDuration += block.timestamp - pausableVesting.pauseStartTime; pausableVesting.pauseStartTime = 0; emit VestingPausedStateChanged(account, false); } function _onlyValidPhase() internal view override {} }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./FairVestingBase.sol"; /** * Fair Vesting Ambassador * * Attributes: * - Fair token vesting over a period of time with Full unlock at 12 month */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract FairVestingAmbassador is FairVestingBase { // One month in seconds uint256 private constant ONE_MONTH = 30 days; // Duration of a vest uint256 private constant _DURATION = 12 * ONE_MONTH; /* ========== CONSTRUCTOR ========== */ constructor( Fair _token ) FairVestingBase(_token, 0, _DURATION, 0, 0, IFair.Phase.KOL) {} /** * @dev Calculate the vested tokens available to claim. * @param account Address of the account to calculate the claim amount for * @return claimableAmount amount of tokens available to claim from the vestedAmount */ function calculateVestingClaim( address account ) public view override returns (uint256) { VestingPeriod memory accountVesting = vestedAccount[account]; if (block.timestamp < accountVesting.startTime + DURATION) return 0; if (accountVesting.claimed >= accountVesting.amountVested) return 0; return accountVesting.amountVested - accountVesting.claimed; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "../interfaces/vesting/IFairVesting.sol"; import "../dependencies/FSOwnable.sol"; import "../token/Fair.sol"; interface IFairSideVestingBaseErrors { /** * @dev FairSideVestingBase-related custom errors */ error FSVestingBase_NotEnoughFair(); error FSVestingBase_NotEnoughAllowance(); error FSVestingBase_NoVestingCreated(); error FSVestingBase_LessThanClaimed(); error FSVestingBase_DifferentSizedArrays(); error FSVestingBase_ZeroClaimableTokens(); error FSVestingBase_AlreadyHasVesting(); error FSVestingBase_CallerIsNotTheVestingBeneficiary(); error FSVestingBase_InvalidPhase(); } /** * Fair Vesting Base * * Attributes: * - Fair token vesting over a period of time with a cliff * - Allow users to vote with vested tokens */ contract FairVestingBase is IFairVesting, IFairSideVestingBaseErrors, FSOwnable { /* ========== STATE VARIABLES ========== */ // Cliff period for a vest uint256 internal immutable CLIFF; // Duration of a vest uint256 internal immutable DURATION; // inital % to be unlocked when cliff is reached uint256 internal immutable INITIAL_UNLOCK; // Vesting duration after cliff uint256 internal immutable LINEAR_VEST_AFTER_CLIFF; // Valid phase for vesting IFair.Phase public immutable VALID_PHASE; //total Fair vested in contract uint256 public totalVestedTokens; //total Fair claimed in contract uint256 public totalClaimedTokens; /// @param claimed Amount of Fair claimed from the vesting contract /// @param amountVested of Fair that are vested /// @param startTime Vesting start timestamp in seconds /// @param lastClaimAt Latest claim timestamp in seconds struct VestingPeriod { uint256 claimed; uint256 amountVested; uint256 startTime; uint256 lastClaimAt; } mapping(address => VestingPeriod) public vestedAccount; // FairSide Token address Fair public immutable fair; /* ========== EVENTS ========== */ // An event emitted when a user claims their vested tokens event TokensClaimed( address indexed beneficiary, uint256 amount, uint256 claimedAt ); // An event emitted when admin vests tokens to address event VestingCreated(address indexed account, uint256 amount); /* ========== CONSTRUCTOR ========== */ constructor( Fair _token, uint256 _cliff, uint256 _duration, uint256 _initialLock, uint256 _linearVestAfterCliff, IFair.Phase _phase ) { fair = _token; CLIFF = _cliff; DURATION = _duration; INITIAL_UNLOCK = _initialLock; LINEAR_VEST_AFTER_CLIFF = _linearVestAfterCliff; VALID_PHASE = _phase; } function getTotalVestedTokens() external view override returns (uint256) { return totalVestedTokens; } function getTotalClaimedTokens() external view override returns (uint256) { return totalClaimedTokens; } function getUnclaimedTokens() external view override returns (int256) { return int256(totalVestedTokens - totalClaimedTokens); } /** * @dev returns current amount that has NOT been claimed from the vestedAmount * amountVested - ClaimedAmount */ function getCurrentVestingAmount( address account ) external view override returns (uint256) { return vestedAccount[account].amountVested - vestedAccount[account].claimed; } /** * @dev returns the total amount vested in contract for {account} */ function getVestedAmount( address account ) external view override returns (uint256) { return vestedAccount[account].amountVested; } /** * @dev creates vesting for an account * @param account Address of the user to create vesting for * @param _amount Amount of tokens to be vested */ function createVesting( address account, uint256 _amount ) external override onlyOwner onlyValidPhase { if (fair.balanceOf(msg.sender) < _amount) { revert FSVestingBase_NotEnoughFair(); } if (fair.allowance(msg.sender, address(this)) < _amount) { revert FSVestingBase_NotEnoughAllowance(); } _createVesting(account, _amount); } /** * @dev Increase the amount of vested tokens for an account * @param account Address of the user to increase the vested amount for * @param _amount Amount of tokens to increase the vested amount by */ function increaseAccountVesting( address account, uint256 _amount ) external override onlyOwner onlyValidPhase { if (vestedAccount[account].amountVested == 0) { revert FSVestingBase_NoVestingCreated(); } if (fair.allowance(msg.sender, address(this)) < _amount) { revert FSVestingBase_NotEnoughAllowance(); } vestedAccount[account].amountVested += _amount; totalVestedTokens += _amount; fair.transferFrom(msg.sender, address(this), _amount); } /** * @dev Reduce the amount of vested tokens for an account * @param account Address of the user to decrease the vested amount for * @param _amount Amount of tokens to decrease the vested amount by */ function decreaseAccountVesting( address account, uint256 _amount ) external override onlyOwner onlyValidPhase { if (vestedAccount[account].amountVested == 0) { revert FSVestingBase_NoVestingCreated(); } if ( vestedAccount[account].amountVested < vestedAccount[account].claimed + _amount ) { revert FSVestingBase_LessThanClaimed(); } vestedAccount[account].amountVested -= _amount; totalVestedTokens -= _amount; fair.transfer(msg.sender, _amount); } /** * @dev Create multiple vesting contracts in one call * @param accounts An array of address of the users to create vesting for * @param _amounts An array of amounts of tokens to be vested for each address */ function batchCreateVesting( address[] calldata accounts, uint256[] calldata _amounts ) external override onlyOwner onlyValidPhase { uint256 accountLength = accounts.length; uint256 amountToVest; if (accountLength != _amounts.length) { revert FSVestingBase_DifferentSizedArrays(); } //validate approval of amount to vest for (uint8 i; i < accountLength; ++i) { amountToVest = amountToVest + _amounts[i]; } if (fair.balanceOf(msg.sender) < amountToVest) { revert FSVestingBase_NotEnoughFair(); } if (fair.allowance(msg.sender, address(this)) < amountToVest) { revert FSVestingBase_NotEnoughAllowance(); } for (uint8 i; i < accountLength; ++i) { _createVesting(accounts[i], _amounts[i]); } } /** * @dev Calculate the vested tokens available to claim. * @param account Address of the account to calculate the claim amount for * @return claimableAmount the vested tokens available to claim */ function calculateVestingClaim( address account ) public view virtual returns (uint256) { uint256 vestedAmount; VestingPeriod memory accountVesting = vestedAccount[account]; if (block.timestamp >= accountVesting.startTime + DURATION) { vestedAmount = accountVesting.amountVested; } else if (block.timestamp >= accountVesting.startTime + CLIFF) { vestedAmount = (accountVesting.amountVested * INITIAL_UNLOCK) / 100; // 5% unlock uint256 linearClaim = ((accountVesting.amountVested - vestedAmount) * (block.timestamp - (accountVesting.startTime + CLIFF))) / LINEAR_VEST_AFTER_CLIFF; vestedAmount = vestedAmount + linearClaim; } else { return 0; } if (accountVesting.claimed >= vestedAmount) return 0; return vestedAmount - accountVesting.claimed; } /** * @dev Allows a vesting beneficiary to claim the vested tokens. */ function claimVestedTokens() external override onlyVestedAccount { uint256 tokenClaim = calculateVestingClaim(msg.sender); if (tokenClaim <= 0) { revert FSVestingBase_ZeroClaimableTokens(); } vestedAccount[msg.sender].claimed += tokenClaim; vestedAccount[msg.sender].lastClaimAt = block.timestamp; totalClaimedTokens += tokenClaim; fair.transfer(msg.sender, tokenClaim); emit TokensClaimed(msg.sender, tokenClaim, block.timestamp); } /** * @dev creates a vesting. * @param account Address of the account to create vesting for * @param _amount Amount of tokens to vest */ function _createVesting(address account, uint256 _amount) private { VestingPeriod storage accountVesting = vestedAccount[account]; if (accountVesting.amountVested != 0) { revert FSVestingBase_AlreadyHasVesting(); } accountVesting.amountVested = _amount; accountVesting.startTime = block.timestamp; totalVestedTokens += _amount; //takes amount from fair.transferFrom(msg.sender, address(this), _amount); emit VestingCreated(account, _amount); } /** * @dev Throws if called by any account other than the vesting beneficiary. */ modifier onlyVestedAccount() { if (vestedAccount[msg.sender].amountVested == 0) { revert FSVestingBase_CallerIsNotTheVestingBeneficiary(); } _; } function _onlyValidPhase() internal view virtual { if (fair.currentPhase() != VALID_PHASE) { revert FSVestingBase_InvalidPhase(); } } /** * @dev only phase is permitted to create the vesting. */ modifier onlyValidPhase() { _onlyValidPhase(); _; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./FairVestingBase.sol"; /** * Fair Vesting PRESEED * * Attributes: * - Fair token vesting over a period of time with a cliff * - Allow users to vote with vested tokens * - Vesting duration of 30 months with a 12-month cliff * - 5% unlocked after the 12 months cliff period */ contract FairVestingPreseed is FairVestingBase { constructor( Fair _token ) FairVestingBase( _token, 12 * 30 days, 30 * 30 days, 5, 18 * 30 days, IFair.Phase.Premine ) {} }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "../interfaces/vesting/IFairVesting.sol"; import "../interfaces/vesting/IFairVestingRegistry.sol"; /** * Fair Vesting Registry */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* contract FairVestingRegistry is IFairVestingRegistry, Initializable, OwnableUpgradeable, UUPSUpgradeable { IFairVesting public VestingPre; IFairVesting public VestingVC; IFairVesting public VestingAmbassador; IFairVesting public VestingPausable; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( IFairVesting _vestingPre, IFairVesting _vestingVC, IFairVesting _vestingAmbassador, IFairVesting _vestingPausable ) public initializer { __Ownable_init(); __UUPSUpgradeable_init(); VestingPre = _vestingPre; VestingVC = _vestingVC; VestingAmbassador = _vestingAmbassador; VestingPausable = _vestingPausable; } /** * @dev returns the total of vested amount for account in VestingPre, VestingVC and VestingAmbassador contracts contracts * @param account address of the account */ function getTotalVestedAmount( address account ) external view override returns (uint256) { return (VestingPre.getVestedAmount(account) + VestingAmbassador.getVestedAmount(account) + VestingVC.getVestedAmount(account) + VestingPausable.getVestedAmount(account)); } /** * @dev returns the current amount that has NOT been claimed from the vestedAmount for account in VestingPre, VestingVC and VestingAmbassador contracts * @param account address of the account */ function getCurrentVesting( address account ) external view override returns (uint256) { return (VestingPre.getCurrentVestingAmount(account) + VestingAmbassador.getCurrentVestingAmount(account) + VestingVC.getCurrentVestingAmount(account) + VestingPausable.getCurrentVestingAmount(account)); } /** * @dev returns total amount of vested tokens claimed from VestingPre, VestingVC and VestingAmbassador contracts */ function getTotalClaimedVesting() external view returns (uint256) { return (VestingPre.getTotalClaimedTokens() + VestingAmbassador.getTotalClaimedTokens() + VestingVC.getTotalClaimedTokens() + VestingPausable.getTotalClaimedTokens()); } /** * @dev returns total amount of vested tokens from VestingPre, VestingVC and VestingAmbassador contracts */ function getTotalVested() external view override returns (uint256) { return (VestingPre.getTotalVestedTokens() + VestingAmbassador.getTotalVestedTokens() + VestingVC.getTotalVestedTokens() + VestingPausable.getTotalVestedTokens()); } /** * @dev returns total amount of vested tokens that has NOT been claimed from VestingPre, VestingVC and VestingAmbassador contracts */ function getTotalUnclaimedVesting() external view override returns (int256) { return (VestingPre.getUnclaimedTokens() + VestingAmbassador.getUnclaimedTokens() + VestingVC.getUnclaimedTokens() + VestingPausable.getUnclaimedTokens()); } function version() external pure virtual returns (string memory) { return "1.0"; } function _authorizeUpgrade( address newImplementation ) internal override onlyOwner {} }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "./FairVestingBase.sol"; /** * Fair Vesting for VC * * Attributes: * - Fair token vesting over a period of time with a cliff * - Allow users to vote with vested tokens * - Vesting duration of 24 months with a 12-month cliff * - 5% unlocked after the cliff period */ contract FairVestingVC is FairVestingBase { constructor( Fair _token ) FairVestingBase( _token, 12 * 30 days, 24 * 30 days, 5, 12 * 30 days, IFair.Phase.VCWL ) {} }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.22; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "../interfaces/token/IFair.sol"; interface IFairSideZapperErrors { /** * @dev FairSideZapper-related custom errors */ error FSZapper_WrongInput(); error FSZapper_FailedToSwap(); } /** * @dev Implementation {Zapper} ERC20 tokens contract. * * The Zapper contract allows using ERC-20 tokens to mint Fair by bonding it to the curve * - ERC20 token is converted to ETH which is then bonded to the curve. * * Attributes: * - receives the user's preferred ERC-20 token to mint Fair * - receives ETH only from 1inch's router * - Bonds the received ETH to the curve using the bondTo method */ // solhint-disable not-rely-on-time, var-name-mixedcase, reason-string /* interface IOneInchRouter { function unoswapTo( address recipient, address srcToken, uint256 amount, uint256 minReturn, bytes32[] calldata pools ) external payable returns (uint256 returnAmount); } contract Zapper is Ownable, IFairSideZapperErrors { using SafeERC20 for IERC20; using Address for address; IFair private Fair; address public immutable WETH9; constructor(IFair _fair, address _WETH9) { Fair = _fair; WETH9 = _WETH9; } /** * @dev Allows using ERC-20 tokens to mint Fair ones instead of ETH * * Requirements: * - the Fair token must be during its Community whitelist phase * - the user should approve the contract before initiating the swap * - the Fair token amount being minted must not exceed parameter {tokenMaximum} */ function swapFromDexAndBond( address tokenAddr, uint256 amount, address dex, uint256 tokenMinimum, bytes memory data ) public returns (bool) { if (data.length <= 0) { revert FSZapper_WrongInput(); } IERC20(tokenAddr).safeTransferFrom(msg.sender, address(this), amount); IERC20(tokenAddr).approve(dex, amount); dex.functionCall(data); Fair.bondTo(msg.sender, tokenMinimum); return true; } function swapFromUniswapAndBond( address UNISWAP_V3_ROUTER, address tokenAddress, uint256 tokenAmount, uint256 amountOutMin, uint24 poolFee, uint160 sqrtPrice, address to ) public returns (bool) { IERC20(tokenAddress).transferFrom( msg.sender, address(this), tokenAmount ); IERC20(tokenAddress).approve(address(UNISWAP_V3_ROUTER), tokenAmount); ISwapRouter.ExactInputSingleParams memory params = ISwapRouter .ExactInputSingleParams({ tokenIn: tokenAddress, tokenOut: WETH9, fee: poolFee, recipient: address(this), deadline: block.timestamp + 10, amountIn: tokenAmount, amountOutMinimum: amountOutMin, sqrtPriceLimitX96: sqrtPrice }); uint256 amountIn = ISwapRouter(UNISWAP_V3_ROUTER).exactInputSingle( params ); if (amountIn <= 0) { revert FSZapper_FailedToSwap(); } Fair.bondTo(to, amountIn); return true; } /** * @dev Allows using ERC-20 tokens to mint Fair instead of ETH * * Requirements: * - the Fair token must be during its Final phase * - the user should approve the contract before initiating the swap * - the Fair token amount being minted must not exceed parameter {tokenMaximum} */ function swapFrom1inchUnoswapAndBond( address oneInchDexRouter, address srcToken, uint256 amount, uint256 minReturn, bytes32[] calldata pools, address to ) public returns (bool) { uint256 swappedAmount = IOneInchRouter(oneInchDexRouter).unoswapTo( address(this), srcToken, amount, minReturn, pools ); if (swappedAmount <= 0) { revert FSZapper_FailedToSwap(); } Fair.bondTo(to, swappedAmount); return true; } }
{ "evmVersion": "paris", "optimizer": { "enabled": true, "mode": "3", "runs": 200 }, "outputSelection": { "*": { "*": [ "abi" ] } }, "detectMissingLibraries": false, "forceEVMLA": false, "enableEraVMExtensions": false, "libraries": { "contracts/dependencies/FairSideFormula2.sol": { "FairSideFormula2": "0x4D036202f75B8ed506cea871095227B4b0A0EF11" }, "contracts/dependencies/EstimateEthInputLib.sol": { "EstimateEthInputLib": "0xC22349B1dabA46a973FFC5fE2692Db985dfC823D" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FSNetwork_ActiveMembershipRequired","type":"error"},{"inputs":[],"name":"FSNetwork_CannotChange","type":"error"},{"inputs":[],"name":"FSNetwork_ChainlinkMalfunction","type":"error"},{"inputs":[],"name":"FSNetwork_ChainlinkPriceStale","type":"error"},{"inputs":[],"name":"FSNetwork_CurveIsClosedUseETH","type":"error"},{"inputs":[],"name":"FSNetwork_ExceedsCSBLimitPerAccount","type":"error"},{"inputs":[],"name":"FSNetwork_ExceedsCostShareBenefitLimitPerAccount","type":"error"},{"inputs":[],"name":"FSNetwork_ExceedsMaxCostShareBenefitLimit","type":"error"},{"inputs":[],"name":"FSNetwork_FairPurchaseDisabled","type":"error"},{"inputs":[],"name":"FSNetwork_IncorrectLossRatioSpecified","type":"error"},{"inputs":[],"name":"FSNetwork_IncorrectSlippageSpecified","type":"error"},{"inputs":[],"name":"FSNetwork_IncorrectValueSpecified","type":"error"},{"inputs":[],"name":"FSNetwork_InsufficientApproval","type":"error"},{"inputs":[],"name":"FSNetwork_InsufficientPrivileges","type":"error"},{"inputs":[],"name":"FSNetwork_InsufficientPrivilegesOnlyAdmin","type":"error"},{"inputs":[],"name":"FSNetwork_InsufficientPrivilegesOnlyGuardian","type":"error"},{"inputs":[],"name":"FSNetwork_InvalidCostShareBenefitSpecified","type":"error"},{"inputs":[],"name":"FSNetwork_InvalidCoverIdForAccount","type":"error"},{"inputs":[],"name":"FSNetwork_MembershipBlocked","type":"error"},{"inputs":[],"name":"FSNetwork_MembershipExpired","type":"error"},{"inputs":[],"name":"FSNetwork_MembershipNotExpired","type":"error"},{"inputs":[],"name":"FSNetwork_MembershipTopupDisabled","type":"error"},{"inputs":[],"name":"FSNetwork_MembershipTypeDisabled","type":"error"},{"inputs":[],"name":"FSNetwork_NotEnoughFair","type":"error"},{"inputs":[],"name":"FSNetwork_OnlyFairSideBountyPoolCanCall","type":"error"},{"inputs":[],"name":"FSNetwork_OnlyFairSideClaimsCanCall","type":"error"},{"inputs":[],"name":"FSNetwork_OnlyMembershipPurchaseProxyCanCall","type":"error"},{"inputs":[],"name":"FSNetwork_OnlyPremiumPoolCanCall","type":"error"},{"inputs":[],"name":"FSNetwork_PremiumFeeSentIsLessThanRequired","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"},{"indexed":false,"internalType":"uint256","name":"coverId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"costshareBenefit","type":"uint256"},{"indexed":true,"internalType":"address","name":"coverAddress","type":"address"},{"indexed":false,"internalType":"enum FairSideNetwork.TokenType","name":"tokenType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"membershipTypeId","type":"uint256"}],"name":"NewMembership","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fundingPremium","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"parntersPremium","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"curveReserve","type":"uint256"}],"name":"PremiumEthDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fundingPremium","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"parntersPremium","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"curveReserve","type":"uint256"}],"name":"PremiumFairDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"premiumRewardContract","type":"address"}],"name":"SetETHPremiumReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"premiumRewardContract","type":"address"}],"name":"SetFairPremiumReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"fairPurchaseEnabled","type":"bool"}],"name":"SetFairPurchaseEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fundingPoolAllocation","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"partnersPoolAllocation","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lossRatio","type":"uint256"}],"name":"SetFeeDistributionPercenages","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lossRatio","type":"uint256"}],"name":"SetLossRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"networkGearingFactor","type":"uint256"}],"name":"SetNetworkGearingFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"riskBasedCapital","type":"uint256"}],"name":"SetRiskBasedCapital","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenGearingFactor","type":"uint256"}],"name":"TokenGearingFactorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"},{"indexed":false,"internalType":"uint256","name":"coverId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"costshareBenefit","type":"uint256"},{"indexed":false,"internalType":"enum FairSideNetwork.TokenType","name":"tokenType","type":"uint8"}],"name":"TopUpCover","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"FUNDING_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FUNDING_POOL_ALLOCATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FairSIDE_BOUNTY_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PARTNERS_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PARTNERS_POOL_ALLOCATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PREMIUMS_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PREMIUM_REWARD_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_REWARDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"gracePeriod","type":"uint256"},{"internalType":"uint256","name":"topupDisabledPeriod","type":"uint256"},{"internalType":"uint256","name":"minimumPurchaseAmount","type":"uint256"},{"internalType":"uint256","name":"maximumBenefitPerUser","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"}],"name":"addMembershipType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"coverId","type":"uint256"},{"internalType":"bool","name":"blocked","type":"bool"}],"name":"blockMembership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"costShareBenefit","type":"uint256"}],"name":"decrementTotalPWPCSB","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"disableMembershipType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"costShareBenefit","type":"uint256"},{"internalType":"uint256","name":"expirationDate","type":"uint256"},{"internalType":"uint256","name":"membershipTypeId","type":"uint256"}],"name":"estimateCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fairPurchaseEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fairSideClaims","outputs":[{"internalType":"contract IFairSideClaims","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenContractAddress","type":"address"},{"internalType":"address payable","name":"destination","type":"address"}],"name":"flushAsset","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountCoveredWallets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountMembership","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCapitalPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"membershipTypeId","type":"uint256"}],"name":"getCoverCost","outputs":[{"internalType":"uint256","name":"coverCost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFairPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxTotalCostShareBenefits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"coverId","type":"uint256"}],"name":"getMembership","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint80","name":"creation","type":"uint80"},{"internalType":"bool","name":"blocked","type":"bool"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint80","name":"expirationDate","type":"uint80"},{"internalType":"uint256","name":"availableCostShareBenefits","type":"uint256"},{"internalType":"uint256","name":"paidCostShareBenefits","type":"uint256"},{"internalType":"uint256","name":"membershipTypeId","type":"uint256"},{"internalType":"uint256","name":"coverCost","type":"uint256"}],"internalType":"struct IFairSideSchema.Membership","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNetworkFShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalOpenRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"coverId","type":"uint256"}],"name":"hasPassedGracePeriod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"coverId","type":"uint256"},{"internalType":"bool","name":"increase","type":"bool"}],"name":"increaseOrDecreaseCSB","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFair","name":"_fair","type":"address"},{"internalType":"address","name":"fundingPool","type":"address"},{"internalType":"address","name":"premiumsPool","type":"address"},{"internalType":"contract IFairsideAdmin","name":"_fairsideAdmin","type":"address"},{"internalType":"address","name":"timelock","type":"address"},{"internalType":"address","name":"patnersPool","type":"address"},{"internalType":"address","name":"premiumReward","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOpenCurve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"membershipCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"membershipPurchaseProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"membershipTypes","outputs":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"gracePeriod","type":"uint256"},{"internalType":"uint256","name":"topupDisabledPeriod","type":"uint256"},{"internalType":"uint256","name":"minimumPurchaseAmount","type":"uint256"},{"internalType":"uint256","name":"maximumBenefitPerUser","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"networkGearingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numMembershipTypes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"costShareBenefit","type":"uint256"},{"internalType":"address","name":"coverAddress","type":"address"},{"internalType":"uint256","name":"membershipType","type":"uint256"}],"name":"purchaseMembership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"primaryAddress","type":"address"},{"internalType":"uint256","name":"costShareBenefit","type":"uint256"},{"internalType":"address","name":"coverAddress","type":"address"},{"internalType":"uint256","name":"membershipType","type":"uint256"}],"name":"purchaseMembershipFromProxy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"costShareBenefit","type":"uint256"},{"internalType":"address","name":"coverAddress","type":"address"},{"internalType":"uint256","name":"membershipType","type":"uint256"}],"name":"purchaseMembershipWithFair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"primaryAddress","type":"address"},{"internalType":"uint256","name":"costShareBenefit","type":"uint256"},{"internalType":"address","name":"coverAddress","type":"address"},{"internalType":"uint256","name":"membershipType","type":"uint256"}],"name":"purchaseMembershipWithFairFromProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"coverId","type":"uint256"}],"name":"removeExpiredMembershipCSB","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"riskBasedCapital","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_fairPurchaseEnabled","type":"bool"}],"name":"setEnableFairPurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fairSideBountyPool","type":"address"}],"name":"setFairSideBountyPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFairSideClaims","name":"_fairSideClaims","type":"address"}],"name":"setFairSideClaims","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fundingPoolAllocation","type":"uint256"},{"internalType":"uint256","name":"_partnersPoolAllocation","type":"uint256"},{"internalType":"uint256","name":"_stakingRewards","type":"uint256"},{"internalType":"uint256","name":"_lossRatio","type":"uint256"}],"name":"setFeeDistributionPercentages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newFundingPool","type":"address"}],"name":"setFundingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMembershipPurchaseProxy","type":"address"}],"name":"setMembershipPurchaseProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gearingFactor","type":"uint256"}],"name":"setNetworkGearingFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPartnersPool","type":"address"}],"name":"setPartnersPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPremiumRewardAddress","type":"address"}],"name":"setPremiumRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPremiumsPool","type":"address"}],"name":"setPremiumsPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_riskBasedCapital","type":"uint256"}],"name":"setRiskBasedCapital","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"coverId","type":"uint256"},{"internalType":"uint256","name":"costshareBenefit","type":"uint256"}],"name":"topupMembership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"coverId","type":"uint256"},{"internalType":"uint256","name":"costshareBenefit","type":"uint256"}],"name":"topupMembershipWithFair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCoverCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPWPCSB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]
Contract Creation Code
9c4d535b000000000000000000000000000000000000000000000000000000000000000001000b939c1fcd08ae4bf6d73b3a0dbe524b853c4126986d27ea6dcddad3477500000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x0001000000000002000d00000000000200000000000103550000000100200190000000650000c13d000000000701034f000000600110027000000a90011001970000008002000039000000400020043f000000040010008c0000158f0000413d000000000207043b000000e00220027000000a980020009c0000008a0000213d00000ac60020009c000000c90000a13d00000ac70020009c0000016e0000213d00000ad30020009c000003510000213d00000ad90020009c0000050d0000213d00000adc0020009c0000098b0000613d00000add0020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000000460000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000000420000c13d000000000006004b000000530000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000dc80000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d000000800200043d000000000002004b0000000003000039000000010300c039000000000032004b0000158f0000c13d000000000002004b000003fe0000613d000000a5010000390000112f0000013d000000a001000039000000400010043f0000000001000416000000000001004b0000158f0000c13d0000000001000410000000800010043f000000000200041a0000ff0000200190000000bd0000c13d000000ff0320018f000000ff0030008c000000820000613d000000ff012001bf000000000010041b000000ff01000039000000a00010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000a95011001c70000800d02000039000000010300003900000a96040000412a392a2a0000040f00000001002001900000158f0000613d000000800100043d00000001020000390000014000000443000001600010044300000020010000390000010000100443000001200020044300000a970100004100002a3a0001042e00000a990020009c000001400000a13d00000a9a0020009c000002e90000213d00000aa60020009c000003620000213d00000aac0020009c0000053f0000213d00000aaf0020009c000009960000613d00000ab00020009c0000158f0000c13d000000440010008c0000158f0000413d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000002401700370000000000101043b000900000001001d00000af40010009c0000158f0000213d000000a501000039000000000101041a00000af4011001970000000002000411000000000012004b00000ed60000c13d00000000010004100000000a02000029000000000002004b000010160000c13d00000b1a0200004100000000002004430000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f00000001002001900000153d0000613d000000000201043b00000009010000292a391c460000040f000000000100001900002a3a0001042e00000a9101000041000000a00010043f0000002001000039000000a40010043f0000002701000039000000c40010043f00000a9201000041000000e40010043f00000a9301000041000001040010043f00000a940100004100002a3b0001043000000ade0020009c000003170000a13d00000adf0020009c000003310000213d00000ae50020009c000003b30000213d00000ae80020009c000007480000613d00000ae90020009c0000158f0000c13d000000e40010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000002401700370000000000101043b000900000001001d00000af40010009c0000158f0000213d0000004401700370000000000101043b000800000001001d00000af40010009c0000158f0000213d0000006401700370000000000101043b000700000001001d00000af40010009c0000158f0000213d0000008401700370000000000101043b000600000001001d00000af40010009c0000158f0000213d000000a401700370000000000101043b000500000001001d00000af40010009c0000158f0000213d000000c401700370000000000101043b000400000001001d00000af40010009c0000158f0000213d00000000010004150000000c0110008a0002000500100218000000000100041a000300000001001d0001ff0000100194000001080000c13d00000000010004150000000b0110008a00020005001002180000000301000029000000ff00100190000001200000613d00000b3801000041000000000010044300000000010004100000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000000001004b000013ab0000c13d0000000301000029000000ff0110018f000000010010008c00000002010000290000000501100270000000000100003f000000010100603f000013ae0000c13d000000030200002900000b6c0120019700000001011001bf00000b530220019700000101022001bf000000010000006b000000000201c019000000000020041b000000400100043d000300000001001d0000ff0000200190000013b80000c13d0000000303000029000000640130003900000b61020000410000000000210435000000440130003900000b6202000041000000000021043500000024013000390000002b02000039000000000021043500000a9101000041000000000013043500000004013000390000002002000039000000000021043500000a900030009c00000a9003008041000000400130021000000b31011001c700002a3b0001043000000ab10020009c000003240000a13d00000ab20020009c0000033c0000213d00000ab80020009c000004000000213d00000abb0020009c000007750000613d00000abc0020009c0000158f0000c13d000000440010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000002401700370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b0000158f0000c13d000000a301000039000000000101041a00000af4011001970000000002000411000000000012004b00000da10000c13d0000000401700370000000000101043b000000000010043f0000009701000039000000200010043f000000400200003900000000010000192a3929f70000040f0000000a02000029000000f00220021000000afa02200197000000000301041a00000b2103300197000000000223019f000000000021041b000000000100001900002a3a0001042e00000ac80020009c000003710000213d00000ace0020009c0000054b0000213d00000ad10020009c0000099b0000613d00000ad20020009c0000158f0000c13d000000840010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000004401700370000000000101043b000900000001001d00000af40010009c0000158f0000213d0000006401700370000000000301043b0000002401700370000000000201043b000000ae01000039000000000101041a000000ff0010019000000c490000613d000800000003001d000700000002001d000000a201000039000000000101041a00000af302000041000000800020043f000000000300041400000af40210019700000a900030009c00000a9003008041000000c00130021000000af5011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000001a90000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000001a50000c13d000000000006004b000001b60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000010820000613d0000001f01400039000000600210018f00000080012001bf000000400010043f000000200030008c0000158f0000413d000000800300043d000000030030008c0000158f0000213d000010c90000c13d000000a803000039000000000303041a00000af4033001970000000004000411000000000034004b000012e90000c13d0000006503000039000000000403041a000000020040008c00000ec80000613d0000000201000039000000000013041b0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000301100039000000000101041a000000070010006c00000e4e0000213d0000009d01000039000000000101041a000000070010002a000009bd0000413d0000009f02000039000000000302041a000000a002000039000000000402041a00000000024300a9000000000004004b000001ee0000613d00000000044200d9000000000034004b000009bd0000c13d0000000701100029000000000021004b000010c60000213d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d000600000002001d00000afb0020009c00000be00000213d000000000101043b0000000604000029000000e002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a000000600340003900000000002304350000000402100039000000000202041a000000800340003900000000002304350000000502100039000000000202041a000000a003400039000500000003001d0000000000230435000000c0024000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c0390000000000120435000012eb0000613d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000401100039000000000101041a000000070010006b000011a40000213d000000050100002900000000030104330000000601000029000000000201043300000007010000292a39198e0000040f000500000001001d2a3921cd0000040f0000009c01000039000000000201041a0000000102200039000000000021041b000300000002001d000000000020043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000400000001001d0000009d01000039000000000101041a000000070010002a000009bd0000413d00000007011000290000009d02000039000000000012041b0000009e01000039000000000201041a000000050020002a000009bd0000413d0000000502200029000000000021041b000000040100002900000002011000390000000702000029000000000021041b00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d0000000404000029000000000204041a00000b0c03200197000000000201043b000000a00120021000000b0d01100197000000000113019f000000000014041b00000006030000290000000003030433000000000023001a000009bd0000413d0000000002230019000000a00220021000000b0d0220019700000004050000290000000103500039000000000403041a00000b0e04400197000000000242019f0000000a022001af000000000023041b00000b070110019700000009011001af000000000015041b00000004015000390000000802000029000000000021041b0000000501500039000000000201041a000000050020002a000009bd0000413d0000000502200029000000000021041b0000000a01000029000000000010043f0000009801000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000600000002001d00000b090020009c00000be00000213d00000006020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b00000006011000290000000302000029000000000021041b0000000a01000029000000000010043f0000009901000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000600000002001d00000b090020009c00000be00000213d00000006020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000601100029000000000201041a00000b07022001970000000906000029000000000262019f000000000021041b000000400100043d0000006002100039000000080300002900000000003204350000000102000039000000400310003900000000002304350000002002100039000000070300002900000000003204350000000302000029000000000021043500000a900010009c00000a90010080410000004001100210000000000200041400000d830000013d00000a9b0020009c0000037c0000213d00000aa10020009c000005540000213d00000aa40020009c000009ac0000613d00000aa50020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000000000010043f0000009a01000039000000200010043f000000400200003900000000010000192a3929f70000040f0000000602100039000000000202041a0000000503100039000000000303041a0000000404100039000000000404041a0000000305100039000000000505041a0000000206100039000000000606041a0000000107100039000000000707041a000000000101041a000000800010043f000000a00070043f000000c00060043f000000e00050043f000001000040043f000001200030043f000000ff002001900000000001000039000000010100c039000001400010043f00000b0a0100004100002a3a0001042e00000aea0020009c0000039d0000a13d00000aeb0020009c000004090000213d00000aee0020009c000007bf0000613d00000aef0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000ac0100003900000a060000013d00000abd0020009c000003a80000a13d00000abe0020009c000004680000213d00000ac10020009c000007c40000613d00000ac20020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d0000009f0100003900000a060000013d00000ae00020009c000004b60000213d00000ae30020009c000007c90000613d00000ae40020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d0000009c0100003900000a060000013d00000ab30020009c000004bf0000213d00000ab60020009c000008260000613d00000ab70020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000000000010043f0000009a01000039000000200010043f000000400200003900000000010000192a3929f70000040f000000050110003900000a060000013d00000ad40020009c000005a20000213d00000ad70020009c000009c30000613d00000ad80020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000ae01000039000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f00000b020100004100002a3a0001042e00000aa70020009c000005c50000213d00000aaa0020009c000009c80000613d00000aab0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d0000009f01000039000000000201041a000000a001000039000000000101041a2a3919800000040f0000098f0000013d00000ac90020009c0000061b0000213d00000acc0020009c000009e10000613d00000acd0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000a40100003900000d910000013d00000a9c0020009c000006240000213d00000a9f0020009c00000a020000613d00000aa00020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000000aa02000039000000000202041a00000af4022001970000000003000411000000000023004b00000d9d0000c13d000000000001004b00000db50000613d0000009f02000039000000000012041b000000800010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b03011001c70000800d02000039000000010300003900000b040400004100000bc50000013d00000af00020009c00000a0a0000613d00000af10020009c000008930000613d00000af20020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000a30100003900000d910000013d00000ac30020009c00000a340000613d00000ac40020009c000008980000613d00000ac50020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000a80100003900000d910000013d00000ae60020009c000008cb0000613d00000ae70020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000003e10000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000003dd0000c13d000000000006004b000003ee0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000dd40000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d000000800200043d000000000002004b0000000003000039000000010300c039000000000032004b0000158f0000c13d000000000002004b000010ce0000c13d00000b2502000041000010ca0000013d00000ab90020009c000008ec0000613d00000aba0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d0000009b0100003900000a060000013d00000aec0020009c000009470000613d00000aed0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000a201000039000000000101041a00000b1a02000041000000000020044300000af4011001970000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000900000001001d000000a301000039000000000201041a000000400300043d000a00000003001d00000b6801000041000000000013043500000a900030009c00000a900100004100000000010340190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000af8011001c700000af4022001972a392a2f0000040f0000000a0b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000004430000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000043f0000c13d000000000006004b000004500000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000de00000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000b090010009c00000be00000213d000000010020019000000be00000c13d000000400010043f000000200030008c0000158f0000413d00000000020b0433000000090220006b000009bd0000413d000000000021043500000a900010009c00000a9001008041000000400110021000000b11011001c700002a3a0001042e00000abf0020009c0000094c0000613d00000ac00020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000004960000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000004920000c13d000000000006004b000004a30000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000dec0000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000a7c0000613d000000a9010000390000112f0000013d00000ae10020009c000009510000613d00000ae20020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000a90100003900000d910000013d00000ab40020009c000009860000613d00000ab50020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000004ed0000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000004e90000c13d000000000006004b000004fa0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000df80000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000a7c0000613d000000a6010000390000112f0000013d00000ada0020009c00000a810000613d00000adb0020009c0000158f0000c13d000000640010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000004401700370000000000101043b000000000010043f0000009a01000039000000200010043f00000040020000390000000001000019000a0000000703532a3929f70000040f0000016002000039000000400020043f000000000301041a000000800030043f0000000102100039000000000202041a000000a00020043f0000000202100039000000000202041a000000c00020043f0000000302100039000000000202041a000000e00020043f0000000402100039000000000202041a000001000020043f00000006021000390000000501100039000000000401041a000001200040043f000000000102041a000000ff001001900000000001000039000000010100c039000001400010043f0000000a0100035f00000024021003700000000401100370000000000101043b000000000202043b2a391a770000040f0000098f0000013d00000aad0020009c00000bad0000613d00000aae0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d2a3919150000040f000000000001004b0000000001000039000000010100c0390000098f0000013d00000acf0020009c00000bca0000613d00000ad00020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d2a39169e0000040f0000098f0000013d00000aa20020009c00000be60000613d00000aa30020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000005820000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b0000057e0000c13d000000000006004b0000058f0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000e040000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000a7c0000613d000000a8010000390000112f0000013d00000ad50020009c00000c370000613d00000ad60020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d00000b2d010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a900010009c00000a9001008041000000c00110021000000b2e011001c700008005020000392a392a2f0000040f00000001002001900000153d0000613d000000400300043d00000a900030009c00000a900200004100000000020340190000004002200210000000000101043b00000af4011001970000000004000410000000000014004b00000e100000c13d00000b3201000041000000000013043500000b11012001c700002a3a0001042e00000aa80020009c00000c4d0000613d00000aa90020009c0000158f0000c13d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000005ee0000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000005ea0000c13d000000000006004b000005fb0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000da50000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000a7c0000613d00000004010000390000000001100367000000000101043b000000000010043f0000009a01000039000000200010043f000000400200003900000000010000192a3929f70000040f0000000601100039000000000301041a00000b6c02300197000000000021041b000000000100001900002a3a0001042e00000aca0020009c00000d8d0000613d00000acb0020009c0000158f0000c13d0000000001000416000000000001004b0000158f0000c13d000000a70100003900000d910000013d00000a9d0020009c00000d960000613d00000a9e0020009c0000158f0000c13d000000440010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000002401700370000000000201043b0000000401700370000000000301043b000000ae01000039000000000101041a000000ff0010019000000c490000613d000a00000003001d000900000002001d000000a201000039000000000101041a00000af302000041000000800020043f000000000300041400000af40210019700000a900030009c00000a9003008041000000c00130021000000af5011001c72a392a2f0000040f000000800a000039000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000006510000613d000000000801034f000000008908043c000000000a9a043600000000005a004b0000064d0000c13d000000000006004b0000065e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000e200000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d000000800200043d000000030020008c0000158f0000213d000010c90000c13d0000000a01000029000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000101041a00000afa0010019800000dc50000c13d0000006501000039000000000201041a000000020020008c000007640000613d0000000202000039000000000021041b0000000a01000029000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000700000001001d0000000401100039000000000101041a000800000001001d000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000301100039000000000101041a000000090010006c00000e4e0000213d0000009d01000039000000000101041a000000090010002a000009bd0000413d0000009f02000039000000000302041a000000a002000039000000000402041a00000000024300a9000000000004004b000006b20000613d00000000044200d9000000000034004b000009bd0000c13d0000000901100029000000000021004b000010c60000213d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d000600000002001d00000afb0020009c00000be00000213d000000000101043b0000000605000029000000e002500039000000400020043f000000000201041a00000000022504360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400350003900000000002304350000000303100039000000000303041a000000600450003900000000003404350000000403100039000000000303041a000000800450003900000000003404350000000503100039000000000303041a000000a004500039000400000004001d0000000000340435000000c0035000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c039000000000013043500000007010000290000000101100039000000000101041a000000a00110027000030afc0010019b000000030120006b000500000001001d000009bd0000413d00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000050010006c000015450000813d00000007010000290000000201100039000200000001001d000000000201041a000500000002001d000000090020002a000009bd0000413d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d0000000503000029000500090030002d000000000101043b0000000401100039000000000101041a000000050010006b00000f730000213d0000000401000029000000000401043300000006010000290000000003010433000000090100002900000003020000292a391a770000040f000800000001001d2a3921cd0000040f0000009d01000039000000000101041a000000090010002a000009bd0000413d00000009011000290000009d02000039000000000012041b0000009e01000039000000000201041a000000080020002a000009bd0000413d0000000802200029000000000021041b00000002010000290000000502000029000000000021041b00000007010000290000000501100039000000000201041a000000080020002a000009bd0000413d0000000802200029000000000021041b0000000701000029000000000201041a000000400100043d0000004003100039000000010400003900000000004304350000002003100039000000090400002900000000004304350000000a03000029000000000031043500000a900010009c00000a9001008041000000400110021000000000030004140000157e0000013d000000440010008c0000158f0000413d0000002401700370000000000101043b000900000001001d0000000401700370000000000101043b000a00000001001d000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000101041a00000afa0010019800000dc50000c13d0000006501000039000000000201041a000000020020008c00000eda0000c13d000000400100043d000000440210003900000b1203000041000000000032043500000024021000390000001f03000039000000000032043500000a9102000041000000000021043500000004021000390000002003000039000000000032043500000a900010009c00000a9001008041000000400110021000000b2a011001c700002a3b00010430000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf0000079f0000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b0000079b0000c13d000000000006004b000007ac0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000e2c0000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000a7c0000613d000000a4010000390000112f0000013d0000000001000416000000000001004b0000158f0000c13d000000a10100003900000a060000013d0000000001000416000000000001004b0000158f0000c13d2a39183a0000040f0000098f0000013d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d000001a001000039000000400010043f000000800000043f000000a00000043f000000c00000043f000000e00000043f000001000000043f000001200000043f0000000401700370000001400000043f000001600000043f000001800000043f000000000101043b000000000010043f0000009701000039000000200010043f000000400200003900000000010000192a3929f70000040f000a00000001001d000001a0010000392a3916170000040f0000000a04000029000000000104041a00000af402100197000001a00020043f000000a00310027000000afc03300197000001c00030043f00000afa001001980000000001000039000000010100c039000001e00010043f0000000101400039000000000101041a00000af403100197000002000030043f000000a00110027000000afc01100197000002200010043f0000000201400039000000000101041a000002400010043f0000000301400039000000000101041a000002600010043f0000000401400039000000000101041a000002800010043f0000000501400039000000000101041a000002a00010043f000000400100043d0000000002210436000001c00300043d00000afc033001970000000000320435000001e00200043d000000000002004b0000000002000039000000010200c03900000040031000390000000000230435000002000200043d00000af40220019700000060031000390000000000230435000002200200043d00000afc0220019700000080031000390000000000230435000000a002100039000002400300043d0000000000320435000000c002100039000002600300043d0000000000320435000000e002100039000002800300043d00000000003204350000010002100039000002a00300043d000000000032043500000a900010009c00000a9001008041000000400110021000000b47011001c700002a3a0001042e000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d000000a901000039000000000101041a00000af4011001970000000002000411000000000012004b00000db10000c13d0000000401700370000000000101043b000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000201043b0000000201200039000000000301041a000000000003004b00000e870000613d000900000003001d000800000001001d000a00000002001d0000000401200039000000000101041a000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d00000afb0020009c00000be00000213d000000000101043b000000e003200039000000400030043f000000000301041a00000000033204360000000104100039000000000504041a00000000005304350000000203100039000000000303041a000000400420003900000000003404350000000303100039000000000303041a000000600420003900000000003404350000000403100039000000000303041a000000800420003900000000003404350000000503100039000000000303041a000000a0042000390000000000340435000000c0022000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c03900000000001204350000000a010000290000000101100039000000000101041a000000a00110027000000afc01100197000700000005001d000600000001001d000000000051001a000009bd0000413d00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d00000006030000290000000702300029000000000101043b000000000021004b000011ad0000813d000000400100043d00000b1d0200004100000e890000013d0000000001000416000000000001004b0000158f0000c13d000000ab0100003900000a060000013d000000840010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000006401700370000000000101043b0000004402700370000000000202043b0000002403700370000000000303043b0000000404700370000000000404043b000000aa05000039000000000505041a00000af4055001970000000006000411000000000056004b00000d9d0000c13d000000000043001a000009bd0000413d0000000005430019000000000052001a000009bd0000413d0000000005520019000000000015001a000009bd0000413d000000000515001900000b220050009c00000db50000c13d000000ad05000039000000000045041b000000ac05000039000000000035041b000000ab05000039000000000025041b000000a105000039000000000015041b000000800040043f000000a00030043f000000c00020043f000000e00010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b23011001c70000800d02000039000000010300003900000b240400004100000bc50000013d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d00000b2d010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a900010009c00000a9001008041000000c00110021000000b2e011001c700008005020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b00000af4011001970000000002000410000000000012004b00000f760000c13d000000400100043d000000640210003900000b5003000041000010050000013d000000c40010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d000000a401700370000000000101043b000900000001001d0000008401700370000000000101043b000700000001001d0000006401700370000000000101043b000500000001001d0000004401700370000000000101043b000800000001001d0000002401700370000000000101043b000600000001001d0000000401700370000000000101043b000a00000001001d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000009230000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b0000091f0000c13d000000000006004b000009300000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000db90000613d0000001f01400039000000600110018f000400000001001d00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000a7c0000613d0000000a03000029000000000003004b000010d00000c13d00000b200100004100000a7d0000013d0000000001000416000000000001004b0000158f0000c13d000000a60100003900000d910000013d0000000001000416000000000001004b0000158f0000c13d000000a00100003900000a060000013d000000840010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000900000001001d0000002401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000006401700370000000000201043b000000000002004b0000000001000039000000010100c039000800000002001d000000000012004b0000158f0000c13d000000a301000039000000000101041a00000af4011001970000000002000411000000000012004b00000da10000c13d0000004401700370000000000101043b000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000102100039000000000202041a0000000a0220014f00000af4002001980000112b0000c13d0000000201100039000000000201041a000000080000006b000011a70000c13d0000000903000029000009bb0000013d0000000001000416000000000001004b0000158f0000c13d0000009d0100003900000a060000013d0000000001000416000000000001004b0000158f0000c13d2a3916370000040f000000400200043d000000000012043500000a900020009c00000a9002008041000000400120021000000b11011001c700002a3a0001042e0000000001000416000000000001004b0000158f0000c13d000000ad0100003900000a060000013d0000000001000416000000000001004b0000158f0000c13d000000c001000039000000400010043f0000000502000039000000800020043f00000b2b02000041000000a00020043f00000080020000392a3916220000040f000000c00110008a00000a900010009c00000a9001008041000000600110021000000b2c011001c700002a3a0001042e000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d000000a301000039000000000101041a00000af4011001970000000002000411000000000012004b00000da10000c13d0000009d01000039000000000201041a0000000403700370000000000303043b000000000232004b000011320000813d00000b6901000041000000000010043f0000001101000039000000040010043f00000b6a0100004100002a3b000104300000000001000416000000000001004b0000158f0000c13d000000a50100003900000d910000013d000000640010008c0000158f0000413d0000002401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000004401700370000000000401043b0000000401700370000000000301043b0000006501000039000000000201041a000000020020008c00000e380000c13d00000a9101000041000000800010043f0000002001000039000000840010043f0000001f01000039000000a40010043f00000b1201000041000000c40010043f00000b130100004100002a3b00010430000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000aa02000039000000000202041a00000af4022001970000000003000411000000000023004b00000d9d0000c13d000000ae02000039000000000302041a00000b6c03300197000000000313019f000000000032041b000000800010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b03011001c70000800d02000039000000010300003900000b270400004100000bc50000013d0000000001000416000000000001004b0000158f0000c13d0000009e01000039000000000101041a000000800010043f00000b020100004100002a3a0001042e000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b00000af40010009c0000158f0000213d000000000010043f0000009801000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000a00000002001d000000800020043f000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d00000020020000390000000a06000029000000000006004b0000108e0000c13d000000a00100003900000000040200190000109d0000013d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d000000ae01000039000000000101041a00000b0502000041000000800020043f0000000102000039000000840020043f000000000200041100000af402200197000000a40020043f0000000003000414000000080110027000000af40210019700000a900030009c00000a9003008041000000c00130021000000b06011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf00000a5e0000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b00000a5a0000c13d000000000006004b00000a6b0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000e510000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c0000158f0000413d0000000004010019000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b0000112e0000c13d00000b25010000410000000000140435000000400140021000000af8011001c700002a3b00010430000000440010008c0000158f0000413d0000000402700370000000000202043b000a00000002001d00000af40020009c0000158f0000213d0000002402700370000000000302043b00000b090030009c0000158f0000213d0000002302300039000000000012004b0000158f0000813d0000000404300039000000000247034f000000000202043b00000b090020009c00000be00000213d0000001f0620003900000b6d066001970000003f0660003900000b6d0660019700000b360060009c00000be00000213d0000008006600039000000400060043f000000800020043f00000000032300190000002403300039000000000013004b0000158f0000213d0000002001400039000000000317034f00000b6d042001980000001f0520018f000000a00140003900000aad0000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000016004b00000aa90000c13d000000000005004b00000aba0000613d000000000343034f0000000304500210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000310435000000a001200039000000000001043500000b2d010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000a900010009c00000a9001008041000000c00110021000000b2e011001c700008005020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b00000af4011001970000000002000410000000000012004b000008e80000613d00000b3202000041000000000202041a00000af402200197000000000012004b000010020000c13d000000ae01000039000000000201041a000000000100041100000af401100197000000400400043d000900000004001d0000002403400039000000000013043500000b0501000041000000000014043500000004014000390000000403000039000000000031043500000a900040009c00000a900100004100000000010440190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000b19011001c7000000080220027000000af4022001972a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000090b000029000000090570002900000afe0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000afa0000c13d000000000006004b00000b0b0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000012ee0000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000800000002001d00000b090020009c00000be00000213d000000010010019000000be00000c13d0000000801000029000000400010043f000000200030008c0000158f0000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b00000fcb0000613d00000b3701000041000000000101041a000000ff001001900000154a0000c13d00000b39010000410000000802000029000000000012043500000a900020009c00000a900100004100000000010240190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000af8011001c70000000a020000292a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000080570002900000b460000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b00000b420000c13d000000000006004b00000b530000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000001002001900000153e0000613d0000001f01400039000000600110018f000000080110002900000b090010009c00000be00000213d000000400010043f000000200030008c0000158f0000413d0000000802000029000000000202043300000b320020009c000015910000c13d00000b380100004100000000001004430000000a010000290000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000000001004b000015330000613d00000b3201000041000000000201041a00000b07022001970000000a05000029000000000252019f000000000021041b000000000100041400000a900010009c00000a9001008041000000c00110021000000b3c011001c70000800d02000039000000020300003900000b3d040000412a392a2a0000040f00000001002001900000158f0000613d000000400100043d000900000001001d00000b3e0010009c00000be00000213d00000009030000290000006001300039000000400010043f000000400130003900000b3f020000410000000000210435000000200130003900000b4002000041000000000021043500000027010000390000000000130435000000800100043d00000a900010009c00000a90010080410000006001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b41011001c70000000a020000292a392a340000040f000000600310027000000a9005300198000015ca0000c13d0000006003000039000000800400003900000000010304330000000100200190000015f10000613d000000000001004b00000bc80000c13d00000b380100004100000000001004430000000a0100002900000004001004430000000001000414000013990000013d000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d000000aa01000039000000000101041a00000af4011001970000000002000411000000000012004b00000d9d0000c13d0000000401700370000000000101043b000000a002000039000000000012041b000000800010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b03011001c70000800d02000039000000010300003900000b14040000412a392a2a0000040f00000001002001900000158f0000613d000000000100001900002a3a0001042e000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d00000b280020009c00000e5d0000a13d00000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000000240010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000000401700370000000000101043b00000af40010009c0000158f0000213d000000000010043f0000009901000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000301041a000000400200043d000900000002001d000800000003001d0000000002320436000a00000002001d000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d0000000805000029000000000005004b0000000a06000029000000000206001900000c1b0000613d000000000101043b00000000030000190000000002060019000000000401041a00000af404400197000000000242043600000001011000390000000103300039000000000053004b00000c140000413d000000090300002900000000013200490000001f0110003900000b6d021001970000000001320019000000000021004b0000000002000039000000010200403900000b090010009c00000be00000213d000000010020019000000be00000c13d000000400010043f00000020020000390000000002210436000000000303043300000000003204350000004002100039000000000003004b000010ac0000613d0000000004000019000000006506043400000af40550019700000000025204360000000104400039000000000034004b00000c300000413d000010ac0000013d000000640010008c0000158f0000413d0000000001000416000000000001004b0000158f0000c13d0000002401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000004401700370000000000301043b0000000401700370000000000201043b000000ae01000039000000000101041a000000ff0010019000000e8f0000c13d00000b3501000041000000800010043f00000af50100004100002a3b00010430000000840010008c0000158f0000413d0000000401700370000000000101043b000a00000001001d00000af40010009c0000158f0000213d0000004401700370000000000101043b000900000001001d00000af40010009c0000158f0000213d0000006401700370000000000401043b0000002401700370000000000301043b000000a801000039000000000101041a00000af4011001970000000002000411000000000012004b00000fd30000c13d0000006501000039000000000201041a000000020020008c000009d70000613d000800000003001d0000000202000039000000000021041b000700000004001d000000000040043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000301100039000000000101041a000000080010006c00000e4e0000213d0000009d01000039000000000101041a000000080010002a000009bd0000413d0000009f02000039000000000302041a000000a002000039000000000402041a00000000024300a9000000000004004b00000c8a0000613d00000000044200d9000000000034004b000009bd0000c13d0000000801100029000000000021004b000010c60000213d0000000701000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d000600000002001d00000afb0020009c00000be00000213d000000000101043b0000000604000029000000e002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a000000600340003900000000002304350000000402100039000000000202041a000000800340003900000000002304350000000502100039000000000202041a000000a003400039000500000003001d0000000000230435000000c0024000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c0390000000000120435000012eb0000613d0000000701000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000401100039000000000101041a000000080010006b000011a40000213d000000050100002900000000030104330000000601000029000000000201043300000008010000292a39198e0000040f000500000001001d2a391cbf0000040f0000009c01000039000000000201041a0000000102200039000000000021041b000300000002001d000000000020043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000400000001001d0000009d01000039000000000101041a000000080010002a000009bd0000413d00000008011000290000009d02000039000000000012041b0000009e01000039000000000201041a000000050020002a000009bd0000413d0000000502200029000000000021041b000000040100002900000002011000390000000802000029000000000021041b00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d0000000404000029000000000204041a00000b0c03200197000000000201043b000000a00120021000000b0d01100197000000000113019f000000000014041b00000006030000290000000003030433000000000023001a000009bd0000413d0000000002230019000000a00220021000000b0d0220019700000004050000290000000103500039000000000403041a00000b0e04400197000000000242019f0000000a022001af000000000023041b00000b070110019700000009011001af000000000015041b00000004015000390000000702000029000000000021041b0000000501500039000000000201041a000000050020002a000009bd0000413d0000000502200029000000000021041b0000000a01000029000000000010043f0000009801000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000600000002001d00000b090020009c00000be00000213d00000006020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b00000006011000290000000302000029000000000021041b0000000a01000029000000000010043f0000009901000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000600000002001d00000b090020009c00000be00000213d00000006020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000601100029000000000201041a00000b07022001970000000906000029000000000262019f000000000021041b000000400100043d000000600210003900000007030000290000000000320435000000200210003900000008030000290000000000320435000000030200002900000000002104350000004002100039000000000002043500000a900010009c00000a90010080410000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b0f011001c70000800d02000039000000030300003900000b10040000410000000a05000029000015870000013d0000000001000416000000000001004b0000158f0000c13d000000aa01000039000000000101041a00000af401100197000000800010043f00000b020100004100002a3a0001042e0000000001000416000000000001004b0000158f0000c13d00000b0101000041000000800010043f00000b020100004100002a3a0001042e00000b2601000041000000800010043f00000af50100004100002a3b0001043000000b4501000041000000800010043f00000af50100004100002a3b000104300000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000dac0000c13d0000114c0000013d00000b1c01000041000000800010043f00000af50100004100002a3b0001043000000b2001000041000000800010043f00000af50100004100002a3b000104300000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000dc00000c13d0000114c0000013d000000400100043d00000b630200004100000e890000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000dcf0000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000ddb0000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000de70000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000df30000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000dff0000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000e0b0000c13d0000114c0000013d000000640130003900000b2f040000410000000000410435000000440130003900000b3004000041000000000041043500000024013000390000003804000039000000000041043500000a9101000041000000000013043500000004013000390000002003000039000000000031043500000b31012001c700002a3b000104300000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000e270000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000e330000c13d0000114c0000013d000900000003001d0000000202000039000000000021041b000800000004001d000000000040043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000301100039000000000101041a0000000905000029000000000051004b000010b50000a13d000000400100043d00000b670200004100000e890000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000e580000c13d0000114c0000013d000000000101043b0000012003200039000000400030043f000000000301041a00000afa003001980000000004000039000000010400c03900000040052000390000000000450435000000a00430027000000afc044001970000002005200039000000000045043500000af40330019700000000003204350000000103100039000000000303041a000000600420003900000af4053001970000000000540435000000a00330027000000afc06300197000000800320003900000000006304350000000203100039000000000403041a000000a00320003900000000004304350000000303100039000000000303041a000000c00520003900000000003504350000000403100039000000000303041a000000e005200039000000000035043500000100022000390000000501100039000000000101041a0000000000120435000000000004004b00000fd70000c13d000000400100043d00000b2902000041000000000021043500000a900010009c00000a9001008041000000400110021000000af8011001c700002a3b00010430000900000003001d000800000002001d000000a201000039000000000101041a00000af302000041000000800020043f000000000300041400000af40210019700000a900030009c00000a9003008041000000c00130021000000af5011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf00000eab0000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b00000ea70000c13d000000000006004b00000eb80000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000ff60000613d0000001f01400039000000600210018f00000080012001bf000000400010043f000000200030008c0000158f0000413d000000800300043d000000030030008c0000158f0000213d000010c90000c13d0000006503000039000000000403041a000000020040008c000011bf0000c13d00000a9103000041000000000031043500000084032001bf00000020040000390000000000430435000000c40320003900000b12040000410000000000430435000000a4022000390000001f030000390000000000320435000000400110021000000b2a011001c700002a3b0001043000000b1501000041000000800010043f00000af50100004100002a3b000104300000000202000039000000000021041b0000000a01000029000000000010043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000700000001001d0000000401100039000000000101041a000800000001001d000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000301100039000000000101041a000000090010006c00000e4e0000213d0000009d01000039000000000101041a000000090010002a000009bd0000413d0000009f02000039000000000302041a000000a002000039000000000402041a00000000024300a9000000000004004b00000f0d0000613d00000000044200d9000000000034004b000009bd0000c13d0000000901100029000000000021004b000010c60000213d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d000600000002001d00000afb0020009c00000be00000213d000000000101043b0000000605000029000000e002500039000000400020043f000000000201041a00000000022504360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400350003900000000002304350000000303100039000000000303041a000000600450003900000000003404350000000403100039000000000303041a000000800450003900000000003404350000000503100039000000000303041a000000a004500039000400000004001d0000000000340435000000c0035000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c039000000000013043500000007010000290000000101100039000000000101041a000000a00110027000030afc0010019b000000030120006b000500000001001d000009bd0000413d00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000050010006c000015450000813d00000007010000290000000201100039000200000001001d000000000201041a000500000002001d000000090020002a000009bd0000413d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d0000000503000029000500090030002d000000000101043b0000000401100039000000000101041a000000050010006b000015500000a13d000000400100043d00000b650200004100000e890000013d00000b3202000041000000000202041a00000af402200197000000000012004b000010020000c13d000000ae01000039000000000201041a000000000100041100000af401100197000000400400043d000900000004001d0000002403400039000000000013043500000b0501000041000000000014043500000004014000390000000403000039000000000031043500000a900040009c00000a900100004100000000010440190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000b19011001c7000000080220027000000af4022001972a392a2f0000040f000000090b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900000fa50000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000fa10000c13d000000000006004b00000fb20000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000011350000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000800000002001d00000b090020009c00000be00000213d000000010010019000000be00000c13d0000000801000029000000400010043f000000200030008c0000158f0000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b0000158f0000c13d000000000001004b000012fa0000c13d00000b44010000410000000802000029000000000012043500000a900020009c00000a9002008041000000400120021000000af8011001c700002a3b0001043000000b0b01000041000000800010043f00000af50100004100002a3b00010430000a00000006001d000000000030043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000101100039000000000101041a0000000a02000029000000000021001a000009bd0000413d000a00000021001d0000800b01000039000000040300003900000000040004150000000d0440008a000000050440021000000afd020000412a392a0c0000040f0000000a0010006c000000000100003900000001010020390000098f0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000ffd0000c13d0000114c0000013d000000400100043d000000640210003900000b48030000410000000000320435000000440210003900000b4903000041000000000032043500000024021000390000002c03000039000000000032043500000a9102000041000000000021043500000004021000390000002003000039000000000032043500000a900010009c00000a9001008041000000400110021000000b31011001c700002a3b0001043000000b1603000041000000800030043f000000840010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b17011001c72a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf0000102e0000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b0000102a0000c13d000000000006004b0000103b0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000011410000613d0000001f01400039000000600110018f00000080021001bf000800000002001d000000400020043f000000200030008c0000158f0000413d000000800200043d00000b18030000410000000805000029000000000035043500000084031001bf00000009040000290000000000430435000000a4011000390000000000210435000000000100041400000a900010009c00000a9001008041000000c0011002100000004002500210000000000121019f00000b19011001c70000000a020000292a392a2a0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000805700029000010650000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b000010610000c13d000000000006004b000010720000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000012dd0000613d0000001f01400039000000600110018f0000000801100029000000400010043f000000200030008c0000158f0000413d00000008010000290000000001010433000000000001004b0000000002000039000000010200c039000000000021004b00000bc80000613d0000158f0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000010890000c13d0000114c0000013d000000a004000039000000000101043b00000000030000190000000005040019000000000401041a000000000445043600000001011000390000000103300039000000000063004b000010910000413d000000410150008a00000b6d0410019700000b6b0040009c00000be00000813d0000008001400039000000400010043f0000000000210435000000a002400039000000800300043d0000000000320435000000c002400039000000000003004b000010ac0000613d000000a0040000390000000005000019000000004604043400000000026204360000000105500039000000000035004b000010a70000413d000000000212004900000a900020009c00000a9002008041000000600220021000000a900010009c00000a90010080410000004001100210000000000112019f00002a3a0001042e0000009d01000039000000000101041a000000000051001a000009bd0000413d0000009f02000039000000000302041a000000a002000039000000000402041a00000000024300a9000000000004004b000010c30000613d00000000044200d9000000000034004b000009bd0000c13d0000000001510019000000000021004b0000115f0000a13d000000400100043d00000b660200004100000e890000013d00000af7020000410000000000210435000000400110021000000af8011001c700002a3b00010430000000a7010000390000112f0000013d00000b1e1030012a000000000001004b000009450000c13d000000090000006b000009450000613d000000080030006b000009450000213d000000060100002900000b1f0010009c000009450000213d000000070000006b000009450000613d0000000702000029000000050020006c000009450000413d0000000001040019000300000004001d2a39160c0000040f00000003010000290000000a02000029000000000021043500000004020000290000014003200039000a00000003001d000000010100003900000000001304350000012003200039000200000003001d0000000901000029000000000013043500000100032001bf000900000003001d00000007010000290000000000130435000000e003200039000700000003001d00000005010000290000000000130435000000c003200039000500000003001d00000008010000290000000000130435000000a002200039000800000002001d000000060100002900000000001204350000009b01000039000000000101041a000000000010043f0000009a01000039000000200010043f000000400200003900000000010000192a3929f70000040f00000003020000290000000002020433000000000021041b000000080200002900000000020204330000000103100039000000000023041b000000050200002900000000020204330000000203100039000000000023041b000000070200002900000000020204330000000303100039000000000023041b000000090200002900000000020204330000000403100039000000000023041b000000020200002900000000020204330000000503100039000000000023041b0000000601100039000000000301041a00000b6c023001970000000a030000290000000003030433000000000003004b000000010220c1bf000000000021041b0000009b02000039000000000102041a0000000101100039000000000012041b000000000100001900002a3a0001042e000000400100043d00000b460200004100000e890000013d000000a301000039000000000201041a00000b07022001970000000a022001af000000000021041b000000000100001900002a3a0001042e0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000113c0000c13d0000114c0000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000011480000c13d000000000005004b000011590000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a900020009c00000a90020080410000004002200210000000000112019f00002a3b000104300000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d000700000002001d00000afb0020009c00000be00000213d000000000101043b0000000704000029000000e002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a000000600340003900000000002304350000000402100039000000000202041a000000800340003900000000002304350000000502100039000000000202041a000000a003400039000600000003001d0000000000230435000000c0024000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c0390000000000120435000012eb0000613d0000000801000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000401100039000000000101041a000000090010006b000014680000a13d000000400100043d00000b340200004100000e890000013d000000090020002a000009bd0000413d0000000902200029000000000021041b000000000100001900002a3a0001042e0000009d01000039000000000201041a000000090220006c000009bd0000413d000000000021041b0000009e02000039000000000302041a0000000a010000290000000501100039000000000401041a000000000343004b000009bd0000413d000000000032041b0000000802000029000000000002041b000000000001041b000000000100001900002a3a0001042e0000000201000039000000000013041b0000000901000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000301100039000000000101041a000000080010006c00000e4e0000213d0000009d01000039000000000101041a000000080010002a000009bd0000413d0000009f02000039000000000302041a000000a002000039000000000402041a00000000024300a9000000000004004b000011e10000613d00000000044200d9000000000034004b000009bd0000c13d0000000801100029000000000021004b000010c60000213d0000000901000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000400200043d000700000002001d00000afb0020009c00000be00000213d000000000101043b0000000704000029000000e002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a000000600340003900000000002304350000000402100039000000000202041a000000800340003900000000002304350000000502100039000000000202041a000000a003400039000600000003001d0000000000230435000000c0024000390000000601100039000000000101041a000000ff001001900000000001000039000000010100c0390000000000120435000012eb0000613d0000000901000029000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000401100039000000000101041a000000080010006b000011a40000213d000000060100002900000000030104330000000701000029000000000201043300000008010000292a39198e0000040f000600000001001d2a3921cd0000040f0000009c01000039000000000201041a0000000102200039000000000021041b000400000002001d000000000020043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000500000001001d0000009d01000039000000000101041a000000080010002a000009bd0000413d00000008011000290000009d02000039000000000012041b0000009e01000039000000000201041a000000060020002a000009bd0000413d0000000602200029000000000021041b000000050100002900000002011000390000000802000029000000000021041b00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d0000000504000029000000000204041a00000b0c03200197000000000201043b000000a00120021000000b0d01100197000000000113019f000000000014041b00000007030000290000000003030433000000000023001a000009bd0000413d0000000002230019000000a00220021000000b0d0220019700000005050000290000000103500039000000000403041a00000b0e04400197000000000224019f0000000004000411000000000242019f000000000023041b00000b07011001970000000a011001af000000000015041b00000004015000390000000902000029000000000021041b0000000501500039000000000201041a000000060020002a000009bd0000413d0000000602200029000000000021041b0000000001000411000000000010043f0000009801000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000700000002001d00000b090020009c00000be00000213d00000007020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b00000007011000290000000402000029000000000021041b0000000001000411000000000010043f0000009901000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000700000002001d00000b090020009c00000be00000213d00000007020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000701100029000000000201041a00000b07022001970000000a06000029000000000262019f000000000021041b000000400100043d0000006002100039000000090300002900000000003204350000000102000039000000400310003900000000002304350000002002100039000000080300002900000000003204350000000402000029000000000021043500000a900010009c00000a900100804100000040011002100000000002000414000015190000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012e40000c13d0000114c0000013d00000b0b02000041000010ca0000013d000000400100043d00000b330200004100000e890000013d0000001f0530018f00000af606300198000000400200043d00000000046200190000114c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012f50000c13d0000114c0000013d000000080100002900000b4a0010009c00000be00000213d00000008010000290000002002100039000900000002001d000000400020043f000000000001043500000b3701000041000000000101041a000000ff00100190000015230000c13d000000400200043d000700000002001d00000b3901000041000000000012043500000a900020009c00000a900100004100000000010240190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000af8011001c70000000a020000292a392a2f0000040f000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000070b0000290000000705700029000013260000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000013220000c13d000000000006004b000013330000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000001002001900000153e0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000b090010009c00000be00000213d000000010020019000000be00000c13d000000400010043f000000200030008c0000158f0000413d00000000020b043300000b320020009c000015910000c13d00000b380100004100000000001004430000000a010000290000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000000001004b000015330000613d00000b3201000041000000000201041a00000b07022001970000000a05000029000000000252019f000000000021041b000000000100041400000a900010009c00000a9001008041000000c00110021000000b3c011001c70000800d02000039000000020300003900000b3d040000412a392a2a0000040f00000001002001900000158f0000613d00000008010000290000000001010433000000000001004b00000bc80000613d000000400100043d000700000001001d00000b3e0010009c00000be00000213d00000007030000290000006001300039000000400010043f000000400130003900000b3f020000410000000000210435000000200130003900000b4002000041000000000021043500000027010000390000000000130435000000090100002900000a900010009c00000a900100804100000040011002100000000802000029000000000202043300000a900020009c00000a90020080410000006002200210000000000112019f000000000200041400000a900020009c00000a9002008041000000c002200210000000000121019f0000000a020000292a392a340000040f000000600310027000000a90053001980000159a0000c13d0000006003000039000000800400003900000000010304330000000100200190000015c10000613d000000000001004b00000bc80000c13d00000b380100004100000000001004430000000a010000290000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000000001004b00000bc80000c13d000000400100043d000000440210003900000b4d03000041000000000032043500000024021000390000001d030000390000076a0000013d00000002010000290000000501100270000000000100003f000000400100043d000000640210003900000b51030000410000000000320435000000440210003900000b5203000041000000000032043500000024021000390000002e030000390000100b0000013d0000000a0100002900000af402100197000000080100002900000af403100197000000060100002900000af404100197000000050100002900000af405100197000000040100002900000af40110019700000001070000390000006506000039000000000076041b000000a206000039000000000706041a00000b0707700197000000000227019f000000000026041b000000a402000039000000000602041a00000b070660019700000009066001af000000000062041b000000a502000039000000000602041a00000b0706600197000000000336019f000000000032041b000000aa02000039000000000302041a00000b0703300197000000000343019f000000ae04000039000000000604041a000000000032041b000000a602000039000000000302041a00000b0703300197000000000353019f000000000032041b000000a702000039000000000302041a00000b0703300197000000000113019f000000000012041b000000a801000039000000000201041a00000b07022001970000000003000411000000000232019f000000000021041b0000000701000029000000080110021000000b540110019700000b5502600197000000000112019f000000000014041b00000b5601000041000000ab02000039000000000012041b00000b5701000041000000ac02000039000000000012041b00000b5801000041000000ad02000039000000000012041b00000b5901000041000000a002000039000000000012041b00000b5a01000041000000a102000039000000000012041b00000032010000390000009f02000039000000000012041b000000030100002900000afb0010009c00000be00000213d0000000302000029000000e001200039000000400010043f000000c0032000390000000101000039000a00000003001d0000000000130435000000a00320003900000b5b01000041000900000003001d0000000000130435000000800320003900000b5c01000041000800000003001d0000000000130435000000600320003900000b5d01000041000700000003001d0000000000130435000000400320003900000b5e01000041000600000003001d000000000013043500000b5f01000041000000000212043600000b6001000041000500000002001d00000000001204350000009b01000039000000000101041a000000000010043f0000009a01000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d00000003020000290000000002020433000000000101043b000000000021041b000000050200002900000000020204330000000103100039000000000023041b000000060200002900000000020204330000000203100039000000000023041b000000070200002900000000020204330000000303100039000000000023041b000000080200002900000000020204330000000403100039000000000023041b000000090200002900000000020204330000000503100039000000000023041b0000000601100039000000000201041a00000b6c022001970000000a030000290000000003030433000000000003004b000000010220c1bf000000000021041b0000009b02000039000000000102041a0000000101100039000000000012041b000000010000006b00000bc80000c13d000000000200041a00000b6e01200197000000000010041b000000400100043d0000000103000039000000000031043500000a900010009c00000a90010080410000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b08011001c70000800d0200003900000a960400004100000bc50000013d000000060100002900000000030104330000000701000029000000000201043300000009010000292a39198e0000040f000600000001001d2a391cbf0000040f0000009c01000039000000000201041a0000000102200039000000000021041b000400000002001d000000000020043f0000009701000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000500000001001d0000009d02000039000000000102041a0000000903000029000000000031001a000009bd0000413d0000000001310019000000000012041b0000009e01000039000000000201041a000000060020002a000009bd0000413d0000000602200029000000000021041b00000005010000290000000201100039000000000031041b00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f00000001002001900000153d0000613d0000000504000029000000000204041a00000b0c03200197000000000201043b000000a00120021000000b0d01100197000000000113019f000000000014041b00000007030000290000000003030433000000000023001a000009bd0000413d0000000002230019000000a00220021000000b0d0220019700000005050000290000000103500039000000000403041a00000b0e04400197000000000224019f0000000004000411000000000242019f000000000023041b00000b07011001970000000a011001af000000000015041b00000004015000390000000802000029000000000021041b0000000501500039000000000201041a000000060020002a000009bd0000413d0000000602200029000000000021041b0000000001000411000000000010043f0000009801000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000700000002001d00000b090020009c00000be00000213d00000007020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b00000007011000290000000402000029000000000021041b0000000001000411000000000010043f0000009901000039000000200010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000af9011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b000000000201041a000700000002001d00000b090020009c00000be00000213d00000007020000290000000102200039000000000021041b000000000010043f000000000100041400000a900010009c00000a9001008041000000c00110021000000b08011001c700008010020000392a392a2f0000040f00000001002001900000158f0000613d000000000101043b0000000701100029000000000201041a00000b07022001970000000a06000029000000000262019f000000000021041b000000400100043d000000600210003900000008030000290000000000320435000000200210003900000009030000290000000000320435000000040200002900000000002104350000004002100039000000000002043500000a900010009c00000a90010080410000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b0f011001c70000800d02000039000000030300003900000b10040000410000000005000411000015870000013d00000b380100004100000000001004430000000a010000290000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f00000001002001900000153d0000613d000000000101043b000000000001004b000015480000c13d000000400100043d000000640210003900000b4e030000410000000000320435000000440210003900000b4f03000041000000000032043500000024021000390000002d030000390000100b0000013d000000000001042f000000400100043d000000640210003900000b4b030000410000000000320435000000440210003900000b4c03000041000013b40000013d000000400100043d00000b640200004100000e890000013d00000b32010000410000112f0000013d00000b380100004100000000001004430000000a0100002900000004001004430000000001000414000015280000013d0000000401000029000000000401043300000006010000290000000003010433000000090100002900000003020000292a391a770000040f000800000001001d2a391cbf0000040f0000009d01000039000000000101041a000000090010002a000009bd0000413d00000009011000290000009d02000039000000000012041b0000009e01000039000000000201041a000000080020002a000009bd0000413d0000000802200029000000000021041b00000002010000290000000502000029000000000021041b00000007010000290000000501100039000000000201041a000000080020002a000009bd0000413d0000000802200029000000000021041b0000000701000029000000000201041a000000400100043d0000002003100039000000090400002900000000004304350000000a0300002900000000003104350000004003100039000000000003043500000a900010009c00000a90010080410000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000aff011001c700000af4052001970000800d02000039000000020300003900000b00040000412a392a2a0000040f00000001002001900000158f0000613d00000001010000390000006502000039000000000012041b000000000100001900002a3a0001042e000000000100001900002a3b00010430000000640210003900000b3a030000410000000000320435000000440210003900000b3b030000410000000000320435000000240210003900000029030000390000100b0000013d0000001f0350003900000b42033001970000003f0330003900000b4304300197000000400300043d0000000004430019000000000034004b0000000006000039000000010600403900000b090040009c00000be00000213d000000010060019000000be00000c13d000000400040043f0000001f0650018f000000000453043600000af6075001980000000005740019000015b30000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000059004b000015af0000c13d000000000006004b0000138f0000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000138f0000013d000000000001004b000016040000c13d000000400200043d000a00000002001d00000a9101000041000000000012043500000004012000390000000702000029000015f90000013d0000001f0350003900000b42033001970000003f0330003900000b4304300197000000400300043d0000000004430019000000000034004b0000000006000039000000010600403900000b090040009c00000be00000213d000000010060019000000be00000c13d000000400040043f0000001f0650018f000000000453043600000af6075001980000000005740019000015e30000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000059004b000015df0000c13d000000000006004b00000ba20000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000ba20000013d000000000001004b000016040000c13d000000400200043d000a00000002001d00000a91010000410000000000120435000000040120003900000009020000292a3916220000040f0000000a02000029000000000121004900000a900010009c00000a9001008041000000600110021000000a900020009c00000a90020080410000004002200210000000000121019f00002a3b0001043000000a900040009c00000a9004008041000000400240021000000a900010009c00000a90010080410000006001100210000000000121019f00002a3b0001043000000b6f0010009c000016110000813d000000e001100039000000400010043f000000000001042d00000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b0001043000000b700010009c0000161c0000813d0000012001100039000000400010043f000000000001042d00000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b0001043000000020030000390000000004310436000000003202043400000000002404350000004001100039000000000002004b000016310000613d000000000400001900000000054100190000000006430019000000000606043300000000006504350000002004400039000000000024004b0000162a0000413d000000000321001900000000000304350000001f0220003900000b6d022001970000000001210019000000000001042d0001000000000002000000a301000039000000000201041a000000400300043d000100000003001d00000b6801000041000000000013043500000a900030009c00000a900100004100000000010340190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000af8011001c700000af4022001972a392a2f0000040f000000010b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b00190000165a0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000016560000c13d000000000006004b000016670000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000016780000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000b090010009c000016960000213d0000000100200190000016960000c13d000000400010043f0000001f0030008c0000169c0000a13d00000000010b0433000000000001042d0000001f0530018f00000af606300198000000400200043d0000000004620019000016830000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000167f0000c13d000000000005004b000016900000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a900020009c00000a90020080410000004002200210000000000112019f00002a3b0001043000000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000000000100001900002a3b0001043000040000000000020000009e01000039000000000101041a000000a102000039000000000202041a000000000002004b000016c40000613d00000b710020009c000000000402001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700430008c000016cb0000413d000000000004004b000016cd0000613d000000000242022f000016cd0000013d00000000020000190000000003000019000000000001004b000016d40000c13d00000000010000190000000005000019000016fa0000013d000000700430008900000000024201cf00000b72022001970000007003300210000000000223019f00000b730220009a0000008003200210000000000001004b000016c80000613d00000b710010009c000000000501001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700540008c000016f30000413d000000000005004b000016f50000613d000000000151022f000016f50000013d000000700540008900000000015101cf00000b72011001970000007004400210000000000114019f00000b730110009a0000008005100210000000f00430027000007fff0040008c000018010000613d000000f00650027000007fff0060008c000018010000613d000000a007000039000000000707041a00000b720220019700000b750030009c00000b74022081c700000b720110019700000b750050009c00000b74011081c700000000012100aa0000172d0000613d000000010040008c000000010400a039000000010060008c000000010600a039000000000246001900000b760010009c0000172f0000813d00000b770010009c000017310000213d00000b710010009c000000000401001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000017320000013d00000000010000190000176d0000013d000000e103000039000017320000013d000000e00300003900000000042300190000406f0040008c00000000050000190000000006000019000017580000a13d000040e00040008c000017410000413d0000c0dd0040008c000017490000213d000000700230008c000017510000213d000017520000613d000000700230008900000000012101cf000017520000013d000040700320008c0000174c0000413d000000000003004b000017560000613d00000000053101cf000000ff0030008c0000000005002019000017570000013d00000b78060000410000000005000019000017580000013d0000407003200089000000000531022f00003f710020008c0000000005004019000017570000013d000000000121022f00000b7205100197000000700140021000000b790610009a000017580000013d00000000050100190000000006000019000000000356019f000000700130027000007fff0210018f00003fff0020008c00000000010000190000176d0000413d000000800130021000000b7a0010009c000018010000213d000040ff0020008c000018010000813d00000b720130019700000b74011001c70000406f0320008c0000176b0000413d000000000003004b0000176d0000613d00000000013101cf0000176d0000013d0000406f02200089000000000121022f00020b2200100132000000020070002a000018160000413d000400000007001d000000a201000039000000000101041a00000b1a02000041000000000020044300000af4011001970000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f0000000100200190000018090000613d000000000101043b000100000001001d000000a301000039000000000201041a000000400300043d000300000003001d00000b6801000041000000000013043500000a900030009c00000a900100004100000000010340190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000af8011001c700000af4022001972a392a2f0000040f000000030b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000017a40000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000017a00000c13d000000000006004b000017b10000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000180a0000613d0000001f01400039000000600110018f0000000004b10019000000000014004b0000000001000039000000010100403900000b090040009c0000000402000029000018030000213d0000000100100190000018030000c13d000000400040043f000000200030008c000018010000413d00000000010b0433000000010110006b000018160000413d00000002022000290000002403400039000000000023043500000b7b0200004100000000002404350000000402400039000000000012043500000a900040009c00000a900100004100000000010440190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b19011001c700000a8f02000041000400000004001d2a392a340000040f000000040b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000017e80000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000017e40000c13d000000000006004b000017f50000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000181c0000613d0000001f01400039000000600110018f0000000001b1001900000b090010009c000018030000213d000000400010043f000000200030008c000018010000413d00000000010b0433000000000001042d000000000100001900002a3b0001043000000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000000000001042f0000001f0530018f00000af606300198000000400200043d0000000004620019000018270000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000018110000c13d000018270000013d00000b6901000041000000000010043f0000001101000039000000040010043f00000b6a0100004100002a3b000104300000001f0530018f00000af606300198000000400200043d0000000004620019000018270000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000018230000c13d000000000005004b000018340000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a900020009c00000a90020080410000004002200210000000000112019f00002a3b000104300000009e01000039000000000101041a000000a102000039000000000202041a000000000002004b0000185f0000613d00000b710020009c000000000402001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700430008c000018660000413d000000000004004b000018680000613d000000000242022f000018680000013d00000000020000190000000003000019000000000001004b0000186f0000c13d00000000050000190000000006000019000018950000013d000000700430008900000000024201cf00000b72022001970000007003300210000000000223019f00000b730220009a0000008003200210000000000001004b000018630000613d00000b710010009c000000000501001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700540008c0000188e0000413d000000000005004b000018900000613d000000000151022f000018900000013d000000700540008900000000015101cf00000b72011001970000007004400210000000000114019f00000b730510009a0000008006500210000000f00430027000007fff0040008c0000190d0000613d000000f00760027000007fff0070008c0000190d0000613d000000a001000039000000000101041a00000b720220019700000b750030009c00000b74022081c700000b720350019700000b750060009c00000b74033081c700000000022300aa000018c80000613d000000010040008c000000010400a039000000010070008c000000010700a039000000000347001900000b760020009c000018ca0000813d00000b770020009c000018cc0000213d00000b710020009c000000000502001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000018cd0000013d0000000002000019000019080000013d000000e104000039000018cd0000013d000000e00400003900000000053400190000406f0050008c00000000060000190000000007000019000018f30000a13d000040e00050008c000018dc0000413d0000c0dd0050008c000018e40000213d000000700340008c000018ec0000213d000018ed0000613d000000700340008900000000023201cf000018ed0000013d000040700430008c000018e70000413d000000000004004b000018f10000613d00000000064201cf000000ff0040008c0000000006002019000018f20000013d00000b78070000410000000006000019000018f30000013d0000407004300089000000000642022f00003f710030008c0000000006004019000018f20000013d000000000232022f00000b7206200197000000700250021000000b790720009a000018f30000013d00000000060200190000000007000019000000000467019f000000700240027000007fff0320018f00003fff0030008c0000000002000019000019080000413d000000800240021000000b7a0020009c0000190d0000213d000040ff0030008c0000190d0000813d00000b720240019700000b74022001c70000406f0430008c000019060000413d000000000004004b000019080000613d00000000024201cf000019080000013d0000406f03300089000000000232022f00000b220220012a000000000012001a0000190f0000413d0000000001120019000000000001042d000000000100001900002a3b0001043000000b6901000041000000000010043f0000001101000039000000040010043f00000b6a0100004100002a3b000104300001000000000002000000a201000039000000000201041a000000400300043d000100000003001d00000af301000041000000000013043500000a900030009c00000a900100004100000000010340190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000af8011001c700000af4022001972a392a2f0000040f000000010b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000019380000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000019340000c13d000000000006004b000019450000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000195c0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000b090010009c0000197a0000213d00000001002001900000197a0000c13d000000400010043f0000001f0030008c0000195a0000a13d00000000010b0433000000030010008c0000195a0000213d00000000010000390000000101006039000000000001042d000000000100001900002a3b000104300000001f0530018f00000af606300198000000400200043d0000000004620019000019670000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000019630000c13d000000000005004b000019740000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a900020009c00000a90020080410000004002200210000000000112019f00002a3b0001043000000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000000000301001900000000011200a9000000000003004b000019870000613d00000000033100d9000000000023004b000019880000c13d000000000001042d00000b6901000041000000000010043f0000001101000039000000040010043f00000b6a0100004100002a3b000104300002000000000002000100000002001d000000000001004b000019b10000613d00000b710010009c000000000401001900000080044022700000000002000039000000800200203900000b090040009c00000040022021bf000000400440227000000a900040009c00000020022021bf00000020044022700000ffff0040008c00000010022021bf0000001004402270000000ff0040008c000000080220203900000008044022700000000f0040008c00000004022020390000000404402270000000030040008c00000002022020390000000204402270000000010040008c0000000102202039000000700420008c000019b80000413d000000000004004b000019ba0000613d000000000141022f000019ba0000013d00000000010000190000000002000019000000000003004b000019c10000c13d00000000040000190000000005000019000019e70000013d000000700420008900000000014101cf00000b72011001970000007002200210000000000112019f00000b730110009a0000008002100210000000000003004b000019b50000613d00000b710030009c000000000503001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700540008c000019e00000413d000000000005004b000019e20000613d000000000353022f000019e20000013d000000700540008900000000035301cf00000b72033001970000007004400210000000000334019f00000b730430009a0000008005400210000000f00320027000007fff0030008c00001a6e0000613d000000f00650027000007fff0060008c00001a6e0000613d00000b720110019700000b750020009c00000b74011081c700000b720240019700000b750050009c00000b74022081c700000000011200aa00001a180000613d000000010030008c000000010300a039000000010060008c000000010600a039000000000236001900000b760010009c00001a1a0000813d00000b770010009c00001a1c0000213d00000b710010009c000000000401001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c000000010330203900001a1d0000013d000000000300001900001a580000013d000000e10300003900001a1d0000013d000000e00300003900000000042300190000406f0040008c0000000005000019000000000600001900001a430000a13d000040e00040008c00001a2c0000413d0000c0dd0040008c00001a340000213d000000700230008c00001a3c0000213d00001a3d0000613d000000700230008900000000012101cf00001a3d0000013d000040700320008c00001a370000413d000000000003004b00001a410000613d00000000053101cf000000ff0030008c000000000500201900001a420000013d00000b7806000041000000000500001900001a430000013d0000407003200089000000000531022f00003f710020008c000000000500401900001a420000013d000000000121022f00000b7205100197000000700140021000000b790610009a00001a430000013d00000000050100190000000006000019000000000256019f000000700120027000007fff0110018f00003fff0010008c000000000300001900001a580000413d000000800320021000000b7a0030009c00001a6e0000213d000040ff0010008c00001a6e0000813d00000b720220019700000b74032001c70000406f0210008c00001a560000413d000000000002004b00001a580000613d00000000032301cf00001a580000013d0000406f01100089000000000313022f000200000003001d00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f000000010020019000001a700000613d000000000101043b000000000001004b000000020100002900001a6c0000c13d000000010100002900000b7c0010009c000000000100001900001a710000a13d00000b220110012a000000000001042d000000000100001900002a3b00010430000000000001042f00000b6901000041000000000010043f0000001201000039000000040010043f00000b6a0100004100002a3b000104300005000000000002000100000003001d00000000090200190000000007010019000000000001004b00001a9d0000613d00000b710070009c000000000207001900000080022022700000000001000039000000800100203900000b090020009c00000040011021bf000000400220227000000a900020009c00000020011021bf00000020022022700000ffff0020008c00000010011021bf0000001002202270000000ff0020008c000000080110203900000008022022700000000f0020008c00000004011020390000000402202270000000030020008c00000002011020390000000202202270000000010020008c0000000101102039000000700310008c00001aa40000413d000000000003004b000000000207001900001aa60000613d000000000237022f00001aa60000013d00000000010000190000000002000019000000000004004b00001aad0000c13d0000000008000019000000000500001900001ad40000013d000000700210008900000000022701cf00000b72022001970000007001100210000000000121019f00000b730110009a0000008002100210000000000004004b00001aa10000613d00000b710040009c000000000504001900000080055022700000000003000039000000800300203900000b090050009c00000040033021bf000000400550227000000a900050009c00000020033021bf00000020055022700000ffff0050008c00000010033021bf0000001005502270000000ff0050008c000000080330203900000008055022700000000f0050008c00000004033020390000000405502270000000030050008c00000002033020390000000205502270000000010050008c0000000103302039000000700530008c00001acd0000413d000000000005004b000000000604001900001acf0000613d000000000654022f00001acf0000013d000000700530008900000000065401cf00000b72056001970000007003300210000000000353019f00000b730830009a0000008005800210000000f00320027000007fff0030008c00001c370000613d000000f00650027000007fff0060008c00001c370000613d00000b720110019700000b750020009c00000b74011081c700000b720280019700000b750050009c00000b74022081c700000000011200aa00001b050000613d000000010030008c000000010300a039000000010060008c000000010600a039000000000236001900000b760010009c00001b070000813d00000b770010009c00001b090000213d00000b710010009c000000000501001900000080055022700000000003000039000000800300203900000b090050009c00000040033021bf000000400550227000000a900050009c00000020033021bf00000020055022700000ffff0050008c00000010033021bf0000001005502270000000ff0050008c000000080330203900000008055022700000000f0050008c00000004033020390000000405502270000000030050008c00000002033020390000000205502270000000010050008c000000010330203900001b0a0000013d000000000300001900001b450000013d000000e10300003900001b0a0000013d000000e00300003900000000082300190000406f0080008c0000000005000019000000000600001900001b300000a13d000040e00080008c00001b190000413d0000c0dd0080008c00001b210000213d000000700230008c00001b290000213d00001b2a0000613d000000700230008900000000012101cf00001b2a0000013d000040700320008c00001b240000413d000000000003004b00001b2e0000613d00000000053101cf000000ff0030008c000000000500201900001b2f0000013d00000b7806000041000000000500001900001b300000013d0000407003200089000000000531022f00003f710020008c000000000500401900001b2f0000013d000000000121022f00000b7205100197000000700180021000000b790610009a00001b300000013d00000000050100190000000006000019000000000256019f000000700120027000007fff0110018f00003fff0010008c000000000300001900001b450000413d000000800320021000000b7a0030009c00001c370000213d000040ff0010008c00001c370000813d00000b720220019700000b74032001c70000406f0210008c00001b430000413d000000000002004b00001b450000613d00000000032301cf00001b450000013d0000406f01100089000000000313022f000200000003001d000300000009001d000400000004001d000500000007001d00000afd010000410000000000100443000000000100041400000a900010009c00000a9001008041000000c00110021000000afe011001c70000800b020000392a392a2f0000040f000000010020019000001c390000613d000000000101043b000000030110006b00000005040000290000000405000029000000020300002900001c350000413d000000010200002900000b7c0020009c00001c3a0000a13d00000b1e3210012a000000000003004b00001b620000613d000000010220003900001b650000013d00000b1e0010009c000000000100001900001b6c0000413d000000010100002900000b1e0110012a00000000031500d900000000013200a900000000022100d9000000000032004b00001c400000c13d000000000004004b00001b8d0000613d00000b710040009c000000000304001900000080033022700000000002000039000000800200203900000b090030009c00000040022021bf000000400330227000000a900030009c00000020022021bf00000020033022700000ffff0030008c00000010022021bf0000001003302270000000ff0030008c000000080220203900000008033022700000000f0030008c00000004022020390000000403302270000000030030008c00000002022020390000000203302270000000010030008c0000000102202039000000700320008c00001b940000413d000000000003004b00001b960000613d000000000434022f00001b960000013d00000000020000190000000003000019000000000001004b00001b9d0000c13d0000000001000019000000000500001900001bc30000013d000000700320008900000000043401cf00000b72034001970000007002200210000000000232019f00000b730220009a0000008003200210000000000001004b00001b910000613d00000b710010009c000000000501001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700540008c00001bbc0000413d000000000005004b00001bbe0000613d000000000151022f00001bbe0000013d000000700540008900000000015101cf00000b72011001970000007004400210000000000114019f00000b730110009a0000008005100210000000f00430027000007fff0040008c00001c370000613d000000f00650027000007fff0060008c00001c370000613d00000b720220019700000b750030009c00000b74022081c700000b720110019700000b750050009c00000b74011081c700000000012100aa00001bf40000613d000000010040008c000000010400a039000000010060008c000000010600a039000000000246001900000b760010009c00001bf60000813d00000b770010009c00001bf80000213d00000b710010009c000000000401001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c000000010330203900001bf90000013d00000b220100012a000000000001042d000000e10300003900001bf90000013d000000e00300003900000000042300190000406f0040008c0000000005000019000000000600001900001c1f0000a13d000040e00040008c00001c080000413d0000c0dd0040008c00001c100000213d000000700230008c00001c180000213d00001c190000613d000000700230008900000000012101cf00001c190000013d000040700320008c00001c130000413d000000000003004b00001c1d0000613d00000000053101cf000000ff0030008c000000000500201900001c1e0000013d00000b7806000041000000000500001900001c1f0000013d0000407003200089000000000531022f00003f710020008c000000000500401900001c1e0000013d000000000121022f00000b7205100197000000700140021000000b790610009a00001c1f0000013d00000000050100190000000006000019000000000256019f000000700120027000007fff0110018f00003fff0010008c000000000300001900001c350000413d000000800320021000000b7a0030009c00001c370000213d000040fe0010008c00001c370000213d00000b720220019700000b74032001c70000406f0210008c00001c330000413d000000000002004b00001c350000613d00000000032301cf00000b220130012a000000000001042d0000406f01100089000000000313022f00000b220130012a000000000001042d000000000100001900002a3b00010430000000000001042f00000b6901000041000000000010043f0000001201000039000000040010043f00000b6a0100004100002a3b0001043000000b6901000041000000000010043f0000001101000039000000040010043f00000b6a0100004100002a3b000104300002000000000002000200000002001d000100000001001d00000b1a01000041000000000010044300000000010004100000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f000000010020019000001c930000613d000000000101043b0000000203000029000000000031004b00001c940000413d000000010100002900000af404100197000000000100041400000a900010009c00000a9001008041000000c001100210000000000003004b00001c660000613d00000b3c011001c70000800902000039000000000500001900001c670000013d00000000020400192a392a2a0000040f000000600310027000000a900330019800001c900000613d0000001f0430003900000b42044001970000003f0440003900000b4304400197000000400500043d0000000004450019000000000054004b0000000006000039000000010600403900000b090040009c00001cb90000213d000000010060019000001cb90000c13d000000400040043f0000001f0430018f000000000635043600000af605300198000000000356001900001c830000613d000000000701034f000000007807043c0000000006860436000000000036004b00001c7f0000c13d000000000004004b00001c900000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000010020019000001ca50000613d000000000001042d000000000001042f000000400100043d000000440210003900000b7f03000041000000000032043500000024021000390000001d03000039000000000032043500000a9102000041000000000021043500000004021000390000002003000039000000000032043500000a900010009c00000a9001008041000000400110021000000b2a011001c700002a3b00010430000000400100043d000000640210003900000b7d030000410000000000320435000000440210003900000b7e03000041000000000032043500000024021000390000003a03000039000000000032043500000a9102000041000000000021043500000004021000390000002003000039000000000032043500000a900010009c00000a9001008041000000400110021000000b31011001c700002a3b0001043000000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000a00000000000200000000080100190000000001000416000000000081004b000021a50000413d000000ad01000039000000000201041a000000000008004b000000800180027000001ce90000613d00000b710080009c000000000408001900000000040120190000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700530008c00001cf00000413d000000000005004b000000000408001900001cf20000613d000000000458022f00001cf20000013d00000000030000190000000004000019000000000002004b00001cf90000c13d0000000002000019000000000600001900001d1f0000013d000000700430008900000000044801cf00000b72044001970000007003300210000000000343019f00000b730330009a0000008004300210000000000002004b00001ced0000613d00000b710020009c000000000602001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c0000000105502039000000700650008c00001d180000413d000000000006004b00001d1a0000613d000000000262022f00001d1a0000013d000000700650008900000000026201cf00000b72022001970000007005500210000000000225019f00000b730220009a0000008006200210000000f00540027000007fff0050008c000021770000613d000000f00760027000007fff0070008c000021770000613d00000b720330019700000b750040009c00000b74033081c700000b720220019700000b750060009c00000b74022081c700000000023200aa00001d500000613d000000010050008c000000010500a039000000010070008c000000010700a039000000000357001900000b760020009c00001d520000813d00000b770020009c00001d540000213d00000b710020009c000000000502001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c000000010440203900001d550000013d000000000900001900001d900000013d000000e10400003900001d550000013d000000e00400003900000000053400190000406f0050008c0000000006000019000000000700001900001d7b0000a13d000040e00050008c00001d640000413d0000c0dd0050008c00001d6c0000213d000000700340008c00001d740000213d00001d750000613d000000700340008900000000023201cf00001d750000013d000040700430008c00001d6f0000413d000000000004004b00001d790000613d00000000064201cf000000ff0040008c000000000600201900001d7a0000013d00000b7807000041000000000600001900001d7b0000013d0000407004300089000000000642022f00003f710030008c000000000600401900001d7a0000013d000000000232022f00000b7206200197000000700250021000000b790720009a00001d7b0000013d00000000060200190000000007000019000000000367019f000000700230027000007fff0220018f00003fff0020008c000000000900001900001d900000413d000000800430021000000b7a0040009c000021770000213d000040ff0020008c000021770000813d00000b720330019700000b74093001c70000406f0320008c00001d8e0000413d000000000003004b00001d900000613d00000000093901cf00001d900000013d0000406f02200089000000000929022f000000ac02000039000000000202041a000000000008004b00001db40000613d00000b710080009c000000000408001900000000040120190000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700530008c00001dbb0000413d000000000005004b000000000408001900001dbd0000613d000000000458022f00001dbd0000013d00000000030000190000000004000019000000000002004b00001dc40000c13d0000000002000019000000000600001900001dea0000013d000000700430008900000000044801cf00000b72044001970000007003300210000000000343019f00000b730330009a0000008004300210000000000002004b00001db80000613d00000b710020009c000000000602001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c0000000105502039000000700650008c00001de30000413d000000000006004b00001de50000613d000000000262022f00001de50000013d000000700650008900000000026201cf00000b72022001970000007005500210000000000225019f00000b730220009a0000008006200210000000f00540027000007fff0050008c000021770000613d000000f00760027000007fff0070008c000021770000613d00000b720330019700000b750040009c00000b74033081c700000b720220019700000b750060009c00000b74022081c700000000023200aa00001e1b0000613d000000010050008c000000010500a039000000010070008c000000010700a039000000000357001900000b760020009c00001e1d0000813d00000b770020009c00001e1f0000213d00000b710020009c000000000502001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c000000010440203900001e200000013d000000000400001900001e5b0000013d000000e10400003900001e200000013d000000e00400003900000000053400190000406f0050008c0000000006000019000000000700001900001e460000a13d000040e00050008c00001e2f0000413d0000c0dd0050008c00001e370000213d000000700340008c00001e3f0000213d00001e400000613d000000700340008900000000023201cf00001e400000013d000040700430008c00001e3a0000413d000000000004004b00001e440000613d00000000064201cf000000ff0040008c000000000600201900001e450000013d00000b7807000041000000000600001900001e460000013d0000407004300089000000000642022f00003f710030008c000000000600401900001e450000013d000000000232022f00000b7206200197000000700250021000000b790720009a00001e460000013d00000000060200190000000007000019000000000367019f000000700230027000007fff0220018f00003fff0020008c000000000400001900001e5b0000413d000000800430021000000b7a0040009c000021770000213d000040fe0020008c000021770000213d00000b720330019700000b74043001c70000406f0320008c00001e590000413d000000000003004b00001e5b0000613d00000000043401cf00001e5b0000013d0000406f02200089000000000424022f000a00000004001d000000ab02000039000000000202041a000000000008004b00001e800000613d00000b710080009c000000000408001900000000040120190000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700530008c00001e870000413d000000000005004b000000000408001900001e890000613d000000000458022f00001e890000013d00000000030000190000000004000019000000000002004b00001e900000c13d0000000002000019000000000600001900001eb60000013d000000700430008900000000044801cf00000b72044001970000007003300210000000000343019f00000b730330009a0000008004300210000000000002004b00001e840000613d00000b710020009c000000000602001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c0000000105502039000000700650008c00001eaf0000413d000000000006004b00001eb10000613d000000000262022f00001eb10000013d000000700650008900000000026201cf00000b72022001970000007005500210000000000225019f00000b730220009a0000008006200210000000f00540027000007fff0050008c000021770000613d000000f00760027000007fff0070008c000021770000613d00000b720330019700000b750040009c00000b74033081c700000b720220019700000b750060009c00000b74022081c700000000023200aa00001ee70000613d000000010050008c000000010500a039000000010070008c000000010700a039000000000357001900000b760020009c00001ee90000813d00000b770020009c00001eeb0000213d00000b710020009c000000000502001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c000000010440203900001eec0000013d000000000400001900001f270000013d000000e10400003900001eec0000013d000000e00400003900000000053400190000406f0050008c0000000006000019000000000700001900001f120000a13d000040e00050008c00001efb0000413d0000c0dd0050008c00001f030000213d000000700340008c00001f0b0000213d00001f0c0000613d000000700340008900000000023201cf00001f0c0000013d000040700430008c00001f060000413d000000000004004b00001f100000613d00000000064201cf000000ff0040008c000000000600201900001f110000013d00000b7807000041000000000600001900001f120000013d0000407004300089000000000642022f00003f710030008c000000000600401900001f110000013d000000000232022f00000b7206200197000000700250021000000b790720009a00001f120000013d00000000060200190000000007000019000000000367019f000000700230027000007fff0220018f00003fff0020008c000000000400001900001f270000413d000000800430021000000b7a0040009c000021770000213d000040fe0020008c000021770000213d00000b720330019700000b74043001c70000406f0320008c00001f250000413d000000000003004b00001f270000613d00000000043401cf00001f270000013d0000406f02200089000000000424022f000900000004001d000000a102000039000000000202041a000000000008004b00001f4b0000613d00000b710080009c000000000108a0190000000003000039000000800300203900000b090010009c00000040033021bf000000400110227000000a900010009c00000020033021bf00000020011022700000ffff0010008c00000010033021bf0000001001102270000000ff0010008c000000080330203900000008011022700000000f0010008c00000004033020390000000401102270000000030010008c00000002033020390000000201102270000000010010008c0000000103302039000000700430008c00001f520000413d000000000004004b000000000108001900001f540000613d000000000148022f00001f540000013d00000000010000190000000003000019000000000002004b00001f5b0000c13d0000000004000019000000000500001900001f810000013d000000700130008900000000011801cf00000b72011001970000007003300210000000000113019f00000b730110009a0000008003100210000000000002004b00001f4f0000613d00000b710020009c000000000502001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700540008c00001f7a0000413d000000000005004b00001f7c0000613d000000000252022f00001f7c0000013d000000700540008900000000025201cf00000b72022001970000007004400210000000000224019f00000b730420009a0000008005400210000000f00230027000007fff0020008c000021770000613d000000f00650027000007fff0060008c000021770000613d00000b720110019700000b750030009c00000b74011081c700000b720340019700000b750050009c00000b74033081c700000000011300aa00001fb20000613d000000010020008c000000010200a039000000010060008c000000010600a039000000000226001900000b760010009c00001fb40000813d00000b770010009c00001fb60000213d00000b710010009c000000000401001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c000000010330203900001fb70000013d000000000300001900001ff20000013d000000e10300003900001fb70000013d000000e00300003900000000042300190000406f0040008c0000000005000019000000000600001900001fdd0000a13d000040e00040008c00001fc60000413d0000c0dd0040008c00001fce0000213d000000700230008c00001fd60000213d00001fd70000613d000000700230008900000000012101cf00001fd70000013d000040700320008c00001fd10000413d000000000003004b00001fdb0000613d00000000053101cf000000ff0030008c000000000500201900001fdc0000013d00000b7806000041000000000500001900001fdd0000013d0000407003200089000000000531022f00003f710020008c000000000500401900001fdc0000013d000000000121022f00000b7205100197000000700140021000000b790610009a00001fdd0000013d00000000050100190000000006000019000000000256019f000000700120027000007fff0110018f00003fff0010008c000000000300001900001ff20000413d000000800320021000000b7a0030009c000021770000213d000040fe0010008c000021770000213d00000b720220019700000b74032001c70000406f0210008c00001ff00000413d000000000002004b00001ff20000613d00000000032301cf00001ff20000013d0000406f01100089000000000313022f000500000003001d000700000009001d000400000008001d000000a401000039000000000101041a000600000001001d00000b1a01000041000000000010044300000000010004100000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f0000000100200190000021790000613d000000070200002900080b2200200132000000000101043b000000080010006c0000217a0000413d000000060100002900000af404100197000000000100041400000a900010009c00000a9001008041000000c00110021000000b800020009c000020140000213d0000000002040019000020180000013d00000b3c011001c70000800902000039000000080300002900000000050000192a392a2a0000040f000000600310027000000a9003300198000020410000613d0000001f0430003900000b42044001970000003f0440003900000b4304400197000000400500043d0000000004450019000000000054004b0000000006000039000000010600403900000b090040009c0000219f0000213d00000001006001900000219f0000c13d000000400040043f0000001f0430018f000000000635043600000af6053001980000000003560019000020340000613d000000000701034f000000007807043c0000000006860436000000000036004b000020300000c13d000000000004004b000020410000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000001002001900000218b0000613d000000a601000039000000000101041a000600000001001d00000b1a01000041000000000010044300000000010004100000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f0000000100200190000021790000613d0000000a0200002900070b2200200132000000000101043b000000070010006c0000217a0000413d000000060100002900000af404100197000000000100041400000a900010009c00000a9001008041000000c0011002100000000a0200002900000b800020009c000020630000213d0000000002040019000020670000013d00000b3c011001c70000800902000039000000070300002900000000050000192a392a2a0000040f000000600310027000000a9003300198000020900000613d0000001f0430003900000b42044001970000003f0440003900000b4304400197000000400500043d0000000004450019000000000054004b0000000006000039000000010600403900000b090040009c0000219f0000213d00000001006001900000219f0000c13d000000400040043f0000001f0430018f000000000635043600000af6053001980000000003560019000020830000613d000000000701034f000000007807043c0000000006860436000000000036004b0000207f0000c13d000000000004004b000020900000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000001002001900000218b0000613d000000a701000039000000000101041a000a00000001001d00000b1a01000041000000000010044300000000010004100000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f0000000100200190000021790000613d000000090200002900000b220320012a000000000101043b000000000031004b0000217a0000413d0000000a0100002900000af404100197000000000100041400000a900010009c00000a9001008041000000c001100210000000090200002900000b800020009c000600000003001d000020b30000213d0000000002040019000020b60000013d00000b3c011001c7000080090200003900000000050000192a392a2a0000040f000000600310027000000a9003300198000020df0000613d0000001f0430003900000b42044001970000003f0440003900000b4304400197000000400500043d0000000004450019000000000054004b0000000006000039000000010600403900000b090040009c0000219f0000213d00000001006001900000219f0000c13d000000400040043f0000001f0430018f000000000635043600000af6053001980000000003560019000020d20000613d000000000701034f000000007807043c0000000006860436000000000036004b000020ce0000c13d000000000004004b000020df0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000001002001900000218b0000613d000000a201000039000000000101041a00000b3802000041000000000020044300000af401100197000a00000001001d0000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f0000000100200190000021790000613d000000000101043b000000000001004b0000000502000029000021770000613d00000b220320012a000000400400043d00000b81010000410000000001140436000100000001001d00000a900040009c000900000004001d00000a900100004100000000010440190002004000100218000000000100041400000a900010009c00000a9001008041000000c00110021000000002011001af00000b800020009c000300000003001d0000210a0000213d00000af8011001c70000000a020000290000210e0000013d00000b82011001c700008009020000390000000a0400002900000000050000192a392a2a0000040f00000001002001900000000903000029000021ad0000613d00000b090030009c00000003020000290000219f0000213d000000400030043f0000006001300039000000000021043500000040013000390000000602000029000000000021043500000007010000290000000102000029000000000012043500000008010000290000000000130435000000000100041400000a900010009c00000a9001008041000000c00110021000000002011001af00000b0f011001c70000800d02000039000000010300003900000b83040000412a392a2a0000040f00000001002001900000000401000029000021770000613d0000000002000416000000000112004b000021760000a13d000a00000001001d00000b1a01000041000000000010044300000000010004100000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f0000000100200190000021790000613d000000000101043b0000000a03000029000000000031004b0000217a0000413d0000000001000411000000000200041400000af40410019700000a900020009c00000a9002008041000000c00120021000000b3c011001c7000080090200003900000000050000192a392a2a0000040f000000600310027000000a9003300198000021740000613d0000001f0430003900000b42044001970000003f0440003900000b4304400197000000400500043d0000000004450019000000000054004b0000000006000039000000010600403900000b090040009c0000219f0000213d00000001006001900000219f0000c13d000000400040043f0000001f0430018f000000000635043600000af6053001980000000003560019000021670000613d000000000701034f000000007807043c0000000006860436000000000036004b000021630000c13d000000000004004b000021740000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000001002001900000218b0000613d000000000001042d000000000100001900002a3b00010430000000000001042f000000400100043d000000440210003900000b7f03000041000000000032043500000024021000390000001d03000039000000000032043500000a9102000041000000000021043500000004021000390000002003000039000000000032043500000a900010009c00000a9001008041000000400110021000000b2a011001c700002a3b00010430000000400100043d000000640210003900000b7d030000410000000000320435000000440210003900000b7e03000041000000000032043500000024021000390000003a03000039000000000032043500000a9102000041000000000021043500000004021000390000002003000039000000000032043500000a900010009c00000a9001008041000000400110021000000b31011001c700002a3b0001043000000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000000400100043d00000b8402000041000000000021043500000a900010009c00000a9001008041000000400110021000000af8011001c700002a3b0001043000000060061002700000001f0460018f00000af605600198000000400200043d0000000003520019000021b90000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000021b50000c13d00000a9006600197000000000004004b000021c70000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000600160021000000a900020009c00000a90020080410000004002200210000000000121019f00002a3b0001043000080000000000020000009e02000039000000000602041a000000a102000039000000000202041a000000000002004b000021f30000613d00000b710020009c000000000402001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700430008c000021fb0000413d000000000004004b000021fd0000613d000000000242022f000021fd0000013d00000000020000190000000003000019000000000006004b000400000001001d000022050000c13d000000000100001900000000050000190000222b0000013d000000700430008900000000024201cf00000b72022001970000007003300210000000000223019f00000b730220009a0000008003200210000000000006004b000400000001001d000021f80000613d00000b710060009c000000000506001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700540008c000022240000413d000000000005004b000022260000613d000000000656022f000022260000013d000000700540008900000000065601cf00000b72016001970000007004400210000000000114019f00000b730110009a0000008005100210000000f00430027000007fff0040008c000029450000613d000000f00650027000007fff0060008c000029450000613d000000a007000039000000000707041a00000b720220019700000b750030009c00000b74022081c700000b720110019700000b750050009c00000b74011081c700000000012100aa0000225e0000613d000000010040008c000000010400a039000000010060008c000000010600a039000000000246001900000b760010009c000022600000813d00000b770010009c000022620000213d00000b710010009c000000000401001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000022630000013d00000000010000190000229e0000013d000000e103000039000022630000013d000000e00300003900000000042300190000406f0040008c00000000050000190000000006000019000022890000a13d000040e00040008c000022720000413d0000c0dd0040008c0000227a0000213d000000700230008c000022820000213d000022830000613d000000700230008900000000012101cf000022830000013d000040700320008c0000227d0000413d000000000003004b000022870000613d00000000053101cf000000ff0030008c0000000005002019000022880000013d00000b78060000410000000005000019000022890000013d0000407003200089000000000531022f00003f710020008c0000000005004019000022880000013d000000000121022f00000b7205100197000000700140021000000b790610009a000022890000013d00000000050100190000000006000019000000000356019f000000700130027000007fff0210018f00003fff0020008c00000000010000190000229e0000413d000000800130021000000b7a0010009c000029450000213d000040ff0020008c000029450000813d00000b720130019700000b74011001c70000406f0320008c0000229c0000413d000000000003004b0000229e0000613d00000000013101cf0000229e0000013d0000406f02200089000000000121022f00060b2200100132000000060070002a0000294e0000413d000800000007001d000000a201000039000000000101041a00000b1a02000041000000000020044300000af4011001970000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c70000800a020000392a392a2f0000040f00000001002001900000294d0000613d000000000101043b000500000001001d000000a301000039000000000201041a000000400300043d000700000003001d00000b6801000041000000000013043500000a900030009c00000a900100004100000000010340190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000af8011001c700000af4022001972a392a2f0000040f000000070b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000022d50000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000022d10000c13d000000000006004b000022e20000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000029540000613d0000001f01400039000000600110018f0000000004b10019000000000014004b0000000001000039000000010100403900000b090040009c0000000802000029000029470000213d0000000100100190000029470000c13d000000400040043f000000200030008c000029450000413d00000000010b0433000000050110006b0000294e0000413d00000006022000290000002403400039000000000023043500000b7b0200004100000000002404350000000402400039000000000012043500000a900040009c00000a900100004100000000010440190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b19011001c700000a8f02000041000800000004001d2a392a340000040f000000080b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000023190000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000023150000c13d000000000006004b000023260000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000029600000613d0000001f01400039000000600110018f0000000008b1001900000b090080009c000029470000213d000000400080043f000000200030008c000029450000413d00000000010b04330000000403000029000000000003004b000023590000613d00000b22023000d100000000033200d900000b220030009c0000294e0000c13d000000000002004b000023590000613d00000b710020009c000000000402001900000080044022700000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700430008c000023870000413d000000000004004b000023890000613d000000000242022f000023890000013d00000000040000190000000003000019000000000001004b000023900000613d00000b710010009c000000000501001900000080055022700000000002000039000000800200203900000b090050009c00000040022021bf000000400550227000000a900050009c00000020022021bf00000020055022700000ffff0050008c00000010022021bf0000001005502270000000ff0050008c000000080220203900000008055022700000000f0050008c00000004022020390000000405502270000000030050008c00000002022020390000000205502270000000010050008c0000000102202039000000700520008c0000237c0000413d000000000005004b0000237e0000613d000000000151022f0000237e0000013d000000700520008900000000015101cf000000f00220021000000b72011001970000008001100210000000000112019f00000b850610009a000000f00230027000007fff0020008c000023940000c13d000029450000013d000000700430008900000000024201cf00000b72022001970000007003300210000000000223019f00000b730420009a0000008003400210000000000001004b0000235d0000c13d0000000006000019000000f00230027000007fff0020008c000029450000613d000000f00160027000007fff0010008c0000239b0000c13d00000b8c0060019800000000040000190000243b0000613d000029450000013d000000000006004b000029450000613d000000800560027000000b720550019700000b750060009c00000b74055081c700000b7204400197000000010010008c000000010100a03900000b750030009c000023cd0000813d000000000004004b000023f90000613d00000b090040009c000000000204001900000040022022700000000003000039000000400300203900000a900020009c00000020033021bf00000020022022700000ffff0020008c00000010033021bf0000001002202270000000ff0020008c00000008033021bf00000008022022700000000f0020008c00000004033020390000000402202270000000030020008c00000002033020390000000202202270000000010600008a000000010020008c000000000600a0190000000002360049000000e20320003900000000033401cf000000000112001900000001020000390000007001100039000000000005004b000023d10000c13d00000b6901000041000000000010043f0000001201000039000000040010043f00000b6a0100004100002a3b00010430000000720340021000000b86033001c7000000000005004b000023c70000613d000000000035004b00000000040000190000243b0000213d00000000035300d900000b870030009c000029f00000a13d00000b880030009c000023df0000813d00000b890030009c000023fe0000213d00000b8a0030009c00000071040000390000007004004039000023ff0000013d00000b710030009c000000000503001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000023ff0000013d00000000030000190000000002000019000000000005004b000023d10000c13d000023c70000013d000000720400003900000000062400190000407105100039000000000056004b000024060000a13d00000b78070000410000000005000019000024260000013d00003ffc05600039000000000015004b00000000050000190000000007000019000024260000413d00003f8c05600039000000000015004b000024150000813d00003ffc04200039000000000014004b0000241d0000a13d000000000112004900003ffc0110003900000000051301cf000024210000013d000000700240008c0000000002004019000000000223022f0000000001160049000000700110021000000b8b0710009a00000b7205200197000024260000013d000024240000813d000000000121004900003ffc0110008a000000000513022f000000ff0010008c0000000005002019000024250000013d00000000050300190000000007000019000000000257019f000000700120027000007fff0110018f00003fff0010008c00000000040000190000243b0000413d000000800320021000000b7a0030009c000029450000213d000040fe0010008c000029450000213d00000b720220019700000b74042001c70000406f0210008c000024390000413d000000000002004b0000243b0000613d00000000042401cf0000243b0000013d0000406f01100089000000000414022f000700000004001d000000a201000039000000000201041a00000b1601000041000000000018043500000004018000390000000003000411000000000031043500000a900080009c00000a900100004100000000010840190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000b6a011001c700000af402200197000600000002001d000800000008001d2a392a2f0000040f000000080b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000024610000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000245d0000c13d000000000006004b0000246e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000007020000290000296c0000613d0000001f01400039000000600110018f0000000004b1001900000b090040009c000029470000213d000000400040043f000000200030008c000029450000413d00000000010b0433000000000021004b000029780000413d0000004401400039000000000021043500000b8d01000041000000000014043500000004014000390000000002000411000000000021043500000024014000390000000002000410000000000021043500000a900040009c00000a900100004100000000010440190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b2a011001c70000000602000029000800000004001d2a392a2a0000040f000000080b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000024a30000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000249f0000c13d000000000006004b000024b00000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000297f0000613d0000001f01400039000000600110018f0000000004b1001900000b090040009c000029470000213d000000400040043f000000200030008c000029450000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b000029450000c13d000000a201000039000000000201041a00000b1601000041000000000014043500000004014000390000000003000410000000000031043500000a900040009c00000a900100004100000000010440190000004001100210000000000300041400000a900030009c00000a9003008041000000c003300210000000000113019f00000b6a011001c700000af402200197000800000002001d000600000004001d2a392a2f0000040f000000060b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000024e50000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000024e10000c13d000000000006004b000024f20000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000000070a0000290000298b0000613d0000001f01400039000000600110018f0000000009b1001900000b090090009c000029470000213d000000400090043f000000200030008c000029450000413d00000000010b04330000000000a1004b000029970000413d000000ad01000039000000000201041a00000000000a004b0000008001a00270000025250000613d00000b7100a0009c00000000040a001900000000040120190000000003000039000000800300203900000b090040009c00000040033021bf000000400440227000000a900040009c00000020033021bf00000020044022700000ffff0040008c00000010033021bf0000001004402270000000ff0040008c000000080330203900000008044022700000000f0040008c00000004033020390000000404402270000000030040008c00000002033020390000000204402270000000010040008c0000000103302039000000700530008c0000252c0000413d000000000005004b00000000040a00190000252e0000613d00000000045a022f0000252e0000013d00000000030000190000000004000019000000000002004b000025350000c13d000000000200001900000000060000190000255b0000013d000000700430008900000000044a01cf00000b72044001970000007003300210000000000343019f00000b730330009a0000008004300210000000000002004b000025290000613d00000b710020009c000000000602001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c0000000105502039000000700650008c000025540000413d000000000006004b000025560000613d000000000262022f000025560000013d000000700650008900000000026201cf00000b72022001970000007005500210000000000225019f00000b730220009a0000008006200210000000f00540027000007fff0050008c000029450000613d000000f00760027000007fff0070008c000029450000613d00000b720330019700000b750040009c00000b74033081c700000b720220019700000b750060009c00000b74022081c700000000023200aa0000258c0000613d000000010050008c000000010500a039000000010070008c000000010700a039000000000357001900000b760020009c0000258e0000813d00000b770020009c000025900000213d00000b710020009c000000000502001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000025910000013d0000000002000019000025cc0000013d000000e104000039000025910000013d000000e00400003900000000053400190000406f0050008c00000000060000190000000007000019000025b70000a13d000040e00050008c000025a00000413d0000c0dd0050008c000025a80000213d000000700340008c000025b00000213d000025b10000613d000000700340008900000000023201cf000025b10000013d000040700430008c000025ab0000413d000000000004004b000025b50000613d00000000064201cf000000ff0040008c0000000006002019000025b60000013d00000b78070000410000000006000019000025b70000013d0000407004300089000000000642022f00003f710030008c0000000006004019000025b60000013d000000000232022f00000b7206200197000000700250021000000b790720009a000025b70000013d00000000060200190000000007000019000000000467019f000000700240027000007fff0320018f00003fff0030008c0000000002000019000025cc0000413d000000800240021000000b7a0020009c000029450000213d000040fe0030008c000029450000213d00000b720240019700000b74022001c70000406f0430008c000025ca0000413d000000000004004b000025cc0000613d00000000024201cf000025cc0000013d0000406f03300089000000000232022f000000ac03000039000000000303041a00000000000a004b000025f00000613d00000b7100a0009c00000000050a001900000000050120190000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700640008c000025f70000413d000000000006004b00000000050a0019000025f90000613d00000000056a022f000025f90000013d00000000040000190000000005000019000000000003004b000026000000c13d00000000030000190000000007000019000026260000013d000000700540008900000000055a01cf00000b72055001970000007004400210000000000454019f00000b730440009a0000008005400210000000000003004b000025f40000613d00000b710030009c000000000703001900000080077022700000000006000039000000800600203900000b090070009c00000040066021bf000000400770227000000a900070009c00000020066021bf00000020077022700000ffff0070008c00000010066021bf0000001007702270000000ff0070008c000000080660203900000008077022700000000f0070008c00000004066020390000000407702270000000030070008c00000002066020390000000207702270000000010070008c0000000106602039000000700760008c0000261f0000413d000000000007004b000026210000613d000000000373022f000026210000013d000000700760008900000000037301cf00000b72033001970000007006600210000000000336019f00000b730330009a0000008007300210000000f00650027000007fff0060008c000029450000613d000000f00870027000007fff0080008c000029450000613d00000b720440019700000b750050009c00000b74044081c700000b720330019700000b750070009c00000b74033081c700000000034300aa000026570000613d000000010060008c000000010600a039000000010080008c000000010800a039000000000468001900000b760030009c000026590000813d00000b770030009c0000265b0000213d00000b710030009c000000000603001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c00000001055020390000265c0000013d0000000008000019000026970000013d000000e1050000390000265c0000013d000000e00500003900000000064500190000406f0060008c00000000070000190000000008000019000026820000a13d000040e00060008c0000266b0000413d0000c0dd0060008c000026730000213d000000700450008c0000267b0000213d0000267c0000613d000000700450008900000000034301cf0000267c0000013d000040700540008c000026760000413d000000000005004b000026800000613d00000000075301cf000000ff0050008c0000000007002019000026810000013d00000b78080000410000000007000019000026820000013d0000407005400089000000000753022f00003f710040008c0000000007004019000026810000013d000000000343022f00000b7207300197000000700360021000000b790830009a000026820000013d00000000070300190000000008000019000000000478019f000000700340027000007fff0330018f00003fff0030008c0000000008000019000026970000413d000000800540021000000b7a0050009c000029450000213d000040fe0030008c000029450000213d00000b720440019700000b74084001c70000406f0430008c000026950000413d000000000004004b000026970000613d00000000084801cf000026970000013d0000406f03300089000000000838022f000000ab03000039000000000303041a00000000000a004b000026bb0000613d00000b7100a0009c00000000050a001900000000050120190000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000000700640008c000026c30000413d000000000006004b00000000050a0019000026c50000613d00000000056a022f000026c50000013d00000000040000190000000005000019000000000003004b000600000008001d000026cd0000c13d00000000030000190000000007000019000026f30000013d000000700540008900000000055a01cf00000b72055001970000007004400210000000000454019f00000b730440009a0000008005400210000000000003004b000600000008001d000026c00000613d00000b710030009c000000000703001900000080077022700000000006000039000000800600203900000b090070009c00000040066021bf000000400770227000000a900070009c00000020066021bf00000020077022700000ffff0070008c00000010066021bf0000001007702270000000ff0070008c000000080660203900000008077022700000000f0070008c00000004066020390000000407702270000000030070008c00000002066020390000000207702270000000010070008c0000000106602039000000700760008c000026ec0000413d000000000007004b000026ee0000613d000000000373022f000026ee0000013d000000700760008900000000037301cf00000b72033001970000007006600210000000000336019f00000b730330009a0000008007300210000000f00650027000007fff0060008c000029450000613d000000f00870027000007fff0080008c000029450000613d00000b720440019700000b750050009c00000b74044081c700000b720330019700000b750070009c00000b74033081c700000000034300aa000027240000613d000000010060008c000000010600a039000000010080008c000000010800a039000000000468001900000b760030009c000027260000813d00000b770030009c000027280000213d00000b710030009c000000000603001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c0000000105502039000027290000013d0000000007000019000027640000013d000000e105000039000027290000013d000000e00500003900000000064500190000406f0060008c000000000700001900000000080000190000274f0000a13d000040e00060008c000027380000413d0000c0dd0060008c000027400000213d000000700450008c000027480000213d000027490000613d000000700450008900000000034301cf000027490000013d000040700540008c000027430000413d000000000005004b0000274d0000613d00000000075301cf000000ff0050008c00000000070020190000274e0000013d00000b780800004100000000070000190000274f0000013d0000407005400089000000000753022f00003f710040008c00000000070040190000274e0000013d000000000343022f00000b7207300197000000700360021000000b790830009a0000274f0000013d00000000070300190000000008000019000000000478019f000000700340027000007fff0330018f00003fff0030008c0000000007000019000027640000413d000000800540021000000b7a0050009c000029450000213d000040fe0030008c000029450000213d00000b720440019700000b74074001c70000406f0430008c000027620000413d000000000004004b000027640000613d00000000074701cf000027640000013d0000406f03300089000000000737022f000000a103000039000000000303041a00000000000a004b000027860000613d00000b7100a0009c00000000010aa0190000000004000039000000800400203900000b090010009c00000040044021bf000000400110227000000a900010009c00000020044021bf00000020011022700000ffff0010008c00000010044021bf0000001001102270000000ff0010008c000000080440203900000008011022700000000f0010008c00000004044020390000000401102270000000030010008c00000002044020390000000201102270000000010010008c0000000104402039000000700140008c0000278e0000413d000000000001004b000027900000613d000000000a1a022f000027900000013d00000000010000190000000004000019000000000003004b000500000007001d000027980000c13d00000000050000190000000006000019000027be0000013d0000007001400089000000000a1a01cf00000b7201a001970000007004400210000000000114019f00000b730110009a0000008004100210000000000003004b000500000007001d0000278b0000613d00000b710030009c000000000603001900000080066022700000000005000039000000800500203900000b090060009c00000040055021bf000000400660227000000a900060009c00000020055021bf00000020066022700000ffff0060008c00000010055021bf0000001006602270000000ff0060008c000000080550203900000008066022700000000f0060008c00000004055020390000000406602270000000030060008c00000002055020390000000206602270000000010060008c0000000105502039000000700650008c000027b70000413d000000000006004b000027b90000613d000000000363022f000027b90000013d000000700650008900000000036301cf00000b72033001970000007005500210000000000335019f00000b730530009a0000008006500210000000f00340027000007fff0030008c000029450000613d000000f00760027000007fff0070008c000029450000613d00000b720110019700000b750040009c00000b74011081c700000b720450019700000b750060009c00000b74044081c700000000011400aa000027ef0000613d000000010030008c000000010300a039000000010070008c000000010700a039000000000337001900000b760010009c000027f10000813d00000b770010009c000027f30000213d00000b710010009c000000000501001900000080055022700000000004000039000000800400203900000b090050009c00000040044021bf000000400550227000000a900050009c00000020044021bf00000020055022700000ffff0050008c00000010044021bf0000001005502270000000ff0050008c000000080440203900000008055022700000000f0050008c00000004044020390000000405502270000000030050008c00000002044020390000000205502270000000010050008c0000000104402039000027f40000013d00000000040000190000282f0000013d000000e104000039000027f40000013d000000e00400003900000000053400190000406f0050008c000000000600001900000000070000190000281a0000a13d000040e00050008c000028030000413d0000c0dd0050008c0000280b0000213d000000700340008c000028130000213d000028140000613d000000700340008900000000013101cf000028140000013d000040700430008c0000280e0000413d000000000004004b000028180000613d00000000064101cf000000ff0040008c0000000006002019000028190000013d00000b780700004100000000060000190000281a0000013d0000407004300089000000000641022f00003f710030008c0000000006004019000028190000013d000000000131022f00000b7206100197000000700150021000000b790710009a0000281a0000013d00000000060100190000000007000019000000000367019f000000700130027000007fff0110018f00003fff0010008c00000000040000190000282f0000413d000000800430021000000b7a0040009c000029450000213d000040fe0010008c000029450000213d00000b720330019700000b74043001c70000406f0310008c0000282d0000413d000000000003004b0000282f0000613d00000000043401cf0000282f0000013d0000406f01100089000000000414022f000400000004001d00000b220320012a000000a401000039000000000101041a0000002402900039000300000003001d000000000032043500000b1802000041000000000029043500000af4011001970000000402900039000000000012043500000a900090009c00000a900100004100000000010940190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b19011001c70000000802000029000700000009001d2a392a2a0000040f000000070b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000028580000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000028540000c13d000000000006004b000028650000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000299e0000613d0000001f01400039000000600110018f0000000004b1001900000b090040009c000029470000213d000000400040043f000000200030008c000029450000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b000029450000c13d000000060100002900000b220310012a000000a601000039000000000101041a0000002402400039000600000003001d000000000032043500000b1802000041000000000024043500000af4011001970000000402400039000000000012043500000a900040009c00000a900100004100000000010440190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b19011001c70000000802000029000700000004001d2a392a2a0000040f000000070b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b00190000289e0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000289a0000c13d000000000006004b000028ab0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000029aa0000613d0000001f01400039000000600110018f0000000004b1001900000b090040009c000029470000213d000000400040043f000000200030008c000029450000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b000029450000c13d000000050100002900000b220310012a000000a701000039000000000101041a0000002402400039000500000003001d000000000032043500000b1802000041000000000024043500000af4011001970000000402400039000000000012043500000a900040009c00000a900100004100000000010440190000004001100210000000000200041400000a900020009c00000a9002008041000000c002200210000000000121019f00000b19011001c70000000802000029000700000004001d2a392a2a0000040f000000070b000029000000600310027000000a9003300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000028e40000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000028e00000c13d000000000006004b000028f10000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000029b60000613d0000001f01400039000000600110018f0000000001b1001900000b090010009c000029470000213d000000400010043f000000200030008c000029450000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b000029450000c13d00000b3801000041000000000010044300000008010000290000000400100443000000000100041400000a900010009c00000a9001008041000000c00110021000000b1b011001c700008002020000392a392a2f0000040f00000001002001900000294d0000613d000000000101043b000000000001004b000029450000613d000000040100002900000b220310012a000000400200043d00000b8e010000410000000001120436000100000001001d0000000401200039000200000003001d000000000031043500000a900020009c000700000002001d00000a900100004100000000010240190004004000100218000000000100041400000a900010009c00000a9001008041000000c00110021000000004011001af00000b6a011001c700000008020000292a392a2a0000040f0000000100200190000029d40000613d000000070300002900000b090030009c000029470000213d000000400030043f00000060013000390000000202000029000000000021043500000040013000390000000502000029000000000021043500000006010000290000000102000029000000000012043500000003010000290000000000130435000000000100041400000a900010009c00000a9001008041000000c00110021000000004011001af00000b0f011001c70000800d02000039000000010300003900000b8f040000412a392a2a0000040f0000000100200190000029450000613d000000000001042d000000000100001900002a3b0001043000000b6901000041000000000010043f0000004101000039000000040010043f00000b6a0100004100002a3b00010430000000000001042f00000b6901000041000000000010043f0000001101000039000000040010043f00000b6a0100004100002a3b000104300000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000295b0000c13d000029c10000013d0000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029670000c13d000029c10000013d0000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029730000c13d000029c10000013d00000b9001000041000000000014043500000a900040009c00000a9004008041000000400140021000000af8011001c700002a3b000104300000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029860000c13d000029c10000013d0000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029920000c13d000029c10000013d00000b9001000041000000000019043500000a900090009c00000a9009008041000000400190021000000af8011001c700002a3b000104300000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029a50000c13d000029c10000013d0000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029b10000c13d000029c10000013d0000001f0530018f00000af606300198000000400200043d0000000004620019000029c10000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000029bd0000c13d000000000005004b000029ce0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000a900020009c00000a90020080410000004002200210000000000112019f00002a3b0001043000000060061002700000001f0460018f00000af605600198000000400200043d0000000003520019000029e00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000029dc0000c13d00000a9006600197000000000004004b000029ee0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000029cf0000013d00000b6901000041000000000010043f0000000101000039000000040010043f00000b6a0100004100002a3b00010430000000000001042f00000a900010009c00000a9001008041000000400110021000000a900020009c00000a90020080410000006002200210000000000112019f000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b3c011001c700008010020000392a392a2f0000040f000000010020019000002a0a0000613d000000000101043b000000000001042d000000000100001900002a3b0001043000000000050100190000000000200443000000050030008c00002a1a0000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b00002a120000413d00000a900030009c00000a90030080410000006001300210000000000200041400000a900020009c00000a9002008041000000c002200210000000000112019f00000b91011001c700000000020500192a392a2f0000040f000000010020019000002a290000613d000000000101043b000000000001042d000000000001042f00002a2d002104210000000102000039000000000001042d0000000002000019000000000001042d00002a32002104230000000102000039000000000001042d0000000002000019000000000001042d00002a37002104250000000102000039000000000001042d0000000002000019000000000001042d00002a390000043200002a3a0001042e00002a3b000104300000000000000000000000004d036202f75b8ed506cea871095227b4b0a0ef1100000000000000000000000000000000000000000000000000000000ffffffff08c379a000000000000000000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320696e697469616c697a696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084000000a000000000000000000200000000000000000000000000000000000020000000a000000000000000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249800000002000000000000000000000000000000800000010000000000000000000000000000000000000000000000000000000000000000000000000082de825200000000000000000000000000000000000000000000000000000000aea60aa300000000000000000000000000000000000000000000000000000000da7117bd00000000000000000000000000000000000000000000000000000000eccee64100000000000000000000000000000000000000000000000000000000f72c0d8a00000000000000000000000000000000000000000000000000000000f72c0d8b00000000000000000000000000000000000000000000000000000000f942922e00000000000000000000000000000000000000000000000000000000eccee64200000000000000000000000000000000000000000000000000000000f100600900000000000000000000000000000000000000000000000000000000e53c8e9600000000000000000000000000000000000000000000000000000000e53c8e9700000000000000000000000000000000000000000000000000000000e8d4b33c00000000000000000000000000000000000000000000000000000000da7117be00000000000000000000000000000000000000000000000000000000e22f729800000000000000000000000000000000000000000000000000000000c0b2b03d00000000000000000000000000000000000000000000000000000000c98e050200000000000000000000000000000000000000000000000000000000c98e050300000000000000000000000000000000000000000000000000000000d42d803000000000000000000000000000000000000000000000000000000000c0b2b03e00000000000000000000000000000000000000000000000000000000c2bcf23600000000000000000000000000000000000000000000000000000000b8cc5f8500000000000000000000000000000000000000000000000000000000b8cc5f8600000000000000000000000000000000000000000000000000000000bba0485200000000000000000000000000000000000000000000000000000000aea60aa400000000000000000000000000000000000000000000000000000000b68270ac000000000000000000000000000000000000000000000000000000009974c94f00000000000000000000000000000000000000000000000000000000a5effdbd00000000000000000000000000000000000000000000000000000000a791f5bd00000000000000000000000000000000000000000000000000000000a791f5be00000000000000000000000000000000000000000000000000000000ad3ad0ee00000000000000000000000000000000000000000000000000000000a5effdbe00000000000000000000000000000000000000000000000000000000a6f66727000000000000000000000000000000000000000000000000000000009a884a47000000000000000000000000000000000000000000000000000000009a884a4800000000000000000000000000000000000000000000000000000000a1ad607f000000000000000000000000000000000000000000000000000000009974c9500000000000000000000000000000000000000000000000000000000099fbfd3f00000000000000000000000000000000000000000000000000000000920e197c0000000000000000000000000000000000000000000000000000000093399379000000000000000000000000000000000000000000000000000000009339937a00000000000000000000000000000000000000000000000000000000975d97c100000000000000000000000000000000000000000000000000000000920e197d000000000000000000000000000000000000000000000000000000009307c1e60000000000000000000000000000000000000000000000000000000082de82530000000000000000000000000000000000000000000000000000000084439e5e000000000000000000000000000000000000000000000000000000008946f50f000000000000000000000000000000000000000000000000000000003ee543fd0000000000000000000000000000000000000000000000000000000054fd4d4f000000000000000000000000000000000000000000000000000000006e498698000000000000000000000000000000000000000000000000000000007aadef8a000000000000000000000000000000000000000000000000000000007aadef8b0000000000000000000000000000000000000000000000000000000080815c6c000000000000000000000000000000000000000000000000000000006e49869900000000000000000000000000000000000000000000000000000000724a7a4b0000000000000000000000000000000000000000000000000000000067de48030000000000000000000000000000000000000000000000000000000067de4804000000000000000000000000000000000000000000000000000000006d1600690000000000000000000000000000000000000000000000000000000054fd4d50000000000000000000000000000000000000000000000000000000005554648400000000000000000000000000000000000000000000000000000000507dd46700000000000000000000000000000000000000000000000000000000510dbd9800000000000000000000000000000000000000000000000000000000510dbd990000000000000000000000000000000000000000000000000000000052d1902d00000000000000000000000000000000000000000000000000000000507dd4680000000000000000000000000000000000000000000000000000000050f3b823000000000000000000000000000000000000000000000000000000004f1ef285000000000000000000000000000000000000000000000000000000004f1ef286000000000000000000000000000000000000000000000000000000004fd6a7ce000000000000000000000000000000000000000000000000000000003ee543fe000000000000000000000000000000000000000000000000000000004a510d950000000000000000000000000000000000000000000000000000000032cc4dc60000000000000000000000000000000000000000000000000000000038fbf2c5000000000000000000000000000000000000000000000000000000003a1f3e19000000000000000000000000000000000000000000000000000000003a1f3e1a000000000000000000000000000000000000000000000000000000003bb2620d0000000000000000000000000000000000000000000000000000000038fbf2c60000000000000000000000000000000000000000000000000000000039bd22ae000000000000000000000000000000000000000000000000000000003659cfe5000000000000000000000000000000000000000000000000000000003659cfe6000000000000000000000000000000000000000000000000000000003748c6720000000000000000000000000000000000000000000000000000000032cc4dc7000000000000000000000000000000000000000000000000000000003587647600000000000000000000000000000000000000000000000000000000097548e2000000000000000000000000000000000000000000000000000000001fe6189d000000000000000000000000000000000000000000000000000000001fe6189e00000000000000000000000000000000000000000000000000000000300752fc00000000000000000000000000000000000000000000000000000000097548e300000000000000000000000000000000000000000000000000000000136f653400000000000000000000000000000000000000000000000000000000028426b60000000000000000000000000000000000000000000000000000000007bce0cd0000000000000000000000000000000000000000000000000000000007ff0df3055ad42e00000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000400000080000000000000000000000000000000000000000000000000000000000000000000000000ffffffe07c8c4c98000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000020000000000000000000000000000000000004000000000000000000000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff1f00000000000000000000000000000000000000000000ffffffffffffffffffff796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d9553913202000002000000000000000000000000000000040000000000000000000000000200000000000000000000000000000000000060000000000000000000000000f95a8d7847b8929ff291b705a64aa5db59416254718b1d78369e5b0aa0a5d091189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3000000000000000000000000000000000000002000000080000000000000000002000000000000000000000000000000000000200000008000000000000000001379798179fb49632c5c1c722d26fe4f1c311e264105a6c32618086c3d6a5634913bccdb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000800000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000200000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff00000000000000000000000000000000000000e00000008000000000000000002b2c871e00000000000000000000000000000000000000000000000000000000ffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffff0000000000000000000000000000000000000000ffff00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000800000000000000000000000001d3d0d37d4ba0064f28552027926937e9264bf0faf54a88d24c54bfd52bc109800000000000000000000000000000000000000200000000000000000000000005265656e7472616e637947756172643a207265656e7472616e742063616c6c000000000000000000000000000000000000000064000000800000000000000000fca50d804ff3fe9758c5dd27752a168e99c00aece0d965f47d60519377a4c8358d34a0e80000000000000000000000000000000000000000000000000000000070a08231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000800000000000000000a9059cbb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f3902000002000000000000000000000000000000240000000000000000000000009ac58899000000000000000000000000000000000000000000000000000000005bb8e37e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000bbf81e005342ace400000000000000000000000000000000000000000000000000000000ff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000de0b6b3a76400000200000000000000000000000000000000000080000000800000000000000000aa072bdf65f470d4cddd476d32ebda7060c64a4935db12d33420d4ce700c53497dbb76c200000000000000000000000000000000000000000000000000000000ba2f13fa0000000000000000000000000000000000000000000000000000000076d41cd05f36b0de5f19b24db7cc6a9dca49440f8df94aeb31a07de1698f787d000000000000000000000000000000000000000000000000fffffffffffffedff59e295d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000312e302e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e02000002000000000000000000000000000000440000000000000000000000006c6564207468726f7567682064656c656761746563616c6c0000000000000000555550535570677261646561626c653a206d757374206e6f742062652063616c0000000000000000000000000000000000000084000000000000000000000000360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcfad3ba5100000000000000000000000000000000000000000000000000000000a00c4d9000000000000000000000000000000000000000000000000000000000c027d19600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91431806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8352d1902d000000000000000000000000000000000000000000000000000000006961626c6555554944000000000000000000000000000000000000000000000045524331393637557067726164653a20756e737570706f727465642070726f780200000000000000000000000000000000000000000000000000000000000000bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b000000000000000000000000000000000000000000000000ffffffffffffff9f206661696c656400000000000000000000000000000000000000000000000000416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c0000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000003ffffffe0a65e9ba800000000000000000000000000000000000000000000000000000000053a207400000000000000000000000000000000000000000000000000000000ecbe3a240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000006163746976652070726f7879000000000000000000000000000000000000000046756e6374696f6e206d7573742062652063616c6c6564207468726f75676820000000000000000000000000000000000000000000000000ffffffffffffffdf6f6e206973206e6f74205555505300000000000000000000000000000000000045524331393637557067726164653a206e657720696d706c656d656e74617469416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006f74206120636f6e747261637400000000000000000000000000000000000000455243313936373a206e657720696d706c656d656e746174696f6e206973206e64656c656761746563616c6c0000000000000000000000000000000000000000647920696e697469616c697a6564000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e747261637420697320616c726561ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000214e8348c4f0000000000000000000000000000000000000000000000000000010a741a462780000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000007facf7419d98000000000000000000000000000000000000000000000000000004547258d1ec0000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000eff1000000000000000000000000000000000000000000000000000000000001e1338000000000000000000000000000000000000000000000000000000000004f1a006e697469616c697a696e67000000000000000000000000000000000000000000496e697469616c697a61626c653a20636f6e7472616374206973206e6f7420697884df6500000000000000000000000000000000000000000000000000000000bf61eea20000000000000000000000000000000000000000000000000000000062a3d19b00000000000000000000000000000000000000000000000000000000b9ab6a390000000000000000000000000000000000000000000000000000000023619a5c00000000000000000000000000000000000000000000000000000000bcdd2ff3000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff80ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff000000000000000000000000000000000000000000000000ffffffffffffff20000000000000000000000000000000000000000000000000fffffffffffffee000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000040df00000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff13d1aa2e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001517f6563697069656e74206d61792068617665207265766572746564000000000000416464726573733a20756e61626c6520746f2073656e642076616c75652c2072416464726573733a20696e73756666696369656e742062616c616e63650000000000000000000000000000000000000000000000000000000de0b6b3a763ffff8d415202000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000004000000000000000000000000a256052d4810d1182d5bb39e0cd5d0e15ea58b7f2b7efb83be4bd2764b925a794117cf6c00000000000000000000000000000000000000000000000000000000c00100000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffff0000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffff0000000000000000000000000000000000020000000000000000000000000000ffffffffffffffffffffffffffffffffc07300000000000000000000000000000000ffffffffffffffffffffffffffff0000000000000000000000000000000023b872dd0000000000000000000000000000000000000000000000000000000042966c6800000000000000000000000000000000000000000000000000000000ea0cafed56f1a1cecc577e143829c729982bc7c6aba95c5d6962a5cc2a60fe532df103110000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000000000000000000000000000005453cd1bbd0f2c50bd6b4c59e05835ded946555d8c740d328766505382848a50
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.